def test_qubit_unitary(self, shots, qvm, compiler): """Test that an arbitrary unitary operation works""" dev1 = qml.device('forest.qvm', device='3q-qvm', shots=shots) dev2 = qml.device('forest.qvm', device='9q-square-qvm', shots=shots) def circuit(): """Reference QNode""" qml.Hadamard(wires=0) qml.CNOT(wires=[0, 1]) qml.QubitUnitary(U2, wires=[0, 1]) return qml.expval.PauliZ(0) circuit1 = qml.QNode(circuit, dev1) circuit2 = qml.QNode(circuit, dev2) out_state = U2 @ np.array([1, 0, 0, 1])/np.sqrt(2) obs = np.kron(np.array([[1, 0], [0, -1]]), I) self.assertAllAlmostEqual(circuit1(), np.vdot(out_state, obs @ out_state), delta=3/np.sqrt(shots)) self.assertAllAlmostEqual(circuit2(), np.vdot(out_state, obs @ out_state), 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_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.expval.Hadamard name = 'Hadamard' dev._expval_queue = [O(wires=[0], do_queue=False), O(wires=[1], do_queue=False)] dev.pre_expval() 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_marginal_probability(self, tol): """Test that a coherent state marginal probability is correct""" cutoff = 10 dev = qml.device("strawberryfields.fock", wires=2, cutoff_dim=cutoff) @qml.qnode(dev) def circuit(a, phi): qml.Displacement(a, phi, wires=1) return qml.probs(wires=1) a = 0.4 phi = -0.12 alpha = a * np.exp(1j * phi) n = np.arange(cutoff) ref_probs = np.abs( np.exp(-0.5 * np.abs(alpha)**2) * alpha**n / np.sqrt(fac(n)))**2 res = circuit(a, phi) assert np.allclose(res, ref_probs, atol=tol, 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 get_angles(x): """Compute rotation angles for state preparation routine. Args: x: original input vector Returns: array[float]: feature vector of angles """ beta0 = 2 * np.arcsin(np.sqrt(x[1]) ** 2 / np.sqrt(x[0] ** 2 + x[1] ** 2 + 1e-12) ) beta1 = 2 * np.arcsin(np.sqrt(x[3]) ** 2 / np.sqrt(x[2] ** 2 + x[3] ** 2 + 1e-12) ) beta2 = 2 * np.arcsin(np.sqrt(x[2] ** 2 + x[3] ** 2) / np.sqrt(x[0] ** 2 + x[1] ** 2 + x[2] ** 2 + x[3] ** 2)) return np.array([beta2, -beta1 / 2, beta1 / 2, -beta0 / 2, beta0 / 2])
def QNNLayer(self, params): ''' Definition of a single ST step for layering QNN ''' ExcInts = params[0:3] ExtField = params[3:6] # Parameters for external # field evol Hx = ExtField[0] Hy = ExtField[1] Hz = ExtField[2] H = np.sqrt(Hx**2 + Hy**2 + Hz**2) # Parameter values for Qiskit PHI = np.arctan2(Hy, Hx) + 2*np.pi THETA = np.arccos(Hz/H) LAMBDA = np.pi # Cascade Spin pair interaction for idx in range(self.num_spins-1): # Convert to computational basis qml.CNOT(wires=[idx, idx+1]) qml.Hadamard(wires=idx) # Compute J3 phase qml.RZ(ExcInts[2], wires=idx+1) # Compute J1 phase qml.RZ(ExcInts[0], wires=idx) # Compute J2 Phase qml.CNOT(wires=[idx, idx+1]) qml.RZ(-ExcInts[1], wires=idx+1) qml.CNOT(wires=[idx, idx+1]) # Return to computational basis qml.Hadamard(wires=idx) qml.CNOT(wires=[idx, idx+1]) # Include external field qml.U3(-THETA, -LAMBDA, -PHI, wires=idx) qml.RZ(H, wires=idx) qml.U3(THETA, PHI, LAMBDA, wires=idx) # Include external field for last spin qml.U3(-THETA, -LAMBDA, -PHI, wires=self.num_spins-1) qml.RZ(H, wires=self.num_spins-1) qml.U3(THETA, PHI, LAMBDA, wires=self.num_spins-1)
def test_one_qubit_wavefunction_circuit(self, device, qvm, compiler): """Test that the wavefunction plugin provides correct result for simple circuit. As the results coming from the qvm are stochastic, a constraint of 2 out of 5 runs was added. """ shots = 100_000 dev = qml.device("forest.qvm", device=device, shots=QVM_SHOTS) a = 0.543 b = 0.123 c = 0.987 @qml.qnode(dev) def circuit(x, y, z): """Reference QNode""" qml.BasisState(np.array([1]), wires=0) qml.Hadamard(wires=0) qml.Rot(x, y, z, wires=0) return qml.expval(qml.PauliZ(0)) self.assertAlmostEqual(circuit(a, b, c), np.cos(a) * np.sin(b), delta=3 / np.sqrt(shots))
def compute_K(generator): """Compute the K hyperparameter controlling # iterations of amplification. Args: generator: An initialized circuit generator (one of the ones above) """ np.random.seed(0) N = 50 target_prob_list = [ generator.target_prob([ np.random.uniform(low=0, high=2 * np.pi) for j in range(generator.num_qubits) ]) for _ in range(N) ] cosphi_list = [2 * p - 1 for p in target_prob_list] cosPhi, cosPhi_error = np.mean( cosphi_list), np.std(cosphi_list) / np.sqrt(N) Phi = np.arccos(cosPhi) K = int(np.pi / (2 * (np.pi - Phi))) return K
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_displaced_squeezed_state(self): """Test the displaced squeezed state is correct.""" self.logTestName() alpha = 0.541 + 0.109j a = abs(alpha) phi_a = np.angle(alpha) r = 0.432 phi_r = 0.123 means, cov = displaced_squeezed_state(a, phi_a, r, phi_r, hbar=hbar) # test vector of means is correct self.assertAllAlmostEqual(means, np.array([alpha.real, alpha.imag]) * np.sqrt(2 * hbar), delta=self.tol) R = rotation(phi_r / 2) expected = R @ np.array([[np.exp(-2 * r), 0], [0, np.exp(2 * r)] ]) * hbar / 2 @ R.T # test covariance matrix is correct self.assertAllAlmostEqual(cov, expected, delta=self.tol)
def test_multi_mode_probability(self, tol): """Test that a product of coherent states returns the correct probability""" dev = qml.device("strawberryfields.gaussian", wires=2) @qml.qnode(dev) def circuit(a, phi): qml.Displacement(a, phi, wires=0) qml.Displacement(a, phi, wires=1) return qml.probs(wires=[0, 1]) a = 0.4 phi = -0.12 cutoff = 10 alpha = a * np.exp(1j * phi) n = np.arange(cutoff) ref_probs = np.abs(np.exp(-0.5 * np.abs(alpha) ** 2) * alpha**n / np.sqrt(fac(n))) ** 2 ref_probs = np.kron(ref_probs, ref_probs) res = circuit(a, phi) assert np.allclose(res, ref_probs, atol=tol, rtol=0)
def test_nonzero_shots(self): """Test that the fock plugin provides correct result for high shot number""" shots = 10**2 dev = qml.device("strawberryfields.fock", wires=1, cutoff_dim=10, shots=shots) @qml.qnode(dev) def circuit(x): qml.Displacement(x, 0, wires=0) return qml.expval(qml.NumberOperator(0)) x = 1 runs = [] for _ in range(100): runs.append(circuit(x)) expected_var = np.sqrt(1 / shots) assert np.allclose(np.mean(runs), x, atol=expected_var)
def test_apply_errors(self, qubit_device_2_wires): """Test that apply fails for incorrect state preparation, and > 2 qubit gates""" with pytest.raises( ValueError, match=r"State vector must be of length 2\*\*wires." ): p = [np.array([1, 0, 1, 1, 1]) / np.sqrt(3)] qubit_device_2_wires.apply("QubitStateVector", wires=[0, 1], par=[p]) with pytest.raises( ValueError, match="BasisState parameter must be an array of 0 or 1 integers of length at most 2." ): qubit_device_2_wires.apply("BasisState", wires=[0, 1], par=[np.array([-0.2, 4.2])]) with pytest.raises( ValueError, match="The default.qubit plugin can apply BasisState only to all of the 2 wires." ): qubit_device_2_wires.apply("BasisState", wires=[0, 1, 2], par=[np.array([0, 1])])
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_apply_errors(self): """Test that apply fails for incorrect state preparation, and > 2 qubit gates""" self.logTestName() with self.assertRaisesRegex( ValueError, r"State vector must be of length 2\*\*wires." ): p = [np.array([1, 0, 1, 1, 1]) / np.sqrt(3)] self.dev.apply("QubitStateVector", wires=[0, 1], par=[p]) with self.assertRaisesRegex( ValueError, "BasisState parameter must be an array of 0 or 1 integers of length at most 2.", ): self.dev.apply("BasisState", wires=[0, 1], par=[np.array([-0.2, 4.2])]) with self.assertRaisesRegex( ValueError, "The default.qubit plugin can apply BasisState only to all of the 2 wires.", ): self.dev.apply("BasisState", wires=[0, 1, 2], par=[np.array([0, 1])])
def test_pauliz_hadamard(self, device, tol, skip_if): """Test that a tensor product involving PauliZ and PauliY and hadamard works correctly""" n_wires = 3 dev = device(n_wires) if dev.shots is None: pytest.skip("Device is in analytic mode, cannot test sampling.") skip_if(dev, {"supports_tensor_observables": False}) theta = 0.432 phi = 0.123 varphi = -0.543 @qml.qnode(dev) def circuit(): qml.RX(theta, wires=[0]) qml.RX(phi, wires=[1]) qml.RX(varphi, wires=[2]) qml.CNOT(wires=[0, 1]) qml.CNOT(wires=[1, 2]) return qml.sample( qml.PauliZ(wires=[0]) @ qml.Hadamard(wires=[1]) @ qml.PauliY(wires=[2])) res = circuit() # s1 should only contain 1 and -1 assert np.allclose(res**2, 1, atol=tol(False)) mean = np.mean(res) expected = -(np.cos(varphi) * np.sin(phi) + np.sin(varphi) * np.cos(theta)) / np.sqrt(2) assert np.allclose(mean, expected, atol=tol(False)) var = np.var(res) expected = (3 + np.cos(2 * phi) * np.cos(varphi)**2 - np.cos(2 * theta) * np.sin(varphi)**2 - 2 * np.cos(theta) * np.sin(phi) * np.sin(2 * varphi)) / 4 assert np.allclose(var, expected, atol=tol(False))
def test_hadamard_expectation(self, device, tol): """Test that Hadamard expectation value is correct""" n_wires = 2 dev = device(n_wires) theta = 0.432 phi = 0.123 @qml.qnode(dev) def circuit(): qml.RY(theta, wires=[0]) qml.RY(phi, wires=[1]) qml.CNOT(wires=[0, 1]) return qml.expval(qml.Hadamard(wires=0)), qml.expval( qml.Hadamard(wires=1)) res = 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) assert np.allclose(res, expected, atol=tol(dev.shots))
def test_nonzero_shots(self): """Test that the default gaussian plugin provides correct result for high shot number""" self.logTestName() shots = 10**4 dev = qml.device('default.gaussian', wires=1, shots=shots) p = 0.543 @qml.qnode(dev) def circuit(x): """Test quantum function""" qml.Displacement(x, 0, wires=0) return qml.expval(qml.X(0)) runs = [] for _ in range(100): runs.append(circuit(p)) self.assertAlmostEqual(np.mean(runs), p * np.sqrt(2 * hbar), delta=0.01)
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_analysis_caching(self, mocker): """Test that the gradient analysis is only executed once per tape""" psi = np.array([1, 0, 1, 0]) / np.sqrt(2) with qml.tape.JacobianTape() as tape: qml.QubitStateVector(psi, wires=[0, 1]) qml.RX(0.543, wires=[0]) qml.RY(-0.654, wires=[1]) qml.CNOT(wires=[0, 1]) qml.probs(wires=[0, 1]) spy = mocker.spy(tape, "_grad_method") _gradient_analysis(tape) spy.assert_called() assert tape._par_info[0]["grad_method"] is None assert tape._par_info[1]["grad_method"] == "A" assert tape._par_info[2]["grad_method"] == "A" spy = mocker.spy(tape, "_grad_method") _gradient_analysis(tape) spy.assert_not_called()
def load(): data = np.loadtxt("data/iris_classes1and2_scaled.txt") X = data[:, 0:2] print("First X sample (original) :", X[0]) # pad the vectors to size 2^2 with constant values padding = 0.3 * np.ones((len(X), 1)) X_pad = np.c_[np.c_[X, padding], np.zeros((len(X), 1))] print("First X sample (padded) :", X_pad[0]) # normalize each input normalization = np.sqrt(np.sum(X_pad**2, -1)) X_norm = (X_pad.T / normalization).T print("First X sample (normalized):", X_norm[0]) # angles for state preparation are new features features = np.array([get_angles(x) for x in X_norm]) print("First features sample :", features[0]) Y = data[:, -1] return (X, X_norm, features, Y)
def test_pauliz_hadamard(self, device, shots, tol): """Test that a tensor product involving PauliZ and PauliY and Hadamard works correctly""" dev = device(3) theta = 0.432 phi = 0.123 varphi = -0.543 @qml.qnode(dev) def circuit(): qml.RX(theta, wires=[0]) qml.RX(phi, wires=[1]) qml.RX(varphi, wires=[2]) qml.CNOT(wires=[0, 1]) qml.CNOT(wires=[1, 2]) return qml.expval( qml.PauliZ(wires=[0]) @ qml.Hadamard(wires=[1]) @ qml.PauliY(wires=[2])) expected = -(np.cos(varphi) * np.sin(phi) + np.sin(varphi) * np.cos(theta)) / np.sqrt(2) assert np.allclose(circuit(), expected, **tol)
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_nonzero_shots(self, qvm, compiler): """Test that the wavefunction plugin provides correct result for high shot number""" shots = 10**2 dev = qml.device('forest.wavefunction', wires=1, shots=shots) a = 0.543 b = 0.123 c = 0.987 @qml.qnode(dev) def circuit(x, y, z): """Test QNode""" qml.BasisState(np.array([1]), wires=0) qml.Hadamard(wires=0) qml.Rot(x, y, z, wires=0) return qml.expval.PauliZ(0) runs = [] for _ in range(100): runs.append(circuit(a, b, c)) expected_var = np.sqrt(1/shots) self.assertAlmostEqual(np.mean(runs), np.cos(a)*np.sin(b), delta=expected_var)
def test_ev(self, ev, tol): """Test that expectation values are calculated correctly""" dev = plf.NumpyWavefunctionDevice(wires=2) # start in the following initial state dev.state = np.array([1, 0, 1, 1]) / np.sqrt(3) dev.active_wires = {0, 1} # get the equivalent pennylane operation class op = getattr(qml.ops, ev) O = test_operation_map[ev] # calculate the expected output if op.num_wires == 1 or op.num_wires == 0: expected_out = dev.state.conj() @ np.kron(O, I) @ dev.state elif op.num_wires == 2: expected_out = dev.state.conj() @ O @ dev.state res = dev.ev(O, wires=[0]) # verify the device is now in the expected state self.assertAllAlmostEqual(res, expected_out, delta=tol)
def test_correct_state(self, tol): """Test that the device state is correct after applying a quantum function on the device""" dev = qml.device("default.qubit.autograd", wires=2) state = dev.state expected = np.array([1, 0, 0, 0]) assert np.allclose(state, expected, atol=tol, rtol=0) @qml.qnode(dev, interface="autograd", diff_method="backprop") def circuit(): qml.Hadamard(wires=0) qml.RZ(np.pi / 4, wires=0) return qml.expval(qml.PauliZ(0)) circuit() state = dev.state amplitude = np.exp(-1j * np.pi / 8) / np.sqrt(2) expected = np.array([amplitude, 0, np.conj(amplitude), 0]) assert np.allclose(state, expected, atol=tol, rtol=0)
def test_nonzero_shots(self): """Test that the fock plugin provides correct result for high shot number""" self.logTestName() shots = 10**2 dev = qml.device('strawberryfields.fock', wires=1, cutoff_dim=10, shots=shots) @qml.qnode(dev) def circuit(x): qml.Displacement(x, 0, wires=0) return qml.expval.MeanPhoton(0) x = 1 runs = [] for _ in range(100): runs.append(circuit(x)) expected_var = np.sqrt(1 / shots) self.assertAlmostEqual(np.mean(runs), x, delta=expected_var)
def circle(samples, center=[0.0, 0.0], radius=np.sqrt(2 / np.pi)): """ Generates a dataset of points with 1/0 labels inside a given radius. Args: samples (int): number of samples to generate center (tuple): center of the circle radius (float: radius of the circle Returns: Xvals (array[tuple]): coordinates of points Xvals (array[int]): classification labels """ Xvals, yvals = [], [] for i in range(samples): x = 2 * (np.random.rand(2)) - 1 y = 0 if np.linalg.norm(x - center) < radius: y = 1 Xvals.append(x) yvals.append(y) return np.array(Xvals), np.array(yvals)
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) )