Skip to content

Commit

Permalink
Reduce use of legacy CircuitInstruction formats (#10416)
Browse files Browse the repository at this point in the history
This removes (as best as our test suite touches) all uses of the
implicit legacy tuple form of `CircuitInstruction` that have crept in
since ea02667 (gh-8093).  The changes are largely just mechanical over
to the new form.
  • Loading branch information
jakelishman authored Jul 12, 2023
1 parent 9f84f26 commit e2674ce
Show file tree
Hide file tree
Showing 9 changed files with 69 additions and 59 deletions.
4 changes: 2 additions & 2 deletions qiskit/algorithms/gradients/reverse/derive_circuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,8 @@ def derive_circuit(

summands, op_context = [], []
for i, op in enumerate(circuit.data):
gate = op[0]
op_context += [op[1:]]
gate = op.operation
op_context.append((op.qubits, op.clbits))
if parameter in gate.params:
coeffs_and_grads = gradient_lookup(gate)
summands += [coeffs_and_grads]
Expand Down
2 changes: 1 addition & 1 deletion qiskit/algorithms/gradients/reverse/split_circuits.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ def split(
if isinstance(param, ParameterExpression) and len(param.parameters) > 0
]
else:
if inst[0].definition is not None:
if inst.operation.definition is not None:
free_inst_params = inst.operation.definition.parameters
else:
free_inst_params = {}
Expand Down
56 changes: 32 additions & 24 deletions qiskit/algorithms/gradients/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,13 +126,13 @@ def _make_lin_comb_gradient_circuit(
circuit_temp.data.insert(1, circuit_temp.data.pop())

lin_comb_circuits = {}
for i, (inst, qregs, _) in enumerate(circuit_temp.data):
if inst.is_parameterized():
for p in inst.params[0].parameters:
gate = _gate_gradient(inst)
for i, instruction in enumerate(circuit_temp.data):
if instruction.operation.is_parameterized():
for p in instruction.operation.params[0].parameters:
gate = _gate_gradient(instruction.operation)
lin_comb_circuit = circuit_temp.copy()
# insert `gate` to i-th position
lin_comb_circuit.append(gate, [qr_aux[0]] + qregs, [])
lin_comb_circuit.append(gate, [qr_aux[0]] + list(instruction.qubits), [])
lin_comb_circuit.data.insert(i, lin_comb_circuit.data.pop())
lin_comb_circuit.h(qr_aux)
if add_measurement:
Expand Down Expand Up @@ -192,44 +192,52 @@ def _make_lin_comb_qgt_circuit(
circuit_temp.data.insert(0, circuit_temp.data.pop())

lin_comb_qgt_circuits = {}
for i, (inst_i, qregs_i, _) in enumerate(circuit_temp.data):
if not inst_i.is_parameterized():
for i, instruction_i in enumerate(circuit_temp.data):
if not instruction_i.operation.is_parameterized():
continue
for j, (inst_j, qregs_j, _) in enumerate(circuit_temp.data):
if not inst_j.is_parameterized():
for j, instruction_j in enumerate(circuit_temp.data):
if not instruction_j.operation.is_parameterized():
continue
# Calculate the QGT of the i-th gate with respect to the j-th gate.
param_i = inst_i.params[0]
param_j = inst_j.params[0]
param_i = instruction_i.operation.params[0]
param_j = instruction_j.operation.params[0]

for p_i in param_i.parameters:
for p_j in param_j.parameters:
if circuit_temp.parameters.data.index(p_i) > circuit_temp.parameters.data.index(
p_j
):
continue
gate_i = _gate_gradient(inst_i)
gate_j = _gate_gradient(inst_j)
gate_i = _gate_gradient(instruction_i.operation)
gate_j = _gate_gradient(instruction_j.operation)
lin_comb_qgt_circuit = circuit_temp.copy()
if i < j:
# insert gate_j to j-th position
lin_comb_qgt_circuit.append(gate_j, [qr_aux[0]] + qregs_j, [])
lin_comb_qgt_circuit.append(
gate_j, [qr_aux[0]] + list(instruction_j.qubits), []
)
lin_comb_qgt_circuit.data.insert(j, lin_comb_qgt_circuit.data.pop())
# insert gate_i to i-th position with two X gates at its sides
lin_comb_qgt_circuit.append(XGate(), [qr_aux[0]], [])
lin_comb_qgt_circuit.data.insert(i, lin_comb_qgt_circuit.data.pop())
lin_comb_qgt_circuit.append(gate_i, [qr_aux[0]] + qregs_i, [])
lin_comb_qgt_circuit.append(
gate_i, [qr_aux[0]] + list(instruction_i.qubits), []
)
lin_comb_qgt_circuit.data.insert(i, lin_comb_qgt_circuit.data.pop())
lin_comb_qgt_circuit.append(XGate(), [qr_aux[0]], [])
lin_comb_qgt_circuit.data.insert(i, lin_comb_qgt_circuit.data.pop())
else:
# insert gate_i to i-th position
lin_comb_qgt_circuit.append(gate_i, [qr_aux[0]] + qregs_i, [])
lin_comb_qgt_circuit.append(
gate_i, [qr_aux[0]] + list(instruction_i.qubits), []
)
lin_comb_qgt_circuit.data.insert(i, lin_comb_qgt_circuit.data.pop())
# insert gate_j to j-th position with two X gates at its sides
lin_comb_qgt_circuit.append(XGate(), [qr_aux[0]], [])
lin_comb_qgt_circuit.data.insert(j, lin_comb_qgt_circuit.data.pop())
lin_comb_qgt_circuit.append(gate_j, [qr_aux[0]] + qregs_j, [])
lin_comb_qgt_circuit.append(
gate_j, [qr_aux[0]] + list(instruction_j.qubits), []
)
lin_comb_qgt_circuit.data.insert(j, lin_comb_qgt_circuit.data.pop())
lin_comb_qgt_circuit.append(XGate(), [qr_aux[0]], [])
lin_comb_qgt_circuit.data.insert(j, lin_comb_qgt_circuit.data.pop())
Expand Down Expand Up @@ -290,18 +298,18 @@ def _assign_unique_parameters(
parameter_map = defaultdict(list)
gradient_parameter_map = {}
num_gradient_parameters = 0
for instruction, qargs, cargs in circuit.data:
if instruction.is_parameterized():
new_inst_params = []
for angle in instruction.params:
for instruction in circuit.data:
if instruction.operation.is_parameterized():
new_op_params = []
for angle in instruction.operation.params:
new_parameter = Parameter(f"__gθ{num_gradient_parameters}")
new_inst_params.append(new_parameter)
new_op_params.append(new_parameter)
num_gradient_parameters += 1
for parameter in angle.parameters:
parameter_map[parameter].append((new_parameter, angle.gradient(parameter)))
gradient_parameter_map[new_parameter] = angle
instruction.params = new_inst_params
gradient_circuit.append(instruction, qargs, cargs)
instruction.operation.params = new_op_params
gradient_circuit.append(instruction.operation, instruction.qubits, instruction.clbits)
# For the global phase
gradient_circuit.global_phase = circuit.global_phase
if isinstance(gradient_circuit.global_phase, ParameterExpression):
Expand Down
11 changes: 5 additions & 6 deletions qiskit/circuit/quantumcircuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -441,22 +441,21 @@ def calibrations(self, calibrations: dict):
"""
self._calibrations = defaultdict(dict, calibrations)

def has_calibration_for(self, instr_context: tuple):
def has_calibration_for(self, instruction: CircuitInstruction):
"""Return True if the circuit has a calibration defined for the instruction context. In this
case, the operation does not need to be translated to the device basis.
"""
instr, qargs, _ = instr_context
if not self.calibrations or instr.name not in self.calibrations:
if not self.calibrations or instruction.operation.name not in self.calibrations:
return False
qubits = tuple(self.qubits.index(qubit) for qubit in qargs)
qubits = tuple(self.qubits.index(qubit) for qubit in instruction.qubits)
params = []
for p in instr.params:
for p in instruction.operation.params:
if isinstance(p, ParameterExpression) and not p.parameters:
params.append(float(p))
else:
params.append(p)
params = tuple(params)
return (qubits, params) in self.calibrations[instr.name]
return (qubits, params) in self.calibrations[instruction.operation.name]

@property
def metadata(self) -> dict:
Expand Down
19 changes: 9 additions & 10 deletions qiskit/quantum_info/synthesis/qsd.py
Original file line number Diff line number Diff line change
Expand Up @@ -233,23 +233,22 @@ def _apply_a2(circ):
ccirc = transpile(circ, basis_gates=["u", "cx", "qsd2q"], optimization_level=0)
ind2q = []
# collect 2q instrs
for i, instr_context in enumerate(ccirc.data):
instr, _, _ = instr_context
if instr.name == "qsd2q":
for i, instruction in enumerate(ccirc.data):
if instruction.operation.name == "qsd2q":
ind2q.append(i)
# rolling over diagonals
ind2 = None # lint
for ind1, ind2 in zip(ind2q[0:-1:], ind2q[1::]):
# get neigboring 2q gates separated by controls
instr1, qargs, cargs = ccirc.data[ind1]
mat1 = Operator(instr1).data
instr2, _, _ = ccirc.data[ind2]
mat2 = Operator(instr2).data
instr1 = ccirc.data[ind1]
mat1 = Operator(instr1.operation).data
instr2 = ccirc.data[ind2]
mat2 = Operator(instr2.operation).data
# rollover
dmat, qc2cx = decomposer(mat1)
ccirc.data[ind1] = (qc2cx.to_gate(), qargs, cargs)
ccirc.data[ind1] = instr1.replace(operation=qc2cx.to_gate())
mat2 = mat2 @ dmat
ccirc.data[ind2] = (qiskit.extensions.unitary.UnitaryGate(mat2), qargs, cargs)
ccirc.data[ind2] = instr2.replace(qiskit.extensions.unitary.UnitaryGate(mat2))
qc3 = two_qubit_decompose.two_qubit_cnot_decompose(mat2)
ccirc.data[ind2] = (qc3.to_gate(), qargs, cargs)
ccirc.data[ind2] = ccirc.data[ind2].replace(operation=qc3.to_gate())
return ccirc
12 changes: 6 additions & 6 deletions qiskit/transpiler/passes/basis/basis_translator.py
Original file line number Diff line number Diff line change
Expand Up @@ -334,12 +334,12 @@ def _(self, dag: DAGCircuit):

@_extract_basis.register
def _(self, circ: QuantumCircuit):
for instr_context in circ.data:
instr, _, _ = instr_context
if not circ.has_calibration_for(instr_context):
yield (instr.name, instr.num_qubits)
if isinstance(instr, ControlFlowOp):
for block in instr.blocks:
for instruction in circ.data:
operation = instruction.operation
if not circ.has_calibration_for(instruction):
yield (operation.name, operation.num_qubits)
if isinstance(operation, ControlFlowOp):
for block in operation.blocks:
yield from self._extract_basis(block)

def _extract_basis_target(
Expand Down
2 changes: 1 addition & 1 deletion test/python/circuit/test_circuit_load_from_qpy.py
Original file line number Diff line number Diff line change
Expand Up @@ -1251,7 +1251,7 @@ def test_open_controlled_gate(self):
fd.seek(0)
new_circ = load(fd)[0]
self.assertEqual(qc, new_circ)
self.assertEqual(qc.data[0][0].ctrl_state, new_circ.data[0][0].ctrl_state)
self.assertEqual(qc.data[0].operation.ctrl_state, new_circ.data[0].operation.ctrl_state)
self.assertDeprecatedBitProperties(qc, new_circ)

def test_standard_control_gates(self):
Expand Down
4 changes: 2 additions & 2 deletions test/python/circuit/test_circuit_operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -1165,7 +1165,7 @@ def instruction_tuples_partial():

expected = QuantumCircuit([a, b, c, d], [x, y, z])
for instruction in instructions():
expected.append(*instruction)
expected.append(instruction.operation, instruction.qubits, instruction.clbits)

self.assertEqual(circuit, expected)
self.assertEqual(circuit_tuples, expected)
Expand Down Expand Up @@ -1215,7 +1215,7 @@ def instructions():

expected = QuantumCircuit([a, b], global_phase=0.1)
for instruction in instructions():
expected.append(*instruction)
expected.append(instruction.operation, instruction.qubits, instruction.clbits)

self.assertEqual(circuit, expected)
self.assertEqual(circuit.name, "test")
Expand Down
18 changes: 11 additions & 7 deletions test/python/transpiler/test_clifford_passes.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,14 +84,14 @@ def test_circuit_with_cliffords(self):

# Check that there are indeed two Clifford objects in the circuit,
# and that these are not gates.
cliffords = [inst for inst, _, _ in qc.data if isinstance(inst, Clifford)]
gates = [inst for inst, _, _ in qc.data if isinstance(inst, Gate)]
cliffords = [inst.operation for inst in qc.data if isinstance(inst.operation, Clifford)]
gates = [inst.operation for inst in qc.data if isinstance(inst.operation, Gate)]
self.assertEqual(len(cliffords), 2)
self.assertEqual(len(gates), 4)

# Check that calling QuantumCircuit's decompose(), no Clifford objects remain
qc2 = qc.decompose()
cliffords2 = [inst for inst, _, _ in qc2.data if isinstance(inst, Clifford)]
cliffords2 = [inst.operation for inst in qc2.data if isinstance(inst.operation, Clifford)]
self.assertEqual(len(cliffords2), 0)

def test_can_construct_operator(self):
Expand Down Expand Up @@ -167,8 +167,10 @@ def test_circuit_to_dag_conversion_and_back(self):
# Add this Clifford to a Quantum Circuit, and check that it remains a Clifford
circ0 = QuantumCircuit(4)
circ0.append(cliff, [0, 1, 2])
circ0_cliffords = [inst for inst, _, _ in circ0.data if isinstance(inst, Clifford)]
circ0_gates = [inst for inst, _, _ in circ0.data if isinstance(inst, Gate)]
circ0_cliffords = [
inst.operation for inst in circ0.data if isinstance(inst.operation, Clifford)
]
circ0_gates = [inst.operation for inst in circ0.data if isinstance(inst.operation, Gate)]
self.assertEqual(len(circ0_cliffords), 1)
self.assertEqual(len(circ0_gates), 0)

Expand All @@ -183,8 +185,10 @@ def test_circuit_to_dag_conversion_and_back(self):

# Check that converted DAG to a circuit also preserves Clifford.
circ1 = dag_to_circuit(dag0)
circ1_cliffords = [inst for inst, _, _ in circ1.data if isinstance(inst, Clifford)]
circ1_gates = [inst for inst, _, _ in circ1.data if isinstance(inst, Gate)]
circ1_cliffords = [
inst.operation for inst in circ1.data if isinstance(inst.operation, Clifford)
]
circ1_gates = [inst.operation for inst in circ1.data if isinstance(inst.operation, Gate)]
self.assertEqual(len(circ1_cliffords), 1)
self.assertEqual(len(circ1_gates), 0)

Expand Down

0 comments on commit e2674ce

Please sign in to comment.