def test_circuit_set_parameters_with_dictionary(backend, accelerators): """Check updating parameters of circuit with list.""" original_backend = qibo.get_backend() qibo.set_backend(backend) c = Circuit(3, accelerators) c.add(gates.X(0)) c.add(gates.X(2)) c.add(gates.ZPow(0, theta=0)) c.add(gates.RZ(1, theta=0)) c.add(gates.CZ(1, 2)) c.add(gates.CZPow(0, 2, theta=0)) c.add(gates.H(2)) c.add(gates.Unitary(np.eye(2), 1)) final_state = c() params = [0.123, 0.456, 0.789, np.random.random((2, 2))] target_c = Circuit(3, accelerators) target_c.add(gates.X(0)) target_c.add(gates.X(2)) target_c.add(gates.ZPow(0, theta=params[0])) target_c.add(gates.RZ(1, theta=params[1])) target_c.add(gates.CZ(1, 2)) target_c.add(gates.CZPow(0, 2, theta=params[2])) target_c.add(gates.H(2)) target_c.add(gates.Unitary(params[3], 1)) param_dict = {c.queue[i]: p for i, p in zip([2, 3, 5, 7], params)} c.set_parameters(param_dict) np.testing.assert_allclose(c(), target_c()) qibo.set_backend(original_backend)
def test_zpow_gate(backend): """Check ZPow and CZPow gate fall back to U1 and CU1 respectively.""" original_backend = qibo.get_backend() qibo.set_backend(backend) theta = 0.1234 c = Circuit(1) c.add(gates.X(0)) c.add(gates.ZPow(0, theta)) final_state = c.execute().numpy() target_state = np.zeros_like(final_state) target_state[1] = np.exp(1j * theta) np.testing.assert_allclose(final_state, target_state) assert c.queue[1].name == "u1" c = Circuit(2) c.add([gates.X(0), gates.X(1)]) c.add(gates.CZPow(0, 1, theta)) final_state = c.execute().numpy() target_state = np.zeros_like(final_state) target_state[-1] = np.exp(1j * theta) np.testing.assert_allclose(final_state, target_state) assert c.queue[2].name == "cu1" qibo.set_backend(original_backend)
def _DistributedQFT(nqubits: int, accelerators: Optional[Dict[str, int]] = None, memory_device: str = "/CPU:0") -> DistributedCircuit: """QFT with the order of gates optimized for reduced multi-device communication.""" import numpy as np from qibo import gates circuit = Circuit(nqubits, accelerators, memory_device) icrit = nqubits // 2 + nqubits % 2 if accelerators is not None: circuit.global_qubits = range(circuit.nlocal, nqubits) if icrit < circuit.nglobal: raise_error(NotImplementedError, "Cannot implement QFT for {} qubits " "using {} global qubits." "".format(nqubits, circuit.nglobal)) for i1 in range(nqubits): if i1 < icrit: i1eff = i1 else: i1eff = nqubits - i1 - 1 circuit.add(gates.SWAP(i1, i1eff)) circuit.add(gates.H(i1eff)) for i2 in range(i1 + 1, nqubits): theta = np.pi / 2 ** (i2 - i1) circuit.add(gates.CZPow(i2, i1eff, theta)) return circuit
def test_czpow(backend): original_backend = qibo.get_backend() qibo.set_backend(backend) theta = 0.1234 gatelist = [gates.X(0), gates.X(1), gates.CZPow(0, 1, theta)] final_state = apply_gates(gatelist, nqubits=2) target_state = np.zeros_like(final_state) target_state[-1] = np.exp(1j * theta) np.testing.assert_allclose(final_state, target_state) qibo.set_backend(original_backend)
def QFT(nqubits: int, with_swaps: bool = True, accelerators: Optional[Dict[str, int]] = None, memory_device: str = "/CPU:0") -> Circuit: """Creates a circuit that implements the Quantum Fourier Transform. Args: nqubits (int): Number of qubits in the circuit. with_swaps (bool): Use SWAP gates at the end of the circuit so that the qubit order in the final state is the same as the initial state. accelerators (dict): Accelerator device dictionary in order to use a distributed circuit If ``None`` a simple (non-distributed) circuit will be used. memory_device (str): Device to use for memory in case a distributed circuit is used. Ignored for non-distributed circuits. Returns: A qibo.models.Circuit that implements the Quantum Fourier Transform. Example: :: import numpy as np from qibo.models import QFT nqubits = 6 c = QFT(nqubits) # Random normalized initial state vector init_state = np.random.random(2 ** nqubits) + 1j * np.random.random(2 ** nqubits) init_state = init_state / np.sqrt((np.abs(init_state)**2).sum()) # Execute the circuit final_state = c(init_state) """ if accelerators is not None: if not with_swaps: raise_error(NotImplementedError, "Distributed QFT is only implemented " "with SWAPs.") return _DistributedQFT(nqubits, accelerators, memory_device) import numpy as np from qibo import gates circuit = Circuit(nqubits) for i1 in range(nqubits): circuit.add(gates.H(i1)) for i2 in range(i1 + 1, nqubits): theta = np.pi / 2 ** (i2 - i1) circuit.add(gates.CZPow(i2, i1, theta)) if with_swaps: for i in range(nqubits // 2): circuit.add(gates.SWAP(i, nqubits - i - 1)) return circuit
def test_czpow(): c = Circuit(2) c.add(gates.RX(0, 0.1234)) c.add(gates.RZ(1, 0.4321)) c.add(gates.CZPow(0, 1, 0.567)) target = f"""// Generated by QIBO {__version__} OPENQASM 2.0; include "qelib1.inc"; qreg q[2]; rx(0.1234) q[0]; rz(0.4321) q[1]; crz(0.567) q[0],q[1];""" assert_strings_equal(c.to_qasm(), target)
def test_two_qubit_parametrized_gates(backend, nqubits, ndevices): """Check ``CZPow`` and ``fSim`` gate.""" original_backend = qibo.get_backend() qibo.set_backend(backend) theta = 0.1234 phi = 0.4321 targets = random_active_qubits(nqubits, nactive=2) qibo_gate = gates.CZPow(*targets, np.pi * theta) cirq_gate = [(cirq.CZPowGate(exponent=theta), targets)] assert_gates_equivalent(qibo_gate, cirq_gate, nqubits) targets = random_active_qubits(nqubits, nactive=2) qibo_gate = gates.fSim(*targets, theta, phi) cirq_gate = [(cirq.FSimGate(theta=theta, phi=phi), targets)] assert_gates_equivalent(qibo_gate, cirq_gate, nqubits, ndevices) qibo.set_backend(original_backend)
def test_construct_unitary(backend): qibo.set_backend(backend) target_matrix = np.array([[1, 1], [1, -1]]) / np.sqrt(2) np.testing.assert_allclose(gates.H(0).unitary, target_matrix) target_matrix = np.array([[0, 1], [1, 0]]) np.testing.assert_allclose(gates.X(0).unitary, target_matrix) target_matrix = np.array([[0, -1j], [1j, 0]]) np.testing.assert_allclose(gates.Y(0).unitary, target_matrix) target_matrix = np.array([[1, 0], [0, -1]]) np.testing.assert_allclose(gates.Z(1).unitary, target_matrix) target_matrix = np.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0]]) np.testing.assert_allclose(gates.CNOT(0, 1).unitary, target_matrix) target_matrix = np.diag([1, 1, 1, -1]) np.testing.assert_allclose(gates.CZ(1, 3).unitary, target_matrix) target_matrix = np.array([[1, 0, 0, 0], [0, 0, 1, 0], [0, 1, 0, 0], [0, 0, 0, 1]]) np.testing.assert_allclose(gates.SWAP(2, 4).unitary, target_matrix) target_matrix = np.array([[1, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 0, 1, 0, 0, 0], [0, 0, 0, 0, 0, 1, 0, 0], [0, 0, 0, 0, 0, 0, 0, 1], [0, 0, 0, 0, 0, 0, 1, 0]]) np.testing.assert_allclose(gates.TOFFOLI(1, 2, 3).unitary, target_matrix) theta = 0.1234 target_matrix = np.array([[np.cos(theta / 2.0), -1j * np.sin(theta / 2.0)], [-1j * np.sin(theta / 2.0), np.cos(theta / 2.0)]]) np.testing.assert_allclose(gates.RX(0, theta).unitary, target_matrix) target_matrix = np.array([[np.cos(theta / 2.0), -np.sin(theta / 2.0)], [np.sin(theta / 2.0), np.cos(theta / 2.0)]]) np.testing.assert_allclose(gates.RY(0, theta).unitary, target_matrix) target_matrix = np.diag([np.exp(-1j * theta / 2.0), np.exp(1j * theta / 2.0)]) np.testing.assert_allclose(gates.RZ(0, theta).unitary, target_matrix) target_matrix = np.diag([1, np.exp(1j * theta)]) np.testing.assert_allclose(gates.ZPow(0, theta).unitary, target_matrix) target_matrix = np.diag([1, 1, 1, np.exp(1j * theta)]) np.testing.assert_allclose(gates.CZPow(0, 1, theta).unitary, target_matrix) from qibo import matrices target_matrix = np.array([[1, 0, 0, 0], [0, 0, 1, 0], [0, 1, 0, 0], [0, 0, 0, 1]]) np.testing.assert_allclose(matrices.SWAP, target_matrix)
def test_czpow(backend, accelerators): """Check CZPow gate is working properly on |11>.""" original_backend = qibo.get_backend() qibo.set_backend(backend) theta = 0.1234 c = Circuit(2, accelerators) c.add(gates.X(0)) c.add(gates.X(1)) c.add(gates.CZPow(0, 1, theta)) final_state = c.execute().numpy() phase = np.exp(1j * theta) target_state = np.zeros_like(final_state) target_state[3] = phase np.testing.assert_allclose(final_state, target_state) qibo.set_backend(original_backend)
def test_circuit_copy(backend, accelerators, deep): """Check that circuit copy execution is equivalent to original circuit.""" original_backend = qibo.get_backend() qibo.set_backend(backend) theta = 0.1234 c1 = Circuit(2, accelerators) c1.add([gates.X(0), gates.X(1), gates.CZPow(0, 1, theta)]) if not deep and accelerators is not None: with pytest.raises(ValueError): c2 = c1.copy(deep) else: c2 = c1.copy(deep) target_state = c1.execute().numpy() final_state = c2.execute().numpy() np.testing.assert_allclose(final_state, target_state) qibo.set_backend(original_backend)
def test_from_qasm_parametrized_gates(): import numpy as np target = """OPENQASM 2.0; qreg q[2]; rx(0.1234) q[0]; rz(0.4321) q[1]; crz(0.567) q[0],q[1];""" c = Circuit.from_qasm(target) assert c.depth == 3 assert isinstance(c.queue[0], gates.RX) assert isinstance(c.queue[1], gates.RZ) assert isinstance(c.queue[2], gates.CZPow) c2 = Circuit(2) c2.add( [gates.RX(0, 0.1234), gates.RZ(1, 0.4321), gates.CZPow(0, 1, 0.567)]) np.testing.assert_allclose(c2().numpy(), c().numpy())
def SupremacyLikeCircuit(nqubits: int, nlayers: int): one_qubit_gates = ["RX", "RY", "RZ"] d = 1 for l in range(nlayers): for i in range(nqubits): gate = getattr( gates, one_qubit_gates[int(np.random.randint(0, len(one_qubit_gates)))]) yield gate(i, np.pi / 2.0) for i in range(nqubits): yield gates.CZPow(i, (i + d) % nqubits, np.pi / 6.0) d += 1 if d > nqubits - 1: d = 1 for i in range(nqubits): gate = getattr( gates, one_qubit_gates[int(np.random.randint(0, len(one_qubit_gates)))]) yield gate(i, np.pi / 2.0) yield gates.M(i)
def test_custom_circuit(backend): """Check consistency between Circuit and custom circuits""" import tensorflow as tf original_backend = qibo.get_backend() qibo.set_backend(backend) theta = 0.1234 c = Circuit(2) c.add(gates.X(0)) c.add(gates.X(1)) c.add(gates.CZPow(0, 1, theta)) r1 = c.execute().numpy() # custom circuit def custom_circuit(initial_state, theta): l1 = gates.X(0)(initial_state) l2 = gates.X(1)(l1) o = gates.CZPow(0, 1, theta)(l2) return o init2 = c._default_initial_state() init3 = c._default_initial_state() if backend != "custom": init2 = tf.reshape(init2, (2, 2)) init3 = tf.reshape(init3, (2, 2)) r2 = custom_circuit(init2, theta).numpy().ravel() np.testing.assert_allclose(r1, r2) tf_custom_circuit = tf.function(custom_circuit) if backend == "custom": with pytest.raises(NotImplementedError): r3 = tf_custom_circuit(init3, theta).numpy().ravel() else: r3 = tf_custom_circuit(init3, theta).numpy().ravel() np.testing.assert_allclose(r2, r3) qibo.set_backend(original_backend)
def run_circuit(initial_state): c = Circuit(2) c.add(gates.X(0)) c.add(gates.X(1)) c.add(gates.CZPow(0, 1, theta)) return c.execute(initial_state)
def custom_circuit(initial_state, theta): l1 = gates.X(0)(initial_state) l2 = gates.X(1)(l1) o = gates.CZPow(0, 1, theta)(l2) return o
def ansatz_Fourier(layers, qubits=1): """Fourier Ansatz implementation. It is composed by 3 parameters per layer and qubit: U3(a, b, c) Ry(x) || U3(a, b, c) Ry(log x). Args: layers (int): number of layers. qubits (int): number of qubits. Returns: The circuit, the rotation function and the total number of parameters. """ circuit = models.Circuit(qubits) for l in range(layers - 1): for q in range(qubits): for _ in range(2): circuit.add(gates.RY(q, theta=0)) circuit.add(gates.RZ(q, theta=0)) circuit.add(gates.RY(q, theta=0)) if qubits > 1: for q in range(0, qubits, 2): circuit.add(gates.CZPow(q, q + 1, theta=0)) if qubits > 2: for q in range(1, qubits + 1, 2): circuit.add(gates.CZPow(q, (q + 1) % qubits, theta=0)) for q in range(qubits): for _ in range(2): circuit.add(gates.RY(q, theta=0)) circuit.add(gates.RZ(q, theta=0)) circuit.add(gates.RY(q, theta=0)) def rotation(theta, x): p = circuit.get_parameters() i = 0 j = 0 for l in range(layers - 1): for q in range(qubits): p[i] = map_to(x) p[i + 1:i + 3] = theta[j:j + 2] i += 3 j += 2 p[i] = .5 * maplog_to(x) p[i + 1:i + 3] = theta[j:j + 2] i += 3 j += 2 if qubits > 1: for q in range(0, qubits, 2): p[i] = theta[j] i += 1 j += 1 if qubits > 2: for q in range(1, qubits + 1, 2): p[i] = theta[j] i += 1 j += 1 for q in range(qubits): p[i] = .5 * map_to(x) p[i + 1:i + 3] = theta[j:j + 2] i += 3 j += 2 p[i] = .5 * maplog_to(x) p[i + 1:i + 3] = theta[j:j + 2] i += 3 j += 2 return p nparams = 4 * layers * qubits + \ (layers - 1) * int(np.ceil(qubits / 2)) * \ (int(qubits > 1) + int(qubits > 2)) return circuit, rotation, nparams
def ansatz_Weighted(layers, qubits=1): """Fourier Ansatz implementation. 4 parameters per layer and qubit: Ry(wx + a), Rz(v log(x) + b) Args: layers (int): number of layers. qubits (int): number of qubits. Returns: The circuit, the rotation function and the total number of parameters. """ circuit = models.Circuit(qubits) for _ in range(layers - 1): for q in range(qubits): circuit.add(gates.RY(q, theta=0)) circuit.add(gates.RZ(q, theta=0)) if qubits > 1: for q in range(0, qubits, 2): circuit.add(gates.CZPow(q, (q + 1) % qubits, theta=0)) if qubits > 2: for q in range(1, qubits + 1, 2): circuit.add(gates.CZPow(q, (q + 1) % qubits, theta=0)) for q in range(qubits): circuit.add(gates.RY(q, theta=0)) circuit.add(gates.RZ(q, theta=0)) def rotation(theta, x): p = circuit.get_parameters() i = 0 j = 0 for l in range(layers - 1): for q in range(qubits): p[i] = theta[j] + theta[j + 1] * map_to(x) p[i + 1] = theta[j + 2] + theta[j + 3] * maplog_to(x) i += 2 j += 4 if qubits > 1: for q in range(0, qubits, 2): p[i] = theta[j] i += 1 j += 1 if qubits > 2: for q in range(1, qubits + 1, 2): p[i] = theta[j] i += 1 j += 1 for q in range(qubits): p[i] = theta[j] + theta[j + 1] * map_to(x) p[i + 1] = theta[j + 2] + theta[j + 3] * maplog_to(x) i += 2 j += 4 return p nparams = 4 * layers * qubits + \ (layers - 1) * int(np.ceil(qubits / 2)) * \ (int(qubits > 1) + int(qubits > 2)) return circuit, rotation, nparams
def create_circuit(theta = 0.1234): c = Circuit(2) c.add(gates.X(0)) c.add(gates.X(1)) c.add(gates.CZPow(0, 1, theta)) return c