Exemple #1
0
def target_alignment(
    X,
    Y,
    kernel,
    assume_normalized_kernel=False,
    rescale_class_labels=True,
):
    """Kernel-target alignment between kernel and labels."""

    K = qml.kernels.square_kernel_matrix(
        X,
        kernel,
        assume_normalized_kernel=assume_normalized_kernel,
    )

    if rescale_class_labels:
        nplus = np.count_nonzero(np.array(Y) == 1)
        nminus = len(Y) - nplus
        _Y = np.array([y / nplus if y == 1 else y / nminus for y in Y])
    else:
        _Y = np.array(Y)

    T = np.outer(_Y, _Y)
    inner_product = np.sum(K * T)
    norm = np.sqrt(np.sum(K * K) * np.sum(T * T))
    inner_product = inner_product / norm

    return inner_product
    def test_fock_density_matrix(self, tol):
        """Test that the FockDensityMatrix gate works correctly"""
        dm = np.outer(psi, psi.conj())

        wires = [0]

        gate_name = "FockDensityMatrix"
        operation = qml.FockDensityMatrix

        cutoff_dim = 10
        dev = qml.device("strawberryfields.fock", wires=2, cutoff_dim=cutoff_dim)

        sf_operation = dev._operation_map[gate_name]

        assert dev.supports_operation(gate_name)

        @qml.qnode(dev)
        def circuit(*args):
            qml.TwoModeSqueezing(0.1, 0, wires=[0, 1])
            operation(*args, wires=wires)
            return qml.expval(qml.NumberOperator(0)), qml.expval(qml.NumberOperator(1))

        res = circuit(dm)
        sf_res = SF_gate_reference(sf_operation, cutoff_dim, wires, dm)
        assert np.allclose(res, sf_res, atol=tol, rtol=0)
def model_cost(params, E_A, E_B, E_C, E_D):
    """Compute the model cost for relative parameters and given function data.
    Args:
        params (array[float]): Relative parameters at which to evaluate the model.
        E_A (float): Coefficients E^(A) in the model.
        E_B (array[float]): Coefficients E^(B) in the model.
        E_C (array[float]): Coefficients E^(C) in the model.
        E_D (array[float]): Coefficients E^(D) in the model.
            The lower left triangular part and diagonal must be 0.
    Returns:
        cost (float): The model cost at the relative parameters.
    """
    A = np.prod(np.cos(0.5 * params)**2)
    # For the other terms we only compute the prefactor relative to A
    B_over_A = 2 * np.tan(0.5 * params)
    C_over_A = B_over_A**2 / 2
    D_over_A = np.outer(B_over_A, B_over_A)
    all_terms_over_A = [
        E_A,
        np.dot(E_B, B_over_A),
        np.dot(E_C, C_over_A),
        np.dot(B_over_A, E_D @ B_over_A),
    ]
    cost = A * np.sum(all_terms_over_A)

    return cost
Exemple #4
0
def density_matrix(alpha):
    """Creates a density matrix from a pure state."""
    # DO NOT MODIFY anything in this code block
    psi = alpha * np.array([1, 0], dtype=float) + np.sqrt(1 - alpha**2) * np.array(
        [0, 1], dtype=float
    )
    psi = np.kron(psi, np.array([1, 0, 0, 0], dtype=float))
    return np.outer(psi, np.conj(psi))
