def metric_tensor_entry(i, j, unshifted, shift=np.pi / 2):
        shifted_plus = params.copy()
        shifted_plus[i] += shift
        shifted_plus[j] += shift
        qnode(shifted_plus)
        forward = dev.state
        ov_forward = abs(np.vdot(unshifted, forward))**2

        shifted_min_plu = params.copy()
        shifted_min_plu[i] -= shift
        shifted_min_plu[j] += shift
        qnode(shifted_min_plu)
        min_plu = dev.state
        ov_min_plu = abs(np.vdot(unshifted, min_plu))**2

        shifted_plu_min = params.copy()
        shifted_plu_min[i] += shift
        shifted_plu_min[j] -= shift
        qnode(shifted_plu_min)
        plu_min = dev.state
        ov_plu_min = abs(np.vdot(unshifted, plu_min))**2

        shifted_minus = params.copy()
        shifted_minus[i] -= shift
        shifted_minus[j] -= shift
        qnode(shifted_minus)
        backward = dev.state
        ov_backward = abs(np.vdot(unshifted, backward))**2

        me = (1 / 8) * (-ov_forward + ov_plu_min + ov_min_plu - ov_backward)

        return me
Example #2
0
    def test_qubit_unitary(self, shots, qvm, compiler):
        """Test that an arbitrary unitary operation works"""
        dev1 = qml.device("forest.qvm",
                          device="3q-qvm",
                          shots=shots,
                          parametric_compilation=False)
        dev2 = qml.device("forest.qvm",
                          device="9q-square-qvm",
                          shots=shots,
                          parametric_compilation=False)
        print(shots)

        def circuit():
            """Reference QNode"""
            qml.Hadamard(wires=0)
            qml.CNOT(wires=[0, 1])
            qml.QubitUnitary(U2, wires=[0, 1])
            return qml.expval(qml.PauliZ(0))

        circuit1 = qml.QNode(circuit, dev1)
        circuit2 = qml.QNode(circuit, dev2)

        out_state = U2 @ np.array([1, 0, 0, 1]) / np.sqrt(2)
        obs = np.kron(np.array([[1, 0], [0, -1]]), I)

        self.assertAllAlmostEqual(circuit1(),
                                  np.vdot(out_state, obs @ out_state),
                                  delta=3 / np.sqrt(shots))
        self.assertAllAlmostEqual(circuit2(),
                                  np.vdot(out_state, obs @ out_state),
                                  delta=3 / np.sqrt(shots))
Example #3
0
    def test_apply(self, gate, apply_unitary, shots):
        """Test the application of gates"""
        dev = plf.QVMDevice(device="3q-pyqvm", shots=shots)

        try:
            # get the equivalent pennylane operation class
            op = getattr(qml.ops, gate)
        except AttributeError:
            # get the equivalent pennylane-forest operation class
            op = getattr(plf, gate)

        # the list of wires to apply the operation to
        w = list(range(op.num_wires))

        obs = qml.expval(qml.PauliZ(0))
        if op.par_domain == "A":
            # the parameter is an array
            if gate == "QubitUnitary":
                p = np.array(U)
                w = [0]
                state = apply_unitary(U, 3)
            elif gate == "BasisState":
                p = np.array([1, 1, 1])
                state = np.array([0, 0, 0, 0, 0, 0, 0, 1])
                w = list(range(dev.num_wires))

            circuit_graph = CircuitGraph([op(p, wires=w)] + [obs], {})
        else:
            p = [0.432423, 2, 0.324][:op.num_params]
            fn = test_operation_map[gate]
            if callable(fn):
                # if the default.qubit is an operation accepting parameters,
                # initialise it using the parameters generated above.
                O = fn(*p)
            else:
                # otherwise, the operation is simply an array.
                O = fn

            # calculate the expected output
            state = apply_unitary(O, 3)
            # Creating the circuit graph using a parametrized operation
            if p:
                circuit_graph = CircuitGraph([op(*p, wires=w)] + [obs], {})
            # Creating the circuit graph using an operation that take no parameters
            else:
                circuit_graph = CircuitGraph([op(wires=w)] + [obs], {})

        dev.apply(circuit_graph.operations,
                  rotations=circuit_graph.diagonalizing_gates)

        dev.generate_samples()

        res = dev.expval(obs)
        expected = np.vdot(state, np.kron(np.kron(Z, I), I) @ state)

        # verify the device is now in the expected state
        # Note we have increased the tolerance here, since we are only
        # performing 1024 shots.
        self.assertAllAlmostEqual(res, expected, delta=3 / np.sqrt(shots))
