Skip to content
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
181 changes: 45 additions & 136 deletions qiskit_ibm_runtime/qpy/binary_io/circuits.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
from qiskit.extensions import quantum_initializer
from qiskit.quantum_info.operators import SparsePauliOp
from qiskit.synthesis import evolution as evo_synth
from .. import common, formats, exceptions, type_keys
from .. import common, formats, type_keys
from . import value, schedules


Expand Down Expand Up @@ -179,22 +179,13 @@ def _read_instruction( # type: ignore[no-untyped-def]
params = []
condition_tuple = None
if instruction.has_condition:
# If an invalid register name is used assume it's a single bit
# condition and treat the register name as a string of the clbit index
if ClassicalRegister.name_format.match(condition_register) is None:
# If invalid register prefixed with null character it's a clbit
# index for single bit condition
if condition_register[0] == "\x00":
conditional_bit = int(condition_register[1:])
condition_tuple = (
circuit.clbits[conditional_bit],
instruction.condition_value,
)
else:
raise ValueError(
f"Invalid register name: {condition_register} for condition register of "
f"instruction: {gate_name}"
)
# If register name prefixed with null character it's a clbit index for single bit condition.
if condition_register[0] == "\x00":
conditional_bit = int(condition_register[1:])
condition_tuple = (
circuit.clbits[conditional_bit],
instruction.condition_value,
)
else:
condition_tuple = (
registers["c"][condition_register],
Expand Down Expand Up @@ -257,7 +248,7 @@ def _read_instruction( # type: ignore[no-untyped-def]
inst_obj.label = label
if circuit is None:
return inst_obj
circuit._append(CircuitInstruction(inst_obj, qargs, cargs))
circuit._append(inst_obj, qargs, cargs)
return None
elif hasattr(library, gate_name):
gate_class = getattr(library, gate_name)
Expand All @@ -275,7 +266,14 @@ def _read_instruction( # type: ignore[no-untyped-def]
if gate_name in {"IfElseOp", "WhileLoopOp"}:
gate = gate_class(condition_tuple, *params)
elif version >= 5 and issubclass(gate_class, ControlledGate):
if gate_name in {"MCPhaseGate", "MCU1Gate"}:
if gate_name in {
"MCPhaseGate",
"MCU1Gate",
"MCXGrayCode",
"MCXGate",
"MCXRecursive",
"MCXVChain",
}:
gate = gate_class(*params, instruction.num_ctrl_qubits)
else:
gate = gate_class(*params)
Expand All @@ -294,12 +292,12 @@ def _read_instruction( # type: ignore[no-untyped-def]
gate.condition = condition_tuple
if instruction.label_size > 0:
gate.label = label
if circuit is None:
return gate
if circuit is None:
return gate
if not isinstance(gate, Instruction):
circuit.append(gate, qargs, cargs)
else:
circuit._append(gate, qargs, cargs)
circuit._append(CircuitInstruction(gate, qargs, cargs))
return None


Expand Down Expand Up @@ -420,6 +418,7 @@ def _read_custom_operations(file_obj, version, vectors): # type: ignore[no-unty
file_obj.read(formats.CUSTOM_CIRCUIT_INST_DEF_V2_SIZE),
)
)

name = file_obj.read(data.gate_name_size).decode(common.ENCODE)
type_str = data.type
definition_circuit = None
Expand Down Expand Up @@ -676,6 +675,9 @@ def _write_custom_operation( # type: ignore[no-untyped-def]
# state is open, and the definition setter (during a subsequent read) uses the "fully
# excited" control definition only.
has_definition = True
# Build internal definition to support overloaded subclasses by
# calling definition getter on object
operation.definition # pylint: disable=pointless-statement
data = common.data_to_binary(operation._definition, write_circuit)
size = len(data)
num_ctrl_qubits = operation.num_ctrl_qubits
Expand Down Expand Up @@ -895,128 +897,35 @@ def read_circuit(file_obj, version, metadata_deserializer=None): # type: ignore
num_registers = header["num_registers"]
num_instructions = header["num_instructions"]
out_registers = {"q": {}, "c": {}}
circ = QuantumCircuit(
[Qubit() for _ in [None] * num_qubits],
[Clbit() for _ in [None] * num_clbits],
name=name,
global_phase=global_phase,
metadata=metadata,
)
if num_registers > 0:
circ = QuantumCircuit(name=name, global_phase=global_phase, metadata=metadata)
if version < 4:
registers = _read_registers(file_obj, num_registers)
else:
registers = _read_registers_v4(file_obj, num_registers)

for bit_type_label, bit_type, reg_type in [
("q", Qubit, QuantumRegister),
("c", Clbit, ClassicalRegister),
for bit_type_label, reg_type in [
("q", QuantumRegister),
("c", ClassicalRegister),
]:
register_bits = set()
# Add quantum registers and bits
for register_name in registers[bit_type_label]:
standalone, indices, in_circuit = registers[bit_type_label][
register_name
]
indices_defined = [x for x in indices if x >= 0]
# If a register has no bits in the circuit skip it
if not indices_defined:
continue
if standalone:
start = min(indices_defined)
count = start
out_of_order = False
for index in indices:
if index < 0:
out_of_order = True
continue
if not out_of_order and index != count:
out_of_order = True
count += 1
if index in register_bits:
# If we have a bit in the position already it's been
# added by an earlier register in the circuit
# otherwise it's invalid qpy
if not in_circuit:
continue
raise exceptions.QpyError("Duplicate register bits found")

register_bits.add(index)

num_reg_bits = len(indices)
# Create a standlone register of the appropriate length (from
# the number of indices in the qpy data) and add it to the circuit
reg = reg_type(num_reg_bits, register_name)
# If any bits from qreg are out of order in the circuit handle
# is case
if out_of_order or not in_circuit:
for index, pos in sorted(
enumerate(x for x in indices if x >= 0), key=lambda x: x[1]
):
if bit_type_label == "q":
bit_len = len(circ.qubits)
else:
bit_len = len(circ.clbits)
if pos < bit_len:
# If we have a bit in the position already it's been
# added by an earlier register in the circuit
# otherwise it's invalid qpy
if not in_circuit:
continue
raise exceptions.QpyError(
"Duplicate register bits found"
)
# Fill any holes between the current register bit and the
# next one
if pos > bit_len:
bits = [bit_type() for _ in range(pos - bit_len)]
circ.add_bits(bits)
circ.add_bits([reg[index]])
if in_circuit:
circ.add_register(reg)
else:
if bit_type_label == "q":
bit_len = len(circ.qubits)
else:
bit_len = len(circ.clbits)
# If there is a hole between the start of the register and the
# current bits and standalone bits to fill the gap.
if start > len(circ.qubits):
bits = [bit_type() for _ in range(start - bit_len)]
circ.add_bits(bit_len)
if in_circuit:
circ.add_register(reg)
out_registers[bit_type_label][register_name] = reg
else:
for index in indices:
if bit_type_label == "q":
bit_len = len(circ.qubits)
else:
bit_len = len(circ.clbits)
# Add any missing bits
bits = [bit_type() for _ in range(index + 1 - bit_len)]
circ.add_bits(bits)
if index in register_bits:
raise exceptions.QpyError("Duplicate register bits found")
register_bits.add(index)
if bit_type_label == "q":
bits = [circ.qubits[i] for i in indices]
else:
bits = [circ.clbits[i] for i in indices]
reg = reg_type(name=register_name, bits=bits)
if in_circuit:
circ.add_register(reg)
out_registers[bit_type_label][register_name] = reg
# If we don't have sufficient bits in the circuit after adding
# all the registers add more bits to fill the circuit
if len(circ.qubits) < num_qubits:
qubits = [Qubit() for _ in range(num_qubits - len(circ.qubits))]
circ.add_bits(qubits)
if len(circ.clbits) < num_clbits:
clbits = [Clbit() for _ in range(num_qubits - len(circ.clbits))]
circ.add_bits(clbits)
else:
circ = QuantumCircuit(
num_qubits,
num_clbits,
name=name,
global_phase=global_phase,
metadata=metadata,
)
circuit_bits = {"q": circ.qubits, "c": circ.clbits}[bit_type_label]
for register_name, (_, indices, in_circuit) in registers[
bit_type_label
].items():
register = reg_type(
name=register_name,
bits=[circuit_bits[x] for x in indices if x >= 0],
)
if in_circuit:
circ.add_register(register)
out_registers[bit_type_label][register_name] = register
custom_operations = _read_custom_operations(file_obj, version, vectors)
for _instruction in range(num_instructions):
_read_instruction(
Expand Down
Loading