Exemple #5
0
def mitigate_depolarizing_noise(K, num_wires, method, use_entries=None):
    r"""Estimate depolarizing noise rate(s) using on the diagonal entries of a kernel
    matrix and mitigate the noise, assuming a global depolarizing noise model.

    Args:
        K (array[float]): Noisy kernel matrix.
        num_wires (int): Number of wires/qubits of the quantum embedding kernel.
        method (``'single'`` | ``'average'`` | ``'split_channel'``): Strategy for mitigation

            * ``'single'``: An alias for ``'average'`` with ``len(use_entries)=1``.
            * ``'average'``: Estimate a global noise rate based on the average of the diagonal
              entries in ``use_entries``, which need to be measured on the quantum computer.
            * ``'split_channel'``: Estimate individual noise rates per embedding, requiring
              all diagonal entries to be measured on the quantum computer.
        use_entries (array[int]): Diagonal entries to use if method in ``['single', 'average']``.
            If ``None``, defaults to ``[0]`` (``'single'``) or ``range(len(K))`` (``'average'``).

    Returns:
        array[float]: Mitigated kernel matrix.

    Reference:
        This method is introduced in Section V in
        `arXiv:2105.02276 <https://arxiv.org/abs/2105.02276>`_.

    **Example:**

    For an example usage of ``mitigate_depolarizing_noise`` please refer to the
    `PennyLane demo on the kernel module <https://github.com/PennyLaneAI/qml/tree/master/demonstrations/tutorial_kernel_module.py>`_ or `the postprocessing demo for arXiv:2105.02276 <https://github.com/thubregtsen/qhack/blob/master/paper/post_processing_demo.py>`_.
    """
    dim = 2**num_wires

    if method == "single":
        if use_entries is None:
            use_entries = (0, )
        diagonal_element = K[use_entries[0], use_entries[0]]
        noise_rate = (1 - diagonal_element) * dim / (dim - 1)
        mitigated_matrix = (K - noise_rate / dim) / (1 - noise_rate)

    elif method == "average":
        if use_entries is None:
            diagonal_elements = np.diag(K)
        else:
            diagonal_elements = np.diag(K)[np.array(use_entries)]
        noise_rates = (1 - diagonal_elements) * dim / (dim - 1)
        mean_noise_rate = np.mean(noise_rates)
        mitigated_matrix = (K - mean_noise_rate / dim) / (1 - mean_noise_rate)

    elif method == "split_channel":
        eff_noise_rates = np.clip((1 - np.diag(K)) * dim / (dim - 1), 0.0, 1.0)
        noise_rates = 1 - np.sqrt(1 - eff_noise_rates)
        inverse_noise = (-np.outer(noise_rates, noise_rates) +
                         noise_rates.reshape(
                             (1, len(K))) + noise_rates.reshape((len(K), 1)))
        mitigated_matrix = (K - inverse_noise / dim) / (1 - inverse_noise)

    return mitigated_matrix
 def BuildDensityBasisState(self, params, num=0):
     '''
     Build density matrix associated
     to params and initial basis state
     '''
     # Get device state
     self.ThermalQNode(params, i=Dec2nbitBin(num, self.num_spins))
     state = self.device.state
     # Return density matrix
     return np.outer(state, np.conj(state))
Exemple #7
0
def _reduced_row_echelon(binary_matrix):
    r"""Returns the reduced row echelon form (RREF) of a matrix in a binary finite field :math:`\mathbb{Z}_2`.

    Args:
        binary_matrix (array[int]): binary matrix representation of the Hamiltonian
    Returns:
        array[int]: reduced row-echelon form of the given `binary_matrix`

    **Example**

    >>> binary_matrix = np.array([[1, 0, 0, 0, 0, 1, 0, 0],
    ...                           [1, 0, 1, 0, 0, 0, 1, 0],
    ...                           [0, 0, 0, 1, 1, 0, 0, 1]])
    >>> _reduced_row_echelon(binary_matrix)
    array([[1, 0, 0, 0, 0, 1, 0, 0],
           [0, 0, 1, 0, 0, 1, 1, 0],
           [0, 0, 0, 1, 1, 0, 0, 1]])
    """
    rref_mat = binary_matrix.copy()
    shape = rref_mat.shape
    icol = 0

    for irow in range(shape[0]):

        while icol < shape[1] and not rref_mat[irow][icol]:

            # get the nonzero indices in the remainder of column icol
            non_zero_idx = rref_mat[irow:, icol].nonzero()[0]

            if len(non_zero_idx
                   ) == 0:  # if remainder of column icol is all zero
                icol += 1
            else:
                # find value and index of largest element in remainder of column icol
                krow = irow + non_zero_idx[0]

                # swap rows krow and irow
                rref_mat[irow, icol:], rref_mat[krow, icol:] = (
                    rref_mat[krow, icol:].copy(),
                    rref_mat[irow, icol:].copy(),
                )
        if icol < shape[1] and rref_mat[irow][icol]:

            # store remainder right hand side columns of the pivot row irow
            rpvt_cols = rref_mat[irow, icol:].copy()

            # get the column icol and set its irow element to 0 to avoid XORing pivot row with itself
            currcol = rref_mat[:, icol].copy()
            currcol[irow] = 0

            # XOR the right hand side of the pivot row irow with all of the other rows
            rref_mat[:, icol:] ^= np.outer(currcol, rpvt_cols)
            icol += 1

    return rref_mat.astype(int)