Example #4
0
def _exact(x_new, A_samples, B_samples, featmap, n_inp, pars):
    """Calculates the analytical result of the fidelity measurement,

        overlap_A = \sum_i p_A |<\phi(x_new)|\phi(a_i)>|^2,
        overlap_B = \sum_i p_B |<\phi(x_new)|\phi(b_i)>|^2,

        using numpy as well as pennylane to simulate the feature map.
     """

    dev = qml.device('default.qubit', wires=n_inp)

    @qml.qnode(dev)
    def fm(weights, x=None):
        """Circuit to get the state after feature map"""
        featmap(weights, x, range(n_inp))
        return qml.expval(qml.PauliZ(0))

    # Compute feature states for A
    A_states = []
    for a in A_samples:
        fm(pars, x=a)
        phi_a = dev._state
        A_states.append(phi_a)

    # Compute feature states for B
    B_states = []
    for b in B_samples:
        fm(pars, x=b)
        phi_b = dev._state
        B_states.append(phi_b)

    # Get feature state for new input
    fm(pars, x=x_new)
    phi_x = dev._state

    # Put together
    overlap_A = sum([np.abs(np.vdot(phi_x, phi_a))**2 for phi_a in A_states])
    overlap_A = overlap_A / len(A_states)

    overlap_B = sum([np.abs(np.vdot(phi_x, phi_b))**2 for phi_b in B_states])
    overlap_B = overlap_B / len(B_states)

    return overlap_A, overlap_B
    def getTensorValue(params, i, j, qstate):

        params1 = params.copy()
        params1[i], params1[j] = params[i] + np.pi / 2, params[j] + np.pi / 2

        params2 = params.copy()
        params2[i], params2[j] = params[i] + np.pi / 2, params[j] - np.pi / 2

        params3 = params.copy()
        params3[i], params3[j] = params[i] - np.pi / 2, params[j] + np.pi / 2

        params4 = params.copy()
        params4[i], params4[j] = params[i] - np.pi / 2, params[j] - np.pi / 2

        answer = ((-(np.abs(np.vdot(qstate, state(params1))))**2 +
                   (np.abs(np.vdot(qstate, state(params2))))**2 +
                   (np.abs(np.vdot(qstate, state(params3))))**2 -
                   (np.abs(np.vdot(qstate, state(params4))))**2) / 8)

        return answer
    def test_hermitian_expectation(self, tol, qvm, compiler):
        """Test that an arbitrary Hermitian expectation value works"""
        dev = qml.device('forest.wavefunction', wires=1)

        @qml.qnode(dev)
        def circuit():
            """Test QNode"""
            qml.Hadamard(wires=0)
            qml.PauliY(wires=0)
            return qml.expval.Hermitian(H, 0)

        out_state = 1j*np.array([-1, 1])/np.sqrt(2)
        self.assertAllAlmostEqual(circuit(), np.vdot(out_state, H @ out_state), delta=tol)
Example #7
0
    def test_apply(self, gate, apply_unitary, shots):
        """Test the application of gates"""
        dev = plf.QVMDevice(device='3q-pyqvm', shots=shots)

        try:
            # get the equivalent pennylane operation class
            op = getattr(qml.ops, gate)
        except AttributeError:
            # get the equivalent pennylane-forest operation class
            op = getattr(plf, gate)

        # the list of wires to apply the operation to
        w = list(range(op.num_wires))

        if op.par_domain == 'A':
            # the parameter is an array
            if gate == 'QubitUnitary':
                p = [U]
                w = [0]
                state = apply_unitary(U, 3)
            elif gate == 'BasisState':
                p = [np.array([1, 1, 1])]
                state = np.array([0, 0, 0, 0, 0, 0, 0, 1])
        else:
            p = [0.432423, 2, 0.324][:op.num_params]
            fn = test_operation_map[gate]

            if callable(fn):
                # if the default.qubit is an operation accepting parameters,
                # initialise it using the parameters generated above.
                O = fn(*p)
            else:
                # otherwise, the operation is simply an array.
                O = fn

            # calculate the expected output
            state = apply_unitary(O, 3)

        dev.apply(gate, wires=w, par=p)
        dev._expval_queue = []
        dev.pre_expval()

        res = dev.expval('PauliZ', wires=[0], par=None)
        expected = np.vdot(state, np.kron(np.kron(Z, I), I) @ state)

        # verify the device is now in the expected state
        # Note we have increased the tolerance here, since we are only
        # performing 1024 shots.
        self.assertAllAlmostEqual(res, expected, delta=3 / np.sqrt(shots))
    def test_qubit_unitary(self, tol, qvm, compiler):
        """Test that an arbitrary unitary operation works"""
        dev = qml.device('forest.wavefunction', wires=3)

        @qml.qnode(dev)
        def circuit():
            """Test QNode"""
            qml.Hadamard(wires=0)
            qml.CNOT(wires=[0, 1])
            qml.QubitUnitary(U2, wires=[0, 1])
            return qml.expval.PauliZ(0)

        out_state = U2 @ np.array([1, 0, 0, 1])/np.sqrt(2)
        obs = np.kron(np.array([[1, 0], [0, -1]]), I)
        self.assertAllAlmostEqual(circuit(), np.vdot(out_state, obs @ out_state), delta=tol)
    def test_state_preparation_fidelity(self, tol, qubit_device_3_wires,
                                        state_vector, wires, target_state):
        """Tests that the template MottonenStatePreparation integrates correctly with PennyLane
        and produces states with correct fidelity."""
        @qml.qnode(qubit_device_3_wires)
        def circuit():
            MottonenStatePreparation(state_vector, wires)

            return qml.expval(qml.PauliZ(0)), qml.expval(
                qml.PauliZ(1)), qml.expval(qml.PauliZ(2))

        circuit()

        state = circuit.device.state.ravel()
        fidelity = abs(np.vdot(state, target_state))**2

        # We test for fidelity here, because the vector themselves will hardly match
        # due to imperfect state preparation
        assert np.isclose(fidelity, 1, atol=tol, rtol=0)
    def state(params):
        qstate = np.zeros([
            8,
        ])

        prob0 = probabs(params, 0)
        prob1 = probabs(params, 1)
        prob2 = probabs(params, 2)

        index = 0
        for i in range(2):
            for j in range(2):
                for k in range(2):
                    qstate[index] = np.abs(
                        np.sqrt((prob0[i] * prob1[j] * prob2[k])))
                    index += 1
        normalise = np.vdot(qstate, qstate)
        normalise = 1 / np.abs((np.sqrt(normalise)))
        qstate = normalise * qstate

        return qstate
