def decompose_ua(phi, wires=None): r"""Implements the circuit decomposing the controlled application of the unitary :math:`U_A(\phi)` .. math:: U_A(\phi) = \left(\begin{array}{cc} 0 & e^{-i\phi} \\ e^{-i\phi} & 0 \\ \end{array}\right) in terms of the quantum operations supported by PennyLane. :math:`U_A(\phi)` is used in `arXiv:1805.04340 <https://arxiv.org/abs/1805.04340>`_, to define two-qubit exchange gates required to build particle-conserving VQE ansatze for quantum chemistry simulations. See :func:`~.ParticleConservingU1`. :math:`U_A(\phi)` is expressed in terms of ``PhaseShift``, ``Rot`` and ``PauliZ`` operations :math:`U_A(\phi) = R_\phi(-2\phi) R(-\phi, \pi, \phi) \sigma_z`. Args: phi (float): angle :math:`\phi` defining the unitary :math:`U_A(\phi)` wires (Iterable): the wires ``n`` and ``m`` the circuit acts on """ n, m = wires qml.CZ(wires=wires) qml.CRot(-phi, np.pi, phi, wires=wires) # decomposition of C-PhaseShift(2*phi) gate qml.PhaseShift(-phi, wires=m) qml.CNOT(wires=wires) qml.PhaseShift(phi, wires=m) qml.CNOT(wires=wires) qml.PhaseShift(-phi, wires=n)
def decomposition(wires): decomp_ops = [ qml.PhaseShift(np.pi / 2, wires=wires), qml.RX(np.pi / 2, wires=wires), qml.PhaseShift(np.pi / 2, wires=wires), ] return decomp_ops
def test_with_qfunc_op(self): """Test if the transform works as expected if the operation is a qfunc rather than single operation""" def op(x, y, wires): qml.RX(x, wires=wires) qml.PhaseShift(y, wires=wires) tape = insert(op, [0.4, 0.5], position="end")(self.tape) with QuantumTape() as tape_exp: qml.RX(0.9, wires=0) qml.RY(0.4, wires=1) qml.CNOT(wires=[0, 1]) qml.RY(0.5, wires=0) qml.RX(0.6, wires=1) qml.RX(0.4, wires=0) qml.PhaseShift(0.5, wires=0) qml.RX(0.4, wires=1) qml.PhaseShift(0.5, wires=1) qml.expval(qml.PauliZ(0) @ qml.PauliZ(1)) assert all(o1.name == o2.name for o1, o2 in zip(tape.operations, tape_exp.operations)) assert all(o1.wires == o2.wires for o1, o2 in zip(tape.operations, tape_exp.operations)) assert all( np.allclose(o1.parameters, o2.parameters) for o1, o2 in zip(tape.operations, tape_exp.operations)) assert len(tape.measurements) == 1 assert tape.observables[0].name == ["PauliZ", "PauliZ"] assert tape.observables[0].wires.tolist() == [0, 1] assert tape.measurements[0].return_type is Expectation
def decomposition(phi, wires): return [ qml.PhaseShift(phi / 2, wires=[wires[0]]), qml.PhaseShift(phi / 2, wires=[wires[1]]), qml.CNOT(wires=wires), qml.PhaseShift(-phi / 2, wires=[wires[1]]), qml.CNOT(wires=wires), ]
def decomposition(phi, wires): decomp_ops = [ qml.PhaseShift(phi / 2, wires=wires[0]), qml.CNOT(wires=wires), qml.PhaseShift(-phi / 2, wires=wires[1]), qml.CNOT(wires=wires), qml.PhaseShift(phi / 2, wires=wires[1]), ] return decomp_ops
def test_construct_subcircuit(self): """Test correct subcircuits constructed""" dev = qml.device("default.qubit", wires=2) with qml.tape.QuantumTape() as tape: qml.RX(np.array(1.0, requires_grad=True), wires=0) qml.RY(np.array(1.0, requires_grad=True), wires=0) qml.CNOT(wires=[0, 1]) qml.PhaseShift(np.array(1.0, requires_grad=True), wires=1) return qml.expval(qml.PauliX(0)), qml.expval(qml.PauliX(1)) tapes, _ = qml.metric_tensor(tape, approx="block-diag") assert len(tapes) == 3 # first parameter subcircuit assert len(tapes[0].operations) == 1 assert isinstance(tapes[0].operations[0], qml.Hadamard) # PauliX decomp # second parameter subcircuit assert len(tapes[1].operations) == 4 assert isinstance(tapes[1].operations[0], qml.RX) # PauliY decomp assert isinstance(tapes[1].operations[1], qml.PauliZ) assert isinstance(tapes[1].operations[2], qml.S) assert isinstance(tapes[1].operations[3], qml.Hadamard) # third parameter subcircuit assert len(tapes[2].operations) == 4 assert isinstance(tapes[2].operations[0], qml.RX) assert isinstance(tapes[2].operations[1], qml.RY) assert isinstance(tapes[2].operations[2], qml.CNOT) # Phase shift generator assert isinstance(tapes[2].operations[3], qml.QubitUnitary)
def test_unwrap_tensorflow(): """Test that unwrapping a tape with TensorFlow parameters works as expected""" tf = pytest.importorskip("tensorflow") p = [tf.Variable(0.1), tf.constant(0.2), np.array(0.5), tf.Variable(0.3)] with tf.GradientTape(): with qml.tape.QuantumTape() as tape: qml.RX(p[0], wires=0) qml.RY(p[1], wires=0) qml.PhaseShift(p[2], wires=0) qml.RZ(p[3], wires=0) params = tape.get_parameters(trainable_only=False) tape.trainable_params = qml.math.get_trainable_indices(params) with tape.unwrap() as unwrapped_tape: # inside the context manager, all parameters # will be unwrapped to NumPy arrays params = tape.get_parameters(trainable_only=False) assert all(isinstance(i, (float, np.float32)) for i in params) assert np.allclose(params, [0.1, 0.2, 0.5, 0.3]) assert tape.trainable_params == [0, 3] # outside the context, the original parameters have been restored. assert tape.get_parameters(trainable_only=False) == p
def compute_decomposition(phi, wires): return [ qml.SWAP(wires=wires), qml.CNOT(wires=wires), qml.PhaseShift(phi, wires=[wires[1]]), qml.CNOT(wires=wires), ]
def test_expand_fn_with_kwarg(self, mocker, perform_expansion): """Test that kwargs are respected in the expansion.""" class MyTransform: """Dummy class to allow spying to work""" def my_transform(self, tape, **kwargs): tape1 = tape.copy() tape2 = tape.copy() return [tape1, tape2], None spy_transform = mocker.spy(MyTransform, "my_transform") transform_fn = qml.batch_transform( MyTransform().my_transform, expand_fn=self.expand_logic_with_kwarg) with qml.tape.QuantumTape() as tape: qml.PhaseShift(0.5, wires=0) qml.expval(qml.PauliX(0)) spy_expand = mocker.spy(transform_fn, "expand_fn") transform_fn(tape, perform_expansion=perform_expansion) spy_transform.assert_called() spy_expand.assert_called( ) # The expand_fn of transform_fn always is called input_tape = spy_transform.call_args[0][1] assert len(input_tape.operations) == 1 assert input_tape.operations[0].name == ("RZ" if perform_expansion else "PhaseShift") assert input_tape.operations[0].parameters == [0.5]
def local_hadamard_test(weights, l=None, lp=None, j=None, part=None): # First Hadamard gate applied to the ancillary qubit. qml.Hadamard(wires=ancilla_idx) # For estimating the imaginary part of the coefficient "mu", we must add a "-i" phase gate. if part == "Im" or part == "im": qml.PhaseShift(-np.pi / 2, wires=ancilla_idx) # Variational circuit generating a guess for the solution vector |x> variational_block(weights) # Controlled application of the unitary component A_l of the problem matrix A. CA(l) # Adjoint of the unitary U_b associated to the problem vector |b>. # In this specific example Adjoint(U_b) = U_b. U_b() # Controlled Z operator at position j. If j = -1, apply the identity. if j != -1: qml.CZ(wires=[ancilla_idx, j]) # Unitary U_b associated to the problem vector |b>. U_b() # Controlled application of Adjoint(A_lp). # In this specific example Adjoint(A_lp) = A_lp. CA(lp) # Second Hadamard gate applied to the ancillary qubit. qml.Hadamard(wires=ancilla_idx) # Expectation value of Z for the ancillary qubit. return qml.expval(qml.PauliZ(wires=ancilla_idx))
def apply_single_clifford(clifford_string, inverse=False): for gate in clifford_string: if gate == 'H': qml.Hadamard(wires=0) else: sign = -1 if inverse else 1 qml.PhaseShift(sign * np.pi / 2, wires=0)
def test_unwrap_torch(): """Test that unwrapping a tape with Torch parameters works as expected""" torch = pytest.importorskip("torch") p = [ torch.tensor(0.1, requires_grad=True), torch.tensor(0.2), np.array(0.5), torch.tensor(0.3, requires_grad=True), ] with qml.tape.QuantumTape() as tape: qml.RX(p[0], wires=0) qml.RY(p[1], wires=0) qml.PhaseShift(p[2], wires=0) qml.RZ(p[3], wires=0) with tape.unwrap() as unwrapped_tape: # inside the context manager, all parameters # will be unwrapped to NumPy arrays params = tape.get_parameters(trainable_only=False) assert all(isinstance(i, float) for i in params) assert np.allclose(params, [0.1, 0.2, 0.5, 0.3]) assert tape.trainable_params == {0, 3} # outside the context, the original parameters have been restored. assert tape.get_parameters(trainable_only=False) == p
def test_expand_fn(self, mocker): """Test that if an expansion function is provided, that the input tape is expanded before being transformed.""" class MyTransform: """Dummy class to allow spying to work""" def my_transform(self, tape): tape1 = tape.copy() tape2 = tape.copy() return [tape1, tape2], None spy_transform = mocker.spy(MyTransform, "my_transform") transform_fn = qml.batch_transform(MyTransform().my_transform, expand_fn=self.phaseshift_expand) with qml.tape.QuantumTape() as tape: qml.PhaseShift(0.5, wires=0) qml.expval(qml.PauliX(0)) spy_expand = mocker.spy(transform_fn, "expand_fn") transform_fn(tape) spy_transform.assert_called() spy_expand.assert_called() input_tape = spy_transform.call_args[0][1] assert len(input_tape.operations) == 1 assert input_tape.operations[0].name == "RZ" assert input_tape.operations[0].parameters == [0.5]
def test_unwrap_autograd(): """Test that unwrapping a tape with Autograd parameters works as expected""" from pennylane import numpy as anp p = [ anp.tensor(0.1, requires_grad=True), anp.tensor(0.2, requires_grad=False), 0.5, anp.tensor(0.3, requires_grad=True), ] with qml.tape.QuantumTape() as tape: qml.RX(p[0], wires=0) qml.RY(p[1], wires=0) qml.PhaseShift(p[2], wires=0) qml.RZ(p[3], wires=0) with tape.unwrap() as unwrapped_tape: # inside the context manager, all parameters # will be unwrapped to NumPy arrays params = tape.get_parameters(trainable_only=False) assert all(isinstance(i, float) for i in params) assert np.allclose(params, [0.1, 0.2, 0.5, 0.3]) assert tape.trainable_params == {0, 2, 3} # outside the context, the original parameters have been restored. assert tape.get_parameters(trainable_only=False) == p
def qfunc(a, b, c, angles): qml.RX(a, wires=0) qml.RX(b, wires=1) qml.PauliZ(1) qml.CNOT(wires=[0, 1]).inv() qml.CRY(b, wires=[3, 1]) qml.RX(angles[0], wires=0) qml.RX(4 * angles[1], wires=1) qml.PhaseShift(17 / 9 * c, wires=2) qml.RZ(b, wires=3) qml.RX(angles[2], wires=2).inv() qml.CRY(0.3589, wires=[3, 1]).inv() qml.CSWAP(wires=[4, 2, 1]).inv() qml.QubitUnitary(np.eye(2), wires=[2]) qml.Toffoli(wires=[0, 2, 1]) qml.CNOT(wires=[0, 2]) qml.PauliZ(wires=[1]) qml.PauliZ(wires=[1]).inv() qml.CZ(wires=[0, 1]) qml.CZ(wires=[0, 2]).inv() qml.CNOT(wires=[2, 1]) qml.CNOT(wires=[0, 2]) qml.SWAP(wires=[0, 2]).inv() qml.CNOT(wires=[1, 3]) qml.RZ(b, wires=3) qml.CSWAP(wires=[4, 0, 1]) return [ qml.expval(qml.PauliY(0)), qml.var(qml.Hadamard(wires=1)), qml.sample(qml.PauliX(2)), qml.expval(qml.Hermitian(np.eye(4), wires=[3, 4])), ]
class TestOperations: """Tests for the operations""" @pytest.mark.parametrize( "op", [ (qml.Hadamard(wires=0)), (qml.PauliX(wires=0)), (qml.PauliY(wires=0)), (qml.PauliZ(wires=0)), (qml.S(wires=0)), (qml.T(wires=0)), (qml.SX(wires=0)), (qml.RX(0.3, wires=0)), (qml.RY(0.3, wires=0)), (qml.RZ(0.3, wires=0)), (qml.PhaseShift(0.3, wires=0)), (qml.Rot(0.3, 0.4, 0.5, wires=0)), ], ) def test_single_qubit_rot_angles(self, op): """Tests that the Rot gates yielded by single_qubit_rot_angles are equivalent to the true operations up to a global phase.""" angles = op.single_qubit_rot_angles() obtained_mat = qml.Rot(*angles, wires=0).matrix # Check whether the two matrices are each others conjugate transposes mat_product = qml.math.dot(op.matrix, qml.math.conj(obtained_mat.T)) mat_product /= mat_product[0, 0] assert qml.math.allclose(mat_product, I)
def test_unwrap_jax(): """Test that unwrapping a tape with JAX parameters works as expected""" jax = pytest.importorskip("jax") from jax import numpy as jnp p = [ jnp.array(0.1), jnp.array(0.2), 0.5, jnp.array(0.3), ] with qml.tape.QuantumTape() as tape: qml.RX(p[0], wires=0) qml.RY(p[1], wires=0) qml.PhaseShift(p[2], wires=0) qml.RZ(p[3], wires=0) with tape.unwrap() as unwrapped_tape: # inside the context manager, all parameters # will be unwrapped to NumPy arrays params = tape.get_parameters(trainable_only=False) assert all(isinstance(i, float) for i in params) assert np.allclose(params, [0.1, 0.2, 0.5, 0.3]) # During the forward pass, JAX has no concept of trainable # arrays. assert tape.trainable_params == set() # outside the context, the original parameters have been restored. assert tape.get_parameters(trainable_only=False) == p
def circuit(): qml.CRZ(0.0, wires=[0, 1]) qml.CRX(0.0, wires=[0, 1]) qml.PhaseShift(0.0, wires=0) qml.ControlledPhaseShift(0.0, wires=[1, 0]) qml.CRot(1.0, 0.0, 0.0, wires=[0, 1]) qml.CRY(0.0, wires=[0, 1]) return qml.sample(qml.PauliZ(wires=0))
def test_phase(self): """Test if the function correctly returns the derivative of PhaseShift""" p = 0.3 op = qml.PhaseShift(p, wires=0) derivative = operation_derivative(op) expected_derivative = np.array([[0, 0], [0, 1j * np.exp(1j * p)]]) assert np.allclose(derivative, expected_derivative)
def Turing(): # distinct fun names in functional placeholders= # [] qml.Hadamard(0) qml.PauliX(1) qml.PauliY(1) qml.PauliZ(1) qml.CNOT(wires=[0, 1]) qml.CZ(wires=[0, 1]) qml.SWAP(wires=[1, 0]) qml.RX(-6.283185307179586, wires=2) qml.RY(-6.283185307179586, wires=2) qml.RZ(-6.283185307179586, wires=2) qml.PhaseShift(3.141592653589793, wires=1) def rot(rad_ang_x, rad_ang_y, rad_ang_z): """ Returns exp(1j*(rad_ang_x*sig_x + rad_ang_y*sig_y + rad_ang_z*sig_z)) where rad_ang_x is an angle in radians and sig_x is the x Pauli matrix, etc. Parameters ---------- rad_ang_x : float rad_ang_y : float rad_ang_z : float Returns ------- np.ndarray """ ty = np.complex128 mat = np.zeros([2, 2], dtype=ty) vec = np.array([rad_ang_x, rad_ang_y, rad_ang_z]) n = np.linalg.norm(vec) # sqrt(dot(vec, vec.conj)) if abs(n) < 1e-8: mat[0, 0] = 1 mat[1, 1] = 1 else: nx = rad_ang_x / n ny = rad_ang_y / n nz = rad_ang_z / n c = np.cos(n) s = np.sin(n) mat[0, 0] = c + 1j * s * nz mat[0, 1] = s * ny + 1j * s * nx mat[1, 0] = -s * ny + 1j * s * nx mat[1, 1] = c - 1j * s * nz return mat qml.QubitUnitary(rot(-6.283185307179586, -6.283185307179586, -6.283185307179586), wires=0) return qml.expval.Hermitian(hamil)
def qfunc(): qml.RZ(0.3, wires="a") qml.RY(0.5, wires="a") qml.Rot(0.1, 0.2, 0.3, wires="b") qml.RX(0.1, wires="a") qml.CNOT(wires=["b", "a"]) qml.SX(wires="b") qml.S(wires="b") qml.PhaseShift(0.3, wires="b")
def expand(self): theta, phi, lam = self.data wires = self.wires with JacobianTape() as tape: qml.Rot(lam, theta, -lam, wires=wires) qml.PhaseShift(phi + lam, wires=wires) return tape
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
def circuit(a, b): # The classical processing function is # f: ([a0, a1], b) -> (a1, a0, b) # So the classical Jacobians will be a permutation matrix and an identity matrix: # classical_jacobian(circuit)(a, b) == ([[0, 1], [1, 0]], [[1]]) qml.RX(a[1], wires=0) qml.RY(a[0], wires=0) qml.CNOT(wires=[0, 1]) qml.PhaseShift(b, wires=1) return qml.expval(qml.PauliX(0)), qml.expval(qml.PauliX(1))
def qfunc(theta): qml.PauliX(wires=2) qml.S(wires=0) qml.CNOT(wires=[0, 1]) qml.PauliY(wires=1) qml.CRY(theta[0], wires=[2, 1]) qml.PhaseShift(theta[1], wires=0) qml.T(wires=0) qml.Toffoli(wires=[0, 1, 2]) return qml.expval(qml.PauliZ(0))
def test_multiple_unwrap(): """Test that unwrapping multiple tapes at once works correctly""" torch = pytest.importorskip("torch") p = [ torch.tensor(0.1, requires_grad=True), torch.tensor(0.2), np.array(0.5), torch.tensor(0.3, requires_grad=True), ] with qml.tape.QuantumTape() as tape1: qml.RX(p[0], wires=0) qml.RY(p[1], wires=0) qml.PhaseShift(p[2], wires=0) qml.RZ(p[3], wires=0) with qml.tape.QuantumTape() as tape2: qml.RX(p[1], wires=0) qml.RY(p[3], wires=0) qml.PhaseShift(p[0], wires=0) qml.RZ(p[2], wires=0) for t in [tape1, tape2]: params = t.get_parameters(trainable_only=False) t.trainable_params = qml.math.get_trainable_indices(params) with qml.tape.Unwrap(tape1, tape2): # inside the context manager, all parameters # will be unwrapped to NumPy arrays params = tape1.get_parameters(trainable_only=False) assert all(isinstance(i, float) for i in params) assert tape1.trainable_params == [0, 3] params = tape2.get_parameters(trainable_only=False) assert all(isinstance(i, float) for i in params) assert tape2.trainable_params == [1, 2] # outside the context, the original parameters have been restored. assert tape1.get_parameters(trainable_only=False) == p assert tape2.get_parameters(trainable_only=False) == [ p[1], p[3], p[0], p[2] ]
def test_inclusion_after_addition(self): """Test that we can add operators to the set in multiple ways.""" new_attribute.add("RX") new_attribute.add(qml.PhaseShift(0.5, wires=0)) new_attribute.add(qml.RY) assert "RX" in new_attribute assert "PhaseShift" in new_attribute assert "RY" in new_attribute assert len(new_attribute) == 8
def test_append_qubit_gates(self): """Test that gates are successfully appended to the queue.""" with qml.beta.queuing.AnnotatedQueue() as q: ops = [ qml.RX(0.5, wires=0), qml.RY(-10.1, wires=1), qml.CNOT(wires=[0, 1]), qml.PhaseShift(-1.1, wires=18), qml.T(wires=99), ] assert q.queue == ops
def qfunc(): qml.PauliZ(wires=2) qml.S(wires=0) qml.CZ(wires=[0, 2]) qml.CNOT(wires=[0, 1]) qml.PhaseShift(0.2, wires=2) qml.T(wires=0) qml.PauliZ(wires=0) qml.CRZ(0.5, wires=[0, 1])
def circuit(x, y, z): for i in range(w): qml.RX(x, wires=i) qml.PhaseShift(z, wires=i) qml.RY(y, wires=i) qml.CNOT(wires=[0, 1]) qml.CNOT(wires=[1, 2]) qml.CNOT(wires=[2, 3]) return qml.probs(wires=[1, 3])