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 mt(*params):
        state = qnode(*params)
        rqnode = lambda *params: np.real(qnode(*params))
        iqnode = lambda *params: np.imag(qnode(*params))
        rjac = qml.jacobian(rqnode)(*params)
        ijac = qml.jacobian(iqnode)(*params)

        if isinstance(rjac, tuple):
            out = []
            for rc, ic in zip(rjac, ijac):
                c = rc + 1j * ic
                psidpsi = np.tensordot(np.conj(state), c, axes=([0], [0]))
                out.append(
                    np.real(
                        np.tensordot(np.conj(c), c, axes=([0], [0])) -
                        np.tensordot(np.conj(psidpsi), psidpsi, axes=0)))
            return tuple(out)

        jac = rjac + 1j * ijac
        psidpsi = np.tensordot(np.conj(state), jac, axes=([0], [0]))
        return np.real(
            np.tensordot(np.conj(jac), jac, axes=([0], [0])) -
            np.tensordot(np.conj(psidpsi), psidpsi, axes=0))
예제 #3
0
# get the fourier transformed values and seperate argument and absolute value
complex_vals = np.fft.fft(c)
scale_arg = np.angle(complex_vals)
scale_abs = np.absolute(complex_vals)

# get the required squeeze scaling argument
r1 = -np.log(scale_abs)

# perform a neural network feed forward using the transformed Fourier matrix, the required phase shift using a rotation gate (phase gate),
# the required squeeze scaling and the Fourier matrix

circ_res = quantum_circ1(x=x,
                         phi_x=phi_x,
                         U1=F_H,
                         U2=F,
                         r=r1,
                         phi_r=phi_r,
                         phi_rot=scale_arg)

# theoretical transformation
mat = F @ np.diag(scale_abs * np.exp(1J * scale_arg)) @ F_H

# applied theoretical result to the input
theo_res = np.real(mat @ x)

# difference int the theoretical transform and the actual result of the circuit
print('theo')
print(theo_res)
print('actual')
print(circ_res)
ang = get_angles(x)


@qml.qnode(dev)
def test(angles=None):

    statepreparation(angles)

    return qml.expval(qml.PauliZ(0))


test(angles=ang)

print("x               : ", x)
print("angles          : ", ang)
print("amplitude vector: ", np.real(dev._state))

##############################################################################
# Note that the ``default.qubit`` simulator provides a shortcut to
# ``statepreparation`` with the command
# ``qml.QubitStateVector(x, wires=[0, 1])``. However, some devices may not
# support an arbitrary state-preparation routine.
#
# Since we are working with only 2 qubits now, we need to update the layer
# function as well.


def layer(W):
    qml.Rot(W[0, 0], W[0, 1], W[0, 2], wires=0)
    qml.Rot(W[1, 0], W[1, 1], W[1, 2], wires=1)
    qml.CNOT(wires=[0, 1])
예제 #5
0
 def loss_fn(x):
     res = func(x)
     return anp.real(
         res
     )  # This errors without the real. Likely an issue with complex
n_coeffs = 5
n_samples = 100

coeffs = []
for i in range(n_samples):

    weights = random_weights()

    def f(x):
        return np.array([quantum_model(weights, x_) for x_ in x])

    coeffs_sample = fourier_coefficients(f, n_coeffs)
    coeffs.append(coeffs_sample)

coeffs = np.array(coeffs)
coeffs_real = np.real(coeffs)
coeffs_imag = np.imag(coeffs)

######################################################################
# Let's plot the real vs. the imaginary part of the coefficients. As a
# sanity check, the :math:`c_0` coefficient should be real, and therefore
# have no contribution on the y-axis.
#

n_coeffs = len(coeffs_real[0])

fig, ax = plt.subplots(1, n_coeffs, figsize=(15, 4))

for idx, ax_ in enumerate(ax):
    ax_.set_title(r"$c_{}$".format(idx))
    ax_.scatter(coeffs_real[:, idx],
예제 #7
0
def second_renyi_entropy(rho):
    """Computes the second Renyi entropy of a given density matrix."""
    # DO NOT MODIFY anything in this code block
    rho_diag_2 = np.diagonal(rho)**2.0
    return -np.real(np.log(np.sum(rho_diag_2)))
예제 #8
0
# Finally, we see how the approximation improves as we increase the
# number of snapshots. We run the estimator 10 times for each :math:`N`.

number_of_runs = 10
snapshots_range = [100, 1000, 6000]
distances = np.zeros((number_of_runs, len(snapshots_range)))

# run the estimation multiple times so that we can include error bars
for i in range(number_of_runs):
    for j, num_snapshots in enumerate(snapshots_range):
        shadow = calculate_classical_shadow(
            bell_state_circuit, params, num_snapshots, num_qubits
        )
        shadow_state = shadow_state_reconstruction(shadow)

        distances[i, j] = np.real(operator_2_norm(bell_state - shadow_state))

plt.errorbar(
    snapshots_range,
    np.mean(distances, axis=0),
    yerr=np.std(distances, axis=0),
)
plt.title("Distance between Ideal and Shadow Bell States")
plt.xlabel("Number of Snapshots")
plt.ylabel("Distance")
plt.show()

##############################################################################
# As expected, when the number of snapshots increases, the state reconstruction
# becomes closer to the ideal state.
 def cost(self, weights, inputs_1=None, inputs_2=None):
     ensemble_1 = self.embedding.generate_ensemble(inputs_1, weights)
     ensemble_2 = self.embedding.generate_ensemble(inputs_2, weights)
     observable = self.class_priors[0] * ensemble_1 - self.class_priors[
         1] * ensemble_2
     return 1 - np.real(np.trace(observable @ observable))