def test_circuit_copy_with_measurements(): c1 = Circuit(4) c1.add([gates.H(0), gates.H(3), gates.CNOT(0, 2)]) c1.add(gates.M(0, 1, register_name="a")) c1.add(gates.M(3, register_name="b")) c2 = c1.copy() assert c2.measurement_gate is c1.measurement_gate assert c2.measurement_tuples == {"a": (0, 1), "b": (3, )}
def test_circuit_add_errors(): c = Circuit(2) with pytest.raises(TypeError): c.add(0) with pytest.raises(ValueError): c.add(gates.H(2)) c._final_state = 0 with pytest.raises(RuntimeError): c.add(gates.H(1))
def test_queue_class(): from qibo.abstractions.circuit import _Queue queue = _Queue(4) gatelist = [gates.H(0), gates.H(1), gates.X(0), gates.H(2), gates.CNOT(1, 2), gates.Y(3)] for g in gatelist: queue.append(g) assert queue.moments == [[gatelist[0], gatelist[1], gatelist[3], gatelist[5]], [gatelist[2], gatelist[4], gatelist[4], None]]
def test_circuit_add(): c = Circuit(2) g1, g2, g3 = gates.H(0), gates.H(1), gates.CNOT(0, 1) c.add(g1) c.add(g2) c.add(g3) assert c.depth == 2 assert c.ngates == 3 assert list(c.queue) == [g1, g2, g3]
def test_circuit_addition_errors(): c1 = Circuit(2) c1.add(gates.H(0)) c1.add(gates.H(1)) c2 = Circuit(1) c2.add(gates.X(0)) with pytest.raises(ValueError): c3 = c1 + c2
def test_simple(): c = Circuit(2) c.add(gates.H(0)) c.add(gates.H(1)) target = f"""// Generated by QIBO {__version__} OPENQASM 2.0; include "qelib1.inc"; qreg q[2]; h q[0]; h q[1];""" assert_strings_equal(c.to_qasm(), target)
def test_gate_types(): import collections c = Circuit(3) c.add(gates.H(0)) c.add(gates.H(1)) c.add(gates.X(2)) c.add(gates.CNOT(0, 2)) c.add(gates.CNOT(1, 2)) c.add(gates.TOFFOLI(0, 1, 2)) target_counter = collections.Counter({"h": 2, "x": 1, "cx": 2, "ccx": 1}) assert c.ngates == 6 assert c.gate_types == target_counter
def test_summary(): c = Circuit(3) c.add(gates.H(0)) c.add(gates.H(1)) c.add(gates.CNOT(0, 2)) c.add(gates.CNOT(1, 2)) c.add(gates.TOFFOLI(0, 1, 2)) c.add(gates.H(2)) target_summary = "\n".join([ "Circuit depth = 5", "Total number of gates = 6", "Number of qubits = 3", "Most common gates:", "h: 3", "cx: 2", "ccx: 1" ]) assert c.summary() == target_summary
def test_circuit_copy(deep): c1 = Circuit(2) c1.add([gates.H(0), gates.H(1), gates.CNOT(0, 1)]) c2 = c1.copy(deep) assert c2.depth == c1.depth assert c2.ngates == c1.ngates assert c2.nqubits == c1.nqubits for g1, g2 in zip(c1.queue, c2.queue): if deep: assert g1.__class__ == g2.__class__ assert g1.target_qubits == g2.target_qubits assert g1.control_qubits == g2.control_qubits else: assert g1 is g2
def test_circuit_add_iterable(): c = Circuit(2) # adding list gatelist = [gates.H(0), gates.H(1), gates.CNOT(0, 1)] c.add(gatelist) assert c.depth == 2 assert c.ngates == 3 assert list(c.queue) == gatelist # adding tuple gatetuple = (gates.H(0), gates.H(1), gates.CNOT(0, 1)) c.add(gatetuple) assert c.depth == 4 assert c.ngates == 6 assert isinstance(c.queue[-1], gates.CNOT)
def test_circuit_on_qubits(): c = Circuit(3) c.add([gates.H(0), gates.X(1), gates.Y(2)]) c.add([gates.CNOT(0, 1), gates.CZ(1, 2)]) c.add(gates.H(1).controlled_by(0, 2)) new_gates = list(c.on_qubits(2, 5, 4)) assert new_gates[0].target_qubits == (2, ) assert new_gates[1].target_qubits == (5, ) assert new_gates[2].target_qubits == (4, ) assert new_gates[3].target_qubits == (5, ) assert new_gates[3].control_qubits == (2, ) assert new_gates[4].target_qubits == (4, ) assert new_gates[4].control_qubits == (5, ) assert new_gates[5].target_qubits == (5, ) assert new_gates[5].control_qubits == (2, 4)
def test_gates_of_type(): c = Circuit(3) c.add(gates.H(0)) c.add(gates.H(1)) c.add(gates.CNOT(0, 2)) c.add(gates.X(1)) c.add(gates.CNOT(1, 2)) c.add(gates.TOFFOLI(0, 1, 2)) c.add(gates.H(2)) h_gates = c.gates_of_type(gates.H) cx_gates = c.gates_of_type("cx") assert h_gates == [(0, c.queue[0]), (1, c.queue[1]), (6, c.queue[6])] assert cx_gates == [(2, c.queue[2]), (4, c.queue[4])] with pytest.raises(TypeError): c.gates_of_type(5)
def test_on_qubits_controlled_by(): gate = gates.H(0).controlled_by(1, 2) gate = gate._on_qubits(5, 4, 6) assert gate.target_qubits == (5,) assert gate.control_qubits == (4, 6) assert isinstance(gate, gates.H) assert gate.is_controlled_by
def test_circuit_set_parameters_with_dictionary(trainable): """Check updating parameters of circuit with list.""" params = [0.123, 0.456, 0.789] c1 = Circuit(3) c1.add(gates.X(0)) c1.add(gates.X(2)) if trainable: c1.add(gates.U1(0, theta=0, trainable=trainable)) else: c1.add(gates.U1(0, theta=params[0], trainable=trainable)) c2 = Circuit(3) c2.add(gates.RZ(1, theta=0)) c2.add(gates.CZ(1, 2)) c2.add(gates.CU1(0, 2, theta=0)) c2.add(gates.H(2)) c = c1 + c2 if trainable: params_dict = {c.queue[i]: p for i, p in zip([2, 3, 5], params)} c.set_parameters(params_dict) assert c.queue[2].parameters == params[0] else: params_dict = {c.queue[3]: params[1], c.queue[5]: params[2]} c.set_parameters(params_dict) assert c.queue[3].parameters == params[1] assert c.queue[5].parameters == params[2] # test not passing all parametrized gates c.set_parameters({c.queue[5]: 0.7891}) if trainable: assert c.queue[2].parameters == params[0] assert c.queue[3].parameters == params[1] assert c.queue[5].parameters == 0.7891
def test_singlequbit_gates(): c = Circuit(2) c.add(gates.H(0)) c.add(gates.X(1)) c.add(gates.Y(0)) c.add(gates.Z(1)) c.add(gates.S(0)) c.add(gates.SDG(1)) c.add(gates.T(0)) c.add(gates.TDG(1)) c.add(gates.I(0)) target = f"""// Generated by QIBO {__version__} OPENQASM 2.0; include "qelib1.inc"; qreg q[2]; h q[0]; x q[1]; y q[0]; z q[1]; s q[0]; sdg q[1]; t q[0]; tdg q[1]; id q[0];""" assert_strings_equal(c.to_qasm(), target)
def test_controlled_by_error(): """Check that using `to_qasm` with controlled by gates raises error.""" c = Circuit(3) c.add(gates.H(0)) c.add(gates.Y(1).controlled_by(0, 2)) with pytest.raises(ValueError): c.to_qasm()
def test_set_nqubits(): c = Circuit(2) gate = gates.H(0) gate.nqubits = 3 gate.is_prepared = True with pytest.raises(RuntimeError): c.add(gate)
def test_fused_gate(): gate = gates.FusedGate(0, 1) gate.append(gates.H(0)) gate.append(gates.CNOT(0, 1)) assert len(gate.gates) == 2 gate.prepend(gates.TOFFOLI(0, 1, 2)) assert gate.qubits == (0, 1, 2) assert len(gate.gates) == 3 assert isinstance(gate.gates[0], gates.TOFFOLI)
def test_circuit_addition(measurements): c1 = Circuit(2) g1, g2 = gates.H(0), gates.CNOT(0, 1) c1.add(g1) c1.add(g2) if measurements: c1.add(gates.M(0, register_name="a")) c2 = Circuit(2) g3 = gates.H(1) c2.add(g3) if measurements: c2.add(gates.M(1, register_name="b")) c3 = c1 + c2 assert c3.depth == 3 assert list(c3.queue) == [g1, g2, g3] if measurements: assert c3.measurement_tuples == {"a": (0, ), "b": (1, )} assert c3.measurement_gate.target_qubits == (0, 1)
def test_gates_commute(): assert gates.H(0).commutes(gates.X(1)) assert gates.H(0).commutes(gates.H(1)) assert gates.H(0).commutes(gates.H(0)) assert not gates.H(0).commutes(gates.Y(0)) assert not gates.CNOT(0, 1).commutes(gates.SWAP(1, 2)) assert not gates.CNOT(0, 1).commutes(gates.H(1)) assert not gates.CNOT(0, 1).commutes(gates.Y(0).controlled_by(2)) assert not gates.CNOT(2, 3).commutes(gates.CNOT(3, 0)) assert gates.CNOT(0, 1).commutes(gates.Y(2).controlled_by(0))
def test_circuit_draw_line_wrap(): """Test circuit text draw with line wrap.""" ref_line_wrap_50 = \ 'q0: ─H─U1─U1─U1─U1───────────────────────────x───I───f ...\n' \ 'q1: ───o──|──|──|──H─U1─U1─U1────────────────|─x─I───| ...\n' \ 'q2: ──────o──|──|────o──|──|──H─U1─U1────────|─|─────| ...\n' \ 'q3: ─────────o──|───────o──|────o──|──H─U1───|─x───M─| ...\n' \ 'q4: ────────────o──────────o───────o────o──H─x───────f ...\n' \ '\n' \ 'q0: ... ─o────gf───M─\n' \ 'q1: ... ─U3───|──o─M─\n' \ 'q2: ... ────X─gf─o─M─\n' \ 'q3: ... ────o────o───\n' \ 'q4: ... ────o────X───' ref_line_wrap_30 = \ 'q0: ─H─U1─U1─U1─U1──────────────── ...\n' \ 'q1: ───o──|──|──|──H─U1─U1─U1───── ...\n' \ 'q2: ──────o──|──|────o──|──|──H─U1 ...\n' \ 'q3: ─────────o──|───────o──|────o─ ...\n' \ 'q4: ────────────o──────────o────── ...\n' \ '\n' \ 'q0: ... ───────────x───I───f─o────gf── ...\n' \ 'q1: ... ───────────|─x─I───|─U3───|──o ...\n' \ 'q2: ... ─U1────────|─|─────|────X─gf─o ...\n' \ 'q3: ... ─|──H─U1───|─x───M─|────o────o ...\n' \ 'q4: ... ─o────o──H─x───────f────o────X ...\n' \ '\n' \ 'q0: ... ─M─\n' \ 'q1: ... ─M─\n' \ 'q2: ... ─M─\n' \ 'q3: ... ───\n' \ 'q4: ... ───' import numpy as np circuit = Circuit(5) for i1 in range(5): circuit.add(gates.H(i1)) for i2 in range(i1 + 1, 5): circuit.add(gates.CU1(i2, i1, theta=0)) circuit.add(gates.SWAP(0, 4)) circuit.add(gates.SWAP(1, 3)) circuit.add(gates.I(*range(2))) circuit.add(gates.M(3, collapse=True)) circuit.add(gates.fSim(0, 4, 0, 0)) circuit.add(gates.CU3(0, 1, 0, 0, 0)) circuit.add(gates.TOFFOLI(4, 3, 2)) circuit.add(gates.GeneralizedfSim(0, 2, np.eye(2), 0)) circuit.add(gates.X(4).controlled_by(1, 2, 3)) circuit.add(gates.M(*range(3))) assert circuit.draw(line_wrap=50) == ref_line_wrap_50 assert circuit.draw(line_wrap=30) == ref_line_wrap_30
def test_circuit_draw_channels(legend): """Check that channels are drawn correctly""" from qibo.models import Circuit as circuit c = circuit(2, density_matrix=True) c.add(gates.H(0)) c.add(gates.PauliNoiseChannel(0, 0.1, 0.0, 0.2)) c.add(gates.H(1)) c.add(gates.PauliNoiseChannel(1, 0.0, 0.2, 0.1)) c.add(gates.CNOT(0, 1)) c.add(gates.PauliNoiseChannel(0, 0.1, 0.0, 0.2)) c.add(gates.PauliNoiseChannel(1, 0.0, 0.2, 0.1)) ref = 'q0: ─H─PN─o─PN─\n' \ 'q1: ─H─PN─X─PN─' if legend: ref += '\n\n Legend for callbacks and channels: \n' \ '| Gate | Symbol |\n' \ '|-------------------+----------|\n' \ '| PauliNoiseChannel | PN |' assert c.draw(legend=legend) == ref
def test_circuit_draw(): """Test circuit text draw.""" ref = 'q0: ─H─U1─U1─U1─U1───────────────────────────x───\n' \ 'q1: ───o──|──|──|──H─U1─U1─U1────────────────|─x─\n' \ 'q2: ──────o──|──|────o──|──|──H─U1─U1────────|─|─\n' \ 'q3: ─────────o──|───────o──|────o──|──H─U1───|─x─\n' \ 'q4: ────────────o──────────o───────o────o──H─x───' circuit = Circuit(5) for i1 in range(5): circuit.add(gates.H(i1)) for i2 in range(i1 + 1, 5): circuit.add(gates.CU1(i2, i1, theta=0)) circuit.add(gates.SWAP(0, 4)) circuit.add(gates.SWAP(1, 3)) assert circuit.draw() == ref
def test_circuit_with_noise(measurements, noise_map): c = Circuit(2) c.add([gates.H(0), gates.H(1), gates.CNOT(0, 1)]) if measurements: c.add(gates.M(0, 1)) noisyc = c.with_noise(noise_map) if not isinstance(noise_map, dict): noise_map = {0: noise_map, 1: noise_map} targetc = Circuit(2) targetc.add(gates.H(0)) targetc.add(gates.PauliNoiseChannel(0, *noise_map[0])) targetc.add(gates.H(1)) targetc.add(gates.PauliNoiseChannel(1, *noise_map[1])) targetc.add(gates.CNOT(0, 1)) targetc.add(gates.PauliNoiseChannel(0, *noise_map[0])) targetc.add(gates.PauliNoiseChannel(1, *noise_map[1])) for g1, g2 in zip(noisyc.queue, targetc.queue): assert isinstance(g1, g2.__class__) assert g1.target_qubits == g2.target_qubits assert g1.control_qubits == g2.control_qubits if measurements: assert noisyc.measurement_gate.target_qubits == (0, 1) assert noisyc.measurement_tuples == {"register0": (0, 1)}
def test_circuit_on_qubits_errors(): smallc = Circuit(2) smallc.add((gates.H(i) for i in range(2))) with pytest.raises(ValueError): next(smallc.on_qubits(0, 1, 2)) smallc = Circuit(2) smallc.add(gates.Flatten(4 * [0.5])) with pytest.raises(NotImplementedError): next(smallc.on_qubits(0, 1)) from qibo.abstractions.callbacks import Callback smallc = Circuit(4) smallc.add(gates.CallbackGate(Callback())) with pytest.raises(NotImplementedError): next(smallc.on_qubits(0, 1, 2, 3))
def test_circuit_invert(measurements): c = Circuit(3) gatelist = [gates.H(0), gates.X(1), gates.Y(2), gates.CNOT(0, 1), gates.CZ(1, 2)] c.add(gatelist) if measurements: c.add(gates.M(0, 2)) invc = c.invert() for g1, g2 in zip(invc.queue, gatelist[::-1]): g2 = g2.dagger() assert isinstance(g1, g2.__class__) assert g1.target_qubits == g2.target_qubits assert g1.control_qubits == g2.control_qubits if measurements: assert invc.measurement_gate.target_qubits == (0, 2) assert invc.measurement_tuples == {"register0": (0, 2)}
def test_multiqubit_gates(): c = Circuit(2) c.add(gates.H(0)) c.add(gates.CNOT(0, 1)) c.add(gates.X(1)) c.add(gates.SWAP(0, 1)) c.add(gates.X(0).controlled_by(1)) # `controlled_by` here falls back to CNOT and should work target = f"""// Generated by QIBO {__version__} OPENQASM 2.0; include "qelib1.inc"; qreg q[2]; h q[0]; cx q[0],q[1]; x q[1]; swap q[0],q[1]; cx q[1],q[0];""" assert_strings_equal(c.to_qasm(), target)
def test_circuit_decompose(measurements): c = Circuit(4) c.add([gates.H(0), gates.X(1), gates.Y(2)]) c.add([gates.CZ(0, 1), gates.CNOT(2, 3), gates.TOFFOLI(0, 1, 3)]) if measurements: c.add(gates.M(0, 2)) decompc = c.decompose() dgates = [] for gate in c.queue: dgates.extend(gate.decompose()) for g1, g2 in zip(decompc.queue, dgates): assert isinstance(g1, g2.__class__) assert g1.target_qubits == g2.target_qubits assert g1.control_qubits == g2.control_qubits if measurements: assert decompc.measurement_gate.target_qubits == (0, 2) assert decompc.measurement_tuples == {"register0": (0, 2)}
def test_circuit_set_parameters_with_list(trainable): """Check updating parameters of circuit with list.""" params = [0.123, 0.456, (0.789, 0.321)] c = Circuit(3) if trainable: c.add(gates.RX(0, theta=0, trainable=trainable)) else: c.add(gates.RX(0, theta=params[0], trainable=trainable)) c.add(gates.RY(1, theta=0)) c.add(gates.CZ(1, 2)) c.add(gates.fSim(0, 2, theta=0, phi=0)) c.add(gates.H(2)) if trainable: c.set_parameters(params) assert c.queue[0].parameters == params[0] else: c.set_parameters(params[1:]) assert c.queue[1].parameters == params[1] assert c.queue[3].parameters == params[2]
def test_get_parameters(trainable, include_not_trainable, format): import numpy as np matrix = np.random.random((2, 2)) c = Circuit(3) c.add(gates.RX(0, theta=0.123)) c.add(gates.RY(1, theta=0.456, trainable=trainable)) c.add(gates.CZ(1, 2)) c.add(gates.Unitary(matrix, 2)) c.add(gates.fSim(0, 2, theta=0.789, phi=0.987, trainable=trainable)) c.add(gates.H(2)) c.param_tensor_types = (np.ndarray, ) params = c.get_parameters(format, include_not_trainable) if trainable or include_not_trainable: target_params = { "list": [0.123, 0.456, (0.789, 0.987)], "dict": { c.queue[0]: 0.123, c.queue[1]: 0.456, c.queue[4]: (0.789, 0.987) }, "flatlist": [0.123, 0.456] } target_params["flatlist"].extend(list(matrix.ravel())) target_params["flatlist"].extend([0.789, 0.987]) else: target_params = { "list": [0.123], "dict": { c.queue[0]: 0.123 }, "flatlist": [0.123] } target_params["flatlist"].extend(list(matrix.ravel())) if format == "list": i = len(target_params["list"]) // 2 + 1 np.testing.assert_allclose(params.pop(i), matrix) elif format == "dict": np.testing.assert_allclose(params.pop(c.queue[3]), matrix) assert params == target_params[format] with pytest.raises(ValueError): c.get_parameters("test")