Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add qubit_subset option to BIPMapping pass #6756

Merged
merged 7 commits into from
Jul 20, 2021
Merged

Add qubit_subset option to BIPMapping pass #6756

merged 7 commits into from
Jul 20, 2021

Conversation

itoko
Copy link
Contributor

@itoko itoko commented Jul 16, 2021

Summary

Add qubit_subset option to BIPMapping pass to provide an easier way to specify physical qubits to be used in mapping.

Details and comments

Current BIP mapper (added at #6580) requires users to supply a reduced coupling map which contains only the physical qubits to be used. That means it requires users to embed the circuit mapped on a reduced coupling map to the original coupling map as postprocessing. This seems a bit demanding. In addition, it also requires users to track virtual qubits -> qubits on reduced coupling map -> physical qubits and update circuit._layout by themselves to print the resulting circuit correctly.

This PR enables to do the above things in one stop (without requiring postprocessing). It can be done by supplying qubit_subset with the original coupling map (reported by the backend). Users don't need to supply reduced coupling map any longer for specifying physical qubits to be used.

For example, suppose the following mapping,

circ = QuantumCircuit(3)
circ.cx(0, 1)
circ.cx(1, 2)
circ.cx(0, 2)
circ.measure_all()

qubit_to_use = [1, 3, 4]
coupling_map = CouplingMap([[0, 1], [1, 2], [1, 3], [3, 4]])

After this PR: The new qubit_subset option enables us to obtain the printable mapped circuit by one line:

transpiled = BIPMapping(coupling_map, qubit_subset=qubit_to_use)(circ)
print(transpiled)
ancilla_0 -> 0 ──────────────────────────────
                    ┌───┐         ░    ┌─┐   
      q_2 -> 1 ─────┤ X ├─X───────░────┤M├───
                    └─┬─┘ │       ░    └╥┘   
ancilla_1 -> 2 ───────┼───┼─────────────╫────
               ┌───┐  │   │ ┌───┐ ░     ║ ┌─┐
      q_1 -> 3 ┤ X ├──■───X─┤ X ├─░─────╫─┤M├
               └─┬─┘        └─┬─┘ ░ ┌─┐ ║ └╥┘
      q_0 -> 4 ──■────────────■───░─┤M├─╫──╫─
                                  ░ └╥┘ ║  ║ 
       meas: 3/══════════════════════╩══╩══╩═
                                     0  1  2 

Before this PR: The current interface requires dozens of lines to obtain the same mapped circuit:

reduced_coupling = coupling_map.reduce(qubit_to_use)  # == CouplingMap([[0, 1], [1, 2]])
transpiled = BIPMapping(reduced_coupling)(circ)

# fill layout with ancilla qubits
def fill_with_ancilla(layout):
    idle_physical_qubits = [q for q in range(coupling_map.size()) if q not in layout.get_physical_bits()]
    if idle_physical_qubits:
        qreg = QuantumRegister(len(idle_physical_qubits), name="ancilla")
        for idx, idle_q in enumerate(idle_physical_qubits):
            layout[idle_q] = qreg[idx]
        layout.add_register(qreg)
    return layout

# recover dag on original coupling map
layout = Layout({q: qubit_to_use[i] for i, q in enumerate(transpiled.qubits)})
for reg in transpiled.qregs:
    layout.add_register(reg)
property_set = {"layout": fill_with_ancilla(layout)}
recovered = ApplyLayout()(transpiled, property_set)

# recover layout
overall_layout = Layout({v: qubit_to_use[q] for v, q in transpiled._layout.get_virtual_bits().items()})
for reg in transpiled.qregs:
    overall_layout.add_register(reg)
recovered._layout = fill_with_ancilla(overall_layout)
print("recovered:", recovered)

Alternatives considered

  • Accept PartialCouplingMap instead of CouplingMap
    CouplingMap class does not accept "holes" in physical qubits. So we may need to introduce another coupling class to allow holes in physical qubits, say PartialCouplingMap. However, PartialCouplingMap would be more likely to be a utility class for pass developers rather than interface class for pass users.

@itoko itoko added the Changelog: New Feature Include in the "Added" section of the changelog label Jul 16, 2021
Copy link
Member

@ajavadia ajavadia left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the approach looks good. And I agree with the mapping of qubits in the global_coupling_map and coupling_map to exist in BIPModel, so it can reason about physical error rates.

qiskit/transpiler/passes/routing/bip_mapping.py Outdated Show resolved Hide resolved
if self.global_qubit is None:
self.global_qubit = list(range(self.coupling_map.size()))
else:
self.coupling_map = self.coupling_map.reduce(self.global_qubit)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is the difference between .reduce() and .subgraph() methods here?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#6738 fixes a bug on .subgraph() btw

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

subgraph() does not retain the order of passed qubits while reduce() does. For example (copied from #6736 (comment)),

coupling = CouplingMap.from_line(6, bidirectional=False)
list(coupling.subgraph([4, 2, 3, 5]).get_edges())
>>> [(0, 1), (1, 2), (2, 3)]
list(coupling.reduce([4, 2, 3, 5]).get_edges())
>>> [(1, 2), (2, 0), (0, 3)]

We need the map from reduced qubits (in coupling_map) to global qubits (in global_coupling_map) to recover the global qubits from reduced qubits. Using reduce(), the map can be naturally represented as the list qubit_subset (and that's why the type of qubit_subset is list (not set) here).

@itoko itoko marked this pull request as ready for review July 19, 2021 09:33
@itoko itoko requested review from manoelmarques, woodsp-ibm and a team as code owners July 19, 2021 09:33
Copy link
Member

@ajavadia ajavadia left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks good, and I'm happy that the pass doesn't call the 3 embedding stages now.

@ajavadia ajavadia merged commit 986d542 into Qiskit:main Jul 20, 2021
@itoko itoko deleted the upgrade-bip-mapper-interface branch July 27, 2021 01:10
@kdk kdk added this to the 0.19 milestone Nov 15, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Changelog: New Feature Include in the "Added" section of the changelog
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants