def test_set_parameters_with_gate_fusion(backend, accelerators): """Check updating parameters of fused circuit.""" original_backend = qibo.get_backend() qibo.set_backend(backend) params = np.random.random(9) c = Circuit(5, accelerators) c.add(gates.RX(0, theta=params[0])) c.add(gates.RY(1, theta=params[1])) c.add(gates.CZ(0, 1)) c.add(gates.RX(2, theta=params[2])) c.add(gates.RY(3, theta=params[3])) c.add(gates.fSim(2, 3, theta=params[4], phi=params[5])) c.add(gates.RX(4, theta=params[6])) c.add(gates.RZ(0, theta=params[7])) c.add(gates.RZ(1, theta=params[8])) fused_c = c.fuse() np.testing.assert_allclose(c(), fused_c()) new_params = np.random.random(9) new_params_list = list(new_params[:4]) new_params_list.append((new_params[4], new_params[5])) new_params_list.extend(new_params[6:]) c.set_parameters(new_params_list) fused_c.set_parameters(new_params_list) np.testing.assert_allclose(c(), fused_c()) qibo.set_backend(original_backend)
def test_set_parameters_with_gate_fusion(backend, trainable): """Check updating parameters of fused circuit.""" params = np.random.random(9) c = Circuit(5) c.add(gates.RX(0, theta=params[0], trainable=trainable)) c.add(gates.RY(1, theta=params[1])) c.add(gates.CZ(0, 1)) c.add(gates.RX(2, theta=params[2])) c.add(gates.RY(3, theta=params[3], trainable=trainable)) c.add(gates.fSim(2, 3, theta=params[4], phi=params[5])) c.add(gates.RX(4, theta=params[6])) c.add(gates.RZ(0, theta=params[7], trainable=trainable)) c.add(gates.RZ(1, theta=params[8])) fused_c = c.fuse() final_state = fused_c() target_state = c() K.assert_allclose(final_state, target_state) if trainable: new_params = np.random.random(9) new_params_list = list(new_params[:4]) new_params_list.append((new_params[4], new_params[5])) new_params_list.extend(new_params[6:]) else: new_params = np.random.random(9) new_params_list = list(new_params[1:3]) new_params_list.append((new_params[4], new_params[5])) new_params_list.append(new_params[6]) new_params_list.append(new_params[8]) c.set_parameters(new_params_list) fused_c.set_parameters(new_params_list) K.assert_allclose(c(), fused_c())
def test_single_fusion_gate(): """Check circuit fusion that creates a single ``FusedGate``.""" queue = [gates.H(0), gates.X(1), gates.CZ(0, 1)] c = Circuit(2) c.add(queue) c = c.fuse() assert len(c.queue) == 1 gate = c.queue[0] for gate, target in zip(gate.gates, queue): assert gate == target
def test_fuse_circuit_two_qubit_gates(backend): """Check circuit fusion in circuit with two-qubit gates only.""" c = Circuit(2) c.add(gates.CNOT(0, 1)) c.add(gates.RX(0, theta=0.1234).controlled_by(1)) c.add(gates.SWAP(0, 1)) c.add(gates.fSim(1, 0, theta=0.1234, phi=0.324)) c.add(gates.RY(1, theta=0.1234).controlled_by(0)) fused_c = c.fuse() K.assert_allclose(fused_c(), c())
def test_inverse_circuit_execution(backend, accelerators, fuse): c = Circuit(4, accelerators) c.add(gates.RX(0, theta=0.1)) c.add(gates.U2(1, phi=0.2, lam=0.3)) c.add(gates.U3(2, theta=0.1, phi=0.3, lam=0.2)) c.add(gates.CNOT(0, 1)) c.add(gates.CZ(1, 2)) c.add(gates.fSim(0, 2, theta=0.1, phi=0.3)) c.add(gates.CU2(0, 1, phi=0.1, lam=0.1)) if fuse: if accelerators: with pytest.raises(NotImplementedError): c = c.fuse() else: c = c.fuse() invc = c.invert() target_state = np.ones(2**4) / 4 final_state = invc(c(np.copy(target_state))) K.assert_allclose(final_state, target_state)
def test_single_fusion_gate(): """Check circuit fusion that creates a single ``FusedGate``.""" queue = [gates.H(0), gates.X(1), gates.CZ(0, 1)] c = Circuit(2) c.add(queue) c = c.fuse() assert len(c.queue) == 1 fgate = c.queue[0] assert fgate.gates[0] == queue[1] assert fgate.gates[1] == queue[0] assert fgate.gates[2] == queue[2]
def test_controlled_by_gates_fusion(backend): """Check circuit fusion that contains ``controlled_by`` gates.""" c = Circuit(4) c.add((gates.H(i) for i in range(4))) c.add(gates.RX(1, theta=0.1234).controlled_by(0)) c.add(gates.RX(3, theta=0.4321).controlled_by(2)) c.add((gates.RY(i, theta=0.5678) for i in range(4))) c.add(gates.RX(1, theta=0.1234).controlled_by(0)) c.add(gates.RX(3, theta=0.4321).controlled_by(2)) fused_c = c.fuse() K.assert_allclose(fused_c(), c())
def test_fusedgate_matrix_calculation(backend): queue = [gates.H(0), gates.H(1), gates.CNOT(0, 1), gates.X(0), gates.X(1)] circuit = Circuit(2) circuit.add(queue) circuit = circuit.fuse() assert len(circuit.queue) == 1 fused_gate = circuit.queue[0] x = np.array([[0, 1], [1, 0]]) h = np.array([[1, 1], [1, -1]]) / np.sqrt(2) cnot = np.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0]]) target_matrix = np.kron(x, x) @ cnot @ np.kron(h, h) K.assert_allclose(fused_gate.matrix, target_matrix)
def test_fuse_circuit_two_qubit_only(): """Check gate fusion in circuit with two-qubit gates only.""" c = Circuit(2) c.add(gates.CNOT(0, 1)) c.add(gates.RX(0, theta=0.1234).controlled_by(1)) c.add(gates.SWAP(0, 1)) c.add(gates.fSim(1, 0, theta=0.1234, phi=0.324)) c.add(gates.RY(1, theta=0.1234).controlled_by(0)) fused_c = c.fuse() target_state = c() final_state = fused_c() np.testing.assert_allclose(final_state, target_state)
def test_fuse_circuit_three_qubit_gate(backend, max_qubits): """Check circuit fusion in circuit with three-qubit gate.""" c = Circuit(4) c.add((gates.H(i) for i in range(4))) c.add(gates.CZ(0, 1)) c.add(gates.CZ(2, 3)) c.add(gates.TOFFOLI(0, 1, 2)) c.add(gates.SWAP(1, 2)) c.add((gates.H(i) for i in range(4))) c.add(gates.CNOT(0, 1)) c.add(gates.CZ(2, 3)) fused_c = c.fuse(max_qubits=max_qubits) K.assert_allclose(fused_c(), c(), atol=1e-12)
def test_two_fusion_gate(): """Check fusion that creates two ``FusedGate``s.""" queue = [gates.X(0), gates.H(1), gates.RX(2, theta=0.1234).controlled_by(1), gates.H(2), gates.Y(1), gates.H(0)] c = Circuit(3) c.add(queue) c = c.fuse() assert len(c.queue) == 2 fgate1, fgate2 = c.queue assert fgate2.gates[0] == queue[0] assert fgate2.gates[1] == queue[-1] assert fgate1.gates == [queue[1], queue[2], queue[4], queue[3]]
def test_callbacks_fusion(backend): """Check entropy calculation in fused circuit.""" from qibo import callbacks entropy = callbacks.EntanglementEntropy([0]) c = Circuit(5) c.add(gates.H(0)) c.add(gates.X(1)) c.add(gates.CallbackGate(entropy)) c.add(gates.CNOT(0, 1)) c.add(gates.CallbackGate(entropy)) fused_c = c.fuse() K.assert_allclose(fused_c(), c()) target_entropy = [0.0, 1.0, 0.0, 1.0] K.assert_allclose(entropy[:], target_entropy, atol=1e-7)
def test_set_parameters_fusion(backend): """Check gate fusion when ``circuit.set_parameters`` is used.""" c = Circuit(2) c.add(gates.RX(0, theta=0.1234)) c.add(gates.RX(1, theta=0.1234)) c.add(gates.CNOT(0, 1)) c.add(gates.RY(0, theta=0.1234)) c.add(gates.RY(1, theta=0.1234)) fused_c = c.fuse() K.assert_allclose(fused_c(), c()) c.set_parameters(4 * [0.4321]) fused_c.set_parameters(4 * [0.4321]) K.assert_allclose(fused_c(), c())
def test_fuse_circuit_with_controlled_by_gates(): """Check gate fusion in circuit that contains ``controlled_by`` gates.""" c = Circuit(4) c.add((gates.H(i) for i in range(4))) c.add(gates.RX(1, theta=0.1234).controlled_by(0)) c.add(gates.RX(3, theta=0.4321).controlled_by(2)) c.add((gates.RY(i, theta=0.5678) for i in range(4))) c.add(gates.RX(1, theta=0.1234).controlled_by(0)) c.add(gates.RX(3, theta=0.4321).controlled_by(2)) fused_c = c.fuse() target_state = c() final_state = fused_c() np.testing.assert_allclose(final_state, target_state)
def test_variational_layer_fusion(backend, nqubits, nlayers, max_qubits): """Check fused variational layer execution.""" theta = 2 * np.pi * np.random.random((2 * nlayers * nqubits,)) theta_iter = iter(theta) c = Circuit(nqubits) for _ in range(nlayers): c.add((gates.RY(i, next(theta_iter)) for i in range(nqubits))) c.add((gates.CZ(i, i + 1) for i in range(0, nqubits - 1, 2))) c.add((gates.RY(i, next(theta_iter)) for i in range(nqubits))) c.add((gates.CZ(i, i + 1) for i in range(1, nqubits - 1, 2))) c.add(gates.CZ(0, nqubits - 1)) fused_c = c.fuse(max_qubits=max_qubits) K.assert_allclose(fused_c(), c())
def test_random_circuit_fusion(backend, nqubits, ngates, max_qubits): """Check gate fusion in randomly generated circuits.""" one_qubit_gates = [gates.RX, gates.RY, gates.RZ] two_qubit_gates = [gates.CNOT, gates.CZ, gates.SWAP] thetas = np.pi * np.random.random((ngates,)) c = Circuit(nqubits) for i in range(ngates): gate = one_qubit_gates[int(np.random.randint(0, 3))] q0 = np.random.randint(0, nqubits) c.add(gate(q0, thetas[i])) gate = two_qubit_gates[int(np.random.randint(0, 3))] q0, q1 = np.random.randint(0, nqubits, (2,)) while q0 == q1: q0, q1 = np.random.randint(0, nqubits, (2,)) c.add(gate(q0, q1)) fused_c = c.fuse(max_qubits=max_qubits) K.assert_allclose(fused_c(), c(), atol=1e-7)
def test_fuse_with_callback(accelerators): """Check entropy calculation in fused circuit.""" from qibo import callbacks entropy = callbacks.EntanglementEntropy([0]) c = Circuit(2, accelerators) c.add(gates.H(0)) c.add(gates.X(1)) c.add(gates.CallbackGate(entropy)) c.add(gates.CNOT(0, 1)) c.add(gates.CallbackGate(entropy)) fused_c = c.fuse() target_state = c() final_state = fused_c() np.testing.assert_allclose(final_state, target_state) target_entropy = [0.0, 1.0, 0.0, 1.0] np.testing.assert_allclose(entropy[:], target_entropy, atol=1e-7)
def test_fusion_errors(): group = fusion.FusionGroup() with pytest.raises(ValueError): group.first_gate(2) group = fusion.FusionGroup() group.add(gates.Flatten(np.ones(4))) group.can_add(gates.H(0)) with pytest.raises(RuntimeError): group.add(gates.H(0)) group = fusion.FusionGroup() group.can_add(gates.H(0)) group.add(gates.H(0)) group.can_add(gates.RX(0, theta=0.1234).controlled_by(1)) with pytest.raises(ValueError): group.add(gates.Flatten(np.ones(4))) group = fusion.FusionGroup() group.add(gates.RX(0, theta=0.1234).controlled_by(1)) with pytest.raises(ValueError): group.add(gates.H(2)) group = fusion.FusionGroup() group.add(gates.RX(0, theta=0.1234).controlled_by(1)) with pytest.raises(ValueError): group.add(gates.CZ(1, 2)) group = fusion.FusionGroup() with pytest.raises(ValueError): group.add(gates.TOFFOLI(0, 1, 2)) group = fusion.FusionGroup() with pytest.raises(RuntimeError): group.calculate() # Fuse distributed circuit after gates are set import qibo if qibo.get_backend() == "custom": c = Circuit(4, accelerators={"/GPU:0": 2}) c.add((gates.H(i) for i in range(4))) final_state = c() with pytest.raises(RuntimeError): fused_c = c.fuse()
def test_inverse_circuit_execution(backend, accelerators, fuse): original_backend = qibo.get_backend() qibo.set_backend(backend) c = Circuit(4, accelerators) c.add(gates.RX(0, theta=0.1)) c.add(gates.U2(1, phi=0.2, lam=0.3)) c.add(gates.U3(2, theta=0.1, phi=0.3, lam=0.2)) c.add(gates.CNOT(0, 1)) c.add(gates.CZ(1, 2)) c.add(gates.fSim(0, 2, theta=0.1, phi=0.3)) c.add(gates.CU2(0, 1, phi=0.1, lam=0.1)) if fuse: c = c.fuse() invc = c.invert() target_state = np.ones(2 ** 4) / 4 final_state = invc(c(np.copy(target_state))) np.testing.assert_allclose(final_state, target_state) qibo.set_backend(original_backend)
def test_two_fusion_gate(): """Check fusion that creates two ``FusedGate``s.""" queue = [ gates.X(0), gates.H(1), gates.RX(2, theta=0.1234).controlled_by(1), gates.H(2), gates.Y(1), gates.H(0) ] c = Circuit(3) c.add(queue) c = c.fuse() assert len(c.queue) == 2 gate1, gate2 = c.queue if len(gate1.gates) > len(gate2.gates): # pragma: no cover # disabling coverage as this may not always happen gate1, gate2 = gate2, gate1 assert gate1.gates == [queue[0], queue[-1]] assert gate2.gates == queue[1:-1]
def test_circuit_set_parameters_errors(): """Check updating parameters errors.""" c = Circuit(2) c.add(gates.RX(0, theta=0.789)) c.add(gates.RX(1, theta=0.789)) c.add(gates.fSim(0, 1, theta=0.123, phi=0.456)) with pytest.raises(ValueError): c.set_parameters({gates.RX(0, theta=1.0): 0.568}) with pytest.raises(ValueError): c.set_parameters([0.12586]) with pytest.raises(ValueError): c.set_parameters(np.random.random(5)) with pytest.raises(ValueError): import tensorflow as tf c.set_parameters(tf.random.uniform((6,), dtype=tf.float64)) with pytest.raises(TypeError): c.set_parameters({0.3568}) fused_c = c.fuse() with pytest.raises(TypeError): fused_c.set_parameters({gates.RX(0, theta=1.0): 0.568})
def test_fuse_random_circuits(nqubits, ngates, accelerators): """Check gate fusion in randomly generated circuits.""" one_qubit_gates = [gates.RX, gates.RY, gates.RZ] two_qubit_gates = [gates.CNOT, gates.CZ, gates.SWAP] for _ in range(10): thetas = np.pi * np.random.random((ngates, )) c = Circuit(nqubits, accelerators) for i in range(ngates): gate = one_qubit_gates[int(np.random.randint(0, 3))] q0 = np.random.randint(0, nqubits) c.add(gate(q0, thetas[i])) gate = two_qubit_gates[int(np.random.randint(0, 3))] q0, q1 = np.random.randint(0, nqubits, (2, )) while q0 == q1: q0, q1 = np.random.randint(0, nqubits, (2, )) c.add(gate(q0, q1)) fused_c = c.fuse() target_state = c() final_state = fused_c() np.testing.assert_allclose(final_state, target_state)
def test_circuit_fuse_variational_layer(backend, nqubits, nlayers, accelerators): """Check fused variational layer execution.""" import qibo if accelerators: backend = "custom" original_backend = qibo.get_backend() qibo.set_backend(backend) theta = 2 * np.pi * np.random.random((2 * nlayers * nqubits, )) theta_iter = iter(theta) c = Circuit(nqubits, accelerators=accelerators) for _ in range(nlayers): c.add((gates.RY(i, next(theta_iter)) for i in range(nqubits))) c.add((gates.CZ(i, i + 1) for i in range(0, nqubits - 1, 2))) c.add((gates.RY(i, next(theta_iter)) for i in range(nqubits))) c.add((gates.CZ(i, i + 1) for i in range(1, nqubits - 2, 2))) c.add(gates.CZ(0, nqubits - 1)) fused_c = c.fuse() target_state = c() final_state = fused_c() np.testing.assert_allclose(final_state, target_state) qibo.set_backend(original_backend)