def assert_gates_equivalent(qibo_gate, cirq_gates, nqubits, ndevices=None, atol=1e-7): """Asserts that QIBO and Cirq gates have equivalent action on a random state. Args: qibo_gate: QIBO gate. cirq_gates: List of tuples (cirq gate, target qubit IDs). nqubits: Total number of qubits in the circuit. atol: Absolute tolerance in state vector comparsion. """ initial_state = random_state(nqubits) target_state, target_depth = execute_cirq(cirq_gates, nqubits, np.copy(initial_state)) accelerators = None if ndevices is not None: accelerators = {"/GPU:0": ndevices} if accelerators: if not K.supports_multigpu: with pytest.raises(NotImplementedError): c = models.Circuit(nqubits, accelerators) elif K.get_platform() == "numba" and len( K.available_platforms) > 1: # pragma: no cover pytest.skip("Skipping distributed cirq test for numba platform.") else: c = models.Circuit(nqubits, accelerators) c.add(qibo_gate) final_state = c(np.copy(initial_state)) assert c.depth == target_depth K.assert_allclose(final_state, target_state, atol=atol)
def test_circuit_with_noise_noise_map(): """Check ``circuit.with_noise() when giving noise map.""" original_backend = qibo.get_backend() qibo.set_backend("matmuleinsum") noise_map = {0: (0.1, 0.2, 0.1), 1: (0.2, 0.3, 0.0), 2: (0.0, 0.0, 0.0)} c = models.Circuit(3) c.add([gates.H(0), gates.H(1), gates.X(2)]) c.add(gates.M(2)) noisy_c = c.with_noise(noise_map, measurement_noise = (0.3, 0.0, 0.0)) target_c = models.Circuit(3) target_c.add(gates.H(0)) target_c.add(gates.NoiseChannel(0, 0.1, 0.2, 0.1)) target_c.add(gates.NoiseChannel(1, 0.2, 0.3, 0.0)) target_c.add(gates.H(1)) target_c.add(gates.NoiseChannel(0, 0.1, 0.2, 0.1)) target_c.add(gates.NoiseChannel(1, 0.2, 0.3, 0.0)) target_c.add(gates.X(2)) target_c.add(gates.NoiseChannel(0, 0.1, 0.2, 0.1)) target_c.add(gates.NoiseChannel(1, 0.2, 0.3, 0.0)) target_c.add(gates.NoiseChannel(2, 0.3, 0.0, 0.0)) final_state = noisy_c().numpy() target_state = target_c().numpy() np.testing.assert_allclose(target_state, final_state) qibo.set_backend(original_backend)
def test_measurements_with_probabilistic_noise(): """Check measurements when simulating noise with repeated execution.""" import tensorflow as tf thetas = np.random.random(5) c = models.Circuit(5) c.add((gates.RX(i, t) for i, t in enumerate(thetas))) c.add((gates.PauliNoiseChannel(i, px=0.0, py=0.2, pz=0.4, seed=123) for i in range(5))) c.add(gates.M(*range(5))) tf.random.set_seed(123) result = c(nshots=20) np.random.seed(123) tf.random.set_seed(123) target_samples = [] for _ in range(20): noiseless_c = models.Circuit(5) noiseless_c.add((gates.RX(i, t) for i, t in enumerate(thetas))) for i in range(5): if np.random.random() < 0.2: noiseless_c.add(gates.Y(i)) if np.random.random() < 0.4: noiseless_c.add(gates.Z(i)) noiseless_c.add(gates.M(*range(5))) target_samples.append(noiseless_c(nshots=1).samples()) target_samples = tf.concat(target_samples, axis=0) np.testing.assert_allclose(result.samples(), target_samples)
def assert_gates_equivalent(qibo_gate, cirq_gates, nqubits, ndevices=None, atol=1e-7): """Asserts that QIBO and Cirq gates have equivalent action on a random state. Args: qibo_gate: QIBO gate. cirq_gates: List of tuples (cirq gate, target qubit IDs). nqubits: Total number of qubits in the circuit. atol: Absolute tolerance in state vector comparsion. """ initial_state = random_state(nqubits) target_state, target_depth = execute_cirq(cirq_gates, nqubits, np.copy(initial_state)) backend = qibo.get_backend() if ndevices is None or "numpy" in backend: accelerators = None else: accelerators = {"/GPU:0": ndevices} if backend != "custom" and accelerators: with pytest.raises(NotImplementedError): c = models.Circuit(nqubits, accelerators) c.add(qibo_gate) else: c = models.Circuit(nqubits, accelerators) c.add(qibo_gate) final_state = c(np.copy(initial_state)) assert c.depth == target_depth np.testing.assert_allclose(final_state, target_state, atol=atol)
def test_measurement_qubit_order_simple(): """Check that measurement results follow order defined by user.""" c = models.Circuit(2) c.add(gates.X(0)) c.add(gates.M(1, 0)) result1 = c(nshots=100) c = models.Circuit(2) c.add(gates.X(0)) c.add(gates.M(1)) c.add(gates.M(0)) result2 = c(nshots=100) target_binary_samples = np.zeros((100, 2)) target_binary_samples[:, 1] = 1 target = { "decimal_samples": np.ones((100, )), "binary_samples": target_binary_samples, "decimal_frequencies": { 1: 100 }, "binary_frequencies": { "01": 100 } } assert_results(result1, **target) assert_results(result2, **target)
def test_measurements_with_probabilistic_noise(backend): """Check measurements when simulating noise with repeated execution.""" original_backend = qibo.get_backend() qibo.set_backend(backend) thetas = np.random.random(5) c = models.Circuit(5) c.add((gates.RX(i, t) for i, t in enumerate(thetas))) c.add((gates.PauliNoiseChannel(i, px=0.0, py=0.2, pz=0.4, seed=123) for i in range(5))) c.add(gates.M(*range(5))) K.set_seed(123) samples = c(nshots=20).samples() np.random.seed(123) K.set_seed(123) target_samples = [] for _ in range(20): noiseless_c = models.Circuit(5) noiseless_c.add((gates.RX(i, t) for i, t in enumerate(thetas))) for i in range(5): if np.random.random() < 0.2: noiseless_c.add(gates.Y(i)) if np.random.random() < 0.4: noiseless_c.add(gates.Z(i)) noiseless_c.add(gates.M(*range(5))) target_samples.append(noiseless_c(nshots=1).samples()) target_samples = np.concatenate(target_samples, axis=0) np.testing.assert_allclose(samples, target_samples) qibo.set_backend(original_backend)
def test_circuit_constructor_hardware_errors(): K.is_hardware = True with pytest.raises(NotImplementedError): c = models.Circuit(5, accelerators={"/GPU:0": 2}) with pytest.raises(NotImplementedError): c = models.Circuit(5, density_matrix=True) K.is_hardware = False
def assert_gates_equivalent(qibo_gate, cirq_gates, nqubits, ndevices=None, atol=1e-7): """Asserts that QIBO and Cirq gates have equivalent action on a random state. Args: qibo_gate: QIBO gate. cirq_gates: List of tuples (cirq gate, target qubit IDs). nqubits: Total number of qubits in the circuit. atol: Absolute tolerance in state vector comparsion. """ initial_state = utils.random_numpy_state(nqubits) target_state = execute_cirq(cirq_gates, nqubits, np.copy(initial_state)) accelerators = None if ndevices is None else {"/GPU:0": ndevices} if isinstance(qibo_gate, native_gates.TensorflowGate) and accelerators: with pytest.raises(NotImplementedError): c = models.Circuit(nqubits, accelerators) c.add(qibo_gate) else: c = models.Circuit(nqubits, accelerators) c.add(qibo_gate) final_state = c(np.copy(initial_state)).numpy() np.testing.assert_allclose(target_state, final_state, atol=atol)
def test_density_matrix_circuit_errors(): """Check errors of circuits that simulate density matrices.""" # Attempt to distribute density matrix circuit with pytest.raises(NotImplementedError): c = models.Circuit(5, accelerators={"/GPU:0": 2}, density_matrix=True) # Attempt to add Kraus channel to non-density matrix circuit c = models.Circuit(5) with pytest.raises(ValueError): c.add(gates.KrausChannel([((0, ), np.eye(2))]))
def test_circuit_addition_with_measurements(backend): c = models.Circuit(2) c.add(gates.H(0)) c.add(gates.H(1)) meas_c = models.Circuit(2) c.add(gates.M(0, 1)) c += meas_c assert len(c.measurement_gate.target_qubits) == 2 assert c.measurement_tuples == {"register0": (0, 1)}
def test_registers_with_same_name_error(): """Check that registers with the same name cannot be added.""" c1 = models.Circuit(2) c1.add(gates.H(0)) c1.add(gates.M(0)) c2 = models.Circuit(2) c2.add(gates.H(1)) c2.add(gates.M(1)) with pytest.raises(KeyError): c = c1 + c2
def test_circuit_addition_with_measurements(): """Check if measurements are transferred during circuit addition.""" c = models.Circuit(2) c.add(gates.H(0)) c.add(gates.H(1)) meas_c = models.Circuit(2) c.add(gates.M(0, 1)) c += meas_c assert len(c.measurement_gate.target_qubits) == 2 assert c.measurement_tuples == {"register0": (0, 1)}
def test_measurement_result_parameters(backend, accelerators, effect): c = models.Circuit(4, accelerators) if effect: c.add(gates.X(0)) output = c.add(gates.M(0, collapse=True)) c.add(gates.RX(1, theta=np.pi * output / 4)) target_c = models.Circuit(4) if effect: target_c.add(gates.X(0)) target_c.add(gates.RX(1, theta=np.pi / 4)) K.assert_allclose(c(), target_c())
def test_circuit_addition_with_measurements_in_both_circuits(backend, accelerators): c1 = models.Circuit(4, accelerators) c1.add(gates.H(0)) c1.add(gates.H(1)) c1.add(gates.M(1, register_name="a")) c2 = models.Circuit(4, accelerators) c2.add(gates.X(0)) c2.add(gates.M(0, register_name="b")) c = c1 + c2 assert len(c.measurement_gate.target_qubits) == 2 assert c.measurement_tuples == {"a": (1,), "b": (0,)}
def test_unsupported_gates_errors(): c = models.Circuit(4, {"/GPU:0": 2}) c.add(gates.H(0)) c.add(gates.H(1)) c.queues.qubits = distutils.DistributedQubits([0], c.nqubits) with pytest.raises(ValueError): c.queues.create(c.queue) c = models.Circuit(4, {"/GPU:0": 4}) c.add(gates.SWAP(0, 1)) c.queues.qubits = distutils.DistributedQubits([0, 1], c.nqubits) with pytest.raises(ValueError): c.queues.create(c.queue)
def test_circuit_addition_with_measurements_in_both_circuits(accelerators): """Check if measurements of two circuits are added during circuit addition.""" c1 = models.Circuit(2, accelerators) c1.add(gates.H(0)) c1.add(gates.H(1)) c1.add(gates.M(1, register_name="a")) c2 = models.Circuit(2, accelerators) c2.add(gates.X(0)) c2.add(gates.M(0, register_name="b")) c = c1 + c2 assert len(c.measurement_gate.target_qubits) == 2 assert c.measurement_tuples == {"a": (1, ), "b": (0, )}
def test_density_matrix_circuit_errors(): """Check errors of circuits that simulate density matrices.""" # Switch `gate.density_matrix` to `True` after setting `nqubits` gate = gates.X(0) gate.nqubits = 2 with pytest.raises(RuntimeError): gate.density_matrix = True # Attempt to distribute density matrix circuit with pytest.raises(NotImplementedError): c = models.Circuit(5, accelerators={"/GPU:0": 2}, density_matrix=True) # Attempt to add Kraus channel to non-density matrix circuit c = models.Circuit(5) with pytest.raises(ValueError): c.add(gates.KrausChannel([((0, ), np.eye(2))]))
def test_registers_with_same_name_error(backend): """Check that circuits that contain registers with the same name cannot be added.""" original_backend = qibo.get_backend() qibo.set_backend(backend) c1 = models.Circuit(2) c1.add(gates.H(0)) c1.add(gates.M(0)) c2 = models.Circuit(2) c2.add(gates.H(1)) c2.add(gates.M(1)) with pytest.raises(KeyError): c = c1 + c2 qibo.set_backend(original_backend)
def test_gate_after_measurement_with_addition_error(backend, accelerators): c = models.Circuit(4, accelerators) c.add(gates.H(0)) c.add(gates.M(1)) # Try to add gate to qubit that is already measured c2 = models.Circuit(4, accelerators) c2.add(gates.H(1)) with pytest.raises(ValueError): c += c2 # Try to add measurement to qubit that is already measured c2 = models.Circuit(4, accelerators) c2.add(gates.M(1, register_name="a")) with pytest.raises(ValueError): c += c2
def test_final_state(backend, accelerators): """Check that final state is logged correctly when using measurements.""" c = models.Circuit(4, accelerators) c.add(gates.X(1)) c.add(gates.X(2)) c.add(gates.M(0, 1)) c.add(gates.M(2)) c.add(gates.X(3)) result = c(nshots=100) c = models.Circuit(4, accelerators) c.add(gates.X(1)) c.add(gates.X(2)) c.add(gates.X(3)) target_state = c() K.assert_allclose(c.final_state, target_state)
def test_circuit_constructor(): from qibo.core.circuit import Circuit, DensityMatrixCircuit from qibo.core.distcircuit import DistributedCircuit c = models.Circuit(5) assert isinstance(c, Circuit) c = models.Circuit(5, density_matrix=True) assert isinstance(c, DensityMatrixCircuit) if not K.supports_multigpu: # pragma: no cover with pytest.raises(NotImplementedError): c = models.Circuit(5, accelerators={"/GPU:0": 2}) else: c = models.Circuit(5, accelerators={"/GPU:0": 2}) assert isinstance(c, DistributedCircuit) with pytest.raises(NotImplementedError): c = models.Circuit(5, accelerators={"/GPU:0": 2}, density_matrix=True)
def test_collapse_gate(backend, nqubits, targets, results): original_backend = qibo.get_backend() qibo.set_backend(backend) initial_psi = utils.random_numpy_state(nqubits) initial_rho = np.outer(initial_psi, initial_psi.conj()) c = models.Circuit(nqubits, density_matrix=True) c.add(gates.Collapse(*targets, result=results)) final_rho = c(np.copy(initial_rho)) c = models.Circuit(nqubits) c.add(gates.Collapse(*targets, result=results)) target_psi = c(np.copy(initial_psi)).numpy() target_rho = np.outer(target_psi, target_psi.conj()) np.testing.assert_allclose(final_rho, target_rho) qibo.set_backend(original_backend)
def ansatz_Fourier_2D(layers, qubits=1): """ 3 parameters per layer: Ry(wx + a), Rz(b) """ circuit = models.Circuit(qubits) for _ in range(layers): circuit.add(gates.RY(0, theta=0)) circuit.add(gates.RZ(0, theta=0)) circuit.add(gates.RY(0, theta=0)) circuit.add(gates.RZ(0, theta=0)) def rotation(theta, x): p = circuit.get_parameters() i = 0 j = 0 for l in range(layers): p[i] = theta[j] p[i + 1] = theta[j + 1] + theta[j + 2:j + 4] @ x p[i + 2] = theta[j + 4] p[i + 3] = theta[j + 5] i += 4 j += 6 return p nparams = 6 * (layers) return circuit, rotation, nparams
def test_unbalanced_probabilistic_measurement(backend, use_samples): original_backend = qibo.get_backend() original_threads = qibo.get_threads() qibo.set_backend(backend) # set single-thread to fix the random values generated from the frequency custom op qibo.set_threads(1) state = np.array([1, 1, 1, np.sqrt(3)]) / np.sqrt(6) c = models.Circuit(2) c.add(gates.Flatten(state)) c.add(gates.M(0, 1)) result = c(nshots=1000) K.set_seed(1234) if use_samples: # calculates sample tensor directly using `tf.random.categorical` # otherwise it uses the frequency-only calculation _ = result.samples() # update reference values based on backend and device if K.name == "tensorflow": if K.gpu_devices: # pragma: no cover # CI does not use GPU decimal_frequencies = {0: 196, 1: 153, 2: 156, 3: 495} else: decimal_frequencies = {0: 168, 1: 188, 2: 154, 3: 490} elif K.name == "numpy": decimal_frequencies = {0: 171, 1: 148, 2: 161, 3: 520} assert sum(result.frequencies().values()) == 1000 assert_result(result, decimal_frequencies=decimal_frequencies) qibo.set_backend(original_backend) qibo.set_threads(original_threads)
def test_circuit_dm(backend): """Check passing density matrix as initial state to a circuit.""" original_backend = qibo.get_backend() qibo.set_backend(backend) theta = 0.1234 initial_rho = utils.random_density_matrix(3) c = models.Circuit(3, density_matrix=True) c.add(gates.H(0)) c.add(gates.H(1)) c.add(gates.CNOT(0, 1)) c.add(gates.H(2)) final_rho = c(np.copy(initial_rho)) 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]]) m1 = np.kron(np.kron(h, h), np.eye(2)) m2 = np.kron(cnot, np.eye(2)) m3 = np.kron(np.eye(4), h) target_rho = m1.dot(initial_rho).dot(m1.T.conj()) target_rho = m2.dot(target_rho).dot(m2.T.conj()) target_rho = m3.dot(target_rho).dot(m3.T.conj()) np.testing.assert_allclose(final_rho, target_rho) qibo.set_backend(original_backend)
def test_post_measurement_bitflips_on_circuit_result(backend): """Check bitflip errors on ``CircuitResult`` objects.""" original_backend = qibo.get_backend() qibo.set_backend(backend) thetas = np.random.random(4) c = models.Circuit(4) c.add((gates.RX(i, theta=t) for i, t in enumerate(thetas))) c.add(gates.M(0, 1, register_name="a")) c.add(gates.M(3, register_name="b")) result = c(nshots=30) samples = result.samples() K.set_seed(123) noisy_result = result.copy().apply_bitflips({0: 0.2, 1: 0.4, 3: 0.3}) noisy_samples = noisy_result.samples(binary=True) register_samples = noisy_result.samples(binary=True, registers=True) K.set_seed(123) sprobs = np.array(K.random_uniform(samples.shape)) flipper = sprobs < np.array([0.2, 0.4, 0.3]) target_samples = (samples + flipper) % 2 np.testing.assert_allclose(noisy_samples, target_samples) # Check register samples np.testing.assert_allclose(register_samples["a"], target_samples[:, :2]) np.testing.assert_allclose(register_samples["b"], target_samples[:, 2:]) qibo.set_backend(original_backend)
def test_probabilistic_measurement(backend, accelerators, use_samples): original_backend = qibo.get_backend() original_threads = qibo.get_threads() qibo.set_backend(backend) # set single-thread to fix the random values generated from the frequency custom op qibo.set_threads(1) c = models.Circuit(4, accelerators) c.add(gates.H(0)) c.add(gates.H(1)) c.add(gates.M(0, 1)) result = c(nshots=1000) K.set_seed(1234) if use_samples: # calculates sample tensor directly using `tf.random.categorical` # otherwise it uses the frequency-only calculation _ = result.samples() # update reference values based on backend and device if K.name == "tensorflow": if K.gpu_devices: # pragma: no cover # CI does not use GPU decimal_frequencies = {0: 273, 1: 233, 2: 242, 3: 252} else: decimal_frequencies = {0: 271, 1: 239, 2: 242, 3: 248} elif K.name == "numpy": decimal_frequencies = {0: 249, 1: 231, 2: 253, 3: 267} assert sum(result.frequencies().values()) == 1000 assert_result(result, decimal_frequencies=decimal_frequencies) qibo.set_backend(original_backend) qibo.set_threads(original_threads)
def main(nqubits, layers, maxsteps, T_max): circuit = models.Circuit(nqubits) for l in range(layers): circuit.add((gates.RY(q, theta=0) for q in range(nqubits))) circuit.add((gates.CZ(q, q + 1) for q in range(0, nqubits - 1, 2))) circuit.add((gates.RY(q, theta=0) for q in range(nqubits))) circuit.add((gates.CZ(q, q + 1) for q in range(1, nqubits - 2, 2))) circuit.add(gates.CZ(0, nqubits - 1)) circuit.add((gates.RY(q, theta=0) for q in range(nqubits))) problem_hamiltonian = hamiltonians.XXZ(nqubits) easy_hamiltonian = hamiltonians.X(nqubits) s = lambda t: t aavqe = models.variational.AAVQE(circuit, easy_hamiltonian, problem_hamiltonian, s, nsteps=maxsteps, t_max=T_max) initial_parameters = np.random.uniform(0, 2 * np.pi*0.1, 2 * nqubits * layers + nqubits) best, params = aavqe.minimize(initial_parameters) print('Final parameters: ', params) print('Final energy: ', best) #We compute the difference from the exact value to check performance eigenvalue = problem_hamiltonian.eigenvalues() print('Difference from exact value: ',best - K.real(eigenvalue[0])) print('Log difference: ',-np.log10(best - K.real(eigenvalue[0])))
def test_vqe_custom_gates_errors(): """Check that ``RuntimeError``s is raised when using custom gates.""" if "qibotf" not in qibo.K.available_backends: # pragma: no cover pytest.skip("Custom backend not available.") original_backend = qibo.get_backend() qibo.set_backend("qibotf") nqubits = 6 circuit = models.Circuit(nqubits) for q in range(nqubits): circuit.add(gates.RY(q, theta=0)) for q in range(0, nqubits - 1, 2): circuit.add(gates.CZ(q, q + 1)) hamiltonian = hamiltonians.XXZ(nqubits=nqubits) initial_parameters = np.random.uniform(0, 2 * np.pi, 2 * nqubits + nqubits) v = models.VQE(circuit, hamiltonian) # compile with custom gates with pytest.raises(RuntimeError): best, params, _ = v.minimize(initial_parameters, method="BFGS", options={'maxiter': 1}, compile=True) # use SGD with custom gates with pytest.raises(RuntimeError): best, params, _ = v.minimize(initial_parameters, method="sgd", compile=False) qibo.set_backend(original_backend)
def test_distributed_circuit_addition(): # Attempt to add circuits with different devices original_backend = qibo.get_backend() qibo.set_backend("custom") devices = {"/GPU:0": 2, "/GPU:1": 2} c1 = models.DistributedCircuit(6, devices) c2 = models.DistributedCircuit(6, {"/GPU:0": 2}) with pytest.raises(ValueError): c = c1 + c2 c2 = models.DistributedCircuit(6, devices) c1.add([gates.H(i) for i in range(6)]) c2.add([gates.CNOT(i, i + 1) for i in range(5)]) c2.add([gates.Z(i) for i in range(6)]) dist_c = c1 + c2 c = models.Circuit(6) c.add([gates.H(i) for i in range(6)]) c.add([gates.CNOT(i, i + 1) for i in range(5)]) c.add([gates.Z(i) for i in range(6)]) target_state = c().numpy() final_state = dist_c().numpy() assert c.depth == dist_c.depth np.testing.assert_allclose(target_state, final_state) qibo.set_backend(original_backend)