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 run(self, dag): """Run the ConsolidateBlocks pass on `dag`. Iterate over each block and replace it with an equivalent Unitary on the same wires. """ if self.decomposer is None: return dag # compute ordered indices for the global circuit wires global_index_map = {wire: idx for idx, wire in enumerate(dag.qubits)} blocks = self.property_set["block_list"] basis_gate_name = self.decomposer.gate.name all_block_gates = set() for block in blocks: if len(block) == 1 and (self.basis_gates and block[0].name not in self.basis_gates): all_block_gates.add(block[0]) dag.substitute_node(block[0], UnitaryGate(block[0].op.to_matrix())) else: basis_count = 0 outside_basis = False block_qargs = set() block_cargs = set() for nd in block: block_qargs |= set(nd.qargs) if isinstance(nd, DAGOpNode) and nd.op.condition: block_cargs |= set(nd.op.condition[0]) all_block_gates.add(nd) q = QuantumRegister(len(block_qargs)) qc = QuantumCircuit(q) if block_cargs: c = ClassicalRegister(len(block_cargs)) qc.add_register(c) block_index_map = self._block_qargs_to_indices(block_qargs, global_index_map) for nd in block: if nd.op.name == basis_gate_name: basis_count += 1 if self.basis_gates and nd.op.name not in self.basis_gates: outside_basis = True qc.append(nd.op, [q[block_index_map[i]] for i in nd.qargs]) unitary = UnitaryGate(Operator(qc)) max_2q_depth = 20 # If depth > 20, there will be 1q gates to consolidate. if ( # pylint: disable=too-many-boolean-expressions self.force_consolidate or unitary.num_qubits > 2 or self.decomposer.num_basis_gates(unitary) < basis_count or len(block) > max_2q_depth or (self.basis_gates is not None and outside_basis) ): dag.replace_block_with_op(block, unitary, block_index_map, cycle_check=False) # If 1q runs are collected before consolidate those too runs = self.property_set["run_list"] or [] for run in runs: if run[0] in all_block_gates: continue if len(run) == 1 and self.basis_gates and run[0].name not in self.basis_gates: dag.substitute_node(run[0], UnitaryGate(run[0].op.to_matrix())) else: qubit = run[0].qargs[0] operator = run[0].op.to_matrix() already_in_block = False for gate in run[1:]: if gate in all_block_gates: already_in_block = True operator = gate.op.to_matrix().dot(operator) if already_in_block: continue unitary = UnitaryGate(operator) dag.replace_block_with_op(run, unitary, {qubit: 0}, cycle_check=False) return dag
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