def perturb( self, amount: Optional[Union[int, float]] = None, mode: PerturbationMode = PerturbationMode.INVERT, value: Optional[float] = np.pi, ): count = self._count_for_amount(amount=amount) if count == 0: return if mode == PerturbationMode.SET: # INVERT might be added here indices = np.array([list(index) for index in np.ndindex(*self.mask.shape)]) elif mode == PerturbationMode.RESET: indices = np.argwhere(self.mask != 0) 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 ) ] ) ) if mode == PerturbationMode.SET and value is not None: self[indices] = value elif mode == PerturbationMode.RESET: self[indices] = 0
def compute_grad( self, objective_fn, args, kwargs ): # pylint: disable=signature-differs,arguments-differ r"""Compute gradient of the objective function, as well as the variance of the gradient, at the given point. Args: objective_fn (function): the objective function for optimization args: arguments to the objective function kwargs: keyword arguments to the objective function Returns: tuple[array[float], array[float]]: a tuple of NumPy arrays containing the gradient :math:`\nabla f(x^{(t)})` and the variance of the gradient """ if isinstance(objective_fn, qml.ExpvalCost): grads = self._single_shot_expval_gradients(objective_fn, args, kwargs) elif isinstance(objective_fn, qml.QNode) or hasattr(objective_fn, "device"): grads = self._single_shot_qnode_gradients(objective_fn, args, kwargs) else: raise ValueError( "The objective function must either be encoded as a single QNode or " "an ExpvalCost object for the Shot adaptive optimizer. " ) # grads will have dimension [max(self.s), *params.shape] # For each parameter, we want to truncate the number of shots to self.s[idx], # and take the mean and the variance. gradients = [] gradient_variances = [] for i, grad in enumerate(grads): p_ind = np.ndindex(*grad.shape[1:]) g = np.zeros_like(grad[0]) s = np.zeros_like(grad[0]) for idx in p_ind: grad_slice = grad[(slice(0, self.s[i][idx]),) + idx] g[idx] = np.mean(grad_slice) s[idx] = np.var(grad_slice, ddof=1) gradients.append(g) gradient_variances.append(s) return gradients, gradient_variances
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 plot_decision_boundaries(classifier, ax, N_gridpoints=14): _xx, _yy = np.meshgrid(np.linspace(-1, 1, N_gridpoints), np.linspace(-1, 1, N_gridpoints)) _zz = np.zeros_like(_xx) for idx in np.ndindex(*_xx.shape): _zz[idx] = classifier.predict( np.array([_xx[idx], _yy[idx]])[np.newaxis, :]) plot_data = {'_xx': _xx, '_yy': _yy, '_zz': _zz} ax.contourf(_xx, _yy, _zz, cmap=mpl.colors.ListedColormap(['#FF0000', '#0000FF']), alpha=.2, levels=[-1, 0, 1]) dataset.plot(ax) return plot_data
def plot_decision_boundaries(classifier, ax, N_gridpoints=14): _xx, _yy = np.meshgrid(np.linspace(-1, 1, N_gridpoints), np.linspace(-1, 1, N_gridpoints)) _zz = np.zeros_like(_xx) for idx in np.ndindex(*_xx.shape): _zz[idx] = classifier.predict( np.array([_xx[idx], _yy[idx]])[np.newaxis, :]) plot_data = {"_xx": _xx, "_yy": _yy, "_zz": _zz} ax.contourf( _xx, _yy, _zz, cmap=mpl.colors.ListedColormap(["#FF0000", "#0000FF"]), alpha=0.2, levels=[-1, 0, 1], ) plot_double_cake_data(X, Y, ax) return plot_data
def test_Rot_gradient(self, mocker, theta, shift, tol): """Tests that the automatic gradient of an arbitrary Euler-angle-parameterized gate is correct.""" spy = mocker.spy(qml.gradients.parameter_shift, "_get_operation_recipe") dev = qml.device("default.qubit", wires=1) params = np.array([theta, theta**3, np.sqrt(2) * theta]) with qml.tape.JacobianTape() as tape: qml.QubitStateVector(np.array([1.0, -1.0], requires_grad=False) / np.sqrt(2), wires=0) qml.Rot(*params, wires=[0]) qml.expval(qml.PauliZ(0)) tape.trainable_params = {1, 2, 3} tapes, fn = qml.gradients.param_shift(tape, shift=shift) assert len(tapes) == 2 * len(tape.trainable_params) autograd_val = fn(dev.batch_execute(tapes)) manualgrad_val = np.zeros_like(autograd_val) for idx in list(np.ndindex(*params.shape)): s = np.zeros_like(params) s[idx] += np.pi / 2 forward = tape.execute(dev, params=params + s) backward = tape.execute(dev, params=params - s) manualgrad_val[0, idx] = (forward - backward) / 2 assert np.allclose(autograd_val, manualgrad_val, atol=tol, rtol=0) assert spy.call_args[1]["shift"] == shift # compare to finite differences tapes, fn = qml.gradients.finite_diff(tape) numeric_val = fn(dev.batch_execute(tapes)) assert np.allclose(autograd_val, numeric_val, atol=tol, rtol=0)