def circuit(state_vector): qml.templates.MottonenStatePreparation(state_vector, wires=range(n_wires)) return qml.expval(qml.PauliX(wires=0))
def circuit(): qml.RY(theta, wires=[0]) qml.RY(phi, wires=[1]) qml.CNOT(wires=[0, 1]) return qml.expval(qml.PauliX(wires=0)), qml.expval(qml.PauliX(wires=1))
def circuit(a, b, c): qml.RX(a, wires=0) qml.RY(b, wires=0) qml.CNOT(wires=[0, 1]) qml.PhaseShift(c, wires=1) return qml.expval(qml.PauliX(0)), qml.expval(qml.PauliX(1))
def circuit(): for w in range(4): qml.PauliX(wires=w) broadcast(unitary=unitary, pattern=pattern, wires=range(4), parameters=parameters) return [qml.expval(qml.PauliZ(wires=w)) for w in range(4)]
def circuit(x): qml.RZ(x, wires=[1]).inv() qml.RZ(x, wires=[1]).inv().inv() return qml.expval(qml.PauliX(0)), qml.expval(qml.PauliZ(1))
def test_differentiable_expand(self, mocker, tol): """Test that operation and nested tapes expansion is differentiable""" mock = mocker.patch.object(qml.operation.Operation, "do_check_domain", False) class U3(qml.U3): def expand(self): tape = JacobianTape() theta, phi, lam = self.data wires = self.wires tape._ops += [ qml.Rot(lam, theta, -lam, wires=wires), qml.PhaseShift(phi + lam, wires=wires), ] return tape tape = JacobianTape() dev = qml.device("default.qubit", wires=1) a = np.array(0.1) p_val = [0.1, 0.2, 0.3] p = torch.tensor(p_val, requires_grad=True) with tape: qml.RX(a, wires=0) U3(p[0], p[1], p[2], wires=0) qml.expval(qml.PauliX(0)) tape = TorchInterface.apply(tape.expand()) assert tape.trainable_params == {1, 2, 3, 4} assert [i.name for i in tape.operations] == ["RX", "Rot", "PhaseShift"] tape_params = [i.detach().numpy() for i in tape.get_parameters()] assert np.allclose( tape_params, [p_val[2], p_val[0], -p_val[2], p_val[1] + p_val[2]], atol=tol, rtol=0) res = tape.execute(device=dev) expected = np.cos(a) * np.cos(p_val[1]) * np.sin(p_val[0]) + np.sin( a) * (np.cos(p_val[2]) * np.sin(p_val[1]) + np.cos(p_val[0]) * np.cos(p_val[1]) * np.sin(p_val[2])) assert np.allclose(res.detach().numpy(), expected, atol=tol, rtol=0) res.backward() expected = np.array([ np.cos(p_val[1]) * (np.cos(a) * np.cos(p_val[0]) - np.sin(a) * np.sin(p_val[0]) * np.sin(p_val[2])), np.cos(p_val[1]) * np.cos(p_val[2]) * np.sin(a) - np.sin(p_val[1]) * (np.cos(a) * np.sin(p_val[0]) + np.cos(p_val[0]) * np.sin(a) * np.sin(p_val[2])), np.sin(a) * (np.cos(p_val[0]) * np.cos(p_val[1]) * np.cos(p_val[2]) - np.sin(p_val[1]) * np.sin(p_val[2])), ]) assert np.allclose(p.grad, expected, atol=tol, rtol=0)
def circuit(): qml.Hadamard(wires=[0]) qml.CNOT(wires=[0, 1]) return qml.sample(qml.PauliZ(0)), qml.expval(qml.PauliX(1))
def circuit(x, y): qml.RX(x, wires=0) qml.RY(y, wires=0) qml.CNOT(wires=[0, 1]) return qml.expval(qml.PauliZ(0) @ qml.PauliX(1)), qml.expval( qml.PauliZ(0))
class TestExpval: """Tests for the expval function""" @pytest.fixture(params=[np.complex64, np.complex128]) def dev(self, request): return qml.device("lightning.qubit", wires=2, c_dtype=request.param) def test_expval_dtype64(self, dev): """Test if expval changes the state dtype""" dev._state = np.array([1, 0]).astype(dev.C_DTYPE) e = dev.expval(qml.PauliX(0)) assert dev._state.dtype == dev.C_DTYPE assert np.allclose(e, 0.0) @pytest.mark.parametrize( "cases", [ [qml.PauliX(0), -0.041892271271228736], [qml.PauliX(1), 0.0], [qml.PauliY(0), -0.5516350865364075], [qml.PauliY(1), 0.0], [qml.PauliZ(0), 0.8330328980789793], [qml.PauliZ(1), 1.0], ], ) def test_expval_qml_tape_wire0(self, cases, tol, dev): """Test expval with a circuit on wires=[0]""" x, y, z = [0.5, 0.3, -0.7] @qml.qnode(dev) def circuit(): qml.RX(0.4, wires=[0]) qml.Rot(x, y, z, wires=[0]) qml.RY(-0.2, wires=[0]) return qml.expval(cases[0]) assert np.allclose(circuit(), cases[1], atol=tol, rtol=0) @pytest.mark.parametrize( "cases", [ [qml.PauliX(0), 0.0], [qml.PauliX(1), -0.19866933079506122], [qml.PauliY(0), -0.3894183423086505], [qml.PauliY(1), 0.0], [qml.PauliZ(0), 0.9210609940028852], [qml.PauliZ(1), 0.9800665778412417], ], ) def test_expval_wire01(self, cases, tol, dev): """Test expval with a circuit on wires=[0,1]""" @qml.qnode(dev) def circuit(): qml.RX(0.4, wires=[0]) qml.RY(-0.2, wires=[1]) return qml.expval(cases[0]) assert np.allclose(circuit(), cases[1], atol=tol, rtol=0) def test_value(self, dev, tol): """Test that the expval interface works""" @qml.qnode(dev) def circuit(x): qml.RX(x, wires=0) return qml.expval(qml.PauliY(0)) x = 0.54 res = circuit(x) expected = -np.sin(x) assert np.allclose(res, expected, atol=tol, rtol=0) def test_not_an_observable(self, dev): """Test that a qml.QuantumFunctionError is raised if the provided argument is not an observable""" @qml.qnode(dev) def circuit(): qml.RX(0.52, wires=0) return qml.expval(qml.CNOT(wires=[0, 1])) with pytest.raises(qml.QuantumFunctionError, match="CNOT is not an observable"): circuit() def test_observable_return_type_is_expectation(self, dev): """Test that the return type of the observable is :attr:`ObservableReturnTypes.Expectation`""" @qml.qnode(dev) def circuit(): res = qml.expval(qml.PauliZ(0)) assert res.return_type is Expectation return res circuit()
def circuit_3(x, y): qml.RY(y, wires=[1]) qml.CNOT(wires=[0, 1]) return qml.expval(qml.PauliZ(0) @ qml.PauliX(1))
class TestBatchExecution: """Tests for the batch_execute method.""" with qml.tape.QuantumTape() as tape1: qml.PauliX(wires=0) qml.expval(qml.PauliZ(wires=0)), qml.expval(qml.PauliZ(wires=1)) with qml.tape.JacobianTape() as tape2: qml.PauliX(wires=0) qml.expval(qml.PauliZ(wires=0)) @pytest.mark.parametrize("n_tapes", [1, 2, 3]) def test_calls_to_execute(self, n_tapes, mocker, mock_qubit_device_with_paulis_and_methods): """Tests that the device's execute method is called the correct number of times.""" dev = mock_qubit_device_with_paulis_and_methods(wires=2) spy = mocker.spy(QubitDevice, "execute") tapes = [self.tape1] * n_tapes dev.batch_execute(tapes) assert spy.call_count == n_tapes @pytest.mark.parametrize("n_tapes", [1, 2, 3]) def test_calls_to_reset(self, n_tapes, mocker, mock_qubit_device_with_paulis_and_methods): """Tests that the device's reset method is called the correct number of times.""" dev = mock_qubit_device_with_paulis_and_methods(wires=2) spy = mocker.spy(QubitDevice, "reset") tapes = [self.tape1] * n_tapes dev.batch_execute(tapes) assert spy.call_count == n_tapes def test_result(self, mock_qubit_device_with_paulis_and_methods, tol): """Tests that the result has the correct shape and entry types.""" dev = mock_qubit_device_with_paulis_and_methods(wires=2) tapes = [self.tape1, self.tape2] res = dev.batch_execute(tapes) assert len(res) == 2 assert np.allclose(res[0], dev.execute(self.tape1), rtol=tol, atol=0) assert np.allclose(res[1], dev.execute(self.tape2), rtol=tol, atol=0) def test_result_empty_tape(self, mock_qubit_device_with_paulis_and_methods, tol): """Tests that the result has the correct shape and entry types for empty tapes.""" dev = mock_qubit_device_with_paulis_and_methods(wires=2) empty_tape = qml.tape.QuantumTape() tapes = [empty_tape] * 3 res = dev.batch_execute(tapes) assert len(res) == 3 assert np.allclose(res[0], dev.execute(empty_tape), rtol=tol, atol=0)
def circuit_2(x, y): qml.RX(x, wires=[0]) qml.CNOT(wires=[0, 1]) return qml.expval(qml.PauliZ(0) @ qml.PauliX(1))
class TestOperations: """Tests the logic related to operations""" def test_op_queue_accessed_outside_execution_context( self, mock_qubit_device): """Tests that a call to op_queue outside the execution context raises the correct error""" with pytest.raises( ValueError, match= "Cannot access the operation queue outside of the execution context!" ): dev = mock_qubit_device() dev.op_queue def test_op_queue_is_filled_during_execution( self, mock_qubit_device_with_paulis_and_methods, monkeypatch): """Tests that the op_queue is correctly filled when apply is called and that accessing op_queue raises no error""" with qml.tape.QuantumTape() as tape: queue = [ qml.PauliX(wires=0), qml.PauliY(wires=1), qml.PauliZ(wires=2) ] observables = [qml.expval(qml.PauliZ(0)), qml.var(qml.PauliZ(1))] call_history = [] with monkeypatch.context() as m: m.setattr( QubitDevice, "apply", lambda self, x, **kwargs: call_history.extend(x + kwargs.get( "rotations", [])), ) m.setattr(QubitDevice, "analytic_probability", lambda *args: None) dev = mock_qubit_device_with_paulis_and_methods() dev.execute(tape) assert call_history == queue assert len(call_history) == 3 assert isinstance(call_history[0], qml.PauliX) assert call_history[0].wires == Wires([0]) assert isinstance(call_history[1], qml.PauliY) assert call_history[1].wires == Wires([1]) assert isinstance(call_history[2], qml.PauliZ) assert call_history[2].wires == Wires([2]) def test_unsupported_operations_raise_error( self, mock_qubit_device_with_paulis_and_methods): """Tests that the operations are properly applied and queued""" with qml.tape.QuantumTape() as tape: queue = [ qml.PauliX(wires=0), qml.PauliY(wires=1), qml.Hadamard(wires=2) ] observables = [qml.expval(qml.PauliZ(0)), qml.var(qml.PauliZ(1))] with pytest.raises(DeviceError, match="Gate Hadamard not supported on device"): dev = mock_qubit_device_with_paulis_and_methods() dev.execute(tape) numeric_queues = [ [qml.RX(0.3, wires=[0])], [ qml.RX(0.3, wires=[0]), qml.RX(0.4, wires=[1]), qml.RX(0.5, wires=[2]), ], ] observables = [[qml.PauliZ(0)], [qml.PauliX(0)], [qml.PauliY(0)]] @pytest.mark.parametrize("observables", observables) @pytest.mark.parametrize("queue", numeric_queues) def test_passing_keyword_arguments_to_execute( self, mock_qubit_device_with_paulis_rotations_and_methods, monkeypatch, queue, observables): """Tests that passing keyword arguments to execute propagates those kwargs to the apply() method""" with qml.tape.QuantumTape() as tape: for op in queue + observables: op.queue() call_history = {} with monkeypatch.context() as m: m.setattr(QubitDevice, "apply", lambda self, x, **kwargs: call_history.update(kwargs)) dev = mock_qubit_device_with_paulis_rotations_and_methods() dev.execute(tape, hash=tape.graph.hash) len(call_history.items()) == 1 call_history["hash"] = tape.graph.hash
def circuit2(data, weights): qml.templates.AngleEmbedding(data, wires=[0, 1]) qml.templates.StronglyEntanglingLayers(weights, wires=[0, 1]) return qml.expval(qml.PauliX(0))
def qf(x): qml.RX(x, wires=[0]) qml.CNOT(wires=[0, 1]) return qml.expval(qml.PauliZ(0)), qml.expval( qml.PauliZ(1)), qml.expval(qml.PauliX(0))
class TestVar: """Tests for the var function""" @pytest.fixture(params=[np.complex64, np.complex128]) def dev(self, request): return qml.device("lightning.qubit", wires=2, c_dtype=request.param) def test_var_dtype64(self, dev): """Test if var changes the state dtype""" dev._state = np.array([1, 0]).astype(np.complex64) v = dev.var(qml.PauliX(0)) assert dev._state.dtype == np.complex64 assert np.allclose(v, 1.0) @pytest.mark.parametrize( "cases", [ [qml.PauliX(0), 0.9982450376077382], [qml.PauliX(1), 1.0], [qml.PauliY(0), 0.6956987716741251], [qml.PauliY(1), 1.0], [qml.PauliZ(0), 0.3060561907181374], [qml.PauliZ(1), -4.440892098500626e-16], ], ) def test_var_qml_tape_wire0(self, cases, tol, dev): """Test var with a circuit on wires=[0]""" x, y, z = [0.5, 0.3, -0.7] @qml.qnode(dev) def circuit(): qml.RX(0.4, wires=[0]) qml.Rot(x, y, z, wires=[0]) qml.RY(-0.2, wires=[0]) return qml.var(cases[0]) assert np.allclose(circuit(), cases[1], atol=tol, rtol=0) @pytest.mark.parametrize( "cases", [ [qml.PauliX(0), 1.0], [qml.PauliX(1), 0.9605304970014426], [qml.PauliY(0), 0.8483533546735826], [qml.PauliY(1), 1.0], [qml.PauliZ(0), 0.15164664532641725], [qml.PauliZ(1), 0.03946950299855745], ], ) def test_var_qml_tape_wire01(self, cases, tol, dev): """Test var with a circuit on wires=[0,1]""" @qml.qnode(dev) def circuit(): qml.RX(0.4, wires=[0]) qml.RY(-0.2, wires=[1]) return qml.var(cases[0]) assert np.allclose(circuit(), cases[1], atol=tol, rtol=0) def test_value(self, dev, tol): """Test that the var function works""" @qml.qnode(dev) def circuit(x): qml.RX(x, wires=0) return qml.var(qml.PauliZ(0)) x = 0.54 res = circuit(x) expected = np.sin(x) ** 2 assert np.allclose(res, expected, atol=tol, rtol=0) def test_not_an_observable(self, dev): """Test that a qml.QuantumFunctionError is raised if the provided argument is not an observable""" @qml.qnode(dev) def circuit(): qml.RX(0.52, wires=0) return qml.var(qml.CNOT(wires=[0, 1])) with pytest.raises(qml.QuantumFunctionError, match="CNOT is not an observable"): res = circuit() def test_observable_return_type_is_variance(self, dev): """Test that the return type of the observable is :attr:`ObservableReturnTypes.Variance`""" @qml.qnode(dev) def circuit(): res = qml.var(qml.PauliZ(0)) assert res.return_type is Variance return res circuit()
class TestRepresentationResolver: """Test the RepresentationResolver class.""" @pytest.mark.parametrize( "list,element,index,list_after", [ ([1, 2, 3], 2, 1, [1, 2, 3]), ([1, 2, 2, 3], 2, 1, [1, 2, 2, 3]), ([1, 2, 3], 4, 3, [1, 2, 3, 4]), ], ) def test_index_of_array_or_append(self, list, element, index, list_after): """Test the method index_of_array_or_append.""" assert RepresentationResolver.index_of_array_or_append(element, list) == index assert list == list_after @pytest.mark.parametrize("par,expected", [ (3, "3"), (5.236422, "5.236"), ]) def test_single_parameter_representation(self, unicode_representation_resolver, par, expected): """Test that single parameters are properly resolved.""" assert unicode_representation_resolver.single_parameter_representation( par) == expected def test_single_parameter_representation_variable( self, unicode_representation_resolver, variable): """Test that variables are properly resolved.""" assert unicode_representation_resolver.single_parameter_representation( variable) == "2" def test_single_parameter_representation_kwarg_variable( self, unicode_representation_resolver, kwarg_variable): """Test that kwarg variables are properly resolved.""" assert (unicode_representation_resolver. single_parameter_representation(kwarg_variable) == "1") @pytest.mark.parametrize("par,expected", [ (3, "3"), (5.236422, "5.236"), ]) def test_single_parameter_representation_varnames( self, unicode_representation_resolver_varnames, par, expected): """Test that single parameters are properly resolved when show_variable_names is True.""" assert (unicode_representation_resolver_varnames. single_parameter_representation(par) == expected) def test_single_parameter_representation_variable_varnames( self, unicode_representation_resolver_varnames, variable): """Test that variables are properly resolved when show_variable_names is True.""" assert (unicode_representation_resolver_varnames. single_parameter_representation(variable) == "test") def test_single_parameter_representation_kwarg_variable_varnames( self, unicode_representation_resolver_varnames, kwarg_variable): """Test that kwarg variables are properly resolved when show_variable_names is True.""" assert ( unicode_representation_resolver_varnames. single_parameter_representation(kwarg_variable) == "kwarg_test") @pytest.mark.parametrize( "op,wire,target", [ (qml.PauliX(wires=[1]), 1, "X"), (qml.CNOT(wires=[0, 1]), 1, "X"), (qml.CNOT(wires=[0, 1]), 0, "C"), (qml.Toffoli(wires=[0, 2, 1]), 1, "X"), (qml.Toffoli(wires=[0, 2, 1]), 0, "C"), (qml.Toffoli(wires=[0, 2, 1]), 2, "C"), (qml.CSWAP(wires=[0, 2, 1]), 1, "SWAP"), (qml.CSWAP(wires=[0, 2, 1]), 2, "SWAP"), (qml.CSWAP(wires=[0, 2, 1]), 0, "C"), (qml.PauliY(wires=[1]), 1, "Y"), (qml.PauliZ(wires=[1]), 1, "Z"), (qml.CZ(wires=[0, 1]), 1, "Z"), (qml.CZ(wires=[0, 1]), 0, "C"), (qml.Identity(wires=[1]), 1, "I"), (qml.Hadamard(wires=[1]), 1, "H"), (qml.CRX(3.14, wires=[0, 1]), 1, "RX(3.14)"), (qml.CRX(3.14, wires=[0, 1]), 0, "C"), (qml.CRY(3.14, wires=[0, 1]), 1, "RY(3.14)"), (qml.CRY(3.14, wires=[0, 1]), 0, "C"), (qml.CRZ(3.14, wires=[0, 1]), 1, "RZ(3.14)"), (qml.CRZ(3.14, wires=[0, 1]), 0, "C"), (qml.CRot(3.14, 2.14, 1.14, wires=[0, 1 ]), 1, "Rot(3.14, 2.14, 1.14)"), (qml.CRot(3.14, 2.14, 1.14, wires=[0, 1]), 0, "C"), (qml.PhaseShift(3.14, wires=[0]), 0, "Rϕ(3.14)"), (qml.Beamsplitter(1, 2, wires=[0, 1]), 1, "BS(1, 2)"), (qml.Beamsplitter(1, 2, wires=[0, 1]), 0, "BS(1, 2)"), (qml.Squeezing(1, 2, wires=[1]), 1, "S(1, 2)"), (qml.TwoModeSqueezing(1, 2, wires=[0, 1]), 1, "S(1, 2)"), (qml.TwoModeSqueezing(1, 2, wires=[0, 1]), 0, "S(1, 2)"), (qml.Displacement(1, 2, wires=[1]), 1, "D(1, 2)"), (qml.NumberOperator(wires=[1]), 1, "n"), (qml.Rotation(3.14, wires=[1]), 1, "R(3.14)"), (qml.ControlledAddition(3.14, wires=[0, 1]), 1, "X(3.14)"), (qml.ControlledAddition(3.14, wires=[0, 1]), 0, "C"), (qml.ControlledPhase(3.14, wires=[0, 1]), 1, "Z(3.14)"), (qml.ControlledPhase(3.14, wires=[0, 1]), 0, "C"), (qml.ThermalState(3, wires=[1]), 1, "Thermal(3)"), ( qml.GaussianState( np.array([1, 2]), np.array([[2, 0], [0, 2]]), wires=[1]), 1, "Gaussian(M0,M1)", ), (qml.QuadraticPhase(3.14, wires=[1]), 1, "P(3.14)"), (qml.RX(3.14, wires=[1]), 1, "RX(3.14)"), (qml.S(wires=[2]), 2, "S"), (qml.T(wires=[2]), 2, "T"), (qml.RX(3.14, wires=[1]), 1, "RX(3.14)"), (qml.RY(3.14, wires=[1]), 1, "RY(3.14)"), (qml.RZ(3.14, wires=[1]), 1, "RZ(3.14)"), (qml.Rot(3.14, 2.14, 1.14, wires=[1]), 1, "Rot(3.14, 2.14, 1.14)"), (qml.U1(3.14, wires=[1]), 1, "U1(3.14)"), (qml.U2(3.14, 2.14, wires=[1]), 1, "U2(3.14, 2.14)"), (qml.U3(3.14, 2.14, 1.14, wires=[1]), 1, "U3(3.14, 2.14, 1.14)"), (qml.BasisState(np.array([0, 1, 0]), wires=[1, 2, 3]), 1, "|0⟩"), (qml.BasisState(np.array([0, 1, 0]), wires=[1, 2, 3]), 2, "|1⟩"), (qml.BasisState(np.array([0, 1, 0]), wires=[1, 2, 3]), 3, "|0⟩"), (qml.QubitStateVector(np.array([0, 1, 0, 0]), wires=[1, 2]), 1, "QubitStateVector(M0)"), (qml.QubitStateVector(np.array([0, 1, 0, 0]), wires=[1, 2]), 2, "QubitStateVector(M0)"), (qml.QubitUnitary(np.eye(2), wires=[1]), 1, "U0"), (qml.QubitUnitary(np.eye(4), wires=[1, 2]), 2, "U0"), (qml.Kerr(3.14, wires=[1]), 1, "Kerr(3.14)"), (qml.CrossKerr(3.14, wires=[1, 2]), 1, "CrossKerr(3.14)"), (qml.CrossKerr(3.14, wires=[1, 2]), 2, "CrossKerr(3.14)"), (qml.CubicPhase(3.14, wires=[1]), 1, "V(3.14)"), (qml.Interferometer(np.eye(4), wires=[1, 3 ]), 1, "Interferometer(M0)"), (qml.Interferometer(np.eye(4), wires=[1, 3 ]), 3, "Interferometer(M0)"), (qml.CatState(3.14, 2.14, 1, wires=[1]), 1, "CatState(3.14, 2.14, 1)"), (qml.CoherentState(3.14, 2.14, wires=[1]), 1, "CoherentState(3.14, 2.14)"), ( qml.FockDensityMatrix(np.kron(np.eye(4), np.eye(4)), wires=[1, 2]), 1, "FockDensityMatrix(M0)", ), ( qml.FockDensityMatrix(np.kron(np.eye(4), np.eye(4)), wires=[1, 2]), 2, "FockDensityMatrix(M0)", ), ( qml.DisplacedSqueezedState(3.14, 2.14, 1.14, 0.14, wires=[1]), 1, "DisplacedSqueezedState(3.14, 2.14, 1.14, 0.14)", ), (qml.FockState(7, wires=[1]), 1, "|7⟩"), (qml.FockStateVector(np.array([4, 5, 7]), wires=[1, 2, 3 ]), 1, "|4⟩"), (qml.FockStateVector(np.array([4, 5, 7]), wires=[1, 2, 3 ]), 2, "|5⟩"), (qml.FockStateVector(np.array([4, 5, 7]), wires=[1, 2, 3 ]), 3, "|7⟩"), (qml.SqueezedState(3.14, 2.14, wires=[1]), 1, "SqueezedState(3.14, 2.14)"), (qml.Hermitian(np.eye(4), wires=[1, 2]), 1, "H0"), (qml.Hermitian(np.eye(4), wires=[1, 2]), 2, "H0"), (qml.X(wires=[1]), 1, "x"), (qml.P(wires=[1]), 1, "p"), (qml.FockStateProjector(np.array([4, 5, 7]), wires=[1, 2, 3]), 1, "|4,5,7╳4,5,7|"), ( qml.PolyXP(np.array([1, 2, 0, -1.3, 6]), wires=[1]), 2, "1+2x₀-1.3x₁+6p₁", ), ( qml.PolyXP(np.array([[1.2, 2.3, 4.5], [-1.2, 1.2, -1.5], [-1.3, 4.5, 2.3]]), wires=[1]), 1, "1.2+1.1x₀+3.2p₀+1.2x₀²+2.3p₀²+3x₀p₀", ), ( qml.PolyXP( np.array([ [1.2, 2.3, 4.5, 0, 0], [-1.2, 1.2, -1.5, 0, 0], [-1.3, 4.5, 2.3, 0, 0], [0, 2.6, 0, 0, 0], [0, 0, 0, -4.7, -1.0], ]), wires=[1], ), 1, "1.2+1.1x₀+3.2p₀+1.2x₀²+2.3p₀²+3x₀p₀+2.6x₀x₁-p₁²-4.7x₁p₁", ), (qml.QuadOperator(3.14, wires=[1]), 1, "cos(3.14)x+sin(3.14)p"), ], ) def test_operator_representation_unicode(self, unicode_representation_resolver, op, wire, target): """Test that an Operator instance is properly resolved.""" assert unicode_representation_resolver.operator_representation( op, wire) == target @pytest.mark.parametrize( "op,wire,target", [ (qml.PauliX(wires=[1]), 1, "X"), (qml.CNOT(wires=[0, 1]), 1, "X"), (qml.CNOT(wires=[0, 1]), 0, "C"), (qml.Toffoli(wires=[0, 2, 1]), 1, "X"), (qml.Toffoli(wires=[0, 2, 1]), 0, "C"), (qml.Toffoli(wires=[0, 2, 1]), 2, "C"), (qml.CSWAP(wires=[0, 2, 1]), 1, "SWAP"), (qml.CSWAP(wires=[0, 2, 1]), 2, "SWAP"), (qml.CSWAP(wires=[0, 2, 1]), 0, "C"), (qml.PauliY(wires=[1]), 1, "Y"), (qml.PauliZ(wires=[1]), 1, "Z"), (qml.CZ(wires=[0, 1]), 1, "Z"), (qml.CZ(wires=[0, 1]), 0, "C"), (qml.Identity(wires=[1]), 1, "I"), (qml.Hadamard(wires=[1]), 1, "H"), (qml.CRX(3.14, wires=[0, 1]), 1, "RX(3.14)"), (qml.CRX(3.14, wires=[0, 1]), 0, "C"), (qml.CRY(3.14, wires=[0, 1]), 1, "RY(3.14)"), (qml.CRY(3.14, wires=[0, 1]), 0, "C"), (qml.CRZ(3.14, wires=[0, 1]), 1, "RZ(3.14)"), (qml.CRZ(3.14, wires=[0, 1]), 0, "C"), (qml.CRot(3.14, 2.14, 1.14, wires=[0, 1 ]), 1, "Rot(3.14, 2.14, 1.14)"), (qml.CRot(3.14, 2.14, 1.14, wires=[0, 1]), 0, "C"), (qml.PhaseShift(3.14, wires=[0]), 0, "Rϕ(3.14)"), (qml.Beamsplitter(1, 2, wires=[0, 1]), 1, "BS(1, 2)"), (qml.Beamsplitter(1, 2, wires=[0, 1]), 0, "BS(1, 2)"), (qml.Squeezing(1, 2, wires=[1]), 1, "S(1, 2)"), (qml.TwoModeSqueezing(1, 2, wires=[0, 1]), 1, "S(1, 2)"), (qml.TwoModeSqueezing(1, 2, wires=[0, 1]), 0, "S(1, 2)"), (qml.Displacement(1, 2, wires=[1]), 1, "D(1, 2)"), (qml.NumberOperator(wires=[1]), 1, "n"), (qml.Rotation(3.14, wires=[1]), 1, "R(3.14)"), (qml.ControlledAddition(3.14, wires=[0, 1]), 1, "X(3.14)"), (qml.ControlledAddition(3.14, wires=[0, 1]), 0, "C"), (qml.ControlledPhase(3.14, wires=[0, 1]), 1, "Z(3.14)"), (qml.ControlledPhase(3.14, wires=[0, 1]), 0, "C"), (qml.ThermalState(3, wires=[1]), 1, "Thermal(3)"), ( qml.GaussianState( np.array([1, 2]), np.array([[2, 0], [0, 2]]), wires=[1]), 1, "Gaussian(M0,M1)", ), (qml.QuadraticPhase(3.14, wires=[1]), 1, "P(3.14)"), (qml.RX(3.14, wires=[1]), 1, "RX(3.14)"), (qml.S(wires=[2]), 2, "S"), (qml.T(wires=[2]), 2, "T"), (qml.RX(3.14, wires=[1]), 1, "RX(3.14)"), (qml.RY(3.14, wires=[1]), 1, "RY(3.14)"), (qml.RZ(3.14, wires=[1]), 1, "RZ(3.14)"), (qml.Rot(3.14, 2.14, 1.14, wires=[1]), 1, "Rot(3.14, 2.14, 1.14)"), (qml.U1(3.14, wires=[1]), 1, "U1(3.14)"), (qml.U2(3.14, 2.14, wires=[1]), 1, "U2(3.14, 2.14)"), (qml.U3(3.14, 2.14, 1.14, wires=[1]), 1, "U3(3.14, 2.14, 1.14)"), (qml.BasisState(np.array([0, 1, 0]), wires=[1, 2, 3]), 1, "|0>"), (qml.BasisState(np.array([0, 1, 0]), wires=[1, 2, 3]), 2, "|1>"), (qml.BasisState(np.array([0, 1, 0]), wires=[1, 2, 3]), 3, "|0>"), (qml.QubitStateVector(np.array([0, 1, 0, 0]), wires=[1, 2]), 1, "QubitStateVector(M0)"), (qml.QubitStateVector(np.array([0, 1, 0, 0]), wires=[1, 2]), 2, "QubitStateVector(M0)"), (qml.QubitUnitary(np.eye(2), wires=[1]), 1, "U0"), (qml.QubitUnitary(np.eye(4), wires=[1, 2]), 2, "U0"), (qml.Kerr(3.14, wires=[1]), 1, "Kerr(3.14)"), (qml.CrossKerr(3.14, wires=[1, 2]), 1, "CrossKerr(3.14)"), (qml.CrossKerr(3.14, wires=[1, 2]), 2, "CrossKerr(3.14)"), (qml.CubicPhase(3.14, wires=[1]), 1, "V(3.14)"), (qml.Interferometer(np.eye(4), wires=[1, 3 ]), 1, "Interferometer(M0)"), (qml.Interferometer(np.eye(4), wires=[1, 3 ]), 3, "Interferometer(M0)"), (qml.CatState(3.14, 2.14, 1, wires=[1]), 1, "CatState(3.14, 2.14, 1)"), (qml.CoherentState(3.14, 2.14, wires=[1]), 1, "CoherentState(3.14, 2.14)"), ( qml.FockDensityMatrix(np.kron(np.eye(4), np.eye(4)), wires=[1, 2]), 1, "FockDensityMatrix(M0)", ), ( qml.FockDensityMatrix(np.kron(np.eye(4), np.eye(4)), wires=[1, 2]), 2, "FockDensityMatrix(M0)", ), ( qml.DisplacedSqueezedState(3.14, 2.14, 1.14, 0.14, wires=[1]), 1, "DisplacedSqueezedState(3.14, 2.14, 1.14, 0.14)", ), (qml.FockState(7, wires=[1]), 1, "|7>"), (qml.FockStateVector(np.array([4, 5, 7]), wires=[1, 2, 3 ]), 1, "|4>"), (qml.FockStateVector(np.array([4, 5, 7]), wires=[1, 2, 3 ]), 2, "|5>"), (qml.FockStateVector(np.array([4, 5, 7]), wires=[1, 2, 3 ]), 3, "|7>"), (qml.SqueezedState(3.14, 2.14, wires=[1]), 1, "SqueezedState(3.14, 2.14)"), (qml.Hermitian(np.eye(4), wires=[1, 2]), 1, "H0"), (qml.Hermitian(np.eye(4), wires=[1, 2]), 2, "H0"), (qml.X(wires=[1]), 1, "x"), (qml.P(wires=[1]), 1, "p"), (qml.FockStateProjector(np.array([4, 5, 7]), wires=[1, 2, 3]), 1, "|4,5,7X4,5,7|"), ( qml.PolyXP(np.array([1, 2, 0, -1.3, 6]), wires=[1]), 2, "1+2x_0-1.3x_1+6p_1", ), ( qml.PolyXP(np.array([[1.2, 2.3, 4.5], [-1.2, 1.2, -1.5], [-1.3, 4.5, 2.3]]), wires=[1]), 1, "1.2+1.1x_0+3.2p_0+1.2x_0^2+2.3p_0^2+3x_0p_0", ), ( qml.PolyXP( np.array([ [1.2, 2.3, 4.5, 0, 0], [-1.2, 1.2, -1.5, 0, 0], [-1.3, 4.5, 2.3, 0, 0], [0, 2.6, 0, 0, 0], [0, 0, 0, -4.7, 0], ]), wires=[1], ), 1, "1.2+1.1x_0+3.2p_0+1.2x_0^2+2.3p_0^2+3x_0p_0+2.6x_0x_1-4.7x_1p_1", ), (qml.QuadOperator(3.14, wires=[1]), 1, "cos(3.14)x+sin(3.14)p"), ], ) def test_operator_representation_ascii(self, ascii_representation_resolver, op, wire, target): """Test that an Operator instance is properly resolved.""" assert ascii_representation_resolver.operator_representation( op, wire) == target @pytest.mark.parametrize( "obs,wire,target", [ (qml.expval(qml.PauliX(wires=[1])), 1, "⟨X⟩"), (qml.expval(qml.PauliY(wires=[1])), 1, "⟨Y⟩"), (qml.expval(qml.PauliZ(wires=[1])), 1, "⟨Z⟩"), (qml.expval(qml.Hadamard(wires=[1])), 1, "⟨H⟩"), (qml.expval(qml.Hermitian(np.eye(4), wires=[1, 2])), 1, "⟨H0⟩"), (qml.expval(qml.Hermitian(np.eye(4), wires=[1, 2])), 2, "⟨H0⟩"), (qml.expval(qml.NumberOperator(wires=[1])), 1, "⟨n⟩"), (qml.expval(qml.X(wires=[1])), 1, "⟨x⟩"), (qml.expval(qml.P(wires=[1])), 1, "⟨p⟩"), ( qml.expval( qml.FockStateProjector(np.array([4, 5, 7]), wires=[1, 2, 3])), 1, "⟨|4,5,7╳4,5,7|⟩", ), ( qml.expval(qml.PolyXP(np.array([1, 2, 0, -1.3, 6]), wires=[1 ])), 2, "⟨1+2x₀-1.3x₁+6p₁⟩", ), ( qml.expval( qml.PolyXP(np.array([[1.2, 2.3, 4.5], [-1.2, 1.2, -1.5], [-1.3, 4.5, 2.3]]), wires=[1])), 1, "⟨1.2+1.1x₀+3.2p₀+1.2x₀²+2.3p₀²+3x₀p₀⟩", ), (qml.expval(qml.QuadOperator( 3.14, wires=[1])), 1, "⟨cos(3.14)x+sin(3.14)p⟩"), (qml.var(qml.PauliX(wires=[1])), 1, "Var[X]"), (qml.var(qml.PauliY(wires=[1])), 1, "Var[Y]"), (qml.var(qml.PauliZ(wires=[1])), 1, "Var[Z]"), (qml.var(qml.Hadamard(wires=[1])), 1, "Var[H]"), (qml.var(qml.Hermitian(np.eye(4), wires=[1, 2])), 1, "Var[H0]"), (qml.var(qml.Hermitian(np.eye(4), wires=[1, 2])), 2, "Var[H0]"), (qml.var(qml.NumberOperator(wires=[1])), 1, "Var[n]"), (qml.var(qml.X(wires=[1])), 1, "Var[x]"), (qml.var(qml.P(wires=[1])), 1, "Var[p]"), ( qml.var( qml.FockStateProjector(np.array([4, 5, 7]), wires=[1, 2, 3])), 1, "Var[|4,5,7╳4,5,7|]", ), ( qml.var(qml.PolyXP(np.array([1, 2, 0, -1.3, 6]), wires=[1])), 2, "Var[1+2x₀-1.3x₁+6p₁]", ), ( qml.var( qml.PolyXP(np.array([[1.2, 2.3, 4.5], [-1.2, 1.2, -1.5], [-1.3, 4.5, 2.3]]), wires=[1])), 1, "Var[1.2+1.1x₀+3.2p₀+1.2x₀²+2.3p₀²+3x₀p₀]", ), (qml.var(qml.QuadOperator( 3.14, wires=[1])), 1, "Var[cos(3.14)x+sin(3.14)p]"), (qml.sample(qml.PauliX(wires=[1])), 1, "Sample[X]"), (qml.sample(qml.PauliY(wires=[1])), 1, "Sample[Y]"), (qml.sample(qml.PauliZ(wires=[1])), 1, "Sample[Z]"), (qml.sample(qml.Hadamard(wires=[1])), 1, "Sample[H]"), (qml.sample(qml.Hermitian(np.eye(4), wires=[1, 2 ])), 1, "Sample[H0]"), (qml.sample(qml.Hermitian(np.eye(4), wires=[1, 2 ])), 2, "Sample[H0]"), (qml.sample(qml.NumberOperator(wires=[1])), 1, "Sample[n]"), (qml.sample(qml.X(wires=[1])), 1, "Sample[x]"), (qml.sample(qml.P(wires=[1])), 1, "Sample[p]"), ( qml.sample( qml.FockStateProjector(np.array([4, 5, 7]), wires=[1, 2, 3])), 1, "Sample[|4,5,7╳4,5,7|]", ), ( qml.sample(qml.PolyXP(np.array([1, 2, 0, -1.3, 6]), wires=[1 ])), 2, "Sample[1+2x₀-1.3x₁+6p₁]", ), ( qml.sample( qml.PolyXP(np.array([[1.2, 2.3, 4.5], [-1.2, 1.2, -1.5], [-1.3, 4.5, 2.3]]), wires=[1])), 1, "Sample[1.2+1.1x₀+3.2p₀+1.2x₀²+2.3p₀²+3x₀p₀]", ), (qml.sample(qml.QuadOperator( 3.14, wires=[1])), 1, "Sample[cos(3.14)x+sin(3.14)p]"), ( qml.expval( qml.PauliX(wires=[1]) @ qml.PauliY(wires=[2]) @ qml.PauliZ(wires=[3])), 1, "⟨X ⊗ Y ⊗ Z⟩", ), ( qml.expval( qml.FockStateProjector(np.array([4, 5, 7]), wires=[1, 2, 3]) @ qml.X(wires=[4])), 1, "⟨|4,5,7╳4,5,7| ⊗ x⟩", ), ( qml.expval( qml.FockStateProjector(np.array([4, 5, 7]), wires=[1, 2, 3]) @ qml.X(wires=[4])), 2, "⟨|4,5,7╳4,5,7| ⊗ x⟩", ), ( qml.expval( qml.FockStateProjector(np.array([4, 5, 7]), wires=[1, 2, 3]) @ qml.X(wires=[4])), 3, "⟨|4,5,7╳4,5,7| ⊗ x⟩", ), ( qml.expval( qml.FockStateProjector(np.array([4, 5, 7]), wires=[1, 2, 3]) @ qml.X(wires=[4])), 4, "⟨|4,5,7╳4,5,7| ⊗ x⟩", ), ( qml.sample( qml.Hermitian(np.eye(4), wires=[1, 2]) @ qml.Hermitian( np.eye(4), wires=[0, 3])), 0, "Sample[H0 ⊗ H0]", ), ( qml.sample( qml.Hermitian(np.eye(4), wires=[1, 2]) @ qml.Hermitian( 2 * np.eye(4), wires=[0, 3])), 0, "Sample[H0 ⊗ H1]", ), ], ) def test_output_representation_unicode(self, unicode_representation_resolver, obs, wire, target): """Test that an Observable instance with return type is properly resolved.""" assert unicode_representation_resolver.output_representation( obs, wire) == target def test_fallback_output_representation_unicode( self, unicode_representation_resolver): """Test that an Observable instance with return type is properly resolved.""" obs = qml.PauliZ(0) obs.return_type = "TestReturnType" assert unicode_representation_resolver.output_representation( obs, 0) == "TestReturnType[Z]" @pytest.mark.parametrize( "obs,wire,target", [ (qml.expval(qml.PauliX(wires=[1])), 1, "<X>"), (qml.expval(qml.PauliY(wires=[1])), 1, "<Y>"), (qml.expval(qml.PauliZ(wires=[1])), 1, "<Z>"), (qml.expval(qml.Hadamard(wires=[1])), 1, "<H>"), (qml.expval(qml.Hermitian(np.eye(4), wires=[1, 2])), 1, "<H0>"), (qml.expval(qml.Hermitian(np.eye(4), wires=[1, 2])), 2, "<H0>"), (qml.expval(qml.NumberOperator(wires=[1])), 1, "<n>"), (qml.expval(qml.X(wires=[1])), 1, "<x>"), (qml.expval(qml.P(wires=[1])), 1, "<p>"), ( qml.expval( qml.FockStateProjector(np.array([4, 5, 7]), wires=[1, 2, 3])), 1, "<|4,5,7X4,5,7|>", ), ( qml.expval(qml.PolyXP(np.array([1, 2, 0, -1.3, 6]), wires=[1 ])), 2, "<1+2x_0-1.3x_1+6p_1>", ), ( qml.expval( qml.PolyXP(np.array([[1.2, 2.3, 4.5], [-1.2, 1.2, -1.5], [-1.3, 4.5, 2.3]]), wires=[1])), 1, "<1.2+1.1x_0+3.2p_0+1.2x_0^2+2.3p_0^2+3x_0p_0>", ), (qml.expval(qml.QuadOperator( 3.14, wires=[1])), 1, "<cos(3.14)x+sin(3.14)p>"), (qml.var(qml.PauliX(wires=[1])), 1, "Var[X]"), (qml.var(qml.PauliY(wires=[1])), 1, "Var[Y]"), (qml.var(qml.PauliZ(wires=[1])), 1, "Var[Z]"), (qml.var(qml.Hadamard(wires=[1])), 1, "Var[H]"), (qml.var(qml.Hermitian(np.eye(4), wires=[1, 2])), 1, "Var[H0]"), (qml.var(qml.Hermitian(np.eye(4), wires=[1, 2])), 2, "Var[H0]"), (qml.var(qml.NumberOperator(wires=[1])), 1, "Var[n]"), (qml.var(qml.X(wires=[1])), 1, "Var[x]"), (qml.var(qml.P(wires=[1])), 1, "Var[p]"), ( qml.var( qml.FockStateProjector(np.array([4, 5, 7]), wires=[1, 2, 3])), 1, "Var[|4,5,7X4,5,7|]", ), ( qml.var(qml.PolyXP(np.array([1, 2, 0, -1.3, 6]), wires=[1])), 2, "Var[1+2x_0-1.3x_1+6p_1]", ), ( qml.var( qml.PolyXP(np.array([[1.2, 2.3, 4.5], [-1.2, 1.2, -1.5], [-1.3, 4.5, 2.3]]), wires=[1])), 1, "Var[1.2+1.1x_0+3.2p_0+1.2x_0^2+2.3p_0^2+3x_0p_0]", ), (qml.var(qml.QuadOperator( 3.14, wires=[1])), 1, "Var[cos(3.14)x+sin(3.14)p]"), (qml.sample(qml.PauliX(wires=[1])), 1, "Sample[X]"), (qml.sample(qml.PauliY(wires=[1])), 1, "Sample[Y]"), (qml.sample(qml.PauliZ(wires=[1])), 1, "Sample[Z]"), (qml.sample(qml.Hadamard(wires=[1])), 1, "Sample[H]"), (qml.sample(qml.Hermitian(np.eye(4), wires=[1, 2 ])), 1, "Sample[H0]"), (qml.sample(qml.Hermitian(np.eye(4), wires=[1, 2 ])), 2, "Sample[H0]"), (qml.sample(qml.NumberOperator(wires=[1])), 1, "Sample[n]"), (qml.sample(qml.X(wires=[1])), 1, "Sample[x]"), (qml.sample(qml.P(wires=[1])), 1, "Sample[p]"), ( qml.sample( qml.FockStateProjector(np.array([4, 5, 7]), wires=[1, 2, 3])), 1, "Sample[|4,5,7X4,5,7|]", ), ( qml.sample(qml.PolyXP(np.array([1, 2, 0, -1.3, 6]), wires=[1 ])), 2, "Sample[1+2x_0-1.3x_1+6p_1]", ), ( qml.sample( qml.PolyXP(np.array([[1.2, 2.3, 4.5], [-1.2, 1.2, -1.5], [-1.3, 4.5, 2.3]]), wires=[1])), 1, "Sample[1.2+1.1x_0+3.2p_0+1.2x_0^2+2.3p_0^2+3x_0p_0]", ), (qml.sample(qml.QuadOperator( 3.14, wires=[1])), 1, "Sample[cos(3.14)x+sin(3.14)p]"), ( qml.expval( qml.PauliX(wires=[1]) @ qml.PauliY(wires=[2]) @ qml.PauliZ(wires=[3])), 1, "<X @ Y @ Z>", ), ( qml.expval( qml.FockStateProjector(np.array([4, 5, 7]), wires=[1, 2, 3]) @ qml.X(wires=[4])), 1, "<|4,5,7X4,5,7| @ x>", ), ( qml.expval( qml.FockStateProjector(np.array([4, 5, 7]), wires=[1, 2, 3]) @ qml.X(wires=[4])), 2, "<|4,5,7X4,5,7| @ x>", ), ( qml.expval( qml.FockStateProjector(np.array([4, 5, 7]), wires=[1, 2, 3]) @ qml.X(wires=[4])), 3, "<|4,5,7X4,5,7| @ x>", ), ( qml.expval( qml.FockStateProjector(np.array([4, 5, 7]), wires=[1, 2, 3]) @ qml.X(wires=[4])), 4, "<|4,5,7X4,5,7| @ x>", ), ( qml.sample( qml.Hermitian(np.eye(4), wires=[1, 2]) @ qml.Hermitian( np.eye(4), wires=[0, 3])), 0, "Sample[H0 @ H0]", ), ( qml.sample( qml.Hermitian(np.eye(4), wires=[1, 2]) @ qml.Hermitian( 2 * np.eye(4), wires=[0, 3])), 0, "Sample[H0 @ H1]", ), ], ) def test_output_representation_ascii(self, ascii_representation_resolver, obs, wire, target): """Test that an Observable instance with return type is properly resolved.""" assert ascii_representation_resolver.output_representation( obs, wire) == target def test_element_representation_none(self, unicode_representation_resolver): """Test that element_representation properly handles None.""" assert unicode_representation_resolver.element_representation(None, 0) == "" def test_element_representation_str(self, unicode_representation_resolver): """Test that element_representation properly handles strings.""" assert unicode_representation_resolver.element_representation( "Test", 0) == "Test" def test_element_representation_calls_output( self, unicode_representation_resolver): """Test that element_representation calls output_representation for returned observables.""" unicode_representation_resolver.output_representation = Mock() obs = qml.sample(qml.PauliX(3)) wire = 3 unicode_representation_resolver.element_representation(obs, wire) assert unicode_representation_resolver.output_representation.call_args[ 0] == (obs, wire) def test_element_representation_calls_operator( self, unicode_representation_resolver): """Test that element_representation calls operator_representation for all operators that are not returned.""" unicode_representation_resolver.operator_representation = Mock() op = qml.PauliX(3) wire = 3 unicode_representation_resolver.element_representation(op, wire) assert unicode_representation_resolver.operator_representation.call_args[ 0] == (op, wire)
class TestTensor: """Unit tests for the Tensor class""" def test_construct(self): """Test construction of a tensor product""" X = qml.PauliX(0) Y = qml.PauliY(2) T = Tensor(X, Y) assert T.obs == [X, Y] T = Tensor(T, Y) assert T.obs == [X, Y, Y] with pytest.raises(ValueError, match="Can only perform tensor products between observables"): Tensor(T, qml.CNOT(wires=[0, 1])) def test_name(self): """Test that the names of the observables are returned as expected""" X = qml.PauliX(0) Y = qml.PauliY(2) t = Tensor(X, Y) assert t.name == [X.name, Y.name] def test_num_wires(self): """Test that the correct number of wires is returned""" p = np.array([0.5]) X = qml.PauliX(0) Y = qml.Hermitian(p, wires=[1, 2]) t = Tensor(X, Y) assert t.num_wires == 3 def test_wires(self): """Test that the correct nested list of wires is returned""" p = np.array([0.5]) X = qml.PauliX(0) Y = qml.Hermitian(p, wires=[1, 2]) t = Tensor(X, Y) assert t.wires == list([0, 1, 2]) def test_params(self): """Test that the correct flattened list of parameters is returned""" p = np.array([0.5]) X = qml.PauliX(0) Y = qml.Hermitian(p, wires=[1, 2]) t = Tensor(X, Y) assert t.params == [p] def test_num_params(self): """Test that the correct number of parameters is returned""" p = np.array([0.5]) X = qml.PauliX(0) Y = qml.Hermitian(p, wires=[1, 2]) Z = qml.Hermitian(p, wires=[1, 2]) t = Tensor(X, Y, Z) assert t.num_params == 2 def test_parameters(self): """Test that the correct nested list of parameters is returned""" p = np.array([0.5]) X = qml.PauliX(0) Y = qml.Hermitian(p, wires=[1, 2]) t = Tensor(X, Y) assert t.parameters == [[], [p]] def test_multiply_obs(self): """Test that multiplying two observables produces a tensor""" X = qml.PauliX(0) Y = qml.Hadamard(2) t = X @ Y assert isinstance(t, Tensor) assert t.obs == [X, Y] def test_multiply_obs_tensor(self): """Test that multiplying an observable by a tensor produces a tensor""" X = qml.PauliX(0) Y = qml.Hadamard(2) Z = qml.PauliZ(1) t = X @ Y t = Z @ t assert isinstance(t, Tensor) assert t.obs == [Z, X, Y] def test_multiply_tensor_obs(self): """Test that multiplying a tensor by an observable produces a tensor""" X = qml.PauliX(0) Y = qml.Hadamard(2) Z = qml.PauliZ(1) t = X @ Y t = t @ Z assert isinstance(t, Tensor) assert t.obs == [X, Y, Z] def test_multiply_tensor_tensor(self): """Test that multiplying a tensor by a tensor produces a tensor""" X = qml.PauliX(0) Y = qml.PauliY(2) Z = qml.PauliZ(1) H = qml.Hadamard(3) t1 = X @ Y t2 = Z @ H t = t2 @ t1 assert isinstance(t, Tensor) assert t.obs == [Z, H, X, Y] def test_multiply_tensor_in_place(self): """Test that multiplying a tensor in-place produces a tensor""" X = qml.PauliX(0) Y = qml.PauliY(2) Z = qml.PauliZ(1) H = qml.Hadamard(3) t = X t @= Y t @= Z @ H assert isinstance(t, Tensor) assert t.obs == [X, Y, Z, H] def test_operation_multiply_invalid(self): """Test that an exception is raised if an observable is multiplied by an operation""" X = qml.PauliX(0) Y = qml.CNOT(wires=[0, 1]) Z = qml.PauliZ(0) with pytest.raises(ValueError, match="Can only perform tensor products between observables"): X @ Y with pytest.raises(ValueError, match="Can only perform tensor products between observables"): T = X @ Z T @ Y with pytest.raises(ValueError, match="Can only perform tensor products between observables"): T = X @ Z Y @ T def test_eigvals(self): """Test that the correct eigenvalues are returned for the Tensor""" X = qml.PauliX(0) Y = qml.PauliY(2) t = Tensor(X, Y) assert np.array_equal(t.eigvals, np.kron([1, -1], [1, -1])) # test that the eigvals are now cached and not recalculated assert np.array_equal(t._eigvals_cache, t.eigvals) @pytest.mark.usefixtures("tear_down_hermitian") def test_eigvals_hermitian(self, tol): """Test that the correct eigenvalues are returned for the Tensor containing an Hermitian observable""" X = qml.PauliX(0) hamiltonian = np.array([[1,0,0,0], [0,1,0,0], [0,0,0,1], [0,0,1,0]]) Herm = qml.Hermitian(hamiltonian, wires=[1, 2]) t = Tensor(X, Herm) d = np.kron(np.array([1., -1.]), np.array([-1., 1., 1., 1.])) t = t.eigvals assert np.allclose(t, d, atol=tol, rtol=0) def test_eigvals_identity(self, tol): """Test that the correct eigenvalues are returned for the Tensor containing an Identity""" X = qml.PauliX(0) Iden = qml.Identity(1) t = Tensor(X, Iden) d = np.kron(np.array([1., -1.]), np.array([1., 1.])) t = t.eigvals assert np.allclose(t, d, atol=tol, rtol=0) def test_eigvals_identity_and_hermitian(self, tol): """Test that the correct eigenvalues are returned for the Tensor containing multiple types of observables""" H = np.diag([1, 2, 3, 4]) O = qml.PauliX(0) @ qml.Identity(2) @ qml.Hermitian(H, wires=[4,5]) res = O.eigvals expected = np.kron(np.array([1., -1.]), np.kron(np.array([1., 1.]), np.arange(1, 5))) assert np.allclose(res, expected, atol=tol, rtol=0) def test_diagonalizing_gates(self, tol): """Test that the correct diagonalizing gate set is returned for a Tensor of observables""" H = np.diag([1, 2, 3, 4]) O = qml.PauliX(0) @ qml.Identity(2) @ qml.PauliY(1) @ qml.Hermitian(H, [5, 6]) res = O.diagonalizing_gates() # diagonalize the PauliX on wire 0 (H.X.H = Z) assert isinstance(res[0], qml.Hadamard) assert res[0].wires == list([0]) # diagonalize the PauliY on wire 1 (U.Y.U^\dagger = Z # where U = HSZ). assert isinstance(res[1], qml.PauliZ) assert res[1].wires == list([1]) assert isinstance(res[2], qml.S) assert res[2].wires == list([1]) assert isinstance(res[3], qml.Hadamard) assert res[3].wires == list([1]) # diagonalize the Hermitian observable on wires 5, 6 assert isinstance(res[4], qml.QubitUnitary) assert res[4].wires == list([5, 6]) O = O @ qml.Hadamard(4) res = O.diagonalizing_gates() # diagonalize the Hadamard observable on wire 4 # (RY(-pi/4).H.RY(pi/4) = Z) assert isinstance(res[-1], qml.RY) assert res[-1].wires == list([4]) assert np.allclose(res[-1].parameters, -np.pi/4, atol=tol, rtol=0) def test_diagonalizing_gates_numerically_diagonalizes(self, tol): """Test that the diagonalizing gate set numerically diagonalizes the tensor observable""" # create a tensor observable acting on consecutive wires H = np.diag([1, 2, 3, 4]) O = qml.PauliX(0) @ qml.PauliY(1) @ qml.Hermitian(H, [2, 3]) O_mat = O.matrix diag_gates = O.diagonalizing_gates() # group the diagonalizing gates based on what wires they act on U_list = [] for _, g in itertools.groupby(diag_gates, lambda x: x.wires): # extract the matrices of each diagonalizing gate mats = [i.matrix for i in g] # Need to revert the order in which the matrices are applied such that they adhere to the order # of matrix multiplication # E.g. for PauliY: [PauliZ(wires=self.wires), S(wires=self.wires), Hadamard(wires=self.wires)] # becomes Hadamard @ S @ PauliZ, where @ stands for matrix multiplication mats = mats[::-1] if len(mats) > 1: # multiply all unitaries together before appending mats = [multi_dot(mats)] # append diagonalizing unitary for specific wire to U_list U_list.append(mats[0]) # since the test is assuming consecutive wires for each observable # in the tensor product, it is sufficient to Kronecker product # the entire list. U = functools.reduce(np.kron, U_list) res = U @ O_mat @ U.conj().T expected = np.diag(O.eigvals) # once diagonalized by U, the result should be a diagonal # matrix of the eigenvalues. assert np.allclose(res, expected, atol=tol, rtol=0) def test_tensor_matrix(self, tol): """Test that the tensor product matrix method returns the correct result""" H = np.diag([1, 2, 3, 4]) O = qml.PauliX(0) @ qml.PauliY(1) @ qml.Hermitian(H, [2, 3]) res = O.matrix expected = np.kron(qml.PauliY._matrix(), H) expected = np.kron(qml.PauliX._matrix(), expected) assert np.allclose(res, expected, atol=tol, rtol=0) def test_multiplication_matrix(self, tol): """If using the ``@`` operator on two observables acting on the same wire, the tensor class should treat this as matrix multiplication.""" O = qml.PauliX(0) @ qml.PauliX(0) res = O.matrix expected = qml.PauliX._matrix() @ qml.PauliX._matrix() assert np.allclose(res, expected, atol=tol, rtol=0) herm_matrix = np.array([ [1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1] ]) tensor_obs = [ ( qml.PauliZ(0) @ qml.Identity(1) @ qml.PauliZ(2), [qml.PauliZ(0), qml.PauliZ(2)] ), ( qml.Identity(0) @ qml.PauliX(1) @ qml.Identity(2) @ qml.PauliZ(3) @ qml.PauliZ(4) @ qml.Identity(5), [qml.PauliX(1), qml.PauliZ(3), qml.PauliZ(4)] ), # List containing single observable is returned ( qml.PauliZ(0) @ qml.Identity(1), [qml.PauliZ(0)] ), ( qml.Identity(0) @ qml.PauliX(1) @ qml.Identity(2), [qml.PauliX(1)] ), ( qml.Identity(0) @ qml.Identity(1), [qml.Identity(0)] ), ( qml.Identity(0) @ qml.Identity(1) @ qml.Hermitian(herm_matrix, wires=[2,3]), [qml.Hermitian(herm_matrix, wires=[2,3])] ) ] @pytest.mark.parametrize("tensor_observable, expected", tensor_obs) def test_non_identity_obs(self, tensor_observable, expected): """Tests that the non_identity_obs property returns a list that contains no Identity instances.""" O = tensor_observable for idx, obs in enumerate(O.non_identity_obs): assert type(obs) == type(expected[idx]) assert obs.wires == expected[idx].wires tensor_obs_pruning = [ ( qml.PauliZ(0) @ qml.Identity(1) @ qml.PauliZ(2), qml.PauliZ(0) @ qml.PauliZ(2) ), ( qml.Identity(0) @ qml.PauliX(1) @ qml.Identity(2) @ qml.PauliZ(3) @ qml.PauliZ(4) @ qml.Identity(5), qml.PauliX(1) @ qml.PauliZ(3) @ qml.PauliZ(4) ), # Single observable is returned ( qml.PauliZ(0) @ qml.Identity(1), qml.PauliZ(0) ), ( qml.Identity(0) @ qml.PauliX(1) @ qml.Identity(2), qml.PauliX(1) ), ( qml.Identity(0) @ qml.Identity(1), qml.Identity(0) ), ( qml.Identity(0) @ qml.Identity(1), qml.Identity(0) ), ( qml.Identity(0) @ qml.Identity(1) @ qml.Hermitian(herm_matrix, wires=[2,3]), qml.Hermitian(herm_matrix, wires=[2,3]) ) ] @pytest.mark.parametrize("tensor_observable, expected", tensor_obs_pruning) @pytest.mark.parametrize("statistics", [qml.expval, qml.var, qml.sample]) def test_prune(self, tensor_observable, expected, statistics): """Tests that the prune method returns the expected Tensor or single non-Tensor Observable.""" O = statistics(tensor_observable) O_expected = statistics(expected) O_pruned = O.prune() assert type(O_pruned) == type(expected) assert O_pruned.wires == expected.wires assert O_pruned.return_type == O_expected.return_type
def circuit(a, p): qml.RX(a, wires=0) U3(p[0], p[1], p[2], wires=0) return qml.expval(qml.PauliX(0))
def ansatz(): qml.Hadamard(wires=0) qml.CNOT(wires=[0, 1]) return qml.expval(qml.PauliX(wires=1))
def circ(x): qml.RX(x[0], wires=0) qml.RY(x[1], wires=1) qml.CNOT(wires=(0, 1)) return qml.expval(qml.PauliZ(0)), qml.expval(qml.PauliX(1))
def circuit(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
def circuit(x): qml.RX(x, wires=[0]) qml.CNOT(wires=[0, 1], do_queue=False) qml.RY(0.4, wires=[0]) qml.RZ(-0.2, wires=[1], do_queue=False) return qml.expval(qml.PauliX(0)), qml.expval(qml.PauliZ(1))
def circuit(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
import pytest from flaky import flaky import pennylane as qml pytestmark = pytest.mark.skip_unsupported # ========================================================== # Some useful global variables # observables for which device support is tested obs = { "Identity": qml.Identity(wires=[0]), "Hadamard": qml.Hadamard(wires=[0]), "Hermitian": qml.Hermitian(np.eye(2), wires=[0]), "PauliX": qml.PauliX(wires=[0]), "PauliY": qml.PauliY(wires=[0]), "PauliZ": qml.PauliZ(wires=[0]), "Projector": qml.Projector(np.array([1]), wires=[0]), } all_obs = obs.keys() # single qubit Hermitian observable A = np.array([[1.02789352, 1.61296440 - 0.3498192j], [1.61296440 + 0.3498192j, 1.23920938 + 0j]]) class TestSupportedObservables: """Test that the device can implement all observables that it supports.""" @pytest.mark.parametrize("observable", all_obs)
def circuit(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
def circuit(a): qml.RX(a, wires=0) return qml.expval(qml.PauliX(0))
def g(y): qml.RY(y, wires=0) return qml.expval(qml.PauliX(0))
def circuit2(params): ansatz(params) return qml.expval(qml.PauliX(0))
def circuit_2( params, generators=None): # generators will be passed as a keyword arg ansatz(params, generators) return qml.expval(qml.PauliX(0))