def test_append_resolves_numpy_integers(self, index): """Test that Numpy's integers can be used to reference qubits and clbits.""" qubits = [Qubit(), Qubit()] clbits = [Clbit(), Clbit()] test = QuantumCircuit(qubits, clbits) test.append(Measure(), [index], [index]) expected = QuantumCircuit(qubits, clbits) expected.append(Measure(), [qubits[int(index)]], [clbits[int(index)]]) self.assertEqual(test, expected)
def test_append_resolves_integers(self, index): """Test that integer arguments to append are correctly resolved.""" # We need to assume that appending ``Bit`` instances will always work, so we have something # to test against. qubits = [Qubit(), Qubit()] clbits = [Clbit(), Clbit()] test = QuantumCircuit(qubits, clbits) test.append(Measure(), [index], [index]) expected = QuantumCircuit(qubits, clbits) expected.append(Measure(), [qubits[index]], [clbits[index]]) self.assertEqual(test, expected)
def test_append_rejects_bits_not_in_circuit(self): """Test that append rejects bits that are not in the circuit.""" test = QuantumCircuit(2, 2) with self.subTest("qubit"), self.assertRaisesRegex(CircuitError, "not in the circuit"): test.append(Measure(), [Qubit()], [test.clbits[0]]) with self.subTest("clbit"), self.assertRaisesRegex(CircuitError, "not in the circuit"): test.append(Measure(), [test.qubits[0]], [Clbit()]) with self.subTest("qubit list"), self.assertRaisesRegex(CircuitError, "not in the circuit"): test.append(Measure(), [[test.qubits[0], Qubit()]], [test.clbits]) with self.subTest("clbit list"), self.assertRaisesRegex(CircuitError, "not in the circuit"): test.append(Measure(), [test.qubits], [[test.clbits[0], Clbit()]])
def test_standalone_and_shared_out_of_order(self): """Test circuit with register bits inserted out of order.""" qr_standalone = QuantumRegister(2, "standalone") qubits = [Qubit() for _ in range(5)] clbits = [Clbit() for _ in range(5)] qc = QuantumCircuit() qc.add_bits(qubits) qc.add_bits(clbits) random.shuffle(qubits) random.shuffle(clbits) qr = QuantumRegister(bits=qubits) cr = ClassicalRegister(bits=clbits) qc.add_register(qr) qc.add_register(cr) qr_standalone = QuantumRegister(2, "standalone") cr_standalone = ClassicalRegister(2, "classical_standalone") qc.add_bits([qr_standalone[1], qr_standalone[0]]) qc.add_bits([cr_standalone[1], cr_standalone[0]]) qc.add_register(qr_standalone) qc.add_register(cr_standalone) qc.unitary(random_unitary(32, seed=42), qr) qc.unitary(random_unitary(4, seed=100), qr_standalone) qc.measure(qr, cr) qc.measure(qr_standalone, cr_standalone) qpy_file = io.BytesIO() dump(qc, qpy_file) qpy_file.seek(0) new_circ = load(qpy_file)[0] self.assertEqual(qc, new_circ)
def test_append_rejects_bit_of_wrong_type(self): """Test that append rejects bits of the wrong type in an argument list.""" qubits = [Qubit(), Qubit()] clbits = [Clbit(), Clbit()] test = QuantumCircuit(qubits, clbits) with self.subTest("c to q"), self.assertRaisesRegex(CircuitError, "Incorrect bit type"): test.append(Measure(), [clbits[0]], [clbits[1]]) with self.subTest("q to c"), self.assertRaisesRegex(CircuitError, "Incorrect bit type"): test.append(Measure(), [qubits[0]], [qubits[1]]) with self.subTest("none to q"), self.assertRaisesRegex(CircuitError, "Incorrect bit type"): test.append(Measure(), [Bit()], [clbits[0]]) with self.subTest("none to c"), self.assertRaisesRegex(CircuitError, "Incorrect bit type"): test.append(Measure(), [qubits[0]], [Bit()]) with self.subTest("none list"), self.assertRaisesRegex(CircuitError, "Incorrect bit type"): test.append(Measure(), [[qubits[0], Bit()]], [[clbits[0], Bit()]])
def test_remove_clbits_without_register(self): """clbits of final measurements not in a register are removed.""" def expected_dag(): q0 = QuantumRegister(1, "q0") qc = QuantumCircuit(q0) return circuit_to_dag(qc) q0 = QuantumRegister(1, "q0") qc = QuantumCircuit(q0) # Add clbit without adding register qc.add_bits([Clbit()]) self.assertFalse(qc.cregs) # Measure to regless clbit qc.measure(0, 0) dag = circuit_to_dag(qc) dag = RemoveFinalMeasurements().run(dag) self.assertFalse(dag.cregs) self.assertFalse(dag.clbits) self.assertEqual(dag, expected_dag())
def test_hybrid_standalone_register(self): """Test qpy serialization with registers that mix bit types""" qr = QuantumRegister(5, "foo") qr = QuantumRegister(name="bar", bits=qr[:3] + [Qubit(), Qubit()]) cr = ClassicalRegister(5, "foo") cr = ClassicalRegister(name="classical_bar", bits=cr[:3] + [Clbit(), Clbit()]) qc = QuantumCircuit(qr, cr) qc.h(0) qc.cx(0, 1) qc.cx(0, 2) qc.cx(0, 3) qc.cx(0, 4) qc.measure(qr, cr) qpy_file = io.BytesIO() dump(qc, qpy_file) qpy_file.seek(0) new_circ = load(qpy_file)[0] self.assertEqual(qc, new_circ)
def test_reverse_bits_with_registerless_bits(self): """Test reversing order of registerless bits.""" q0 = Qubit() q1 = Qubit() c0 = Clbit() c1 = Clbit() qc = QuantumCircuit([q0, q1], [c0, c1]) qc.h(0) qc.cx(0, 1) qc.x(0).c_if(1, True) qc.measure(0, 0) expected = QuantumCircuit([c1, c0], [q1, q0]) expected.h(1) expected.cx(1, 0) expected.x(1).c_if(0, True) expected.measure(1, 1) self.assertEqual(qc.reverse_bits(), expected)
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 test_remove_final_measurements_bit_locations(self): """Test remove_final_measurements properly recalculates clbit indicies and preserves order of remaining cregs and clbits. """ c0 = ClassicalRegister(1) c1_0 = Clbit() c2 = ClassicalRegister(1) c3 = ClassicalRegister(1) # add an individual bit that's not in any register of this circuit circuit = QuantumCircuit(QuantumRegister(1), c0, [c1_0], c2, c3) circuit.measure(0, c1_0) circuit.measure(0, c2[0]) # assert cregs and clbits before measure removal self.assertEqual(circuit.cregs, [c0, c2, c3]) self.assertEqual(circuit.clbits, [c0[0], c1_0, c2[0], c3[0]]) # assert clbit indices prior to measure removal self.assertEqual(circuit.find_bit(c0[0]), BitLocations(0, [(c0, 0)])) self.assertEqual(circuit.find_bit(c1_0), BitLocations(1, [])) self.assertEqual(circuit.find_bit(c2[0]), BitLocations(2, [(c2, 0)])) self.assertEqual(circuit.find_bit(c3[0]), BitLocations(3, [(c3, 0)])) circuit.remove_final_measurements() # after measure removal, creg c2 should be gone, as should lone bit c1_0 # and c0 should still come before c3 self.assertEqual(circuit.cregs, [c0, c3]) self.assertEqual(circuit.clbits, [c0[0], c3[0]]) # there should be no gaps in clbit indices # e.g. c3[0] is now the second clbit self.assertEqual(circuit.find_bit(c0[0]), BitLocations(0, [(c0, 0)])) self.assertEqual(circuit.find_bit(c3[0]), BitLocations(1, [(c3, 0)]))
def test_mixed_registers(self): """Test circuit with mix of standalone and shared registers.""" qubits = [Qubit() for _ in range(5)] clbits = [Clbit() for _ in range(5)] qc = QuantumCircuit() qc.add_bits(qubits) qc.add_bits(clbits) qr = QuantumRegister(bits=qubits) cr = ClassicalRegister(bits=clbits) qc.add_register(qr) qc.add_register(cr) qr_standalone = QuantumRegister(2, "standalone") qc.add_register(qr_standalone) cr_standalone = ClassicalRegister(2, "classical_standalone") qc.add_register(cr_standalone) qc.unitary(random_unitary(32, seed=42), qr) qc.unitary(random_unitary(4, seed=100), qr_standalone) qc.measure(qr, cr) qc.measure(qr_standalone, cr_standalone) qpy_file = io.BytesIO() dump(qc, qpy_file) qpy_file.seek(0) new_circ = load(qpy_file)[0] self.assertEqual(qc, new_circ)
def generate_register_edge_cases(): """Generate register edge case circuits.""" register_edge_cases = [] # Circuit with shared bits in a register qubits = [Qubit() for _ in range(5)] shared_qc = QuantumCircuit() shared_qc.add_bits(qubits) shared_qr = QuantumRegister(bits=qubits) shared_qc.add_register(shared_qr) shared_qc.h(shared_qr) shared_qc.cx(0, 1) shared_qc.cx(0, 2) shared_qc.cx(0, 3) shared_qc.cx(0, 4) shared_qc.measure_all() register_edge_cases.append(shared_qc) # Circuit with registers that have a mix of standalone and shared register # bits qr = QuantumRegister(5, "foo") qr = QuantumRegister(name="bar", bits=qr[:3] + [Qubit(), Qubit()]) cr = ClassicalRegister(5, "foo") cr = ClassicalRegister(name="classical_bar", bits=cr[:3] + [Clbit(), Clbit()]) hybrid_qc = QuantumCircuit(qr, cr) hybrid_qc.h(0) hybrid_qc.cx(0, 1) hybrid_qc.cx(0, 2) hybrid_qc.cx(0, 3) hybrid_qc.cx(0, 4) hybrid_qc.measure(qr, cr) register_edge_cases.append(hybrid_qc) # Circuit with mixed standalone and shared registers qubits = [Qubit() for _ in range(5)] clbits = [Clbit() for _ in range(5)] mixed_qc = QuantumCircuit() mixed_qc.add_bits(qubits) mixed_qc.add_bits(clbits) qr = QuantumRegister(bits=qubits) cr = ClassicalRegister(bits=clbits) mixed_qc.add_register(qr) mixed_qc.add_register(cr) qr_standalone = QuantumRegister(2, "standalone") mixed_qc.add_register(qr_standalone) cr_standalone = ClassicalRegister(2, "classical_standalone") mixed_qc.add_register(cr_standalone) mixed_qc.unitary(random_unitary(32, seed=42), qr) mixed_qc.unitary(random_unitary(4, seed=100), qr_standalone) mixed_qc.measure(qr, cr) mixed_qc.measure(qr_standalone, cr_standalone) register_edge_cases.append(mixed_qc) # Circuit with out of order register bits qr_standalone = QuantumRegister(2, "standalone") qubits = [Qubit() for _ in range(5)] clbits = [Clbit() for _ in range(5)] ooo_qc = QuantumCircuit() ooo_qc.add_bits(qubits) ooo_qc.add_bits(clbits) random.seed(42) random.shuffle(qubits) random.shuffle(clbits) qr = QuantumRegister(bits=qubits) cr = ClassicalRegister(bits=clbits) ooo_qc.add_register(qr) ooo_qc.add_register(cr) qr_standalone = QuantumRegister(2, "standalone") cr_standalone = ClassicalRegister(2, "classical_standalone") ooo_qc.add_bits([qr_standalone[1], qr_standalone[0]]) ooo_qc.add_bits([cr_standalone[1], cr_standalone[0]]) ooo_qc.add_register(qr_standalone) ooo_qc.add_register(cr_standalone) ooo_qc.unitary(random_unitary(32, seed=42), qr) ooo_qc.unitary(random_unitary(4, seed=100), qr_standalone) ooo_qc.measure(qr, cr) ooo_qc.measure(qr_standalone, cr_standalone) register_edge_cases.append(ooo_qc) return register_edge_cases
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
def test_x_measurement(self): """this will give you something different every time, so don't try to test the exact answer""" a = GraphState(self.G) a.x_measurement(a.qreg[0], a.creg[0]) assert isinstance(a.creg[0], type(Clbit(ClassicalRegister(3, 'c2'), 0)))