def test_var(self, shots, qvm, compiler): """Tests for variance calculation""" dev = plf.QVMDevice(device="2q-qvm", shots=shots) phi = 0.543 theta = 0.6543 with qml.tape.QuantumTape() as tape: qml.RX(phi, wires=[0]) qml.RY(theta, wires=[0]) O1 = qml.var(qml.PauliZ(wires=[0])) dev.apply(tape.operations, rotations=tape.diagonalizing_gates) dev._samples = dev.generate_samples() var = np.array([dev.var(O1.obs)]) expected = 0.25 * (3 - np.cos(2 * theta) - 2 * np.cos(theta)**2 * np.cos(2 * phi)) self.assertAlmostEqual(var, expected, delta=3 / np.sqrt(shots))
def test_var(self, shots, qvm, compiler): """Tests for variance calculation""" dev = plf.QVMDevice(device="2q-qvm", shots=shots) phi = 0.543 theta = 0.6543 O1 = qml.var(qml.PauliZ(wires=[0])) circuit_graph = CircuitGraph([qml.RX(phi, wires=[0]), qml.RY(theta, wires=[0])] + [O1], {}, dev.wires) # test correct variance for <Z> of a rotated state dev.apply(circuit_graph.operations, rotations=circuit_graph.diagonalizing_gates) dev._samples = dev.generate_samples() var = np.array([dev.var(O1)]) expected = 0.25 * (3 - np.cos(2 * theta) - 2 * np.cos(theta) ** 2 * np.cos(2 * phi)) self.assertAlmostEqual(var, expected, delta=3 / np.sqrt(shots))
def test_pauliz_expectation(self, shots, qvm, compiler): """Test that PauliZ expectation value is correct""" theta = 0.432 phi = 0.123 dev = plf.QVMDevice(device='2q-qvm', shots=shots) dev.apply('RX', wires=[0], par=[theta]) dev.apply('RX', wires=[1], par=[phi]) dev.apply('CNOT', wires=[0, 1], par=[]) O = qml.expval.PauliZ name = 'PauliZ' dev._expval_queue = [O(wires=[0], do_queue=False), O(wires=[1], do_queue=False)] res = dev.pre_expval() res = np.array([dev.expval(name, [0], []), dev.expval(name, [1], [])]) # below are the analytic expectation values for this circuit self.assertAllAlmostEqual(res, np.array([np.cos(theta), np.cos(theta)*np.cos(phi)]), delta=3/np.sqrt(shots))
def test_identity_expectation(self, shots, qvm, compiler): """Test that identity expectation value (i.e. the trace) is 1""" theta = 0.432 phi = 0.123 dev = plf.QVMDevice(device='2q-qvm', shots=shots) dev.apply('RX', wires=[0], par=[theta]) dev.apply('RX', wires=[1], par=[phi]) dev.apply('CNOT', wires=[0, 1], par=[]) O = qml.expval.qubit.Identity name = 'Identity' dev._expval_queue = [O(wires=[0], do_queue=False), O(wires=[1], do_queue=False)] res = dev.pre_expval() res = np.array([dev.expval(name, [0], []), dev.expval(name, [1], [])]) # below are the analytic expectation values for this circuit (trace should always be 1) self.assertAllAlmostEqual(res, np.array([1, 1]), delta=3/np.sqrt(shots))
def test_sample_values(self, qvm, tol): """Tests if the samples returned by sample have the correct values """ dev = plf.QVMDevice(device="1q-qvm", shots=10) O1 = qml.expval(qml.PauliZ(wires=[0])) circuit_graph = CircuitGraph([qml.RX(1.5708, wires=[0])] + [O1], {}) dev.apply(circuit_graph.operations, rotations=circuit_graph.diagonalizing_gates) dev._samples = dev.generate_samples() s1 = dev.sample(O1) # s1 should only contain 1 and -1 self.assertAllAlmostEqual(s1**2, 1, delta=tol) self.assertAllAlmostEqual(s1, 1 - 2 * dev._samples[:, 0], delta=tol)
def test_sample_values_hermitian(self, qvm, tol): """Tests if the samples of a Hermitian observable returned by sample have the correct values """ theta = 0.543 shots = 1_000_000 A = np.array([[1, 2j], [-2j, 0]]) dev = plf.QVMDevice(device="1q-qvm", shots=shots) O1 = qml.sample(qml.Hermitian(A, wires=[0])) circuit_graph = CircuitGraph([qml.RX(theta, wires=[0])] + [O1], {}, dev.wires) dev.apply(circuit_graph.operations, rotations=circuit_graph.diagonalizing_gates) dev._samples = dev.generate_samples() s1 = dev.sample(O1) # s1 should only contain the eigenvalues of # the hermitian matrix eigvals = np.linalg.eigvalsh(A) assert np.allclose(sorted(list(set(s1))), sorted(eigvals), atol=tol, rtol=0) # the analytic mean is 2*sin(theta)+0.5*cos(theta)+0.5 assert np.allclose(np.mean(s1), 2 * np.sin(theta) + 0.5 * np.cos(theta) + 0.5, atol=0.1, rtol=0) # the analytic variance is 0.25*(sin(theta)-4*cos(theta))^2 assert np.allclose(np.var(s1), 0.25 * (np.sin(theta) - 4 * np.cos(theta))**2, atol=0.1, rtol=0)
def test_hermitian_expectation(self, shots, qvm, compiler): """Test that arbitrary Hermitian expectation values are correct. As the results coming from the qvm are stochastic, a constraint of 3 out of 5 runs was added. """ theta = 0.432 phi = 0.123 dev = plf.QVMDevice(device="2q-qvm", shots=shots) O1 = qml.expval(qml.Hermitian(H, wires=[0])) O2 = qml.expval(qml.Hermitian(H, wires=[1])) circuit_graph = CircuitGraph( [ qml.RY(theta, wires=[0]), qml.RY(phi, wires=[1]), qml.CNOT(wires=[0, 1]) ] + [O1, O2], {}, ) dev.apply(circuit_graph.operations, rotations=circuit_graph.diagonalizing_gates) dev._samples = dev.generate_samples() res = np.array([dev.expval(O1), dev.expval(O2)]) # below are the analytic expectation values for this circuit with arbitrary # Hermitian observable H a = H[0, 0] re_b = H[0, 1].real d = H[1, 1] ev1 = ((a - d) * np.cos(theta) + 2 * re_b * np.sin(theta) * np.sin(phi) + a + d) / 2 ev2 = ((a - d) * np.cos(theta) * np.cos(phi) + 2 * re_b * np.sin(phi) + a + d) / 2 expected = np.array([ev1, ev2]) self.assertAllAlmostEqual(res, expected, delta=4 / np.sqrt(shots))
def test_sample_values_hermitian_multi_qubit(self, qvm, tol): """Tests if the samples of a multi-qubit Hermitian observable returned by sample have the correct values """ theta = 0.543 shots = 100_000 A = np.array([ [1, 2j, 1 - 2j, 0.5j], [-2j, 0, 3 + 4j, 1], [1 + 2j, 3 - 4j, 0.75, 1.5 - 2j], [-0.5j, 1, 1.5 + 2j, -1], ]) dev = plf.QVMDevice(device="2q-qvm", shots=shots) with qml.tape.QuantumTape() as tape: qml.RX(theta, wires=[0]) qml.RY(2 * theta, wires=[1]) qml.CNOT(wires=[0, 1]) O1 = qml.sample(qml.Hermitian(A, wires=[0, 1])) dev.apply(tape.operations, rotations=tape.diagonalizing_gates) dev._samples = dev.generate_samples() s1 = dev.sample(O1.obs) # s1 should only contain the eigenvalues of # the hermitian matrix eigvals = np.linalg.eigvalsh(A) assert np.allclose(sorted(list(set(s1))), sorted(eigvals), atol=tol, rtol=0) # make sure the mean matches the analytic mean expected = (88 * np.sin(theta) + 24 * np.sin(2 * theta) - 40 * np.sin(3 * theta) + 5 * np.cos(theta) - 6 * np.cos(2 * theta) + 27 * np.cos(3 * theta) + 6) / 32 assert np.allclose(np.mean(s1), expected, atol=0.1, rtol=0)
def test_var(self, shots): """Tests for variance calculation""" dev = plf.QVMDevice(device="2q-qvm", shots=shots) phi = 0.543 theta = 0.6543 # test correct variance for <Z> of a rotated state dev.apply("RX", wires=[0], par=[phi]) dev.apply("RY", wires=[0], par=[theta]) O = qml.PauliZ name = "PauliZ" dev._obs_queue = [O(wires=[0], do_queue=False)] dev.pre_measure() var = dev.var(name, [0], []) expected = 0.25 * (3 - np.cos(2 * theta) - 2 * np.cos(theta) ** 2 * np.cos(2 * phi)) self.assertAlmostEqual(var, expected, delta=3 / np.sqrt(shots))
def test_pauliy_expectation(self, shots, qvm, compiler): """Test that PauliY expectation value is correct""" theta = 0.432 phi = 0.123 dev = plf.QVMDevice(device="2q-qvm", shots=shots) dev.apply("RX", wires=[0], par=[theta]) dev.apply("RX", wires=[1], par=[phi]) dev.apply("CNOT", wires=[0, 1], par=[]) O = qml.PauliY name = "PauliY" dev._obs_queue = [O(wires=[0], do_queue=False), O(wires=[1], do_queue=False)] dev.pre_measure() # below are the analytic expectation values for this circuit res = np.array([dev.expval(name, [0], []), dev.expval(name, [1], [])]) self.assertAllAlmostEqual( res, np.array([0, -np.cos(theta) * np.sin(phi)]), delta=3 / np.sqrt(shots) )
def test_hadamard_expectation(self, shots, qvm, compiler): """Test that Hadamard expectation value is correct""" theta = 0.432 phi = 0.123 dev = plf.QVMDevice(device="2q-qvm", shots=shots) dev.apply("RY", wires=[0], par=[theta]) dev.apply("RY", wires=[1], par=[phi]) dev.apply("CNOT", wires=[0, 1], par=[]) O = qml.Hadamard name = "Hadamard" dev._obs_queue = [O(wires=[0], do_queue=False), O(wires=[1], do_queue=False)] dev.pre_measure() res = np.array([dev.expval(name, [0], []), dev.expval(name, [1], [])]) # below are the analytic expectation values for this circuit expected = np.array( [np.sin(theta) * np.sin(phi) + np.cos(theta), np.cos(theta) * np.cos(phi) + np.sin(phi)] ) / np.sqrt(2) self.assertAllAlmostEqual(res, expected, delta=3 / np.sqrt(shots))
def test_identity_expectation(self, shots, qvm, compiler): """Test that identity expectation value (i.e. the trace) is 1""" theta = 0.432 phi = 0.123 dev = plf.QVMDevice(device="2q-qvm", shots=shots) O1 = qml.expval(qml.Identity(wires=[0])) O2 = qml.expval(qml.Identity(wires=[1])) circuit_graph = CircuitGraph( [qml.RX(theta, wires=[0]), qml.RX(phi, wires=[1]), qml.CNOT(wires=[0, 1])], [O1, O2], dev.wires ) dev.apply(circuit_graph.operations, rotations=circuit_graph.diagonalizing_gates) dev._samples = dev.generate_samples() res = np.array([dev.expval(O1), dev.expval(O2)]) # below are the analytic expectation values for this circuit (trace should always be 1) self.assertAllAlmostEqual(res, np.array([1, 1]), delta=3 / np.sqrt(shots))
def test_multi_mode_hermitian_expectation(self, shots, qvm, compiler): """Test that arbitrary multi-mode Hermitian expectation values are correct""" theta = 0.432 phi = 0.123 dev = plf.QVMDevice(device="2q-qvm", shots=10 * shots) dev.apply("RY", wires=[0], par=[theta]) dev.apply("RY", wires=[1], par=[phi]) dev.apply("CNOT", wires=[0, 1], par=[]) O = qml.Hermitian name = "Hermitian" A = np.array( [ [-6, 2 + 1j, -3, -5 + 2j], [2 - 1j, 0, 2 - 1j, -5 + 4j], [-3, 2 + 1j, 0, -4 + 3j], [-5 - 2j, -5 - 4j, -4 - 3j, -6], ] ) dev._obs_queue = [O(A, wires=[0, 1], do_queue=False)] dev.pre_measure() res = np.array([dev.expval(name, [0, 1], [A])]) # below is the analytic expectation value for this circuit with arbitrary # Hermitian observable A expected = 0.5 * ( 6 * np.cos(theta) * np.sin(phi) - np.sin(theta) * (8 * np.sin(phi) + 7 * np.cos(phi) + 3) - 2 * np.sin(phi) - 6 * np.cos(phi) - 6 ) self.assertAllAlmostEqual(res, expected, delta=4 / np.sqrt(shots))
def test_pauliy_expectation(self, shots, qvm, compiler): """Test that PauliY expectation value is correct""" theta = 0.432 phi = 0.123 dev = plf.QVMDevice(device="2q-qvm", shots=shots) with qml.tape.QuantumTape() as tape: qml.RX(theta, wires=[0]) qml.RX(phi, wires=[1]) qml.CNOT(wires=[0, 1]) O1 = qml.expval(qml.PauliY(wires=[0])) O2 = qml.expval(qml.PauliY(wires=[1])) dev.apply(tape.operations, rotations=tape.diagonalizing_gates) dev._samples = dev.generate_samples() res = np.array([dev.expval(O1.obs), dev.expval(O2.obs)]) # below are the analytic expectation values for this circuit self.assertAllAlmostEqual(res, np.array([0, -np.cos(theta) * np.sin(phi)]), delta=3 / np.sqrt(shots))
def test_paulix_expectation(self, shots): """Test that PauliX expectation value is correct""" theta = 0.432 phi = 0.123 dev = plf.QVMDevice(device="2q-pyqvm", shots=shots) O1 = qml.expval(qml.PauliX(wires=[0])) O2 = qml.expval(qml.PauliX(wires=[1])) circuit_graph = CircuitGraph( [qml.RY(theta, wires=[0]), qml.RY(phi, wires=[1]), qml.CNOT(wires=[0, 1])] + [O1, O2], {}, ) dev.apply(circuit_graph.operations, rotations=circuit_graph.diagonalizing_gates) dev._samples = dev.generate_samples() res = np.array([dev.expval(O1), dev.expval(O2)]) # below are the analytic expectation values for this circuit self.assertAllAlmostEqual( res, np.array([np.sin(theta) * np.sin(phi), np.sin(phi)]), delta=3 / np.sqrt(shots) )
def test_multi_qubit_hermitian_expectation(self, shots, qvm, compiler): """Test that arbitrary multi-qubit Hermitian expectation values are correct""" theta = np.random.random() phi = np.random.random() A = np.array( [ [-6, 2 + 1j, -3, -5 + 2j], [2 - 1j, 0, 2 - 1j, -5 + 4j], [-3, 2 + 1j, 0, -4 + 3j], [-5 - 2j, -5 - 4j, -4 - 3j, -6], ] ) dev = plf.QVMDevice(device="2q-pyqvm", shots=10 * shots) O1 = qml.expval(qml.Hermitian(A, wires=[0, 1])) circuit_graph = CircuitGraph( [qml.RY(theta, wires=[0]), qml.RY(phi, wires=[1]), qml.CNOT(wires=[0, 1])] + [O1], {} ) dev.apply(circuit_graph.operations, rotations=circuit_graph.diagonalizing_gates) dev._samples = dev.generate_samples() res = np.array([dev.expval(O1)]) # below is the analytic expectation value for this circuit with arbitrary # Hermitian observable A expected = 0.5 * ( 6 * np.cos(theta) * np.sin(phi) - np.sin(theta) * (8 * np.sin(phi) + 7 * np.cos(phi) + 3) - 2 * np.sin(phi) - 6 * np.cos(phi) - 6 ) self.assertAllAlmostEqual(res, expected, delta=6 / np.sqrt(shots))
def test_apply(self, op, apply_unitary, shots, qvm, compiler): """Test the application of gates to a state""" dev = plf.QVMDevice(device="3q-qvm", shots=shots, parametric_compilation=False) obs = qml.expval(qml.PauliZ(0)) if op.name == "QubitUnitary": state = apply_unitary(U, 3) elif op.name == "BasisState": state = np.array([0, 0, 0, 0, 0, 0, 0, 1]) elif op.name == "CPHASE": state = apply_unitary(test_operation_map["CPHASE"](0.432, 2), 3) elif op.name == "ISWAP": state = apply_unitary(test_operation_map["ISWAP"], 3) elif op.name == "PSWAP": state = apply_unitary(test_operation_map["PSWAP"](0.432), 3) else: state = apply_unitary(op.matrix, 3) with qml.tape.QuantumTape() as tape: qml.apply(op) obs dev.apply(tape.operations, rotations=tape.diagonalizing_gates) dev._samples = dev.generate_samples() res = dev.expval(obs.obs) expected = np.vdot(state, np.kron(np.kron(Z, I), I) @ state) # verify the device is now in the expected state # Note we have increased the tolerance here, since we are only # performing 1024 shots. self.assertAllAlmostEqual(res, expected, delta=3 / np.sqrt(shots))
def test_identity_expectation(self, shots, qvm, compiler): """Test that identity expectation value (i.e. the trace) is 1""" theta = 0.432 phi = 0.123 dev = plf.QVMDevice(device="2q-qvm", shots=shots) with qml.tape.QuantumTape() as tape: qml.RX(theta, wires=[0]) qml.RX(phi, wires=[1]) qml.CNOT(wires=[0, 1]) O1 = qml.expval(qml.Identity(wires=[0])) O2 = qml.expval(qml.Identity(wires=[1])) dev.apply(tape.operations, rotations=tape.diagonalizing_gates) dev._samples = dev.generate_samples() res = np.array([dev.expval(O1.obs), dev.expval(O2.obs)]) # below are the analytic expectation values for this circuit (trace should always be 1) self.assertAllAlmostEqual(res, np.array([1, 1]), delta=3 / np.sqrt(shots))
def test_timeout_set_correctly(self, shots): """Test that the timeout attrbiute for the QuantumComputer stored by the QVMDevice is set correctly when passing a value as keyword argument""" device = np.random.choice(TEST_QPU_LATTICES) dev = plf.QVMDevice(device=device, shots=shots, timeout=100) assert dev.qc.compiler.client.timeout == 100
def test_apply(self, gate, apply_unitary, shots, qvm, compiler): """Test the application of gates""" dev = plf.QVMDevice(device="3q-qvm", shots=shots, parametric_compilation=False) try: # get the equivalent pennylane operation class op = getattr(qml.ops, gate) except AttributeError: # get the equivalent pennylane-forest operation class op = getattr(plf, gate) # the list of wires to apply the operation to w = list(range(op.num_wires)) if op.par_domain == "A": # the parameter is an array if gate == "QubitUnitary": p = np.array(U) w = [0] state = apply_unitary(U, 3) elif gate == "BasisState": p = np.array([1, 1, 1]) state = np.array([0, 0, 0, 0, 0, 0, 0, 1]) w = list(range(dev.num_wires)) with qml.tape.QuantumTape() as tape: op(p, wires=w) obs = qml.expval(qml.PauliZ(0)) else: p = [0.432_423, 2, 0.324][:op.num_params] fn = test_operation_map[gate] if callable(fn): # if the default.qubit is an operation accepting parameters, # initialise it using the parameters generated above. O = fn(*p) else: # otherwise, the operation is simply an array. O = fn # calculate the expected output state = apply_unitary(O, 3) # Creating the tape using a parametrized operation if p: with qml.tape.QuantumTape() as tape: op(*p, wires=w) obs = qml.expval(qml.PauliZ(0)) # Creating the tape using an operation that take no parameters else: with qml.tape.QuantumTape() as tape: op(wires=w) obs = qml.expval(qml.PauliZ(0)) dev.apply(tape.operations, rotations=tape.diagonalizing_gates) dev._samples = dev.generate_samples() res = dev.expval(obs.obs) expected = np.vdot(state, np.kron(np.kron(Z, I), I) @ state) # verify the device is now in the expected state # Note we have increased the tolerance here, since we are only # performing 1024 shots. self.assertAllAlmostEqual(res, expected, delta=3 / np.sqrt(shots))
def test_raise_error_if_shots_is_not_positive(self, shots): """Test that instantiating a QVMDevice if the number of shots is not a postivie integer raises an error""" with pytest.raises(ValueError, match="Number of shots must be a positive integer."): dev = plf.QVMDevice(device="2q-qvm", shots=shots)
def test_raise_error_if_analytic_true(self, shots): """Test that instantiating a QVMDevice in analytic=True mode raises an error""" with pytest.raises( ValueError, match="QVM device cannot be run in analytic=True mode."): dev = plf.QVMDevice(device="2q-qvm", shots=shots, analytic=True)
def test_raise_error_if_shots_is_none(self, shots): """Test that instantiating a QVMDevice to be used for analytic computations raises an error""" with pytest.raises( ValueError, match="QVM device cannot be used for analytic computations."): dev = plf.QVMDevice(device="2q-qvm", shots=None)