def matrix_norm(mixed_state, pure_state):
    """Computes the matrix one-norm of the difference between mixed and pure states.

    Args:
        - mixed_state (np.tensor): A density matrix
        - pure_state (np.tensor): A pure state

    Returns:
        - (float): The matrix one-norm
    """

    return np.sum(np.abs(mixed_state - np.outer(pure_state, np.conj(pure_state))))
    def test_two_qubit_observable(self):
        """Tests expval for two-qubit observables """
        self.logTestName()
        dev = qml.device("default.qubit", wires=2)

        @qml.qnode(dev)
        def circuit(x, target_observable=None):
            qml.RX(x[0], wires=0)
            qml.RY(x[1], wires=0)
            qml.RZ(x[2], wires=0)
            qml.CNOT(wires=[0, 1])
            return qml.expval(qml.Hermitian(target_observable, wires=[0, 1]))

        target_state = 1 / np.sqrt(2) * np.array([1, 0, 0, 1])
        target_herm_op = np.outer(target_state.conj(), target_state)
        weights = np.array([0.5, 0.1, 0.2])
        expval = circuit(weights, target_observable=target_herm_op)
        self.assertAlmostEqual(expval, 0.590556, delta=self.tol)
    def test_fock_density_matrix_unsupported(self, tol):
        """Test that the FockDensityMatrix gate is unsupported for the gaussian
        simulator"""
        dm = np.outer(psi, psi.conj())

        wires = [0]

        gate_name = "FockDensityMatrix"
        operation = qml.FockDensityMatrix

        dev = qml.device("strawberryfields.gaussian", wires=2)

        @qml.qnode(dev)
        def circuit(*args):
            operation(*args, wires=wires)
            return qml.expval(qml.NumberOperator(0)), qml.expval(qml.NumberOperator(1))

        with pytest.raises(
            qml.DeviceError,
            match="Gate {} not supported " "on device strawberryfields.gaussian".format(gate_name),
        ):
            circuit(dm)
