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

Reduce use of legacy CircuitInstruction formats #10416

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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