diff --git a/qiskit_ibm_provider/qpy/binary_io/circuits.py b/qiskit_ibm_provider/qpy/binary_io/circuits.py index ed858a4cc..b2796d2b3 100644 --- a/qiskit_ibm_provider/qpy/binary_io/circuits.py +++ b/qiskit_ibm_provider/qpy/binary_io/circuits.py @@ -25,7 +25,7 @@ from qiskit import circuit as circuit_mod from qiskit import extensions -from qiskit.circuit import library, controlflow, CircuitInstruction +from qiskit.circuit import library, controlflow, CircuitInstruction, ControlFlowOp from qiskit.circuit.classical import expr from qiskit.circuit.classicalregister import ClassicalRegister, Clbit from qiskit.circuit.gate import Gate @@ -158,12 +158,13 @@ def _loads_instruction_parameter( # type: ignore[no-untyped-def] data_bytes.decode(common.ENCODE), circuit, registers ) else: + clbits = circuit.clbits if circuit is not None else () param = value.loads_value( type_key, data_bytes, version, vectors, - clbits=circuit.clbits, + clbits=clbits, cregs=registers["c"], ) @@ -289,8 +290,10 @@ def _read_instruction( # type: ignore[no-untyped-def] else: raise AttributeError("Invalid instruction type: %s" % gate_name) + if instruction.label_size <= 0: + label = None if gate_name in {"IfElseOp", "WhileLoopOp"}: - gate = gate_class(condition, *params) + gate = gate_class(condition, *params, label=label) elif version >= 5 and issubclass(gate_class, ControlledGate): if gate_name in { "MCPhaseGate", @@ -300,12 +303,19 @@ def _read_instruction( # type: ignore[no-untyped-def] "MCXRecursive", "MCXVChain", }: - gate = gate_class(*params, instruction.num_ctrl_qubits) + gate = gate_class(*params, instruction.num_ctrl_qubits, label=label) else: - gate = gate_class(*params) - gate.num_ctrl_qubits = instruction.num_ctrl_qubits - gate.ctrl_state = instruction.ctrl_state - gate.condition = condition + gate = gate_class(*params, label=label) + if ( + gate.num_ctrl_qubits != instruction.num_ctrl_qubits + or gate.ctrl_state != instruction.ctrl_state + ): + if hasattr(gate, "to_mutable"): + gate.to_mutable() + gate.num_ctrl_qubits = instruction.num_ctrl_qubits + gate.ctrl_state = instruction.ctrl_state + if condition: + gate = gate.c_if(*condition) else: if gate_name in { "Initialize", @@ -321,8 +331,15 @@ def _read_instruction( # type: ignore[no-untyped-def] params = [len(qargs)] elif gate_name in {"BreakLoopOp", "ContinueLoopOp"}: params = [len(qargs), len(cargs)] - gate = gate_class(*params) - gate.condition = condition + if label is not None: + gate = gate_class(*params, label=label) + else: + gate = gate_class(*params) + if condition: + if not isinstance(gate, ControlFlowOp): + gate = gate.c_if(*condition) + else: + gate.condition = condition if instruction.label_size > 0: gate.label = label if circuit is None: @@ -568,7 +585,11 @@ def _dumps_instruction_parameter(param, index_map): # type: ignore[no-untyped-d def _write_instruction( # type: ignore[no-untyped-def] file_obj, instruction, custom_operations, index_map ): - gate_class_name = instruction.operation.__class__.__name__ + base_class = getattr(instruction.operation, "base_class", None) + if base_class is None: + gate_class_name = instruction.operation.__class__.__name__ + else: + gate_class_name = instruction.operation.base_class.__name__ custom_operations_list = [] if ( ( @@ -580,13 +601,27 @@ def _write_instruction( # type: ignore[no-untyped-def] ) or gate_class_name == "Gate" or gate_class_name == "Instruction" - or gate_class_name == "ControlledGate" or isinstance(instruction.operation, library.BlueprintCircuit) ): if instruction.operation.name not in custom_operations: custom_operations[instruction.operation.name] = instruction.operation custom_operations_list.append(instruction.operation.name) gate_class_name = instruction.operation.name + # ucr*_dg gates can have different numbers of parameters, + # the uuid is appended to avoid storing a single definition + # in circuits with multiple ucr*_dg gates. + if instruction.operation.name in ["ucrx_dg", "ucry_dg", "ucrz_dg"]: + gate_class_name += "_" + str(uuid.uuid4()) + if gate_class_name not in custom_operations: + custom_operations[gate_class_name] = instruction.operation + custom_operations_list.append(gate_class_name) + elif gate_class_name == "ControlledGate": + # controlled gates can have the same name but different parameter + # values, the uuid is appended to avoid storing a single definition + # in circuits with multiple controlled gates. + gate_class_name = instruction.operation.name + "_" + str(uuid.uuid4()) + custom_operations[gate_class_name] = instruction.operation + custom_operations_list.append(gate_class_name) elif isinstance(instruction.operation, library.PauliEvolutionGate): gate_class_name = r"###PauliEvolutionGate_" + str(uuid.uuid4())