Example #11
0
    def test_apply(self, op, apply_unitary, shots, qvm, compiler):
        """Test the application of gates to a state"""
        dev = plf.QVMDevice(device="3q-qvm",
                            shots=shots,
                            parametric_compilation=False)

        obs = qml.expval(qml.PauliZ(0))

        if op.name == "QubitUnitary":
            state = apply_unitary(U, 3)
        elif op.name == "BasisState":
            state = np.array([0, 0, 0, 0, 0, 0, 0, 1])
        elif op.name == "CPHASE":
            state = apply_unitary(test_operation_map["CPHASE"](0.432, 2), 3)
        elif op.name == "ISWAP":
            state = apply_unitary(test_operation_map["ISWAP"], 3)
        elif op.name == "PSWAP":
            state = apply_unitary(test_operation_map["PSWAP"](0.432), 3)
        else:
            state = apply_unitary(op.matrix, 3)

        with qml.tape.QuantumTape() as tape:
            qml.apply(op)
            obs

        dev.apply(tape.operations, rotations=tape.diagonalizing_gates)

        dev._samples = dev.generate_samples()

        res = dev.expval(obs.obs)
        expected = np.vdot(state, np.kron(np.kron(Z, I), I) @ state)

        # verify the device is now in the expected state
        # Note we have increased the tolerance here, since we are only
        # performing 1024 shots.
        self.assertAllAlmostEqual(res, expected, delta=3 / np.sqrt(shots))
Example #12
0
 def normalise(a1):
     return (np.vdot(a1, a1))
Example #13
0
def natural_gradient(params):
    """Calculate the natural gradient of the qnode() cost function.
    The code you write for this challenge should be completely contained within this function
    between the # QHACK # comment markers.
    You should evaluate the metric tensor and the gradient of the QNode, and then combine these
    together using the natural gradient definition. The natural gradient should be returned as a
    NumPy array.
    The metric tensor should be evaluated using the equation provided in the problem text. Hint:
    you will need to define a new QNode that returns the quantum state before measurement.
    Args:
        params (np.ndarray): Input parameters, of dimension 6
    Returns:
        np.ndarray: The natural gradient evaluated at the input parameters, of dimension 6
    """

    natural_grad = np.zeros(6)

    # QHACK #

    dcircuit = qml.grad(qnode, argnum=0)
    normal_grad = dcircuit(params)

    def normalise(a1):
        return (np.vdot(a1, a1))

    qml.enable_tape()

    @qml.qnode(dev)
    def circuit(params):
        variational_circuit(params)
        return qml.state()

    F_matrix = np.zeros([6, 6], dtype=np.float64)
    initial_prod = circuit(params)
    s = np.pi / 2
    for i in range(6):
        for j in range(6):
            params[i] += s
            params[j] += s
            a11 = circuit(params)
            params[j] -= 2 * s
            a22 = circuit(params)
            params[i] -= 2 * s
            a44 = circuit(params)
            params[j] += 2 * s
            a33 = circuit(params)
            params[i] += s
            params[j] -= s
            aa1 = np.vdot(a11, initial_prod)
            a1 = normalise(aa1)
            aa2 = np.vdot(a22, initial_prod)
            a2 = normalise(aa2)
            aa3 = np.vdot(a33, initial_prod)
            a3 = normalise(aa3)
            aa4 = np.vdot(a44, initial_prod)
            a4 = normalise(aa4)
            #print(str((a2 + a3 - a1 - a4)/8.0))
            #print(a1)
            F_matrix[i][j] = (np.absolute(a2) + np.absolute(a3) -
                              np.absolute(a1) - np.absolute(a4)) / 8.0

    #print(circuit(params))
    final_F = np.linalg.inv(F_matrix)
    natural_grad = final_F.dot(normal_grad)
    # QHACK #

    return natural_grad