def test_exp(self): """Tests multiarg gradients with exp and tanh functions.""" x = -2.5 y = 1.5 gradf = lambda x, y: ( np.exp(x / 3) / 3 * np.tanh(y), np.exp(x / 3) * (1 - np.tanh(y)**2), ) f = lambda x, y: np.exp(x / 3) * np.tanh(y) # gradient wrt first argument gx = qml.grad(f, 0) auto_gradx = gx(x, y) correct_gradx = gradf(x, y)[0] np.allclose(auto_gradx, correct_gradx) # gradient wrt second argument gy = qml.grad(f, 1) auto_grady = gy(x, y) correct_grady = gradf(x, y)[1] np.allclose(auto_grady, correct_grady) # gradient wrt both arguments gxy = qml.grad(f, [0, 1]) auto_gradxy = gxy(x, y) correct_gradxy = gradf(x, y) np.allclose(auto_gradxy, correct_gradxy)
def test_gradient_multiargs(self): """Tests gradients of univariate functions with multiple arguments in signature.""" self.logTestName() for gradf, f, name in zip(self.grad_margs_funcs, self.margs_fns, self.fnames): with self.subTest(i=name): for jdx in range(len(x_vals[:-1])): x = x_vals[jdx] y = x_vals[jdx + 1] # gradient wrt first argument gx = qml.grad(f, 0) auto_gradx = gx(x, y) correct_gradx = gradf(x, y)[0] self.assertAllAlmostEqual(auto_gradx, correct_gradx, delta=self.tol) # gradient wrt second argument gy = qml.grad(f, 1) auto_grady = gy(x, y) correct_grady = gradf(x, y)[1] self.assertAllAlmostEqual(auto_grady, correct_grady, delta=self.tol) # gradient wrt both arguments gxy = qml.grad(f, [0, 1]) auto_gradxy = gxy(x, y) correct_gradxy = gradf(x, y) self.assertAllAlmostEqual(auto_gradxy, correct_gradxy, delta=self.tol)
def test_sin(self): """Tests with sin function.""" x_vals = np.linspace(-10, 10, 16, endpoint=False) g = qml.grad(np.sin, 0) auto_grad = [g(x) for x in x_vals] correct_grad = np.cos(x_vals) np.allclose(auto_grad, correct_grad)
def test_linear(self): """Tests linear function.""" x_vals = np.linspace(-10, 10, 16, endpoint=False) func = lambda x: 2 * x g = qml.grad(func, 0) auto_grad = [g(x) for x in x_vals] correct_grad = x_vals**2 np.allclose(auto_grad, correct_grad)
def test_exp(self): """Tests exp function.""" x_vals = np.linspace(-10, 10, 16, endpoint=False) func = lambda x: np.exp(x / 10.0) / 10.0 g = qml.grad(func, 0) auto_grad = [g(x) for x in x_vals] correct_grad = np.exp(x_vals / 10.0) np.allclose(auto_grad, correct_grad)
def test_quadratic(self): """Tests gradients with a quadratic function.""" multi_var = lambda x: np.sum([x_**2 for x_ in x]) grad_multi_var = lambda x: np.array([2 * x_ for x_ in x]) x_vec = np.random.uniform(-5, 5, size=(2)) g = qml.grad(multi_var, 0) auto_grad = g(x_vec) correct_grad = grad_multi_var(x_vec) np.allclose(auto_grad, correct_grad)
def test_sin(self): """Tests gradients with multivariate sin and cosine.""" multi_var = lambda x: np.sin(x[0]) + np.cos(x[1]) grad_multi_var = lambda x: np.array([np.cos(x[0]), -np.sin(x[1])]) x_vec = [1.5, -2.5] g = qml.grad(multi_var, 0) auto_grad = g(x_vec) correct_grad = grad_multi_var(x_vec) np.allclose(auto_grad, correct_grad)
def test_array_parameters_autograd(self, tol): """Test that gradients of array parameters give same results as positional arguments.""" a, b, c = 0.5, 0.54, 0.3 def ansatz(x, y, z): qml.QubitStateVector(np.array([1, 0, 1, 1]) / np.sqrt(3), wires=[0, 1]) qml.Rot(x, y, z, wires=0) qml.CNOT(wires=[0, 1]) return qml.expval(qml.PauliZ(0)) def circuit1(x, y, z): return ansatz(x, y, z) def circuit2(x, array): return ansatz(x, array[0], array[1]) def circuit3(array): return ansatz(*array) dev = qml.device('default.qubit', wires=2) circuit1 = qml.QNode(circuit1, dev) grad1 = qml.grad(circuit1, argnum=[0, 1, 2]) positional_grad = circuit1.jacobian([a, b, c]) positional_autograd = grad1(a, b, c) assert np.allclose(positional_grad, positional_autograd, atol=tol, rtol=0) circuit2 = qml.QNode(circuit2, dev) grad2 = qml.grad(circuit2, argnum=[0, 1]) circuit3 = qml.QNode(circuit3, dev) grad3 = qml.grad(circuit3, argnum=0) array_grad = circuit3.jacobian([np.array([a, b, c])]) array_autograd = grad3(np.array([a, b, c])) assert np.allclose(array_grad, array_autograd, atol=tol, rtol=0)
def test_linear(self): """Tests gradients with multivariate multidimensional linear func.""" x_vec = np.random.uniform(-5, 5, size=(2)) x_vec_multidim = np.expand_dims(x_vec, axis=1) gradf = lambda x: np.array([[2 * x_[0]] for x_ in x]) f = lambda x: np.sum([x_[0]**2 for x_ in x]) g = qml.grad(f, 0) auto_grad = g(x_vec_multidim) correct_grad = gradf(x_vec_multidim) np.allclose(auto_grad, correct_grad)
def test_exp(self): """Tests gradients with a multivariate exp and tanh.""" multi_var = lambda x: np.exp(x[0] / 3) * np.tanh(x[1]) grad_multi_var = lambda x: np.array([ np.exp(x[0] / 3) / 3 * np.tanh(x[1]), np.exp(x[0] / 3) * (1 - np.tanh(x[1])**2), ]) x_vec = np.random.uniform(-5, 5, size=(2)) g = qml.grad(multi_var, 0) auto_grad = g(x_vec) correct_grad = grad_multi_var(x_vec) np.allclose(auto_grad, correct_grad)
def test_array_parameters_autograd(self): "Test that gradients of array parameters give same results as positional arguments." self.logTestName() a, b, c = 0.5, 0.54, 0.3 def ansatz(x, y, z): qml.QubitStateVector(np.array([1, 0, 1, 1]) / np.sqrt(3), wires=[0, 1]) qml.Rot(x, y, z, wires=0) qml.CNOT(wires=[0, 1]) return qml.expval.PauliZ(0) def circuit1(x, y, z): return ansatz(x, y, z) def circuit2(x, array): return ansatz(x, array[0], array[1]) def circuit3(array): return ansatz(*array) circuit1 = qml.QNode(circuit1, self.dev2) grad1 = qml.grad(circuit1, argnum=[0, 1, 2]) positional_grad = circuit1.jacobian([a, b, c]) positional_autograd = grad1(a, b, c) self.assertAllAlmostEqual(positional_grad, positional_autograd, delta=self.tol) circuit2 = qml.QNode(circuit2, self.dev2) grad2 = qml.grad(circuit2, argnum=[0, 1]) circuit3 = qml.QNode(circuit3, self.dev2) grad3 = qml.grad(circuit3, argnum=0) array_grad = circuit3.jacobian([np.array([a, b, c])]) array_autograd = grad3(np.array([a, b, c])) self.assertAllAlmostEqual(array_grad, array_autograd, delta=self.tol)
def test_sin(self): """Tests gradients with multivariate multidimensional sin and cos.""" x_vec = np.random.uniform(-5, 5, size=(2)) x_vec_multidim = np.expand_dims(x_vec, axis=1) gradf = lambda x: np.array([[np.cos(x[0, 0])], [-np.sin(x[[1]])]], dtype=np.float64) f = lambda x: np.sin(x[0, 0]) + np.cos(x[1, 0]) g = qml.grad(f, 0) auto_grad = g(x_vec_multidim) correct_grad = gradf(x_vec_multidim) np.allclose(auto_grad, correct_grad)
def test_gradient_univar(self): """Tests gradients of univariate unidimensional functions.""" self.logTestName() for gradf, f, name in zip(self.grad_uni_fns, self.univariate_funcs, self.fnames): with self.subTest(i=name): for x in x_vals: g = qml.grad(f, 0) auto_grad = g(x) correct_grad = gradf(x) self.assertAlmostEqual(auto_grad, correct_grad, delta=self.tol)
def test_exp(self): """Tests gradients with multivariate multidimensional exp and tanh.""" x_vec = np.random.uniform(-5, 5, size=(2)) x_vec_multidim = np.expand_dims(x_vec, axis=1) gradf = lambda x: np.array([ [np.exp(x[0, 0] / 3) / 3 * np.tanh(x[1, 0])], [np.exp(x[0, 0] / 3) * (1 - np.tanh(x[1, 0])**2)], ]) f = lambda x: np.exp(x[0, 0] / 3) * np.tanh(x[1, 0]) g = qml.grad(f, 0) auto_grad = g(x_vec_multidim) correct_grad = gradf(x_vec_multidim) np.allclose(auto_grad, correct_grad)
def test_gradient_multivar(self): """Tests gradients of multivariate unidimensional functions.""" self.logTestName() for gradf, f, name in zip(self.grad_multi_funcs, self.multivariate_funcs, self.fnames): with self.subTest(i=name): for jdx in range(len(x_vals[:-1])): x_vec = x_vals[jdx:jdx + 2] g = qml.grad(f, 0) auto_grad = g(x_vec) correct_grad = gradf(x_vec) self.assertAllAlmostEqual(auto_grad, correct_grad, delta=self.tol)
def test_sin(self): """Tests multiarg gradients with sin and cos functions.""" x = -2.5 y = 1.5 gradf = lambda x, y: (np.cos(x), -np.sin(y)) f = lambda x, y: np.sin(x) + np.cos(y) # gradient wrt first argument gx = qml.grad(f, 0) auto_gradx = gx(x, y) correct_gradx = gradf(x, y)[0] np.allclose(auto_gradx, correct_gradx) # gradient wrt second argument gy = qml.grad(f, 1) auto_grady = gy(x, y) correct_grady = gradf(x, y)[1] np.allclose(auto_grady, correct_grady) # gradient wrt both arguments gxy = qml.grad(f, [0, 1]) auto_gradxy = gxy(x, y) correct_gradxy = gradf(x, y) np.allclose(auto_gradxy, correct_gradxy)
def test_linear(self): """Tests multiarg gradients with a linear function.""" x = -2.5 y = 1.5 gradf = lambda x, y: (2 * x, 2 * y) f = lambda x, y: np.sum([x_**2 for x_ in [x, y]]) # gradient wrt first argument gx = qml.grad(f, 0) auto_gradx = gx(x, y) correct_gradx = gradf(x, y)[0] np.allclose(auto_gradx, correct_gradx) # gradient wrt second argument gy = qml.grad(f, 1) auto_grady = gy(x, y) correct_grady = gradf(x, y)[1] np.allclose(auto_grady, correct_grady) # gradient wrt both arguments gxy = qml.grad(f, [0, 1]) auto_gradxy = gxy(x, y) correct_gradxy = gradf(x, y) np.allclose(auto_gradxy, correct_gradxy)
def test_gradient_multivar_multidim(self): """Tests gradients of multivariate multidimensional functions.""" self.logTestName() for gradf, f, name in zip(self.grad_mvar_mdim_funcs, self.mvar_mdim_funcs, self.fnames): with self.subTest(i=name): for jdx in range(len(x_vals[:-1])): x_vec = x_vals[jdx:jdx + 2] x_vec_multidim = np.expand_dims(x_vec, axis=1) g = qml.grad(f, 0) auto_grad = g(x_vec_multidim) correct_grad = gradf(x_vec_multidim) self.assertAllAlmostEqual(auto_grad, correct_grad, delta=self.tol)
def test_qnode_array_parameters(self): "Test that QNode can take arrays as input arguments, and that they interact properly with autograd." self.logTestName() @qml.qnode(self.dev1) def circuit_n1s(dummy1, array, dummy2): qml.RY(0.5 * array[0, 1], wires=0) qml.RY(-0.5 * array[1, 1], wires=0) return qml.expval(qml.PauliX(0)) # returns a scalar @qml.qnode(self.dev1) def circuit_n1v(dummy1, array, dummy2): qml.RY(0.5 * array[0, 1], wires=0) qml.RY(-0.5 * array[1, 1], wires=0) return qml.expval( qml.PauliX(0)), # note the comma, returns a 1-vector @qml.qnode(self.dev2) def circuit_nn(dummy1, array, dummy2): qml.RY(0.5 * array[0, 1], wires=0) qml.RY(-0.5 * array[1, 1], wires=0) qml.RY(array[1, 0], wires=1) return qml.expval(qml.PauliX(0)), qml.expval( qml.PauliX(1)) # returns a 2-vector args = (0.46, np.array([[2., 3., 0.3], [7., 4., 2.1]]), -0.13) grad_target = (np.array(1.), np.array([[0.5, 0.43879, 0], [0, -0.43879, 0]]), np.array(-0.4)) cost_target = 1.03257 for circuit in [circuit_n1s, circuit_n1v, circuit_nn]: def cost(x, array, y): c = circuit(0.111, array, 4.5) if not np.isscalar(c): c = c[0] # get a scalar return c + 0.5 * array[0, 0] + x - 0.4 * y cost_grad = qml.grad(cost, argnum=[0, 1, 2]) self.assertAllAlmostEqual(cost(*args), cost_target, delta=self.tol) self.assertAllAlmostEqual(cost_grad(*args), grad_target, delta=self.tol)
def test_qnode_gradient_agrees(self): "Tests that simple gradient example is consistent." self.logTestName() dev = qml.device('default.qubit', wires=2) @qml.qnode(dev, interface='autograd') def circuit(phi, theta): qml.RX(phi[0], wires=0) qml.RY(phi[1], wires=1) qml.CNOT(wires=[0, 1]) qml.PhaseShift(theta[0], wires=0) return qml.expval(qml.PauliZ(0)) @qml.qnode(dev, interface='torch') def circuit_torch(phi, theta): qml.RX(phi[0], wires=0) qml.RY(phi[1], wires=1) qml.CNOT(wires=[0, 1]) qml.PhaseShift(theta[0], wires=0) return qml.expval(qml.PauliZ(0)) phi = [0.5, 0.1] theta = [0.2] phi_t = torch.autograd.Variable(torch.tensor(phi), requires_grad=True) theta_t = torch.autograd.Variable(torch.tensor(theta), requires_grad=True) dcircuit = qml.grad(circuit, [0, 1]) autograd_grad = dcircuit(phi, theta) torch_eval = circuit_torch(phi_t, theta_t) torch_eval.backward() self.assertAllAlmostEqual(autograd_grad[0], phi_t.grad.detach().numpy(), delta=self.tol) self.assertAllAlmostEqual(autograd_grad[1], theta_t.grad.detach().numpy(), delta=self.tol)
def test_qnode_gradient_agrees(self): "Tests that simple gradient example is consistent." self.logTestName() dev = qml.device('default.qubit', wires=2) @qml.qnode(dev, interface='autograd') def circuit(phi, theta): qml.RX(phi[0], wires=0) qml.RY(phi[1], wires=1) qml.CNOT(wires=[0, 1]) qml.PhaseShift(theta[0], wires=0) return qml.expval.PauliZ(0) @qml.qnode(dev, interface='tfe') def circuit_tfe(phi, theta): qml.RX(phi[0], wires=0) qml.RY(phi[1], wires=1) qml.CNOT(wires=[0, 1]) qml.PhaseShift(theta[0], wires=0) return qml.expval.PauliZ(0) phi = [0.5, 0.1] theta = [0.2] phi_t = tfe.Variable(phi) theta_t = tfe.Variable(theta) dcircuit = qml.grad(circuit, [0, 1]) autograd_grad = dcircuit(phi, theta) dcircuit = tfe.gradients_function(circuit_tfe) tfe_grad = dcircuit(phi_t, theta_t) self.assertAllAlmostEqual(autograd_grad[0], tfe_grad[0], delta=self.tol) self.assertAllAlmostEqual(autograd_grad[1], tfe_grad[1], delta=self.tol)