Source code for hottbox.utils.generation.basic

import itertools
import numpy as np
from hottbox.core.structures import Tensor, BaseTensorTD


def _predefined_distr(distr, shape):
    """

    Parameters
    ----------
    distr : str
    shape : tuple

    Returns
    -------
    np.ndarray
    """
    distrlist = {'uniform': np.random.uniform(size=shape),
                 'normal': np.random.normal(size=shape),
                 'triangular': np.random.triangular(-1, 0, 1, size=shape),
                 'standard-t': np.random.standard_t(10, size=shape),
                 'ones': np.ones(shape),
                 'zeros': np.zeros(shape)}
    if distr not in distrlist:
        raise NameError("The distribution {} is not an available one. "
                        "Please refer to the list of implementations: {}".format(distr, distrlist.keys()))
    return distrlist[distr]


[docs]def dense_tensor(shape, distr='uniform', distr_type=0, fxdind=None): """ Generates a dense tensor of any dimension and fills it accordingly Parameters ---------- shape : tuple Specifies the dimensions of the tensor distr : str, optional Specifies the random generation using a class of the numpy.random module distr_type : int, optional Number of indices to not fix. 0 will be applied globally, 1 will apply to fibers, 2 to slices, etc. Returns ------- Tensor Generated tensor according to the parameters specified """ # fxdind: fixed indices if distr_type == 0: data = _predefined_distr(distr, shape) else: data = np.random.uniform(size=shape) raise NotImplementedError('Not implemented in dataset (basic) class') return Tensor(array=data)
[docs]def sparse_tensor(shape, distr='uniform', distr_type=0, fxdind=None, pct=0.05): """ Generates a sparse tensor of any dimension and fills it accordingly Parameters ---------- shape : tuple Specifies the dimensions of the tensor distr : str, optional Specifies the random generation using a class of the numpy.random module distr_type : int, optional Number of indices to not fix. 0 will be applied globally, 1 will apply to fibers, 2 to slices, etc. pct : float, optional Percentage of the dataset to be filled Returns ------- Tensor Generated tensor according to the parameters specified """ data_size = np.product(shape) if distr_type == 0: number_non_zero_values = int(data_size * pct) data = np.zeros(data_size) index = np.random.randint(low=0, high=data_size, size=number_non_zero_values) data[index] = _predefined_distr(distr, number_non_zero_values) data = data.reshape(shape) else: raise NotImplementedError('Not implemented in dataset (basic) class') return Tensor(array=data)
[docs]def super_diagonal_tensor(shape, distr='ones', values=None): """ Generates a tensor of any dimension with random or specified numbers across the super-diagonal and zeros elsewhere Parameters ---------- shape : tuple Specifies the dimensions of the tensor ``len(shape)`` defines the order of the tensor, whereas its values specify sizes of dimensions of the tensor. distr : str, optional Specifies the random generation using a class of the numpy.random module values : list Array of values on the super-diagonal of a tensor Returns ------- Tensor Generated tensor according to the parameters specified """ if not isinstance(shape, tuple): raise TypeError("Parameter `shape` should be passed as a tuple!") if shape[1:] != shape[:-1]: raise ValueError("All values in `shape` should have the same value!") inds = shape[0] data = np.zeros(shape) if values is None: values = _predefined_distr(distr, inds) if len(values) != inds: raise ValueError("Dimension mismatch! The specified values do not match " "the specified shape of the tensor provided ({} != {})".format(len(values), inds)) values = np.asarray(values).flatten() np.fill_diagonal(data, values) return Tensor(array=data)
[docs]def super_diag_tensor(shape, values=None): """ Super-diagonal tensor of the specified `order`. Parameters ---------- shape : tuple Desired shape of the tensor. ``len(shape)`` defines the order of the tensor, whereas its values specify sizes of dimensions of the tensor. values : np.ndarray Array of values on the super-diagonal of a tensor. By default contains only ones. Length of this vector defines Kryskal rank which is equal to ``shape[0]``. Returns ------- tensor : Tensor """ order = len(shape) rank = shape[0] if not isinstance(shape, tuple): raise TypeError("Parameter `shape` should be passed as a tuple!") if not all(mode_size == shape[0] for mode_size in shape): raise ValueError("All values in `shape` should have the same value!") if values is None: values = np.ones(rank) # set default values elif isinstance(values, np.ndarray): if values.ndim != 1: raise ValueError("The `values` should be 1-dimensional numpy array!") if values.size != rank: raise ValueError("Dimension mismatch! Not enough or too many `values` for the specified `shape`:\n" "{} != {} (values.size != shape[0])".format(values.size, rank)) else: raise TypeError("The `values` should be passed as a numpy array!") core = np.zeros(shape) core[np.diag_indices(rank, ndim=order)] = values tensor = Tensor(core) return tensor
[docs]def super_symmetric_tensor(shape, tensor=None): """ Generates a tensor of equal dimensions with random or specified numbers, with a specified tensor. Parameters ---------- shape : tuple Specifies the dimensions of the tensor ``len(shape)`` defines the order of the tensor, whereas its values specify sizes of dimensions of the tensor. tensor : Tensor, optional Input tensor to be symmetricised Returns ------- Tensor Generated tensor according to the parameters specified """ dims = len(shape) inds = itertools.permutations(np.arange(dims)) inds = np.array(list(inds)) data = np.zeros(shape) if tensor is None: tensor = dense_tensor(shape) for i, _ in enumerate(inds): data = data + np.transpose(tensor.data, tuple(inds[i, :])) return Tensor(array=data)
[docs]def residual_tensor(tensor_orig, tensor_approx): """ Residual tensor Parameters ---------- tensor_orig : Tensor tensor_approx : {Tensor, TensorCPD, TensorTKD, TensorTT} Returns ------- residual : Tensor """ if not isinstance(tensor_orig, Tensor): raise TypeError("Unknown data type of original tensor.\n" "The available type for `tensor_A` is `Tensor`") # TODO: make use of direct subtraction of tensors if isinstance(tensor_approx, Tensor): residual = Tensor(tensor_orig.data - tensor_approx.data) elif isinstance(tensor_approx, BaseTensorTD): residual = Tensor(tensor_orig.data - tensor_approx.reconstruct().data) else: raise TypeError("Unknown data type of the approximation tensor!\n" "The available types for `tensor_B` are `Tensor`, `TensorCPD`, `TensorTKD`, `TensorTT`") return residual