def _read_circuit(file_obj): header, name, metadata = _read_header(file_obj) ( name_size, # pylint: disable=unused-variable global_phase, num_qubits, num_clbits, metadata_size, # pylint: disable=unused-variable num_registers, num_instructions, ) = header registers = {} if num_registers > 0: circ = QuantumCircuit(name=name, global_phase=global_phase, metadata=metadata) # TODO Update to handle registers composed of not continuous bit # indices. Right now this only works for standalone registers or # registers composed bit indices that are continuous registers = _read_registers(file_obj, num_registers) for qreg in registers["q"].values(): min_index = min(qreg["index_map"].keys()) qubits = [Qubit() for i in range(min_index - len(circ.qubits))] if qubits: circ.add_bits(qubits) circ.add_register(qreg["register"]) for creg in registers["c"].values(): min_index = min(creg["index_map"].keys()) clbits = [Clbit() for i in range(min_index - len(circ.clbits))] if clbits: circ.add_bits(clbits) circ.add_register(creg["register"]) else: circ = QuantumCircuit( num_qubits, num_clbits, name=name, global_phase=global_phase, metadata=metadata, ) custom_instructions = _read_custom_instructions(file_obj) for _instruction in range(num_instructions): _read_instruction(file_obj, circ, registers, custom_instructions) return circ
def _read_circuit(file_obj): header, name, metadata = _read_header(file_obj) ( name_size, # pylint: disable=unused-variable global_phase, num_qubits, num_clbits, metadata_size, # pylint: disable=unused-variable num_registers, num_instructions, ) = header out_registers = {"q": {}, "c": {}} if num_registers > 0: circ = QuantumCircuit(name=name, global_phase=global_phase, metadata=metadata) registers = _read_registers(file_obj, num_registers) for bit_type_label, bit_type, reg_type in [ ("q", Qubit, QuantumRegister), ("c", Clbit, ClassicalRegister), ]: register_bits = set() # Add quantum registers and bits for register_name in registers[bit_type_label]: standalone, indices = registers[bit_type_label][register_name] if standalone: start = min(indices) count = start out_of_order = False for index in indices: if not out_of_order and index != count: out_of_order = True count += 1 if index in register_bits: raise QiskitError("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: sorted_indices = np.argsort(indices) for index in sorted_indices: pos = indices[index] if bit_type_label == "q": bit_len = len(circ.qubits) else: bit_len = len(circ.clbits) # 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]]) 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) 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 QiskitError("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) 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, ) custom_instructions = _read_custom_instructions(file_obj) for _instruction in range(num_instructions): _read_instruction(file_obj, circ, out_registers, custom_instructions) return circ
def read_circuit(file_obj, version): """Read a single QuantumCircuit object from the file like object. Args: file_obj (FILE): The file like object to read the circuit data from. version (int): QPY version. Returns: QuantumCircuit: The circuit object from the file. Raises: QpyError: Invalid register. """ vectors = {} if version < 2: header, name, metadata = _read_header(file_obj) else: header, name, metadata = _read_header_v2(file_obj, version, vectors) global_phase = header["global_phase"] num_qubits = header["num_qubits"] num_clbits = header["num_clbits"] num_registers = header["num_registers"] num_instructions = header["num_instructions"] out_registers = {"q": {}, "c": {}} 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), ]: 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, ) custom_instructions = _read_custom_instructions(file_obj, version, vectors) for _instruction in range(num_instructions): _read_instruction(file_obj, circ, out_registers, custom_instructions, version, vectors) for vec_name, (vector, initialized_params) in vectors.items(): if len(initialized_params) != len(vector): warnings.warn( f"The ParameterVector: '{vec_name}' is not fully identical to its " "pre-serialization state. Elements " f"{', '.join([str(x) for x in set(range(len(vector))) - initialized_params])} " "in the ParameterVector will be not equal to the pre-serialized ParameterVector " f"as they weren't used in the circuit: {circ.name}", UserWarning, ) return circ