def test_param_unused(self, operable_mock_device_2_wires): """Test that the gradient is 0 of an unused parameter""" def circuit(x, y): qml.RX(x, wires=[0]) return qml.expval(qml.PauliZ(0)) q = JacobianQNode(circuit, operable_mock_device_2_wires) q._construct([1.0, 1.0], {}) assert q.par_to_grad_method == {0: "F", 1: "0"}
def test_all_finite_difference(self, operable_mock_device_2_wires): """Finite difference is the best method in almost all cases""" def circuit(x, y, z): qml.Rot(x, y, z, wires=[0]) return qml.expval(qml.PauliZ(0)) q = JacobianQNode(circuit, operable_mock_device_2_wires) q._construct([1.0, 1.0, 1.0], {}) assert q.par_to_grad_method == {0: "F", 1: "F", 2: "F"}
def test_no_following_observable(self, operable_mock_device_2_wires): """Test that the gradient is 0 if no observables succeed""" def circuit(x): qml.RX(x, wires=[1]) return qml.expval(qml.PauliZ(0)) q = JacobianQNode(circuit, operable_mock_device_2_wires) q._construct([1.0], {}) assert q.par_to_grad_method == {0: "0"}
def test_not_differentiable(self, operable_mock_device_2_wires): """Test that an operation with grad_method=None is marked as non-differentiable""" def circuit(x): qml.BasisState(x, wires=[1]) return qml.expval(qml.PauliZ(0)) q = JacobianQNode(circuit, operable_mock_device_2_wires) q._construct([np.array([1.0])], {}) assert q.par_to_grad_method == {0: None}
def test_unknown_gradient_method(self, operable_mock_device_2_wires): """ The gradient method is unknown.""" def circuit(x): qml.Rot(0.3, x, -0.2, wires=[0]) return qml.expval(qml.PauliZ(0)) node = JacobianQNode(circuit, operable_mock_device_2_wires) with pytest.raises(ValueError, match="Unknown gradient method"): node.jacobian(0.5, method="unknown")
def test_wrong_order_in_finite_difference(self, operable_mock_device_2_wires): """Finite difference are attempted with wrong order.""" def circuit(x): qml.Rot(0.3, x, -0.2, wires=[0]) return qml.expval(qml.PauliZ(0)) node = JacobianQNode(circuit, operable_mock_device_2_wires) with pytest.raises(ValueError, match="Order must be 1 or 2"): node.jacobian(0.5, method="F", options={'order': 3})
def test_indices_not_unique(self, operable_mock_device_2_wires): """The Jacobian is requested for non-unique indices.""" def circuit(x): qml.Rot(0.3, x, -0.2, wires=[0]) return qml.expval(qml.PauliZ(0)) node = JacobianQNode(circuit, operable_mock_device_2_wires) with pytest.raises(ValueError, match="Parameter indices must be unique."): node.jacobian(0.5, wrt=[0, 0])
def test_gradient_of_sample(self, operable_mock_device_2_wires): """Differentiation of a sampled output.""" def circuit(x): qml.RX(x, wires=[0]) return qml.sample(qml.PauliZ(0)), qml.sample(qml.PauliX(1)) node = JacobianQNode(circuit, operable_mock_device_2_wires) with pytest.raises( QuantumFunctionError, match= "Circuits that include sampling can not be differentiated."): node.jacobian(1.0)
def test_operator_not_supporting_pd_analytic(self, operable_mock_device_2_wires): """Differentiating wrt. a parameter that appears as an argument to an operation that does not support parameter-shift derivatives.""" def circuit(x): qml.RX(x, wires=[0]) return qml.expval(qml.Hermitian(np.diag([x, 0]), 0)) node = JacobianQNode(circuit, operable_mock_device_2_wires) with pytest.raises( ValueError, match="analytic gradient method cannot be used with"): node.jacobian(0.5, method="A")
def test_nondifferentiable_operator(self, operable_mock_device_2_wires): """Differentiating wrt. a parameter that appears as an argument to a nondifferentiable operator.""" def circuit(x): qml.BasisState(np.array([x, 0]), wires=[0, 1]) # not differentiable qml.RX(x, wires=[0]) return qml.expval(qml.PauliZ(0)) node = JacobianQNode(circuit, operable_mock_device_2_wires) with pytest.raises( ValueError, match="Cannot differentiate with respect to the parameters"): node.jacobian(0.5)
def test_interface_str(self, qubit_device_2_wires): """Test that the interface string is correctly identified as None""" def circuit(x, y, z): qml.CNOT(wires=[0, 1]) return qml.expval(qml.PauliZ(0)), qml.expval(qml.PauliY(1)) circuit = JacobianQNode(circuit, qubit_device_2_wires) assert circuit.interface == None
def test_bogus_gradient_method_set(self, operable_mock_device_2_wires): """The gradient method set is bogus.""" def circuit(x): qml.RX(x, wires=[0]) return qml.expval(qml.PauliZ(0)) # in mutable mode, the grad method would be # recomputed and overwritten from the # bogus value 'J'. Caching stops this from happening. node = JacobianQNode(circuit, operable_mock_device_2_wires, mutable=False) node.evaluate([0.0], {}) node.par_to_grad_method[0] = "J" with pytest.raises(ValueError, match="Unknown gradient method"): node.jacobian(0.5)
def test_indices_nonexistant(self, operable_mock_device_2_wires): """ The Jacobian is requested for non-existant parameters.""" def circuit(x): qml.Rot(0.3, x, -0.2, wires=[0]) return qml.expval(qml.PauliZ(0)) node = JacobianQNode(circuit, operable_mock_device_2_wires) with pytest.raises( ValueError, match="Tried to compute the gradient with respect to"): node.jacobian(0.5, wrt=[0, 6]) with pytest.raises( ValueError, match="Tried to compute the gradient with respect to"): node.jacobian(0.5, wrt=[1, -1])