def circuit(w, x, y, z): """Test QNode""" qml.BasisState(np.array([0, 1]), wires=[0, 1]) qml.Hadamard(wires=1) plf.CPHASE(w, 1, wires=[0, 1]) qml.Rot(x, y, z, wires=0) plf.CPHASE(w, 3, wires=[0, 1]) plf.CPHASE(w, 0, wires=[0, 1]) return qml.expval(qml.PauliY(1))
class TestQVMBasic(BaseTest): """Unit tests for the QVM simulator.""" # pylint: disable=protected-access 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_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) 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.PauliZ(wires=[0])) O2 = qml.expval(qml.PauliZ(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([np.cos(theta), np.cos(theta) * np.cos(phi)]), delta=3 / np.sqrt(shots)) def test_paulix_expectation(self, shots, qvm, compiler): """Test that PauliX 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.RY(theta, wires=[0]) qml.RY(phi, wires=[1]) qml.CNOT(wires=[0, 1]) O1 = qml.expval(qml.PauliX(wires=[0])) O2 = qml.expval(qml.PauliX(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([np.sin(theta) * np.sin(phi), np.sin(phi)]), 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) 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_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) with qml.tape.QuantumTape() as tape: qml.RY(theta, wires=[0]) qml.RY(phi, wires=[1]) qml.CNOT(wires=[0, 1]) O1 = qml.expval(qml.Hadamard(wires=[0])) O2 = qml.expval(qml.Hadamard(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 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)) @flaky(max_runs=10, min_passes=3) 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) with qml.tape.QuantumTape() as tape: qml.RY(theta, wires=[0]) qml.RY(phi, wires=[1]) qml.CNOT(wires=[0, 1]) O1 = qml.expval(qml.Hermitian(H, wires=[0])) O2 = qml.expval(qml.Hermitian(H, 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 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_multi_qubit_hermitian_expectation(self, shots, qvm, compiler): """Test that arbitrary multi-qubit Hermitian expectation values are correct""" theta = 0.432 phi = 0.123 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-qvm", shots=10 * shots) with qml.tape.QuantumTape() as tape: qml.RY(theta, wires=[0]) qml.RY(phi, wires=[1]) qml.CNOT(wires=[0, 1]) O1 = qml.expval(qml.Hermitian(A, wires=[0, 1])) dev.apply(tape.operations, rotations=tape.diagonalizing_gates) dev._samples = dev.generate_samples() res = np.array([dev.expval(O1.obs)]) # 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=5 / 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 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_hermitian(self, shots, qvm, compiler): """Tests for variance calculation using an arbitrary Hermitian observable""" dev = plf.QVMDevice(device="2q-qvm", shots=100 * shots) phi = 0.543 theta = 0.6543 A = np.array([[4, -1 + 6j], [-1 - 6j, 2]]) with qml.tape.QuantumTape() as tape: qml.RX(phi, wires=[0]) qml.RY(theta, wires=[0]) O1 = qml.var(qml.Hermitian(A, wires=[0])) # test correct variance for <A> of a rotated state dev.apply(tape.operations, rotations=tape.diagonalizing_gates) dev._samples = dev.generate_samples() var = np.array([dev.var(O1.obs)]) expected = 0.5 * (2 * np.sin(2 * theta) * np.cos(phi)**2 + 24 * np.sin(phi) * np.cos(phi) * (np.sin(theta) - np.cos(theta)) + 35 * np.cos(2 * phi) + 39) self.assertAlmostEqual(var, expected, delta=0.3) @pytest.mark.parametrize( "op", [ qml.QubitUnitary(np.array(U), wires=0), qml.BasisState(np.array([1, 1, 1]), wires=list(range(3))), qml.PauliX(wires=0), qml.PauliY(wires=0), qml.PauliZ(wires=0), qml.S(wires=0), qml.T(wires=0), qml.RX(0.432, wires=0), qml.RY(0.432, wires=0), qml.RZ(0.432, wires=0), qml.Hadamard(wires=0), qml.Rot(0.432, 2, 0.324, wires=0), qml.Toffoli(wires=[0, 1, 2]), qml.SWAP(wires=[0, 1]), qml.CSWAP(wires=[0, 1, 2]), qml.CZ(wires=[0, 1]), qml.CNOT(wires=[0, 1]), qml.PhaseShift(0.432, wires=0), qml.CSWAP(wires=[0, 1, 2]), plf.CPHASE(0.432, 2, wires=[0, 1]), plf.ISWAP(wires=[0, 1]), plf.PSWAP(0.432, wires=[0, 1]), ], ) 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_sample_values(self, qvm, tol): """Tests if the samples returned by sample have the correct values """ dev = plf.QVMDevice(device="1q-qvm", shots=10) with qml.tape.QuantumTape() as tape: qml.RX(1.5708, wires=[0]) O1 = qml.expval(qml.PauliZ(wires=[0])) dev.apply(tape.operations, rotations=tape.diagonalizing_gates) dev._samples = dev.generate_samples() s1 = dev.sample(O1.obs) # 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) with qml.tape.QuantumTape() as tape: qml.RX(theta, wires=[0]) O1 = qml.sample(qml.Hermitian(A, wires=[0])) 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) # 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_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_wires_argument(self): """Test that the wires argument gets processed correctly.""" dev_no_wires = plf.QVMDevice(device="2q-qvm", shots=5) assert dev_no_wires.wires == Wires(range(2)) with pytest.raises(ValueError, match="Device has a fixed number of"): plf.QVMDevice(device="2q-qvm", shots=5, wires=1000) dev_iterable_wires = plf.QVMDevice(device="2q-qvm", shots=5, wires=range(2)) assert dev_iterable_wires.wires == Wires(range(2)) with pytest.raises(ValueError, match="Device has a fixed number of"): plf.QVMDevice(device="2q-qvm", shots=5, wires=range(1000)) @pytest.mark.parametrize("shots", list(range(0, -10, -1))) 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_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) @pytest.mark.parametrize( "device", ["2q-qvm", np.random.choice(TEST_QPU_LATTICES)]) def test_timeout_set_correctly(self, shots, device): """Test that the timeout attrbiute for the QuantumComputer stored by the QVMDevice is set correctly when passing a value as keyword argument""" dev = plf.QVMDevice(device=device, shots=shots, timeout=100) assert dev.qc.compiler.client.timeout == 100 @pytest.mark.parametrize( "device", ["2q-qvm", np.random.choice(TEST_QPU_LATTICES)]) def test_timeout_default(self, shots, device): """Test that the timeout attrbiute for the QuantumComputer stored by the QVMDevice is set correctly when passing a value as keyword argument""" dev = plf.QVMDevice(device=device, shots=shots) qc = pyquil.get_qc(device, as_qvm=True) # Check that the timeouts are equal (it has not been changed as a side effect of # instantiation assert dev.qc.compiler.client.timeout == qc.compiler.client.timeout def test_compiled_program_stored(self, qvm, monkeypatch): """Test that QVM device stores the latest compiled program.""" dev = qml.device("forest.qvm", device="2q-qvm") dev.compiled_program is None theta = 0.432 phi = 0.123 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.generate_samples() dev.compiled_program is not None def test_stored_compiled_program_correct(self, qvm, monkeypatch): """Test that QVM device stores the latest compiled program.""" dev = qml.device("forest.qvm", device="2q-qvm") dev.compiled_program is None theta = 0.432 with qml.tape.QuantumTape() as tape: qml.RZ(theta, wires=[0]) qml.CZ(wires=[0, 1]) O1 = qml.expval(qml.PauliZ(wires=[0])) dev.apply(tape.operations, rotations=tape.diagonalizing_gates) dev.generate_samples() dev.compiled_program.program == compiled_program
class TestWavefunctionBasic(BaseTest): """Unit tests for the NumPy wavefunction simulator.""" def test_var(self, tol): """Tests for variance calculation""" dev = plf.NumpyWavefunctionDevice(wires=2) phi = 0.543 theta = 0.6543 with qml.tape.QuantumTape() as tape: qml.RX(phi, wires=[0]) qml.RY(theta, wires=[0]) O = qml.var(qml.PauliZ(wires=[0])) # test correct variance for <Z> of a rotated state dev.apply(tape.operations, rotations=tape.diagonalizing_gates) var = dev.var(O) expected = 0.25 * (3 - np.cos(2 * theta) - 2 * np.cos(theta)**2 * np.cos(2 * phi)) self.assertAlmostEqual(var, expected, delta=tol) def test_var_hermitian(self, tol): """Tests for variance calculation using an arbitrary Hermitian observable""" dev = plf.NumpyWavefunctionDevice(wires=2) phi = 0.543 theta = 0.6543 H = np.array([[4, -1 + 6j], [-1 - 6j, 2]]) with qml.tape.QuantumTape() as tape: qml.RX(phi, wires=[0]) qml.RY(theta, wires=[0]) O = qml.var(qml.Hermitian(H, wires=[0])) # test correct variance for <Z> of a rotated state dev.apply(tape.operations, rotations=tape.diagonalizing_gates) var = dev.var(O) # test correct variance for <H> of a rotated state expected = 0.5 * (2 * np.sin(2 * theta) * np.cos(phi)**2 + 24 * np.sin(phi) * np.cos(phi) * (np.sin(theta) - np.cos(theta)) + 35 * np.cos(2 * phi) + 39) self.assertAlmostEqual(var, expected, delta=tol) @pytest.mark.parametrize( "op", [ qml.QubitUnitary(np.array(U), wires=0), qml.BasisState(np.array([1, 1, 1]), wires=list(range(3))), qml.PauliX(wires=0), qml.PauliY(wires=0), qml.PauliZ(wires=0), qml.S(wires=0), qml.T(wires=0), qml.RX(0.432, wires=0), qml.RY(0.432, wires=0), qml.RZ(0.432, wires=0), qml.Hadamard(wires=0), qml.Rot(0.432, 2, 0.324, wires=0), qml.Toffoli(wires=[0, 1, 2]), qml.SWAP(wires=[0, 1]), qml.CSWAP(wires=[0, 1, 2]), qml.CZ(wires=[0, 1]), qml.CNOT(wires=[0, 1]), qml.PhaseShift(0.432, wires=0), qml.CSWAP(wires=[0, 1, 2]), plf.CPHASE(0.432, 2, wires=[0, 1]), plf.ISWAP(wires=[0, 1]), plf.PSWAP(0.432, wires=[0, 1]), ], ) def test_apply(self, op, apply_unitary, tol): """Test the application of gates to a state""" dev = plf.NumpyWavefunctionDevice(wires=3) 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) # verify the device is now in the expected state self.assertAllAlmostEqual(dev._state, state, delta=tol) def test_sample_values(self, tol): """Tests if the samples returned by sample have the correct values """ dev = plf.NumpyWavefunctionDevice(wires=1, shots=10) theta = 1.5708 O = qml.sample(qml.PauliZ(0)) with qml.tape.QuantumTape() as tape: qml.RX(theta, wires=[0]) qml.sample(qml.PauliZ(0)) dev.apply(tape._ops, rotations=tape.diagonalizing_gates) dev._samples = dev.generate_samples() s1 = dev.sample(O.obs) # s1 should only contain 1 and -1 self.assertAllAlmostEqual(s1**2, 1, delta=tol) def test_sample_values_hermitian(self, tol): """Tests if the samples of a Hermitian observable returned by sample have the correct values """ dev = plf.NumpyWavefunctionDevice(wires=1, shots=1_000_000) theta = 0.543 A = np.array([[1, 2j], [-2j, 0]]) circuit_operations = [qml.RX(theta, wires=[0])] O = qml.sample(qml.Hermitian(A, wires=[0])) with qml.tape.QuantumTape() as tape: qml.RX(theta, wires=[0]) O = qml.sample(qml.Hermitian(A, wires=[0])) # test correct variance for <Z> of a rotated state dev.apply(tape.operations, rotations=tape.diagonalizing_gates) dev._samples = dev.generate_samples() s1 = dev.sample(O.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) # 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_sample_values_hermitian_multi_qubit(self, tol): """Tests if the samples of a multi-qubit Hermitian observable returned by sample have the correct values """ shots = 1_000_000 dev = plf.NumpyWavefunctionDevice(wires=2, shots=shots) theta = 0.543 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], ]) with qml.tape.QuantumTape() as tape: qml.RX(theta, wires=[0]), qml.RY(2 * theta, wires=[1]), qml.CNOT(wires=[0, 1]), O = qml.sample(qml.Hermitian(A, wires=[0, 1])) # test correct variance for <Z> of a rotated state dev.apply(tape.operations, rotations=tape.diagonalizing_gates) dev._samples = dev.generate_samples() s1 = dev.sample(O.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)