Exemple #11
0
def polarity(
    X,
    Y,
    kernel,
    assume_normalized_kernel=False,
    rescale_class_labels=True,
    normalize=False,
):
    r"""Polarity of a given kernel function.

    For a dataset with feature vectors :math:`\{x_i\}` and associated labels :math:`\{y_i\}`,
    the polarity of the kernel function :math:`k` is given by

    .. math ::

        \operatorname{P}(k) = \sum_{i,j=1}^n y_i y_j k(x_i, x_j)

    If the dataset is unbalanced, that is if the numbers of datapoints in the
    two classes :math:`n_+` and :math:`n_-` differ,
    ``rescale_class_labels=True`` will apply a rescaling according to
    :math:`\tilde{y}_i = \frac{y_i}{n_{y_i}}`. This is activated by default
    and only results in a prefactor that depends on the size of the dataset
    for balanced datasets.

    The keyword argument ``assume_normalized_kernel`` is passed to
    :func:`~.kernels.square_kernel_matrix`, for the computation
    :func:`~.utils.frobenius_inner_product` is used.

    Args:
        X (list[datapoint]): List of datapoints.
        Y (list[float]): List of class labels of datapoints, assumed to be either -1 or 1.
        kernel ((datapoint, datapoint) -> float): Kernel function that maps datapoints to kernel value.
        assume_normalized_kernel (bool, optional): Assume that the kernel is normalized, i.e.
            the kernel evaluates to 1 when both arguments are the same datapoint.
        rescale_class_labels (bool, optional): Rescale the class labels. This is important to take
            care of unbalanced datasets.
        normalize (bool): If True, rescale the polarity to the target_alignment.

    Returns:
        float: The kernel polarity.

    **Example:**

    Consider a simple kernel function based on :class:`~.templates.embeddings.AngleEmbedding`:

    .. code-block :: python

        dev = qml.device('default.qubit', wires=2, shots=None)
        @qml.qnode(dev)
        def circuit(x1, x2):
            qml.templates.AngleEmbedding(x1, wires=dev.wires)
            qml.adjoint(qml.templates.AngleEmbedding)(x2, wires=dev.wires)
            return qml.probs(wires=dev.wires)

        kernel = lambda x1, x2: circuit(x1, x2)[0]

    We can then compute the polarity on a set of 4 (random) feature
    vectors ``X`` with labels ``Y`` via

    >>> X = np.random.random((4, 2))
    >>> Y = np.array([-1, -1, 1, 1])
    >>> qml.kernels.polarity(X, Y, kernel)
    tensor(0.04361349, requires_grad=True)
    """
    K = square_kernel_matrix(X, kernel, assume_normalized_kernel=assume_normalized_kernel)

    if rescale_class_labels:
        nplus = np.count_nonzero(np.array(Y) == 1)
        nminus = len(Y) - nplus
        _Y = np.array([y / nplus if y == 1 else y / nminus for y in Y])
    else:
        _Y = np.array(Y)

    T = np.outer(_Y, _Y)

    return frobenius_inner_product(K, T, normalize=normalize)
    def test_supported_fock_gates(self):
        """Test that all supported gates work correctly"""
        self.logTestName()
        cutoff_dim = 10
        a = 0.312
        b = 0.123
        c = 0.532
        d = 0.124

        dev = qml.device('strawberryfields.fock',
                         wires=2,
                         cutoff_dim=cutoff_dim)

        gates = list(dev._operation_map.items())
        for g, sfop in gates:
            log.info('\tTesting gate {}...'.format(g))
            self.assertTrue(dev.supports_operation(g))

            op = getattr(qml.ops, g)
            if g == "Interferometer":
                wires = [0, 1]
            elif op.num_wires is (qml.operation.Wires.Any
                                  or qml.operation.Wires.All):
                wires = [0]
            else:
                wires = list(range(op.num_wires))

            @qml.qnode(dev)
            def circuit(*args):
                qml.TwoModeSqueezing(0.1, 0, wires=[0, 1])
                op(*args, wires=wires)
                return qml.expval(qml.NumberOperator(0)), qml.expval(
                    qml.NumberOperator(1))

            # compare to reference SF engine
            def SF_reference(*args):
                """SF reference circuit"""
                eng = sf.Engine("fock",
                                backend_options={"cutoff_dim": cutoff_dim})
                prog = sf.Program(2)
                with prog.context as q:
                    sf.ops.S2gate(0.1) | q
                    sfop(*args) | [q[i] for i in wires]

                state = eng.run(prog).state
                return state.mean_photon(0)[0], state.mean_photon(1)[0]

            if g == 'GaussianState':
                r = np.array([0, 0])
                V = np.array([[0.5, 0], [0, 2]])
                self.assertAllEqual(circuit(V, r), SF_reference(V, r))
            elif g == 'Interferometer':
                self.assertAllEqual(circuit(U), SF_reference(U))
            elif g == 'FockDensityMatrix':
                dm = np.outer(psi, psi.conj())
                self.assertAllEqual(circuit(dm), SF_reference(dm))
            elif g == 'FockStateVector':
                self.assertAllEqual(circuit(psi), SF_reference(psi))
            elif g == 'FockState':
                self.assertAllEqual(circuit(1), SF_reference(1))
            elif g == "DisplacedSqueezedState":
                self.assertAllEqual(circuit(a, b, c, d),
                                    SF_reference(a * np.exp(1j * b), c, d))
            elif g == "CatState":
                self.assertAllEqual(circuit(a, b, c),
                                    SF_reference(a * np.exp(1j * b), c))
            elif op.num_params == 1:
                self.assertAllEqual(circuit(a), SF_reference(a))
            elif op.num_params == 2:
                self.assertAllEqual(circuit(a, b), SF_reference(a, b))
