Exemple #1
0
    def Fubini_elem(qnode2, params, i, j):

        # print(dev._state)

        #elem 1
        shifted = params.copy()
        shifted[i] += np.pi / 2
        shifted[j] += np.pi / 2
        ket = qnode2(shifted)  # forward evaluation
        bra = qnode2(params)
        inner_prod_sq1 = np.abs(bra.T @ np.conjugate(ket))**2

        #elem 2
        shifted = params.copy()
        shifted[i] += np.pi / 2
        shifted[j] -= np.pi / 2
        ket = qnode2(shifted)  # forward evaluation
        inner_prod_sq2 = np.abs(bra.T @ np.conjugate(ket))**2

        #elem 3
        shifted = params.copy()
        shifted[i] -= np.pi / 2
        shifted[j] += np.pi / 2
        ket = qnode2(shifted)  # forward evaluation
        inner_prod_sq3 = np.abs(bra.T @ np.conjugate(ket))**2

        #elem 4
        shifted = params.copy()
        shifted[i] -= np.pi / 2
        shifted[j] -= np.pi / 2
        ket = qnode2(shifted)  # forward evaluation
        inner_prod_sq4 = np.abs(bra.T @ np.conjugate(ket))**2

        return (1 / 8) * (-inner_prod_sq1 + inner_prod_sq2 + inner_prod_sq3 -
                          inner_prod_sq4)
def target_function(x):
    """Generate a truncated Fourier series, where the data gets re-scaled."""
    res = coeff0
    for idx, coeff in enumerate(coeffs):
        exponent = np.complex(0, scaling * (idx + 1) * x)
        conj_coeff = np.conjugate(coeff)
        res += coeff * np.exp(exponent) + conj_coeff * np.exp(-exponent)
    return np.real(res)
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
    """

    # QHACK #
    def get_state(params):
        """ Get the state before a measurement """
        qnode(params)
        return dev.state

    # Calculate the unshifted state (its conjugate transpose)
    state_unshifted = np.conjugate(get_state(params)).T

    def shift_vector(i):
        vector = np.zeros(6)
        vector[i] = 1
        return vector

    metric_tensor = np.zeros((6, 6))

    for i in range(6):
        for j in range(i + 1):

            state_shifted_1 = get_state(params +
                                        (shift_vector(i) + shift_vector(j)) *
                                        np.pi / 2)
            state_shifted_2 = get_state(params +
                                        (shift_vector(i) - shift_vector(j)) *
                                        np.pi / 2)
            state_shifted_3 = get_state(params +
                                        (-shift_vector(i) + shift_vector(j)) *
                                        np.pi / 2)
            state_shifted_4 = get_state(params -
                                        (shift_vector(i) + shift_vector(j)) *
                                        np.pi / 2)

            metric_tensor[
                i,
                j] = (-np.abs(np.dot(state_unshifted, state_shifted_1))**2 +
                      np.abs(np.dot(state_unshifted, state_shifted_2))**2 +
                      np.abs(np.dot(state_unshifted, state_shifted_3))**2 -
                      np.abs(np.dot(state_unshifted, state_shifted_4))**2) / 8

            if i != j:
                metric_tensor[j, i] = metric_tensor[i, j]

    grad = qml.grad(qnode)
    gradient = grad(params)[0]

    metric_tensor_inv = np.linalg.inv(metric_tensor)

    natural_grad = np.dot(metric_tensor_inv, gradient)

    # QHACK #

    return natural_grad
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], dtype=np.float64)

    # QHACK #
    gradient = np.zeros([6], dtype=np.float64)

    for i in range(len(params)):
        shifted = params.copy()
        shifted[i] += np.pi / 2
        forward = qnode(shifted)  # forward evaluation:f(theta+s e_i)

        shifted[i] -= np.pi
        backward = qnode(shifted)  # backward evaluation: f(theta-s e_i)
        gradient[i] = 0.5 * (forward - backward)

    @qml.qnode(dev)
    def qnode_shifted(params, i, j, s1, s2):
        shifted = params.copy()
        shifted[i] += s1
        shifted[j] += s2

        variational_circuit(shifted)

        return qml.state()  #qml.expval(qml.PauliX(1))

    F = np.zeros([6, 6])
    for j in range(len(params)):
        for i in range(len(params)):
            F[i, j] = 0.125 * (-np.abs(
                np.conjugate(np.transpose(qnode_shifted(params, i, j, 0, 0)))
                @ qnode_shifted(params, i, j, np.pi / 2, np.pi / 2)
            )**2 + np.abs(
                np.conjugate(np.transpose(qnode_shifted(params, i, j, 0, 0)))
                @ qnode_shifted(params, i, j, np.pi / 2, -np.pi / 2)
            )**2 + np.abs(
                np.conjugate(np.transpose(qnode_shifted(params, i, j, 0, 0)))
                @ qnode_shifted(params, i, j, -np.pi / 2, np.pi / 2)
            )**2 - np.abs(
                np.conjugate(np.transpose(qnode_shifted(params, i, j, 0, 0)))
                @ qnode_shifted(params, i, j, -np.pi / 2, -np.pi / 2))**2)
    #natural_grad=np.linalg.pinv(F)@gradient
    #print(np.round(F,8))
    #print()
    #print(qml.metric_tensor(qnode)(params))
    natural_grad = np.linalg.pinv(F) @ gradient
    # QHACK #
    return natural_grad
Exemple #5
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)

    gradient = np.zeros([natural_grad.shape[0]])
    fim = np.zeros([natural_grad.shape[0], natural_grad.shape[0]])

    eps = np.pi / 2

    for k in range(gradient.shape[0]):
        eps_plus = params.copy()
        eps_plus[k] += eps
        exp_value_plus = qnode(eps_plus)

        eps_minus = params.copy()
        eps_minus[k] -= eps
        exp_value_minus = qnode(eps_minus)

        gradient[k] = (exp_value_plus - exp_value_minus) / (2 * np.sin(eps))

    eps = np.pi / 2

    qnode(params)
    state = dev.state
    for k in range(natural_grad.shape[0]):
        for l in range(gradient.shape[0]):
            if l <= k:
                eps_pp = params.copy()
                eps_pp[k] += eps
                eps_pp[l] += eps

                eps_pm = params.copy()
                eps_pm[k] += eps
                eps_pm[l] -= eps

                eps_mp = params.copy()
                eps_mp[k] -= eps
                eps_mp[l] += eps

                eps_mm = params.copy()
                eps_mm[k] -= eps
                eps_mm[l] -= eps

                qnode(eps_pp)
                state_pp = dev.state
                measure_pp = np.abs(np.conjugate(state) @ state_pp)

                qnode(eps_pm)
                state_pm = dev.state
                measure_pm = np.abs(np.conjugate(state) @ state_pm)

                qnode(eps_mp)
                state_mp = dev.state
                measure_mp = np.abs(np.conjugate(state) @ state_mp)

                qnode(eps_mm)
                state_mm = dev.state
                measure_mm = np.abs(np.conjugate(state) @ state_mm)

                fim[k, l] = (-measure_pp**2 - measure_mm**2 + measure_mp**2 +
                             measure_pm**2) / 8

    for k in range(natural_grad.shape[0]):
        for l in range(natural_grad.shape[0]):
            if l > k:
                fim[k, l] = fim[l, k]

    natural_grad = np.dot(np.linalg.inv(fim), gradient)

    return natural_grad