Пример #1
0
 def perturb(
     self,
     amount: Optional[Union[int, float]] = None,
     mode: PerturbationMode = PerturbationMode.INVERT,
 ):
     count = self._count_for_amount(amount=amount)
     if count == 0:
         return
     if mode == PerturbationMode.SET:
         indices = np.argwhere(~self.mask)
     elif mode == PerturbationMode.INVERT:
         indices = np.array([list(index) for index in np.ndindex(*self.mask.shape)])
     elif mode == PerturbationMode.RESET:
         indices = np.argwhere(self.mask)
     else:
         raise NotImplementedError(f"The perturbation mode {mode} is not supported")
     if indices.size == 0:
         return
     indices = tuple(
         zip(
             *indices[
                 np.random.choice(
                     len(indices), min(count, len(indices)), replace=False
                 )
             ]
         )
     )
     self[indices] = ~self.mask[indices]
Пример #2
0
    def __setitem__(self, key, value: T):
        """
        Convenience function to set the value of a specific position of the
        encapsulated :py:attr:`~.mask`.

        Attention: when working with multi-dimensional masks please use tuple
        convention for accessing the elements as otherwise changes are not
        recognised and a `MaskedCircuit` cannot be informed about changes.

        Instead of

            .. code:
                mask[2][2] = True

        please use

            .. code:
                mask[2, 2] = True
        """
        if isinstance(key, int) or isinstance(key, slice) or isinstance(key, tuple):
            if self._parent is not None:
                before = self.mask.copy()
                self.mask[key] = value
                delta_indices = np.argwhere(before != self.mask)
                self._parent.mask_changed(self, delta_indices)
            else:
                self.mask[key] = value
        else:
            raise NotImplementedError(f"key {key}")
Пример #3
0
    def perturb(
        self,
        amount: Optional[Union[int, float]] = None,
        mode: PerturbationMode = PerturbationMode.INVERT,
    ):
        """
        Perturbs the Mask by the given ``mode`` of type :py:class:`~.PerturbationMode`
        ``amount`` times. If no amount is given or ``amount=None``, a random ``amount``
        is determined given by the actual size of the py:attr:`~.mask`. If ``amount``
        is smaller than `1`, it is interpreted as the fraction of the py:attr:`~.mask` s
        size.
        Note that the ``amount`` is automatically limited to the actual size of the
        py:attr:`~.mask`.

        :param amount: Number of items to perturb given either by an absolute amount
            when amount >= 1 or a fraction of the mask, defaults to None
        :param mode: How to perturb, defaults to PerturbationMode.INVERT
        :raises NotImplementedError: Raised in case of an unknown mode
        """
        assert (
            amount is None or amount >= 0
        ), "Negative values are not supported, please use PerturbationMode.REMOVE"
        if amount is not None:
            if amount < 1:
                amount *= self.mask.size
            amount = round(amount)
        count = abs(amount) if amount is not None else rand.randrange(
            0, self.mask.size)
        if count == 0:
            return
        if mode == PerturbationMode.ADD:
            indices = np.argwhere(~self.mask)
        elif mode == PerturbationMode.INVERT:
            indices = np.array(
                [list(index) for index in np.ndindex(*self.mask.shape)])
        elif mode == PerturbationMode.REMOVE:
            indices = np.argwhere(self.mask)
        else:
            raise NotImplementedError(
                f"The perturbation mode {mode} is not supported")
        if indices.size == 0:
            return
        indices = tuple(
            zip(*indices[np.random.choice(
                len(indices), min(count, len(indices)), replace=False)]))
        self[indices] = ~self.mask[indices]
Пример #4
0
def _simplify(h, cutoff=1.0e-12):
    r"""Add together identical terms in the Hamiltonian.

    The Hamiltonian terms with identical Pauli words are added together and eliminated if the
    overall coefficient is zero.

    Args:
        h (Hamiltonian): PennyLane Hamiltonian
        cutoff (float): cutoff value for discarding the negligible terms

    Returns:
        Hamiltonian: Simplified PennyLane Hamiltonian

    **Example**

    >>> c = np.array([0.5, 0.5])
    >>> h = qml.Hamiltonian(c, [qml.PauliX(0) @ qml.PauliY(1), qml.PauliX(0) @ qml.PauliY(1)])
    >>> print(_simplify(h))
    (1.0) [X0 Y1]
    """
    s = []
    wiremap = dict(zip(h.wires, range(len(h.wires) + 1)))
    for term in h.terms[1]:
        term = qml.operation.Tensor(term).prune()
        s.append(qml.grouping.pauli_word_to_string(term, wire_map=wiremap))

    o = list(set(s))
    c = [0.0] * len(o)
    for i, item in enumerate(s):
        c[o.index(item)] += h.terms[0][i]
    c = qml.math.stack(c)

    coeffs = []
    ops = []
    nonzero_ind = np.argwhere(abs(c) > cutoff).flatten()
    for i in nonzero_ind:
        coeffs.append(c[i])
        ops.append(qml.grouping.string_to_pauli_word(o[i], wire_map=wiremap))
    try:
        coeffs = qml.math.stack(coeffs)
    except ValueError:
        pass

    return qml.Hamiltonian(coeffs, ops)
Пример #5
0
def kernel(x1, x2, params):
    ansatz(x1, params, wires)
    qml.adjoint(ansatz)(x2, params, wires)
    return qml.expval(qml.Projector([0] * width, wires=wires))


# -
# # Data processing

# +
# load the dataset and split
(train_X, train_y), (test_X, test_y) = mnist.load_data()

sample_size = 1000  # leave high here, if you need lower, change it in next step

train_idx0 = np.argwhere(
    train_y == 0)[:sample_size]  # get the images labelled 0
train_X0 = train_X[train_idx0].squeeze() * np.pi / 255  # normalize

train_idx1 = np.argwhere(
    train_y == 1)[:sample_size]  # get the images labelled 1
train_X1 = train_X[train_idx1].squeeze() * np.pi / 255  # normalized

X_train = np.vstack([train_X0[:sample_size], train_X1[:sample_size]])  # stack
y_train = np.hstack([[-1] * sample_size, [1] * sample_size])  # generate labels

test_idx0 = np.argwhere(test_y == 0)[:sample_size]  # same for test
test_X0 = test_X[test_idx0].squeeze() * np.pi / 255

test_idx1 = np.argwhere(test_y == 1)[:sample_size]
test_X1 = test_X[test_idx1].squeeze() * np.pi / 255
Пример #6
0
 def shrink(self, amount: int = 1):
     index = np.argwhere(self.mask != 0)
     index = index[:amount]
     if index.size > 0:
         self[tuple(zip(*index))] = 0