def expand(self): with qml.tape.QuantumTape() as tape: for l in range(self.n_layers): for i in range(len(self.wires)): qml.Rot( self.parameters[0][..., l, i, 0], self.parameters[0][..., l, i, 1], self.parameters[0][..., l, i, 2], wires=self.wires[i], ) if len(self.wires) > 1: for i in range(len(self.wires)): act_on = self.wires.subset([i, i + self.ranges[l]], periodic_boundary=True) self.imprimitive(wires=act_on) return tape
def test_gradient_gate_with_multiple_parameters(self, tol): """Tests that gates with multiple free parameters yield correct gradients.""" x, y, z = [0.5, 0.3, -0.7] with ReversibleTape() as tape: qml.RX(0.4, wires=[0]) qml.Rot(x, y, z, wires=[0]) qml.RY(-0.2, wires=[0]) qml.expval(qml.PauliZ(0)) tape.trainable_params = {1, 2, 3} dev = qml.device("default.qubit", wires=1) grad_A = tape.jacobian(dev, method="analytic") grad_F = tape.jacobian(dev, method="numeric") # gradient has the correct shape and every element is nonzero assert grad_A.shape == (1, 3) assert np.count_nonzero(grad_A) == 3 # the different methods agree assert np.allclose(grad_A, grad_F, atol=tol, rtol=0)
def test_gradient_gate_with_multiple_parameters(self, tol, dev): """Tests that gates with multiple free parameters yield correct gradients.""" x, y, z = [0.5, 0.3, -0.7] with qml.tape.JacobianTape() as tape: qml.RX(0.4, wires=[0]) qml.Rot(x, y, z, wires=[0]) qml.RY(-0.2, wires=[0]) qml.expval(qml.PauliZ(0)) tape.trainable_params = {1, 2, 3} grad_D = dev.adjoint_jacobian(tape) grad_F = (lambda t, fn: fn(qml.execute(t, dev, None)))( *qml.gradients.finite_diff(tape)) # gradient has the correct shape and every element is nonzero assert grad_D.shape == (1, 3) assert np.count_nonzero(grad_D) == 3 # the different methods agree assert np.allclose(grad_D, grad_F, atol=tol, rtol=0)
def variational_ansatz(params, wires): """ Hardware efficient ansatz taken from VQE 100. Args: params (np.ndarray): An array of floating-point numbers with size (n, 3), where n is the number of parameter sets required (this is determined by the problem Hamiltonian). wires (qml.Wires): The device wires this circuit will run on. """ n_qubits = len(wires) n_rotations = len(params) if n_rotations > 1: n_layers = n_rotations // n_qubits n_extra_rots = n_rotations - n_layers * n_qubits # Alternating layers of unitary rotations on every qubit followed by a # ring cascade of CNOTs. for layer_idx in range(n_layers): layer_params = params[layer_idx * n_qubits:layer_idx * n_qubits + n_qubits, :] qml.broadcast(qml.Rot, wires, pattern="single", parameters=layer_params) qml.broadcast(qml.CNOT, wires, pattern="ring") # There may be "extra" parameter sets required for which it's not necessarily # to perform another full alternating cycle. Apply these to the qubits as needed. if n_extra_rots > 0: extra_params = params[-n_extra_rots:, :] extra_wires = wires[:n_qubits - 1 - n_extra_rots:-1] qml.broadcast(qml.Rot, extra_wires, pattern="single", parameters=extra_params) else: # For 1-qubit case, just a single rotation to the qubit qml.Rot(*params[0], wires=wires[0])
def variational_ansatz(params, wires): """ DO NOT MODIFY anything in this function! It is used to judge your solution. This is ansatz is used to help with the problem structure. It applies alternating layers of rotations and CNOTs. Don't worry about the contents of this function for now—you'll be designing your own ansatze in a later problem. Args: params (np.ndarray): An array of floating-point numbers with size (n, 3), where n is the number of parameter sets required (this is determined by the problem Hamiltonian). wires (qml.Wires): The device wires this circuit will run on. """ n_qubits = len(wires) n_rotations = len(params) #param = params[0,:] #print(params.shape[0]) # check this output if n_rotations > 1: n_layers = n_rotations // n_qubits n_extra_rots = n_rotations - n_layers * n_qubits # Alternating layers of unitary rotations on every qubit followed by a # ring cascade of CNOTs. for layer_idx in range(n_layers): layer_params = params[layer_idx * n_qubits : layer_idx * n_qubits + n_qubits, :] qml.broadcast(qml.Rot, wires, pattern="single", parameters=layer_params) qml.broadcast(qml.CNOT, wires, pattern="ring") # There may be "extra" parameter sets required for which it's not necessarily # to perform another full alternating cycle. Apply these to the qubits as needed. extra_params = params[-n_extra_rots:, :] extra_wires = wires[: n_qubits - 1 - n_extra_rots : -1] qml.broadcast(qml.Rot, extra_wires, pattern="single", parameters=extra_params) else: # For 1-qubit case, just a single rotation to the qubit qml.Rot(*params[0], wires=wires[0])
def test_integration(): gates = [ qml.PauliX(wires=0), qml.PauliY(wires=0), qml.PauliZ(wires=0), qml.S(wires=0), qml.T(wires=0), qml.RX(0.4, wires=0), qml.RY(0.4, wires=0), qml.RZ(0.4, wires=0), qml.Hadamard(wires=0), qml.Rot(0.4, 0.5, 0.6, wires=1), qml.CRot(0.4, 0.5, 0.6, wires=(0, 1)), qml.Toffoli(wires=(0, 1, 2)), qml.SWAP(wires=(0, 1)), qml.CSWAP(wires=(0, 1, 2)), qml.U1(0.4, wires=0), qml.U2(0.4, 0.5, wires=0), qml.U3(0.4, 0.5, 0.6, wires=0), qml.CRX(0.4, wires=(0, 1)), qml.CRY(0.4, wires=(0, 1)), qml.CRZ(0.4, wires=(0, 1)), ] layers = 3 np.random.seed(1967) gates_per_layers = [np.random.permutation(gates) for _ in range(layers)] with qml.tape.QuantumTape() as tape: np.random.seed(1967) for gates in gates_per_layers: for gate in gates: qml.apply(gate) base_circ = from_pennylane(tape) tape_recovered = to_pennylane(base_circ) circ_recovered = from_pennylane(tape_recovered) u_1 = cirq.unitary(base_circ) u_2 = cirq.unitary(circ_recovered) cirq.testing.assert_allclose_up_to_global_phase(u_1, u_2, atol=0)
def test_decomposition(self): """Test expanding a tape with operations that have decompositions""" with QuantumTape() as tape: qml.Rot(0.1, 0.2, 0.3, wires=0) new_tape = tape.expand() assert len(new_tape.operations) == 3 assert new_tape.get_parameters() == [0.1, 0.2, 0.3] assert new_tape.trainable_params == {0, 1, 2} assert isinstance(new_tape.operations[0], qml.RZ) assert isinstance(new_tape.operations[1], qml.RY) assert isinstance(new_tape.operations[2], qml.RZ) # check that modifying the new tape does not affect the old tape new_tape.trainable_params = {0} new_tape.set_parameters([10]) assert tape.get_parameters() == [0.1, 0.2, 0.3] assert tape.trainable_params == {0, 1, 2}
def test_rot_diff_circuit_construction(self, mocker): """Test that the diff circuit is correctly constructed for the Rot gate""" dev = qml.device("default.qubit", wires=2) with ReversibleTape() as tape: qml.PauliX(wires=0) qml.Rot(0.1, 0.2, 0.3, wires=0) qml.expval(qml.PauliZ(0)) spy = mocker.spy(dev, "execute") tape.jacobian(dev) tape0 = spy.call_args_list[0][0][0] tape1 = spy.call_args_list[1][0][0] tape2 = spy.call_args_list[2][0][0] tape3 = spy.call_args_list[3][0][0] assert tape0 is tape assert len(tape1.operations) == 6 assert len(tape1.measurements) == 1 assert tape1.operations[0].name == "QubitStateVector" assert tape1.operations[1].name == "RZ.inv" assert tape1.operations[2].name == "RY.inv" assert tape1.operations[3].name == "PauliZ" assert tape1.operations[4].name == "RY" assert tape1.operations[5].name == "RZ" assert len(tape2.operations) == 4 assert len(tape1.measurements) == 1 assert tape1.operations[0].name == "QubitStateVector" assert tape2.operations[1].name == "RZ.inv" assert tape2.operations[2].name == "PauliY" assert tape2.operations[3].name == "RZ" assert len(tape3.operations) == 2 assert len(tape1.measurements) == 1 assert tape1.operations[0].name == "QubitStateVector" assert tape3.operations[1].name == "PauliZ"
def test_depth_only_expansion(self): """Test that passing a depth simply expands to that depth""" dev = qml.device("default.qubit", wires=0) with qml.tape.JacobianTape() as tape: qml.RX(0.2, wires=0) qml.RY(qml.numpy.array(2.1, requires_grad=True), wires=1) qml.Rot(*qml.numpy.array([0.5, 0.2, -0.1], requires_grad=True), wires=0) qml.templates.StronglyEntanglingLayers( qml.numpy.ones([2, 2, 3], requires_grad=True), wires=[0, 1] ) expand_fn = qml.transforms.create_expand_fn(depth=0) new_tape = expand_fn(tape) assert new_tape is tape expand_fn = qml.transforms.create_expand_fn(depth=10) new_tape = expand_fn(tape) assert new_tape.operations[0] == tape.operations[0] assert new_tape.operations[1] == tape.operations[1] assert [op.name for op in new_tape.operations[2:5]] == ["RZ", "RY", "RZ"] assert len(new_tape.operations[6:]) == 15
def test_invalid_decompose(self, operable_mock_device_2_wires): """Test that an error is raised if the device does not support an operation arising from a decomposition.""" class DummyOp(qml.operation.Operation): """Dummy operation""" num_params = 0 num_wires = 1 par_domain = "R" grad_method = "A" @staticmethod def decomposition(wires=None): ops = [qml.Hadamard(wires=wires)] return ops queue = [qml.Rot(0, 1, 2, wires=0), DummyOp(wires=0), qml.RX(6, wires=0)] with pytest.raises(qml.DeviceError, match="DummyOp not supported on device"): decompose_queue(queue, operable_mock_device_2_wires)
def variational_ansatz2(params): wires = range(len(H.wires)) n_qubits = len(wires) n_rotations = len(params) if n_rotations > 1: n_layers = n_rotations // n_qubits n_extra_rots = n_rotations - n_layers * n_qubits # Alternating layers of unitary rotations on every qubit followed by a # ring cascade of CNOTs. for layer_idx in range(n_layers): layer_params = params[layer_idx * n_qubits:layer_idx * n_qubits + n_qubits, :] qml.broadcast(qml.Rot, wires, pattern="single", parameters=layer_params) qml.broadcast(qml.CNOT, wires, pattern="ring") # There may be "extra" parameter sets required for which it's not necessarily # to perform another full alternating cycle. Apply these to the qubits as needed. extra_params = params[-n_extra_rots:, :] extra_wires = wires[:n_qubits - 1 - n_extra_rots:-1] qml.broadcast(qml.Rot, extra_wires, pattern="single", parameters=extra_params) else: # For 1-qubit case, just a single rotation to the qubit qml.Rot(*params[0], wires=wires[0]) qml.inv( qml.templates.state_preparations.MottonenStatePreparation( state0, wires)) projector = np.zeros((2**qubits, 2**qubits)) projector[0, 0] = 1 return qml.expval(qml.Hermitian(projector, wires=range(qubits)))
def test_use_device_state(self, tol, dev): """Tests that when using the device state, the correct answer is still returned.""" x, y, z = [0.5, 0.3, -0.7] with qml.tape.QuantumTape() as tape: qml.RX(0.4, wires=[0]) qml.Rot(x, y, z, wires=[0]) qml.RY(-0.2, wires=[0]) qml.expval(qml.PauliZ(0)) tape.trainable_params = {1, 2, 3} dy = np.array([1.0]) fn1 = dev.vjp(tape.measurements, dy) vjp1 = fn1(tape) qml.execute([tape], dev, None) fn2 = dev.vjp(tape.measurements, dy, use_device_state=True) vjp2 = fn2(tape) assert np.allclose(vjp1, vjp2, atol=tol, rtol=0)
def test_zyz_decomposition_torch(self, U, expected_gate, expected_params): """Test that a one-qubit operation in Torch is correctly decomposed.""" torch = pytest.importorskip("torch") U = torch.tensor(U, dtype=torch.complex128) obtained_gates = zyz_decomposition(U, wire="a") assert len(obtained_gates) == 1 assert isinstance(obtained_gates[0], expected_gate) assert obtained_gates[0].wires == Wires("a") assert qml.math.allclose(qml.math.unwrap(obtained_gates[0].parameters), expected_params) if obtained_gates[0].num_params == 1: obtained_mat = qml.RZ(obtained_gates[0].parameters[0], wires=0).matrix else: obtained_mat = qml.Rot(*obtained_gates[0].parameters, wires=0).matrix assert check_matrix_equivalence(obtained_mat, qml.math.unwrap(U))
def circuit(weights, x=None, y=None, bias=None): # statepreparation(angles) # print(weights[0]) # print("==================") # print(x) # print('==================') # print(y) # print(bias) for W in weights[0]: # qml.Rot(*x, wires=0) # qml.RX(x[0], wires=0) # qml.RY(x[1], wires=0) # qml.RX(x[2], wires=0) # qml.Hadamard(wires=0) # qml.Rot(x[0], x[1],x[2], wires=0) qml.Rot(W[0], W[1], W[2], wires=0) qml.Rot(x[0], x[1], x[2], wires=0) # print("=============") # print(W[0].val) # print("=============") # print(x[0]) # print("=============") # qml.Rot(W[0], W[1], W[2], wires=0) # qml.Rot(x[0], x[1] ,x[2], wires=0) qml.Rot(W[3], W[4], W[5], wires=0) qml.Rot(x[0], x[1], x[2], wires=0) qml.Rot(W[0], W[1], W[2], wires=0) qml.Rot(x[0], x[1], x[2], wires=0) qml.Rot(W[3], W[4], W[5], wires=0) # qml.Rot(x[0], x[1] ,x[2], wires=0) # qml.Rot(W[0], W[1], W[2], wires=0) # qml.Rot(W[0].val * x[0] * W[3].val, W[1].val * x[1] * W[4].val, W[2].val * x[2] * W[5].val, wires=0) # print(len(x)) if y == 0: y = np.array([[1, 0], [0, 0]]) else: y = np.array([[0, 0], [0, 1]]) # qml.RY(W[0, 1], wires=0) # print(y) return qml.expval(qml.Hermitian(y, wires=[0]))
def test_Rot_gradient(self, mocker, theta, shift, tol): """Tests that the automatic gradient of an arbitrary Euler-angle-parameterized gate is correct.""" spy = mocker.spy(qml.gradients.parameter_shift, "_get_operation_recipe") dev = qml.device("default.qubit", wires=1) params = np.array([theta, theta**3, np.sqrt(2) * theta]) with qml.tape.JacobianTape() as tape: qml.QubitStateVector(np.array([1.0, -1.0], requires_grad=False) / np.sqrt(2), wires=0) qml.Rot(*params, wires=[0]) qml.expval(qml.PauliZ(0)) tape.trainable_params = {1, 2, 3} tapes, fn = qml.gradients.param_shift(tape, shift=shift) assert len(tapes) == 2 * len(tape.trainable_params) autograd_val = fn(dev.batch_execute(tapes)) manualgrad_val = np.zeros_like(autograd_val) for idx in list(np.ndindex(*params.shape)): s = np.zeros_like(params) s[idx] += np.pi / 2 forward = tape.execute(dev, params=params + s) backward = tape.execute(dev, params=params - s) manualgrad_val[0, idx] = (forward - backward) / 2 assert np.allclose(autograd_val, manualgrad_val, atol=tol, rtol=0) assert spy.call_args[1]["shift"] == shift # compare to finite differences tapes, fn = qml.gradients.finite_diff(tape) numeric_val = fn(dev.batch_execute(tapes)) assert np.allclose(autograd_val, numeric_val, atol=tol, rtol=0)
def test_inverse(self): """Test that inversion works as expected""" init_state = np.array([1, 1]) p = [0.1, 0.2, 0.3, 0.4] with QuantumTape() as tape: prep = qml.BasisState(init_state, wires=[0, "a"]) ops = [qml.RX(p[0], wires=0), qml.Rot(*p[1:], wires=0).inv(), qml.CNOT(wires=[0, "a"])] m1 = qml.probs(wires=0) m2 = qml.probs(wires="a") tape.inv() # check that operation order is reversed assert tape.operations == [prep] + ops[::-1] # check that operations are inverted assert ops[0].inverse assert not ops[1].inverse assert ops[2].inverse # check that parameter order has reversed assert tape.get_parameters() == [init_state, p[1], p[2], p[3], p[0]]
def variational_ansatz(params, wires=H.wires): n_qubits = len(wires) n_rotations = len(params) if n_rotations > 1: n_layers = n_rotations // n_qubits n_extra_rots = n_rotations - n_layers * n_qubits # Alternating layers of unitary rotations on every qubit followed by a # ring cascade of CNOTs. for layer_idx in range(n_layers): layer_params = params[layer_idx * n_qubits: layer_idx * n_qubits + n_qubits, :] qml.broadcast(qml.Rot, wires, pattern="single", parameters=layer_params) qml.broadcast(qml.CNOT, wires, pattern="ring") # There may be "extra" parameter sets required for which it's not necessarily # to perform another full alternating cycle. Apply these to the qubits as needed. extra_params = params[-n_extra_rots:, :] extra_wires = wires[: n_qubits - 1 - n_extra_rots: -1] qml.broadcast(qml.Rot, extra_wires, pattern="single", parameters=extra_params) else: # For 1-qubit case, just a single rotation to the qubit qml.Rot(*params[0], wires=wires[0])
def test_parameter_transforms(self): """Test that inversion correctly changes trainable parameters""" init_state = np.array([1, 1]) p = [0.1, 0.2, 0.3, 0.4] with QuantumTape() as tape: prep = qml.BasisState(init_state, wires=[0, "a"]) ops = [qml.RX(p[0], wires=0), qml.Rot(*p[1:], wires=0).inv(), qml.CNOT(wires=[0, "a"])] m1 = qml.probs(wires=0) m2 = qml.probs(wires="a") tape.trainable_params = {1, 2} tape.inv() # check that operation order is reversed assert tape.trainable_params == {1, 4} assert tape.get_parameters() == [p[1], p[0]] # undo the inverse tape.inv() assert tape.trainable_params == {1, 2} assert tape.get_parameters() == [p[0], p[1]] assert tape._ops == ops
def circuit_ansatz(params, wires): """Circuit ansatz containing all the parametrized gates""" qml.QubitStateVector(unitary_group.rvs(2**4, random_state=0)[0], wires=wires) qml.RX(params[0], wires=wires[0]) qml.RY(params[1], wires=wires[1]) qml.RX(params[2], wires=wires[2]).inv() qml.RZ(params[0], wires=wires[3]) qml.CRX(params[3], wires=[wires[3], wires[0]]) qml.PhaseShift(params[4], wires=wires[2]) qml.CRY(params[5], wires=[wires[2], wires[1]]) qml.CRZ(params[5], wires=[wires[0], wires[3]]).inv() qml.PhaseShift(params[6], wires=wires[0]).inv() qml.Rot(params[6], params[7], params[8], wires=wires[0]) # # qml.Rot(params[8], params[8], params[9], wires=wires[1]).inv() qml.MultiRZ(params[11], wires=[wires[0], wires[1]]) # # qml.PauliRot(params[12], "XXYZ", wires=[wires[0], wires[1], wires[2], wires[3]]) qml.CPhase(params[12], wires=[wires[3], wires[2]]) qml.IsingXX(params[13], wires=[wires[1], wires[0]]) qml.IsingXY(params[14], wires=[wires[3], wires[2]]) qml.IsingYY(params[14], wires=[wires[3], wires[2]]) qml.IsingZZ(params[14], wires=[wires[2], wires[1]]) qml.U1(params[15], wires=wires[0]) qml.U2(params[16], params[17], wires=wires[0]) qml.U3(params[18], params[19], params[20], wires=wires[1]) # # qml.CRot(params[21], params[22], params[23], wires=[wires[1], wires[2]]).inv() # expected tofail qml.SingleExcitation(params[24], wires=[wires[2], wires[0]]) qml.DoubleExcitation(params[25], wires=[wires[2], wires[0], wires[1], wires[3]]) qml.SingleExcitationPlus(params[26], wires=[wires[0], wires[2]]) qml.SingleExcitationMinus(params[27], wires=[wires[0], wires[2]]) qml.DoubleExcitationPlus(params[27], wires=[wires[2], wires[0], wires[1], wires[3]]) qml.DoubleExcitationMinus(params[27], wires=[wires[2], wires[0], wires[1], wires[3]]) qml.RX(params[28], wires=wires[0]) qml.RX(params[29], wires=wires[1])
def test_decompose_queue(self, operable_mock_device_2_wires): """Test that decompose queue works correctly when an operation exists that can be decomposed""" queue = [qml.Rot(0, 1, 2, wires=0), qml.U3(3, 4, 5, wires=0), qml.RX(6, wires=0)] res = decompose_queue(queue, operable_mock_device_2_wires) assert len(res) == 5 assert res[0].name == "Rot" assert res[0].parameters == [0, 1, 2] assert res[1].name == "Rot" assert res[1].parameters == [5, 3, -5] assert res[2].name == "PhaseShift" assert res[2].parameters == [5] assert res[3].name == "PhaseShift" assert res[3].parameters == [4] assert res[4].name == "RX" assert res[4].parameters == [6]
def test_gradient_gate_with_multiple_parameters_hermitian(self, dev): """Tests that gates with multiple free parameters yield correct gradients.""" x, y, z = [0.5, 0.3, -0.7] with qml.tape.QuantumTape() as tape: qml.RX(0.4, wires=[0]) qml.Rot(x, y, z, wires=[0]) qml.RY(-0.2, wires=[0]) qml.expval(qml.Hermitian([[0, 1], [1, 1]], wires=0)) tape.trainable_params = {1, 2, 3} h = 2e-3 if dev.R_DTYPE == np.float32 else 1e-7 tol = 1e-3 if dev.R_DTYPE == np.float32 else 1e-7 grad_D = dev.adjoint_jacobian(tape) tapes, fn = qml.gradients.finite_diff(tape, h=h) grad_F = fn(qml.execute(tapes, dev, None)) # gradient has the correct shape and every element is nonzero assert grad_D.shape == (1, 3) assert np.count_nonzero(grad_D) == 3 # the different methods agree assert np.allclose(grad_D, grad_F, atol=tol, rtol=0)
def test_provide_starting_state(self, tol, dev): """Tests provides correct answer when provided starting state.""" x, y, z = [0.5, 0.3, -0.7] with qml.tape.QuantumTape() as tape: qml.RX(0.4, wires=[0]) qml.Rot(x, y, z, wires=[0]) qml.RY(-0.2, wires=[0]) qml.expval(qml.PauliZ(0)) tape.trainable_params = {1, 2, 3} dy = np.array([1.0]) fn1 = dev.vjp(tape.measurements, dy) vjp1 = fn1(tape) qml.execute([tape], dev, None) fn2 = dev.vjp(tape.measurements, dy, starting_state=dev._pre_rotated_state) vjp2 = fn2(tape) assert np.allclose(vjp1, vjp2, atol=tol, rtol=0)
def test_expand_multi_par(self): """Test that a tape with single-parameter operations with unitary generators and non-parametric operations is not touched.""" with qml.tape.JacobianTape() as tape: qml.RX(0.2, wires=0) qml.Hadamard(0) qml.Rot(0.9, 1.2, -0.6, wires=0) qml.SingleExcitationPlus(-1.2, wires=[1, 0]) new_tape = qml.transforms.expand_nonunitary_gen(tape) expanded = [ qml.RZ(0.9, wires=0), qml.RY(1.2, wires=0), qml.RZ(-0.6, wires=0), ] assert tape.operations[:2] == new_tape.operations[:2] assert all(exp.name == new.name for exp, new in zip(expanded, new_tape.operations[2:5])) assert all(exp.data == new.data for exp, new in zip(expanded, new_tape.operations[2:5])) assert all(exp.wires == new.wires for exp, new in zip(expanded, new_tape.operations[2:5])) assert tape.operations[3:] == new_tape.operations[5:]
def variational_ansatz1(params, wires): rot_params = params[0] params = params[1:] n_qubits = len(wires) n_rotations = len(params) qml.PauliX(wires=0) qml.RY(rot_params[1], wires=2) if n_rotations > 1: n_layers = n_rotations // n_qubits n_extra_rots = n_rotations - n_layers * n_qubits for layer_idx in range(n_layers): layer_params = params[layer_idx * n_qubits : layer_idx * n_qubits + n_qubits, :] qml.broadcast(qml.Rot, wires, pattern="single", parameters=layer_params) qml.broadcast(qml.CNOT, wires, pattern="ring") extra_params = params[-n_extra_rots:, :] extra_wires = wires[: n_qubits - 1 - n_extra_rots : -1] qml.broadcast(qml.Rot, extra_wires, pattern="single", parameters=extra_params) else: qml.Rot(*params[0], wires=wires[0])
def test_behaviour(self): """Test that the function behaves as expected""" with qml.tape.QuantumTape() as tape: qml.PauliZ(0) qml.RX(1.0, wires=0) qml.CNOT(wires=[0, 2]) qml.Rot(2.0, 3.0, 4.0, wires=0) qml.expval(qml.PauliZ(0)) tape.trainable_params = {0, 2} shifts = [0.1, -0.2, 1.6] res = generate_shifted_tapes(tape, 1, shifts=shifts) assert len(res) == len(shifts) assert res[0].get_parameters(trainable_only=False) == [ 1.0, 2.0, 3.1, 4.0 ] assert res[1].get_parameters(trainable_only=False) == [ 1.0, 2.0, 2.8, 4.0 ] assert res[2].get_parameters(trainable_only=False) == [ 1.0, 2.0, 4.6, 4.0 ]
def test_zyz_decomposition_tf(self, U, expected_gate, expected_params): """Test that a one-qubit operation in Tensorflow is correctly decomposed.""" tf = pytest.importorskip("tensorflow") U = tf.Variable(U, dtype=tf.complex128) obtained_gates = zyz_decomposition(U, wire="a") assert len(obtained_gates) == 1 assert isinstance(obtained_gates[0], expected_gate) assert obtained_gates[0].wires == Wires("a") assert qml.math.allclose(qml.math.unwrap(obtained_gates[0].parameters), expected_params) if obtained_gates[0].num_params == 1: # With TF and RZ, need to cast since can't just unwrap obtained_mat = qml.RZ(obtained_gates[0].parameters[0].numpy(), wires=0).matrix else: obtained_mat = qml.Rot(*qml.math.unwrap( obtained_gates[0].parameters), wires=0).matrix assert check_matrix_equivalence(obtained_mat, U)
from pennylane.transforms.decompositions import zyz_decomposition from gate_data import I, Z, S, T, H, X single_qubit_decomps = [ # First set of gates are diagonal and converted to RZ (I, qml.RZ, [0.0]), (Z, qml.RZ, [np.pi]), (S, qml.RZ, [np.pi / 2]), (T, qml.RZ, [np.pi / 4]), (qml.RZ(0.3, wires=0).matrix, qml.RZ, [0.3]), (qml.RZ(-0.5, wires=0).matrix, qml.RZ, [-0.5]), # Next set of gates are non-diagonal and decomposed as Rots (H, qml.Rot, [np.pi, np.pi / 2, 0.0]), (X, qml.Rot, [0.0, np.pi, np.pi]), (qml.Rot(0.2, 0.5, -0.3, wires=0).matrix, qml.Rot, [0.2, 0.5, -0.3]), (np.exp(1j * 0.02) * qml.Rot(-1.0, 2.0, -3.0, wires=0).matrix, qml.Rot, [-1.0, 2.0, -3.0]), ] class TestQubitUnitaryZYZDecomposition: """Test that the decompositions are correct.""" def test_zyz_decomposition_invalid_input(self): """Test that non-unitary operations throw errors when we try to decompose.""" with pytest.raises(ValueError, match="Operator must be unitary"): zyz_decomposition(I + H, Wires("a")) @pytest.mark.parametrize("U,expected_gate,expected_params", single_qubit_decomps) def test_zyz_decomposition(self, U, expected_gate, expected_params):
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))
def circuit(params): qml.RX(np.array(np.pi / 4, requires_grad=False), wires=[0]) qml.Rot(params[1], params[0], 2 * params[0], wires=[0]) return qml.expval(qml.PauliX(0))
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.24"), ], ) 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 @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.PauliRot(3.14, "XX", wires=[0, 1]), 1, "RX(3.14)"), (qml.PauliRot(3.14, "YZ", wires=[0, 1]), 1, "RZ(3.14)"), (qml.PauliRot(3.14, "IXYZI", wires=[0, 1, 2, 3, 4 ]), 0, "RI(3.14)"), (qml.PauliRot(3.14, "IXYZI", wires=[0, 1, 2, 3, 4 ]), 1, "RX(3.14)"), (qml.PauliRot(3.14, "IXYZI", wires=[0, 1, 2, 3, 4 ]), 2, "RY(3.14)"), (qml.PauliRot(3.14, "IXYZI", wires=[0, 1, 2, 3, 4 ]), 3, "RZ(3.14)"), (qml.PauliRot(3.14, "IXYZI", wires=[0, 1, 2, 3, 4 ]), 4, "RI(3.14)"), (qml.MultiRZ(3.14, wires=[0, 1]), 0, "RZ(3.14)"), (qml.MultiRZ(3.14, wires=[0, 1]), 1, "RZ(3.14)"), (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([[2, 0], [0, 2]]), np.array([1, 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.InterferometerUnitary( np.eye(4), wires=[1, 3]), 1, "InterferometerUnitary(M0)"), (qml.InterferometerUnitary( np.eye(4), wires=[1, 3]), 3, "InterferometerUnitary(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"), (qml.PauliX(wires=[1]).inv(), 1, "X⁻¹"), (qml.CNOT(wires=[0, 1]).inv(), 1, "X⁻¹"), (qml.CNOT(wires=[0, 1]).inv(), 0, "C"), (qml.Toffoli(wires=[0, 2, 1]).inv(), 1, "X⁻¹"), (qml.Toffoli(wires=[0, 2, 1]).inv(), 0, "C"), (qml.Toffoli(wires=[0, 2, 1]).inv(), 2, "C"), (qml.measure.sample(wires=[0, 1]), 0, "basis"), # not providing an observable in (qml.measure.sample(wires=[0, 1]), 1, "basis"), # sample gets displayed as raw (two_wire_quantum_tape(), 0, "QuantumTape:T0"), (two_wire_quantum_tape(), 1, "QuantumTape:T0"), ], ) 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([[2, 0], [0, 2]]), np.array([1, 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.InterferometerUnitary( np.eye(4), wires=[1, 3]), 1, "InterferometerUnitary(M0)"), (qml.InterferometerUnitary( np.eye(4), wires=[1, 3]), 3, "InterferometerUnitary(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"), (qml.QuadOperator(3.14, wires=[1]), 1, "cos(3.14)x+sin(3.14)p"), (qml.PauliX(wires=[1]).inv(), 1, "X^-1"), (qml.CNOT(wires=[0, 1]).inv(), 1, "X^-1"), (qml.CNOT(wires=[0, 1]).inv(), 0, "C"), (qml.Toffoli(wires=[0, 2, 1]).inv(), 1, "X^-1"), (qml.Toffoli(wires=[0, 2, 1]).inv(), 0, "C"), (qml.Toffoli(wires=[0, 2, 1]).inv(), 2, "C"), (qml.measure.sample(wires=[0, 1]), 0, "basis"), # not providing an observable in (qml.measure.sample(wires=[0, 1]), 1, "basis"), # sample gets displayed as raw (two_wire_quantum_tape(), 0, "QuantumTape:T0"), (two_wire_quantum_tape(), 1, "QuantumTape:T0"), ], ) 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]", ), (qml.probs([0]), 0, "Probs"), (state(), 0, "State"), ], ) 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]", ), (qml.probs([0]), 0, "Probs"), (state(), 0, "State"), ], ) 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)