Exemple #13
0
# + tags=[]
# Merge matrix sets
kernel_matrices = {}
for bnr in noise_probabilities:
    sub_fn = f"{sub_filename.split('.')[0]}_{float(bnr)}_{str([0]+shot_numbers).replace(' ', '').replace(',', '_')}_{num_reps}.dill"
    try:
        sub_mats = load(open(sub_fn, 'rb+'))
        kernel_matrices.update(sub_mats)
    except:
        print(sub_fn)
    

# pure_np_kernel_matrices = {key: pure_np.asarray(mat) for key, mat in kernel_matrices.items()}
# dump(pure_np_kernel_matrices, open(filename, 'wb+'))
# + tags=[]
target = np.outer(y_train, y_train)
TA = {}
A = {}
no_noise_mat = kernel_matrices[(0.0, 0)]
for bnr in noise_probabilities:
    no_shot_mat = kernel_matrices[(bnr, 0)]
    for shots in shot_numbers:
        these_mats = [kernel_matrices[(bnr, shots, i)] for i in range(num_reps)]
        these_TA = [qml.math.frobenius_inner_product(mat, target, normalize=True) for mat in these_mats]
        these_A = [qml.math.frobenius_inner_product(mat, no_noise_mat, normalize=True) for mat in these_mats]
        TA[(bnr, shots)] = qml.math.stack(these_TA)
        A[(bnr, shots)] = qml.math.stack(these_A)
    TA[(bnr, 0)] = qml.math.frobenius_inner_product(no_shot_mat, target, normalize=True)
    A[(bnr, 0)] = qml.math.frobenius_inner_product(no_shot_mat, no_noise_mat, normalize=True)

# + tags=[]
import pennylane as qml
from pennylane import numpy as np
from tqdm.notebook import tqdm

# ## Pennylane version
#
# Define the device `default.qubit` and a circuit where one layer contains a general rotation $R(\phi, \theta, \omega) = R_z(\omega)R_x(\theta)R_z(\phi)$ on each qubit, followed by entangling gates. We apply 2 layers. The $R(\phi, \theta, \omega)$ gate is a native in pennylane `qml.Rot()`. We use 4 qubits.

# In[2]:

dev1 = qml.device("default.qubit", wires=4)

# In[3]:

target_state = np.ones(2**4) / np.sqrt(2**4)
density = np.outer(target_state, target_state)


@qml.qnode(dev1)
def circuit(params):
    for j in range(2):  # 2 layers
        for i in range(4):  # 4 qubits
            qml.Rot(*params[j][i], wires=i)
        qml.CNOT(wires=[0, 1])
        qml.CNOT(wires=[2, 3])
        qml.CNOT(wires=[1, 2])
    return qml.expval(qml.Hermitian(density, wires=[0, 1, 2, 3]))


# Define a cost function. In our case we want the overlap of the circuit output to be maximal with the targe_state. Therefore we minimize $1-\frac{1}{\sqrt{|\Sigma|}}\sum_{\sigma_i}\langle \sigma_i | V(\theta) | 0000\rangle$
Exemple #15
0
def density_matrix(state):
    """  Calculates the density matrix representation of a state (a state is a complex vector
         in the canonical basis representation). The density matrix is a Hermitian operator.
    """
    return np.outer(np.conj(state), state)