class BasePermutation(BasePerturbation): """Base permutation. Main structure to manage the permutation perturbation. """ _perturbtype = "element_permutation" def __init__(self, reindices, auto=True): """Perturbations by permuting elements. Parameters ---------- reindices: np.ndarray the reindices to apply permutation perturbations. """ self._initialization() self.basecoreperturbation = BaseCorePermutationArray(reindices, auto) #self._format_reindices(reindices, auto) ###################### Administrative class functions ##################### def _check_features(self, features): """Check the proper format of features. Parameters ---------- features: np.ndarray, shape (n, m) the features to apply perturbation. """ assert(len(features) == len(self.basecoreperturbation.reindices)) assert(len(features.shape) == 2) # # def _format_reindices(self, reindices, auto=True): # """Format reindices. # # Parameters # ---------- # reindices: np.ndarray or tuple # the reindices to apply permutation perturbations. # # """ # if type(reindices) == np.ndarray: # self.k_perturb = reindices.shape[1] # self.reindices = reindices # elif type(reindices) == tuple: # n, k_perturb = reindices # if check_int(n) and check_int(k_perturb): # auto_indices = [np.arange(n)] if auto else [] # self.k_perturb = k_perturb # self.reindices = np.vstack(auto_indices + # [np.random.permutation(n) # for i in xrange(k_perturb)]).T def _filter_indices(self, i, k): """Filter indices to get the transformed data. Parameters ---------- i: int, list, np.ndarray the indices of elements. k: int, list, np.ndarray the indices of perturbations. Returns ------- i: int, list, np.ndarray the indices of elements. k: int, list, np.ndarray the indices of perturbations. info_input: list the boolean information about the if the input is sequencial or only a unique index. """ info_input = [True, True] ## Check i if type(i) == np.ndarray: i = list(i) elif check_int(i): info_input[0] = False i = [i] assert(type(i) == list) ## Check k k = self._format_k_perturb(k) if type(k) == np.ndarray: k = list(k) elif check_int(k): info_input[1] = False k = [k] assert(type(k) == list) return i, k, info_input def _filter_output(self, result, info_input): """Filter output for 2d array results (locations and features array). Parameters ---------- result: np.ndarray, shape: (ni, ndim, nk) the result we want to format to be output. Returns ------- result: np.ndarray properly formatted adapted to the format of the indices input. """ if not info_input[1]: result = result[:, :, 0] if not info_input[0]: result = result[0] return result ########################### Main class functions ########################## def apply2indices(self, i, k=None): """Apply the transformation to the indices. Parameters ---------- i: int, list or np.ndarray the indices of the elements `i`. k: int, list the perturbation indices. Returns ------- i: int, list or np.ndarray the indices of the elements `i`. """ k = self._format_k_perturb(k) if check_int(i): return self.basecoreperturbation.reindices[i, k] elif type(i) == list: return list(self.basecoreperturbation.reindices[i][:, k]) else: return self.basecoreperturbation.reindices[list(i)][:, k] def _apply2someelements(self, array, i, k): """Apply perturbation to array for individual elements. Parameters ---------- array: np.ndarray the spatial information to be perturbed. k: int (default=None) the perturbation indices. Returns ------- array_p: np.ndarray the spatial information perturbated. """ ## Apply permutation to array rei = self.basecoreperturbation.reindices[i][:, k] array_p = array[rei].swapaxes(1, 2) return array_p def _apply2allelements(self, array, k): """Apply perturbation to array of complete elements. """ ## Apply permutation to array array_p = self.basecoreperturbation.apply(array, k) # array_p = array[self.reindices[:, k]].swapaxes(1, 2) return array_p