def test_non_differentiable(self): """Test that a non-differentiable parameter is correctly marked""" with qml.tape.JacobianTape() as tape: qml.FockState(1, wires=0) qml.Displacement(0.543, 0, wires=[1]) qml.Beamsplitter(0, 0, wires=[0, 1]) qml.expval(qml.X(wires=[0])) assert _grad_method(tape, 0) is None assert _grad_method(tape, 1) == "A" assert _grad_method(tape, 2) == "A" assert _grad_method(tape, 3) == "A" assert _grad_method(tape, 4) == "A" _gradient_analysis(tape) 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" assert tape._par_info[3]["grad_method"] == "A" assert tape._par_info[4]["grad_method"] == "A" _gradient_analysis(tape)
def test_unknown_op_grad_method(self, monkeypatch): """Test that an exception is raised if an operator has a grad method defined that the CV parameter-shift tape doesn't recognize""" monkeypatch.setattr(qml.Rotation, "grad_method", "B") with qml.tape.JacobianTape() as tape: qml.Rotation(1.0, wires=0) qml.expval(qml.X(0)) with pytest.raises(ValueError, match="unknown gradient method"): _grad_method(tape, 0)
def test_probability(self): """Probability is the expectation value of a higher order observable, and thus only supports numerical differentiation""" with qml.tape.JacobianTape() as tape: qml.Rotation(0.543, wires=[0]) qml.Squeezing(0.543, 0, wires=[0]) qml.probs(wires=0) assert _grad_method(tape, 0) == "F" assert _grad_method(tape, 1) == "F" assert _grad_method(tape, 2) == "F"
def test_finite_diff(self, monkeypatch): """If an op has grad_method=F, this should be respected by the qml.tape.JacobianTape""" monkeypatch.setattr(qml.Rotation, "grad_method", "F") with qml.tape.JacobianTape() as tape: qml.Rotation(0.543, wires=[0]) qml.Squeezing(0.543, 0, wires=[0]) qml.expval(qml.P(0)) assert _grad_method(tape, 0) == "F" assert _grad_method(tape, 1) == "A" assert _grad_method(tape, 2) == "A"
def test_independent(self): """Test that an independent variable is properly marked as having a zero gradient""" with qml.tape.JacobianTape() as tape: qml.Rotation(0.543, wires=[0]) qml.Rotation(-0.654, wires=[1]) qml.expval(qml.P(0)) assert _grad_method(tape, 0) == "A" assert _grad_method(tape, 1) == "0" _gradient_analysis(tape) assert tape._par_info[0]["grad_method"] == "A" assert tape._par_info[1]["grad_method"] == "0"
def test_second_order_expectation(self): """Test that the expectation of a second-order observable forces the gradient method to use the second-order parameter-shift rule""" with qml.tape.JacobianTape() as tape: qml.Rotation(1.0, wires=[0]) qml.expval(qml.NumberOperator(0)) # second order assert _grad_method(tape, 0) == "A2"
def test_non_gaussian_operation(self): """Test that a non-Gaussian operation succeeding a differentiable Gaussian operation results in numeric differentiation.""" with qml.tape.JacobianTape() as tape: qml.Rotation(1.0, wires=[0]) qml.Rotation(1.0, wires=[1]) # Non-Gaussian qml.Kerr(1.0, wires=[1]) qml.expval(qml.P(0)) qml.expval(qml.X(1)) # First rotation gate has no succeeding non-Gaussian operation assert _grad_method(tape, 0) == "A" # Second rotation gate does no succeeding non-Gaussian operation assert _grad_method(tape, 1) == "F" # Kerr gate does not support the parameter-shift rule assert _grad_method(tape, 2) == "F" with qml.tape.JacobianTape() as tape: qml.Rotation(1.0, wires=[0]) qml.Rotation(1.0, wires=[1]) # entangle the modes qml.Beamsplitter(1.0, 0.0, wires=[0, 1]) # Non-Gaussian qml.Kerr(1.0, wires=[1]) qml.expval(qml.P(0)) qml.expval(qml.X(1)) # After entangling the modes, the Kerr gate now succeeds # both initial rotations assert _grad_method(tape, 0) == "F" assert _grad_method(tape, 1) == "F" assert _grad_method(tape, 2) == "F"
def test_variance(self): """If the variance of the observable is first order, then parameter-shift is supported. If the observable is second order, however, only finite-differences is supported.""" with qml.tape.JacobianTape() as tape: qml.Rotation(1.0, wires=[0]) qml.var(qml.P(0)) # first order assert _grad_method(tape, 0) == "A" with qml.tape.JacobianTape() as tape: qml.Rotation(1.0, wires=[0]) qml.var(qml.NumberOperator(0)) # second order assert _grad_method(tape, 0) == "F" with qml.tape.JacobianTape() as tape: qml.Rotation(1.0, wires=[0]) qml.Rotation(1.0, wires=[1]) qml.Beamsplitter(0.5, 0.0, wires=[0, 1]) qml.var(qml.NumberOperator(0)) # fourth order qml.expval(qml.NumberOperator(1)) assert _grad_method(tape, 0) == "F" assert _grad_method(tape, 1) == "F" assert _grad_method(tape, 2) == "F" assert _grad_method(tape, 3) == "F"