Skip to content

Commit

Permalink
Fix UnitaryGate.qasm() with unused qubits (Qiskit#8234)
Browse files Browse the repository at this point in the history
The OpenQASM 2 exporter has a special case for providing `gate`
definitions, which was implemented purely for `UnitaryGate`.  This is
stateful per instruction, and does not generally behave well with the
rest of the exporter.  This commit fixes one misbehaviour: the way the
qubit operands for the definition was calculated was unreliable in both
order and number of qubits, if any of the qubits were unaffected by
the gate operation.

Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
  • Loading branch information
jakelishman and mergify[bot] authored Jun 24, 2022
1 parent ebf800a commit 8d5e3ca
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 12 deletions.
15 changes: 3 additions & 12 deletions qiskit/extensions/unitary.py
Original file line number Diff line number Diff line change
Expand Up @@ -191,22 +191,13 @@ def qasm(self):
_qasm_escape_gate_name(self.label) if self.label else "unitary" + str(id(self))
)

# map from gates in the definition to params in the method
bit_to_qasm = OrderedDict()
current_bit = 0

qubit_to_qasm = {bit: f"p{i}" for i, bit in enumerate(self.definition.qubits)}
gates_def = ""
for instruction in self.definition.data:

# add bits from this gate to the overall set of params
for bit in instruction.qubits + instruction.clbits:
if bit not in bit_to_qasm:
bit_to_qasm[bit] = "p" + str(current_bit)
current_bit += 1

curr_gate = "\t{} {};\n".format(
instruction.operation.qasm(),
",".join([bit_to_qasm[j] for j in instruction.qubits + instruction.clbits]),
",".join(qubit_to_qasm[qubit] for qubit in instruction.qubits),
)
gates_def += curr_gate

Expand All @@ -215,7 +206,7 @@ def qasm(self):
"gate "
+ self._qasm_name
+ " "
+ ",".join(bit_to_qasm.values())
+ ",".join(qubit_to_qasm[qubit] for qubit in self.definition.qubits)
+ " {\n"
+ gates_def
+ "}"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
fixes:
- |
The OpenQASM 2 exporter (:meth:`.QuantumCircuit.qasm`) will now correctly
define the qubit parameters for :class:`.UnitaryGate` operations that do
not affect all the qubits they are defined over.
Fixed `#8224 <https://github.com/Qiskit/qiskit-terra/issues/8224>`__.
14 changes: 14 additions & 0 deletions test/python/circuit/test_unitary.py
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,20 @@ def test_qasm_2q_unitary(self):
)
self.assertEqual(expected_qasm, qc.qasm())

def test_qasm_unitary_noop(self):
"""Test that an identifier unitary can be converted to OpenQASM 2"""
qc = QuantumCircuit(QuantumRegister(3, "q0"))
qc.unitary(numpy.eye(8), qc.qubits, label="unitary_identity")
expected_qasm = (
"OPENQASM 2.0;\n"
'include "qelib1.inc";\n'
"gate unitary_identity p0,p1,p2 {\n"
"}\n"
"qreg q0[3];\n"
"unitary_identity q0[0],q0[1],q0[2];\n"
)
self.assertEqual(expected_qasm, qc.qasm())

def test_unitary_decomposition(self):
"""Test decomposition for unitary gates over 2 qubits."""
qc = QuantumCircuit(3)
Expand Down

0 comments on commit 8d5e3ca

Please sign in to comment.