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]
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}")
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]
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)
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
def shrink(self, amount: int = 1): index = np.argwhere(self.mask != 0) index = index[:amount] if index.size > 0: self[tuple(zip(*index))] = 0