Source code for hottbox.utils.generation.special
"""
Helper functions for generating synthetic tensors
"""
import itertools
import numpy as np
from scipy.linalg import toeplitz as toeplitz_mat
from hottbox.utils.generation.basic import dense_tensor
def _toeplitz_random(shape, modes, low=None, high=None):
""" Generate the apppropraite number of Toeplitz matrices
according to the required shape
Returns
-------
matC: list[np.ndarray]
List of Toeplitz Matrices
"""
modes = np.asarray(modes)
shape = np.asarray(shape)
matC = []
if low is None:
low = 0
if high is None:
high = 1000
matSz = np.asarray(shape)[modes]
numMats = int(np.prod(shape[~modes]))
if matSz[0] == matSz[1]:
szMult = matSz[0]
else: # minimal generation
szMult = matSz[0]+matSz[1]
toepVals = np.random.randint(low, high, size=(numMats, szMult))
for i in range(numMats):
if matSz[0] == matSz[1]:
_r, _c = toepVals[i], toepVals[i].ravel().conjugate()
else:
_c, _r = toepVals[i][:matSz[0]], toepVals[i][matSz[0]:]
toepMatrix = toeplitz_mat(r=_r, c=_c)
matC.append(toepMatrix)
return matC
[docs]def toeplitz_tensor(shape, modes=None, matC=None, random=False, lh=(None, None)):
""" Function to generate a Toeplitz tensor. Every slice along modes will be a Toeplitz matrix.
Parameters
----------
shape : tuple(int)
Shape of output. If matC is not None, they must match.
modes : int or list(int)
The mode by which the tensor is expected to be circulant
matC : list(np.ndarray) or list(float)
(optional) if None, random is set to True. Two input options.
random : bool
(optional) if true, input matC is ignored
lh : tuple(float, float)
(optional) used with random to define min and max values
"""
dim_req = len(shape)
if matC is None:
random = True
if modes is None:
modes = [0, 1]
if len(shape) == 1:
raise ValueError("Toeplitz must have more than one dimension")
low, high = lh
# Generate a list of Toeplitz matrices
if random:
matC = _toeplitz_random(shape, modes, low, high)
tensor = dense_tensor(shape, 'zeros')
matC = np.asarray(matC)
if len(shape) == 2:
return toeplitz_mat(r=matC, c=matC.ravel().conjugate())
# Fix all axis except modes
availmodes = np.setdiff1d(np.arange(dim_req), modes)
availsz = np.asarray(shape)[availmodes]
all_combs = []
for sz in availsz:
all_combs.append(np.arange(sz))
all_combs = list(itertools.product(*all_combs))
tsz = np.product(availsz[1:])
for currmode in range(availsz[0]):
modecombs = all_combs[tsz*currmode:tsz*(currmode+1)]
for i, m in enumerate(modecombs):
tensor.write_subtensor(np.asarray(m), np.asarray(availmodes), matC[i+currmode])
return tensor