def structured_product(self, x, OMEGA, OMEGA_CONJ): y = np.copy(x) #print(self._d_pr, self._d) if self._d_pr <= self._d: for block in self._BBB[::-1]: # matrix-vector product if block._hash_func == 'random': y = np.dot(block._A, y) if block._hash_func == 'circulant': y = StructuredMatrices.circulant_product(block._col, y) if block._hash_func == 'skew_circulant': y = StructuredMatrices.skew_circulant_product( block._col, y, OMEGA, OMEGA_CONJ) if block._hash_func == 'toeplitz': y = StructuredMatrices.toeplitz_product( block._col, block._row, y) if block._hash_func == 'hadamard': y = StructuredMatrices.hadamard_cross_polytope_product( y, block._D, block._nblocks) if block._hash_func == 'hankel': y = StructuredMatrices.hankel_product( block._col, block._row, y) if block._hash_func == 'low_displacement_rank': y = StructuredMatrices.low_displacement_product( block._G, block._H, block._r, y, OMEGA, OMEGA_CONJ) if block._hash_func == 'kronecker': y = StructuredMatrices.kronecker_product_rec( block._A_list, y) if block._hash_func == 'pure_hadamard': #y = fht.fht1(y) a = ffht.create_aligned(y.shape[0], np.float32) np.copyto(a, y) ffht.fht(a, min(y.shape[0], 1024, 2048)) y = a if block._hash_func == 'diagonal' or block._hash_func == 'diagonal_kronecker' or block._hash_func == 'diagonal_gaussian': y = block._D * y #print(block, y.shape) # all blocks have been handled. # dimensionality reduction y = y[:self._d_pr] if self._normalization: y *= self._norm_factor_list return y else: if len(self._BBB) == 1 and self._BBB[0]._hash_func == 'random': y = np.dot(self._BBB[0]._A, y) return y y_global = np.zeros(self._d_pr) div = self._d_pr // self._d # number of parameters div_real = self._d_pr / self._d #print(div, div_real, self._d_pr, self._d) assert div == div_real # we handle only this case # /!\ + d_pr should be an integral power of 2!!! for i_div in xrange(div): #print('i_div', i_div) y = np.copy(x) # if div_real != div, the last mini block should be truncated => never happened because of the case of hadamard # split y into small vectors and reunit all results after for block in self._BBB[::-1]: #if i_div == div or i_div < div -1: # easy # matrix-vector product if block._hash_func == 'circulant': y = StructuredMatrices.circulant_product( block._col[i_div], y) if block._hash_func == 'skew_circulant': y = StructuredMatrices.skew_circulant_product( block._col[i_div], y, OMEGA, OMEGA_CONJ) if block._hash_func == 'toeplitz': y = StructuredMatrices.toeplitz_product( block._col[i_div], block._row[i_div], y) if block._hash_func == 'hadamard': y = StructuredMatrices.hadamard_cross_polytope_product( y, block._D[i_div], block._nblocks) if block._hash_func == 'hankel': y = StructuredMatrices.hankel_product( block._col[i_div], block._row[i_div], y) if block._hash_func == 'low_displacement_rank': y = StructuredMatrices.low_displacement_product( block._G[i_div], block._H[i_div], block._r, y, OMEGA, OMEGA_CONJ) if block._hash_func == 'kronecker': y = StructuredMatrices.kronecker_product_rec( block._A_list[i_div], y) if block._hash_func == 'pure_hadamard': a = ffht.create_aligned(y.shape[0], np.float32) np.copyto(a, y) ffht.fht(a, min(x.shape[0], 1024, 2048)) y = a if block._hash_func == 'diagonal' or block._hash_func == 'diagonal_kronecker' or block._hash_func == 'diagonal_gaussian': y = block._D[i_div] * y y_global[i_div * self._d:i_div * self._d + self._d] = y #print(y_global) if self._normalization: y_global *= self._norm_factor_list return y_global
def __init__(self, d, d_pr, hash_func, bonus): # intialization # /!\ the following parameters are one parameter if d_pr <= d # or list of parameters if d_pr > d # example: for a circulant matrix : # div = d_pr// d (euclidean division) # so we need div columns parameter to compute the rectangular circulant matrix self._d = d # number of columns self._d_pr = d_pr # number of rows self._hash_func = hash_func self._A = None self._col = None self._row = None # specific to an HDi block self._nblocks = None self._D = None # specific to a low-displacement rank block self._r = None if self._r: assert self._r < self._d self._G = None self._H = None # specific to a kronecker block self._discrete = None # boolean self._de = None self._A_list = None # to be sure I forgot no cases self._check = False assert self._hash_func in [ 'random', 'circulant', 'skew_circulant', 'toeplitz', 'hankel', 'pure_hadamard', 'hadamard', 'low_displacement_rank', 'kronecker', 'diagonal', 'diagonal_kronecker', 'diagonal_gaussian' ] # filling necessary variables # TODO: simplify the code by reunification of the two cases # less rows than columns if self._d_pr <= self._d: if self._hash_func == 'random': self._A = np.random.normal(0.0, 1.0, (self._d_pr, self._d)) self._check = True if self._hash_func == 'circulant' or hash_func == 'skew_circulant' or hash_func == 'toeplitz' or hash_func == 'hankel': self._col = np.random.normal(0.0, 1.0, self._d) self._check = True if self._hash_func == 'hadamard': assert 'nblocks' in bonus self._nblocks = bonus['nblocks'] self._D = StructuredMatrices.compute_diagonal_matrices( self._d, self._nblocks) self._check = True # do not compute Hadamard matrix in advance if self._hash_func == 'toeplitz': self._row = np.random.normal(0.0, 1.0, self._d) self._row[0] = self._col[0] self._check = True if self._hash_func == 'hankel': self._row = np.random.normal(0.0, 1.0, self._d) self._row[0] = self._col[self._d - 1] self._check = True if self._hash_func == 'low_displacement_rank': assert 'r' in bonus self._r = bonus['r'] self._G = np.random.normal(0.0, 1.0, (self._d, self._r)) self._H = np.random.normal(0.0, 1.0, (self._d, self._r)) #TODO: # each column should be 5-sparse for G50C => 10% # UGLY for i in xrange(self._r): zeros = np.random.randint(0, self._r, size=int(0.1 * self._d)) for zero in zeros: self._H[zero, i] = 0 self._check = True if self._hash_func == 'kronecker': assert 'discrete' in bonus assert 'de' in bonus self._discrete = bonus['discrete'] self._de = bonus['de'] self._A_list = StructuredMatrices.kronecker( int(math.log(self._d, 2)), self._de, self._discrete) self._check = True if self._hash_func == 'diagonal': self._D = StructuredMatrices.compute_diagonal_matrices( self._d, 1).reshape(self._d, ) self._check = True if self._hash_func == 'diagonal_kronecker': self._D = StructuredMatrices.compute_kronecker_vector( self._d, n_lev=3, n_bits=2, discrete=True) self._check = True if self._hash_func == 'diagonal_kronecker': self._D = StructuredMatrices.compute_kronecker_vector( self._d, n_lev=3, n_bits=2, discrete=True) self._check = True if self._hash_func == 'diagonal_gaussian': self._D = np.random.normal(0.0, 1.0, self._d) self._check = True if self._hash_func == 'pure_hadamard': self._check = True # nothing to do pass else: # d_pr > d div = self._d_pr // self._d # number of parameters if self._hash_func == 'random': self._A = np.random.normal(0.0, 1.0, (self._d_pr, self._d)) self._check = True if self._hash_func == 'circulant' or hash_func == 'skew_circulant' or hash_func == 'toeplitz' or hash_func == 'hankel': self._col = [ np.random.normal(0.0, 1.0, self._d) for i in xrange(div) ] self._check = True if self._hash_func == 'hadamard': assert 'nblocks' in bonus self._nblocks = bonus['nblocks'] self._D = [ StructuredMatrices.compute_diagonal_matrices( self._d, self._nblocks) for i in xrange(div) ] self._check = True # do not compute Hadamard matrix in advance if self._hash_func == 'toeplitz': self._row = [ np.random.normal(0.0, 1.0, self._d) for i in xrange(div) ] for i in xrange(div): self._row[i][0] = self._col[i][0] self._check = True if self._hash_func == 'hankel': self._row = [ np.random.normal(0.0, 1.0, self._d) for i in xrange(div) ] for i in xrange(div): self._row[i][0] = self._col[i][self._d - 1] self._check = True if self._hash_func == 'low_displacement_rank': assert 'r' in bonus self._r = bonus['r'] self._G = [ np.random.normal(0.0, 1.0, (self._d, self._r)) for i in xrange(div) ] self._H = [ np.random.normal(0.0, 1.0, (self._d, self._r)) for i in xrange(div) ] #TODO: # each column should be 5-sparse for G50C => 10% # UGLY for j in xrange(div): for i in xrange(self._r): zeros = np.random.randint(0, self._r, size=int(0.1 * self._d)) for zero in zeros: self._H[j][zero, i] = 0 self._check = True if self._hash_func == 'kronecker': assert 'discrete' in bonus assert 'de' in bonus self._discrete = bonus['discrete'] self._de = bonus['de'] self._A_list = [ StructuredMatrices.kronecker(int(math.log(self._d, 2)), self._de, self._discrete) for i in xrange(div) ] self._check = True if self._hash_func == 'diagonal': self._D = [ StructuredMatrices.compute_diagonal_matrices( self._d, 1).reshape(self._d, ) for i in xrange(div) ] self._check = True if self._hash_func == 'diagonal_kronecker': self._D = [ StructuredMatrices.compute_kronecker_vector(self._d, n_lev=3, n_bits=2, discrete=True) for i in xrange(div) ] self._check = True if self._hash_func == 'diagonal_gaussian': self._D = [ np.random.normal(0.0, 1.0, self._d) for i in xrange(div) ] self._check = True if self._hash_func == 'pure_hadamard': self._check = True # nothing to do pass # to be sure we entered at least in one if assert self._check