import numpy as np import sys sys.path.insert(0,'..') from copy import deepcopy as dc from collections import defaultdict from itertools import product from time import time from scipy.linalg import cho_factor, cho_solve, cholesky, lu from scipy.linalg.blas import dgemm from problem_tools.geometry_tools import Data, Tree from problem_tools.problem import Problem from functions import test_funcs from numba import jit from scipy.linalg.interpolative import interp_decomp from scipy.sparse import csc_matrix as csc from scipy.sparse import lil_matrix as lil import scipy.sparse as sps import matplotlib.pyplot as plt import fmm3dbie as h3 import fmm3dpy as fmm3d from memory_profiler import profile class Factor(object): def __init__(self,pr, how_comp_T='block',proxy_p=(1,100), proxy_r=1., symmetric_fun = 0,proxy_type='fixed'): self.pr = pr self.csc_fun = pr.csc_fun self.count_proxy = [] self.count_block_based = [] self.proxy_p = proxy_p self.proxy_r = proxy_r self.tree = pr.row_tree self.n = self.tree.index[0].shape[0] tree = self.tree row_size = tree.level[-1] self.row_size = row_size self.L = [None for i in range(row_size)] self.inv_L = [None for i in range(row_size)] self.tail_od = [[] for i in range(row_size)] self.tail_L = [None for i in range(row_size)] self.off_diag = [None for i in range(row_size)] self.abasis = [None for i in range(row_size)] self.basis = [None for i in range(row_size)] self.local_abasis = [None for i in range(row_size)] self.local_basis = [None for i in range(row_size)] self.T = [None for i in range(row_size)] if pr.wtd_T: self.T_wtd = [None for i in range(row_size)] self.index_lvl = [None for i in range(row_size)] self.elim_list = set() self.prev_lvl_schur = {} self.symmetric_fun = symmetric_fun self.n_close_elem = 0 if not pr.symmetric: self.col_tree = pr.col_tree if not symmetric_fun: self.U = [None for i in range(row_size)] self.inv_U = [None for i in range(row_size)] self.tail_od_U = [[] for i in range(row_size)] self.tail_U = [None for i in range(row_size)] self.off_diag_U = [None for i in range(row_size)] def init_index_lvl(self, ind): if not self.tree.child[ind]: self.index_lvl[ind] = self.tree.index[ind] if not self.pr.symmetric: self.index_lvl_U[ind] = self.col_tree.index[ind] def upd_index_lvl(self, ind, upd_type='row'): if upd_type == 'row': if self.tree.child[ind]: basis_ch = np.array([], dtype='uint64') for ch in self.tree.child[ind]: basis_ch = np.hstack((basis_ch,self.basis[ch])) self.index_lvl[ind] = basis_ch else: self.index_lvl[ind] = dc(self.tree.index[ind]) else: if self.col_tree.child[ind]: basis_ch = np.array([], dtype='uint64') for ch in self.col_tree.child[ind]: basis_ch = np.hstack((basis_ch,self.basis_U[ch]))#row_basis[ch])) else: basis_ch = self.col_tree.index[ind] self.index_lvl_U[ind] = basis_ch def ind_to_lvl(self, ind): tree = self.tree level_count = len(tree.level) - 2 pr = self.pr for i in range(level_count-1, -1, -1): job = [j for j in range(tree.level[i], tree.level[i+1])] if ind in job: return i def _dot_L(self, v, tr=0): pr = self.pr tree = self.tree level_count = len(tree.level) - 2 close = pr.lvl_close #res_or = dc(v) res = dc(v) if tr: for i in range(level_count-1, -1, -1): job = [j for j in range(tree.level[i], tree.level[i+1]) if not pr.row_notransition[j]] for ind in job: if pr.wtd_T: T_T = np.linalg.inv(self.T_wtd[ind]) else: T_T = np.linalg.inv(self.T[ind]).T res[self.index_lvl[ind]] = T_T.dot(res[self.index_lvl[ind]]) if self.symmetric_fun: U = self.L[ind].T else: U = self.U[ind] if self.abasis[ind].shape[0] != 0: res[self.abasis[ind]] = U.dot(res[self.abasis[ind]]) else: continue for ii in range(len(close[ind])): if not self.tree.parent[close[ind][ii]] in close[ind]: od_bl = self.off_diag[ind][ii] if od_bl.shape[1] == self.basis[close[ind][ii]].shape[0] and od_bl.shape[1] != 0: res[self.abasis[ind]] += od_bl.dot(res[self.basis[close[ind][ii]]]) elif od_bl.shape[1] == self.index_lvl[close[ind][ii]].shape[0] and od_bl.shape[1] != 0: res[self.abasis[ind]] += od_bl.dot(res[self.index_lvl[close[ind][ii]]]) #res_or = dc(res) return res else: for i in range(level_count): job = [j for j in range(tree.level[i], tree.level[i+1]) if not pr.row_notransition[j]] job.reverse() for ind in job: L = self.L[ind] if self.abasis[ind].shape[0] != 0: res[self.abasis[ind]] = L.dot(res[self.abasis[ind]]) else: continue for ii in range(len(close[ind])): if not self.tree.parent[close[ind][ii]] in close[ind]: if self.symmetric_fun: od_bl = self.off_diag[ind][ii].T else: od_bl = self.off_diag_U[ind][ii] if od_bl.shape[0] == self.basis[close[ind][ii]].shape[0] and od_bl.shape[0] != 0: res[self.basis[close[ind][ii]]] += od_bl.dot(v[self.abasis[ind]]) elif od_bl.shape[0] == self.index_lvl[close[ind][ii]].shape[0] and od_bl.shape[0] != 0: res[self.index_lvl[close[ind][ii]]] += od_bl.dot(v[self.abasis[ind]]) T = np.linalg.inv(self.T[ind]) res[self.index_lvl[ind]] = T.dot(res[self.index_lvl[ind]]) #res_or = dc(res) return res def _dot_L_tail(self, v, tr=0): l = self.tail_lvl pr = self.pr tree = self.tree level_count = len(tree.level) - 2 res = np.zeros(v.shape[0], dtype = self.pr.dtype) if tr: # res = np.zeros(v.shape[0], dtype = self.pr.dtype) for i in range(level_count-1, -1, -1): job = [j for j in range(tree.level[i], tree.level[i+1]) if not pr.row_notransition[j]] if i == l: rem_job = dc(job) for ind in job: if self.symmetric_fun: U = self.tail_L[ind].T else: U = self.tail_U[ind] res[self.basis[ind]] += U.dot(v[self.basis[ind]]) if self.abasis[ind].shape[0] != 0: res[self.abasis[ind]] = v[self.abasis[ind]] rem_job.remove(ind) for ii in range(len(rem_job)): od_bl = self.tail_od[ind][ii] od_bl = np.linalg.inv(self.tail_L[ind]).dot(od_bl) res[self.basis[ind]] += od_bl.dot(v[self.basis[rem_job[ii]]]) else: for ind in job: if self.abasis[ind].shape[0] != 0: res[self.abasis[ind]] = dc(v[self.abasis[ind]]) # if abs((res-v)[self.abasis[10]]).max() > 10e-5: # print (f'tail_1 changed res in self.abasis[10]') return res else: # res = np.zeros(v.shape[0], dtype = self.pr.dtype) for i in range(level_count-1, -1, -1): job = [j for j in range(tree.level[i], tree.level[i+1]) if not pr.row_notransition[j]] if i == l: rem_job = dc(job) for ind in job: res[self.basis[ind]] += self.tail_L[ind].dot(v[self.basis[ind]]) if self.abasis[ind].shape[0] != 0: res[self.abasis[ind]] = v[self.abasis[ind]] rem_job.remove(ind) for ii in range(len(rem_job)): if self.symmetric_fun: od_bl = self.tail_od[ind][ii].T od_bl = od_bl.dot(np.linalg.inv(self.tail_L[ind].T)) else: od_bl = self.tail_od_U[ind][ii] od_bl = od_bl.dot(np.linalg.inv(self.tail_U[ind])) res[self.basis[rem_job[ii]]] += od_bl.dot(v[self.basis[ind]]) else: for ind in job: if self.abasis[ind].shape[0] != 0: res[self.abasis[ind]] = dc(v[self.abasis[ind]]) # if abs((res-v)[self.abasis[10]]).max() > 10e-5: # print (f'tail_0 changed res in self.abasis[10]') return res def dot(self, v): res = self._dot_L(v, tr=1) res = self._dot_L_tail(res, tr=1) res = self._dot_L_tail(res, tr=0) res = self._dot_L(res, tr=0) return res def _solve_L(self, rhs, tr=0): pr = self.pr tree = self.tree level_count = len(tree.level) - 2 close = pr.lvl_close if tr: ans = dc(rhs) for i in range(level_count): job = [j for j in range(tree.level[i], tree.level[i+1]) if not pr.row_notransition[j]] job.reverse() for ind in job: if self.abasis[ind].shape[0] == 0: continue rhs_part = ans[self.abasis[ind]].copy() #new for ii in range(len(close[ind])): if not self.tree.parent[close[ind][ii]] in close[ind]: od_bl = self.off_diag[ind][ii] if od_bl.shape[1] == self.basis[close[ind][ii]].shape[0]:# and od_bl.shape[1] != 0: rhs_part -= od_bl.dot(ans[self.basis[close[ind][ii]]]) # new #rhs[self.abasis[ind]] -= od_bl.dot(ans[self.basis[close[ind][ii]]]) elif od_bl.shape[1] == self.index_lvl[close[ind][ii]].shape[0]:# and od_bl.shape[1] != 0: rhs_part -= od_bl.dot(ans[self.index_lvl[close[ind][ii]]]) # new #rhs[self.abasis[ind]] -= od_bl.dot(ans[self.index_lvl[close[ind][ii]]]) if self.symmetric_fun: #if self.abasis[ind].shape[0] != 0: # ans[self.abasis[ind]] = (np.linalg.inv(self.L[ind]).T).dot(rhs[self.abasis[ind]]) ans[self.abasis[ind]] = (np.linalg.inv(self.L[ind]).T).dot(rhs_part) # new else: #if self.abasis[ind].shape[0] != 0: # ans[self.abasis[ind]] = (np.linalg.inv(self.U[ind])).dot(rhs[self.abasis[ind]]) ans[self.abasis[ind]] = (np.linalg.inv(self.U[ind])).dot(rhs_part) # new if pr.wtd_T: T_T = self.T_wtd[ind] else: T_T = self.T[ind].T ans[self.index_lvl[ind]] = T_T.dot(ans[self.index_lvl[ind]]) #rhs = dc(ans) return ans else: # ans = np.zeros(self.n, dtype = self.pr.dtype) ans = dc(rhs) for i in range(level_count-1, -1, -1): job = [j for j in range(tree.level[i], tree.level[i+1]) if not pr.row_notransition[j]] for ind in job: T = self.T[ind] rhs[self.index_lvl[ind]] = T.dot(rhs[self.index_lvl[ind]]) if self.abasis[ind].shape[0] != 0: ans[self.abasis[ind]] = np.linalg.inv(self.L[ind]).dot(rhs[self.abasis[ind]]) for ii in range(len(close[ind])): if not self.tree.parent[close[ind][ii]] in close[ind]: if self.symmetric_fun: od_bl = self.off_diag[ind][ii].T else: od_bl = self.off_diag_U[ind][ii] if od_bl.shape[0] == self.basis[close[ind][ii]].shape[0] and od_bl.shape[0] != 0: rhs[self.basis[close[ind][ii]]] -= od_bl.dot(ans[self.abasis[ind]]) elif od_bl.shape[0] == self.index_lvl[close[ind][ii]].shape[0] and od_bl.shape[0] != 0: rhs[self.index_lvl[close[ind][ii]]] -= od_bl.dot(ans[self.abasis[ind]]) for ind in job: ans[self.basis[ind]] = rhs[self.basis[ind]] return ans def _solve_L_tail(self, rhs, tr=0): l = self.tail_lvl pr = self.pr tree = self.tree level_count = len(tree.level) - 2 close = pr.lvl_close if tr: ans = dc(rhs) for i in range(level_count): job = [j for j in range(tree.level[i], tree.level[i+1]) if not pr.row_notransition[j]] job.reverse() # print(tree.level[i]) # print(tree.level[i+1]) jlen = tree.level[i+1]-tree.level[i] juse = 0 if i == l: rem_job = dc(job) # print(job) for ind in job: # print(ind) if self.symmetric_fun: U = self.tail_L[ind].T else: U = self.tail_U[ind] ans[self.basis[ind]] = np.linalg.inv(U).dot(rhs[self.basis[ind]]) # print(ind,rem_job) rem_job.remove(ind) # print(len(self.tail_od[ind])) for ii in range(juse): jind = ind + ii+1 # print(ind,jind,ii) od_bl = self.tail_od[ind][ii] od_bl = np.linalg.inv(self.tail_U[ind]).dot(np.linalg.inv(self.tail_L[ind])).dot(od_bl) ans[self.basis[ind]] -= od_bl.dot(ans[self.basis[jind]]) juse += 1 for ind in job: if self.abasis[ind].shape[0] != 0: ans[self.abasis[ind]] = rhs[self.abasis[ind]] else: for ind in job: if self.abasis[ind].shape[0] != 0: ans[self.abasis[ind]] = rhs[self.abasis[ind]] return ans else: ans = dc(rhs) for i in range(level_count-1, -1, -1): job = [j for j in range(tree.level[i], tree.level[i+1]) if not pr.row_notransition[j]] if i == l: rem_job = dc(job) for ind in job: L = self.tail_L[ind] ans[self.basis[ind]] = np.linalg.inv(L).dot(rhs[self.basis[ind]]) rem_job.remove(ind) for ii in range(len(rem_job)): if self.symmetric_fun: od_bl = self.tail_od[ind][ii].T od_bl = od_bl.dot(np.linalg.inv(L.T)) else: od_bl = self.tail_od_U[ind][ii] od_bl = od_bl.dot(np.linalg.inv(self.tail_U[ind])) rhs[self.basis[rem_job[ii]]] -= od_bl.dot(ans[self.basis[ind]]) for ind in job: if self.abasis[ind].shape[0] != 0: ans[self.abasis[ind]] = rhs[self.abasis[ind]] else: for ind in job: if self.abasis[ind].shape[0] != 0: ans[self.abasis[ind]] = rhs[self.abasis[ind]] return ans def solve(self, rhs): ans = self._solve_L(rhs, tr=0) ans = self._solve_L_tail(ans, tr=0) ans = self._solve_L_tail(ans, tr=1) ans = self._solve_L(ans, tr=1) return ans def func(self, row, col): self.n_close_elem += row.shape[0]*col.shape[0] if self.csc_fun: return self.csc[np.ix_(row, col)].toarray() elif self.pr.q_fun: #pr = self.pr #norders = pr.order*np.ones(pr.npatches) #iptype = np.ones(pr.npatches) #npols = int((pr.order+1)*(pr.order+2)/2) #npts = pr.npatches*npols #bl = h3.helm_comb_dir_fds_matgen_woversamp(norders,pr.ixyzs,iptype,pr.srccoefs,pr.srcvals,pr.wts,pr.eps,pr.zpars,pr.ifds,pr.zfds,row+1,col+1) #if np.array_equal(row,col): return gen_block(self.pr, row, col) else: return self.pr._func(self.pr.row_data, row, self.pr.col_data, col) def gen_block(pr,row,col): #norders = pr.order*np.ones(pr.npatches) #iptype = np.ones(pr.npatches) #npols = int((pr.order+1)*(pr.order+2)/2) #npts = pr.npatches*npols # norders, iptype, npols, npts = make_arrays(pr) bl = gen_block_fmm3dbie(pr, row, col) #h3.helm_comb_dir_fds_matgen_woversamp(norders,pr.ixyzs,iptype,pr.srccoefs,pr.srcvals,pr.wts,pr.eps,pr.zpars,pr.ifds,pr.zfds,row+1,col+1) bl = diag_block_upd(bl,pr.zpars[2], row, col, pr.coef) #if np.array_equal(row,col): # bl -= diag_block_upd(pr.zpars[2], row.shape[0])#2*np.pi*pr.zpars[2]*np.identity(row.shape[0]) return bl def diag_block_upd(bl,kk, row, col, coef): if np.array_equal(row,col): bl += coef*kk*np.identity(row.shape[0])/2.0 return bl def gen_block_fmm3dbie(pr, row, col): # if(len(row)*len(col) > 10000): # print("In gen block:",len(row),len(col)) return h3.helm_comb_dir_fds_block_matgen(pr.norders, pr.ixyzs,pr.iptype,pr.srccoefs,pr.srcvals,pr.wts,pr.eps,pr.zpars,pr.ifds,pr.zfds,row+1,col+1,ifwrite=0) def make_arrays(pr): norders = pr.order*np.ones(pr.npatches) iptype = np.ones(pr.npatches) npols = int((pr.order+1)*(pr.order+2)/2) npts = pr.npatches*npols return norders, iptype, npols, npts def buildmatrix_new(ind, factor, tau, l): pr = factor.pr tree = factor.tree ndim = tree.data.ndim pb_ind = [] sch_len = 0 for ii in factor.pr.schur_list[ind]: ban_ind = (ii in factor.pr.lvl_close[ind]) ban_ind = ban_ind or (tree.parent[ii] in factor.pr.lvl_close[ind]) if tree.child[ii]: for ii_ch in tree.child[ii]: ban_ind = ban_ind or (ii_ch in factor.pr.lvl_close[ind]) if not ban_ind: pb_ind += [ii] if not factor.basis[ii] is None: sch_len += factor.basis[ii].shape[0] else: if not factor.index_lvl[ii] is None: sch_len += factor.index_lvl[ii].shape[0] else: print(f'Error: buildmatrix0 ind: {ind}, factor.index_lvl[{ii}] is None!') raise KeyboardInterrupt # proxy build points: lvl = len(tree.level) - 3 p = factor.proxy_p[1]*(factor.proxy_p[0]**(lvl-l)) #print(lvl, l, p, factor.proxy_p[0],factor.proxy_p[1]) r = factor.proxy_r c = np.zeros(ndim) for i_ndim in range(ndim): c[i_ndim] = (factor.tree.aux[ind][:,i_ndim][0] + factor.tree.aux[ind][:,i_ndim][1])/2 box_size = np.linalg.norm(factor.tree.aux[ind][1] - factor.tree.aux[ind][0]) theta = np.linspace(0, 2*np.pi, p, endpoint=False) if ndim == 2: proxy = r * box_size * np.vstack((c[0] + np.cos(theta), c[1] + np.sin(theta))) proxy[0] -= (c * r * box_size - c)[0] proxy[1] -= (c * r * box_size - c)[1] elif ndim == 3: proxy = fibonacci_sphere(p, r * box_size, c) else: raise NameError('In progress') # zero matrix: if factor.symmetric_fun: matrix = np.zeros((factor.index_lvl[ind].shape[0], sch_len + p), dtype=pr.dtype) else: matrix = np.zeros((factor.index_lvl[ind].shape[0], sch_len * 2 + p * 2), dtype=pr.dtype) # build sch blocks index0 = factor.index_lvl[ind] sch = np.zeros((factor.index_lvl[ind].shape[0], sch_len),dtype=pr.dtype) tmp = 0 for ii in pb_ind: if ii in factor.elim_list: tmp_mat = factor.func(factor.index_lvl[ind], factor.index_lvl[ii]) if not tmp_mat is None: if tmp_mat.shape[1] != factor.basis[ii].shape[0]: tmp_mat = tmp_mat[:, factor.local_basis[ii]] sch_tmp = schur(ind, ii , factor, ib_row='i', ib_col='b') if not sch_tmp is None: sch[:,tmp:tmp+sch_tmp.shape[1]] = tmp_mat-sch_tmp tmp += sch_tmp.shape[1] else: if not factor.index_lvl[ii] is None: tmp_mat = factor.func(factor.index_lvl[ind], factor.index_lvl[ii]) sch_tmp = schur(ind, ii , factor, ib_row='i', ib_col='i') if not sch_tmp is None: sch[:,tmp:tmp+sch_tmp.shape[1]] = tmp_mat - sch_tmp tmp += sch_tmp.shape[1] else: print(f'Error: _node_buildmatrix0 ind: {ind}, factor.index_lvl[{ii}] is None!') raise KeyboardInterrupt # add proxy to matrix proxy_data = Data(tree.data.ndim, p, proxy, close_r=tree.data.close_r) proxy_mat0 = factor.pr._func(tree.data, index0, proxy_data, np.arange(p)) D = np.diag(factor.pr.wts[index0]) proxy_mat = D.dot(proxy_mat0) tmp = 0 matrix[:, tmp : tmp + p] = proxy_mat tmp += p matrix[:,tmp:tmp+sch_len] = sch tmp += sch_len if not pr.half_sym: sch = np.zeros((sch_len,factor.index_lvl[ind].shape[0]), dtype=pr.dtype) tmp1 = 0 for ii in pb_ind: if ii in factor.elim_list: tmp_mat = factor.func(factor.index_lvl[ii], factor.index_lvl[ind]) if not tmp_mat is None: if tmp_mat.shape[0] != factor.basis[ii].shape[0]: tmp_mat = tmp_mat[factor.local_basis[ii]] sch_tmp = schur(ii, ind , factor, ib_row='b', ib_col='i') if not sch_tmp is None: sch[tmp1:tmp1+sch_tmp.shape[0]] = tmp_mat-sch_tmp tmp1 += sch_tmp.shape[0] else: if not factor.index_lvl[ii] is None: tmp_mat = factor.func(factor.index_lvl[ii], factor.index_lvl[ind]) sch_tmp = schur(ii, ind , factor, ib_row='i', ib_col='i') if not sch_tmp is None: sch[tmp1:tmp1+sch_tmp.shape[0]] = tmp_mat - sch_tmp tmp1 += sch_tmp.shape[0] else: print(f'Error: _node_buildmatrix0 ind: {ind}, factor.index_lvl[{ii}] is None!') raise KeyboardInterrupt if hasattr(tree.data, 'k'): proxy_data.k = tree.data.k # if hasattr(tree.data, 'norms'): # proxy_data.norms = tree.data.norms test_mat20 = factor.pr._func(tree.data,index0,proxy_data, np.arange(p)) test_mat2 = D.dot(test_mat20) matrix[:, tmp : tmp + p] = test_mat2 tmp += p matrix[:,tmp:tmp+sch_len] = sch.T # print(ind) # if ind == 10: # print (f'col sch: {np.linalg.norm(sch)}') tmp += sch_len return matrix def buildmatrix_new3(ind, factor, tau, l): pr = factor.pr tree = factor.tree ndim = tree.data.ndim pb_ind = [] sch_len = 0 for ii in factor.pr.schur_list[ind]: ban_ind = (ii in factor.pr.lvl_close[ind]) ban_ind = ban_ind or (tree.parent[ii] in factor.pr.lvl_close[ind]) if tree.child[ii]: for ii_ch in tree.child[ii]: ban_ind = ban_ind or (ii_ch in factor.pr.lvl_close[ind]) if not ban_ind: pb_ind += [ii] if not factor.basis[ii] is None: sch_len += factor.basis[ii].shape[0] else: if not factor.index_lvl[ii] is None: sch_len += factor.index_lvl[ii].shape[0] else: print(f'Error: buildmatrix0 ind: {ind}, factor.index_lvl[{ii}] is None!') raise KeyboardInterrupt # proxy build points: lvl = len(tree.level) - 3 p = factor.proxy_p[1]*(factor.proxy_p[0]**(lvl-l)) #print(lvl, l, p, factor.proxy_p[0],factor.proxy_p[1]) r = factor.proxy_r c = np.zeros(ndim) for i_ndim in range(ndim): c[i_ndim] = (factor.tree.aux[ind][:,i_ndim][0] + factor.tree.aux[ind][:,i_ndim][1])/2 box_size = np.linalg.norm(factor.tree.aux[ind][1] - factor.tree.aux[ind][0]) theta = np.linspace(0, 2*np.pi, p, endpoint=False) if ndim == 2: proxy = r * box_size * np.vstack((c[0] + np.cos(theta), c[1] + np.sin(theta))) proxy[0] -= (c * r * box_size - c)[0] proxy[1] -= (c * r * box_size - c)[1] elif ndim == 3: proxy = fibonacci_sphere(p, r * box_size, c) else: raise NameError('In progress') # zero matrix: if factor.symmetric_fun: matrix = np.zeros((factor.index_lvl[ind].shape[0], sch_len + p*3), dtype=pr.dtype) else: matrix = np.zeros((factor.index_lvl[ind].shape[0], sch_len * 2 + p * 3), dtype=pr.dtype) # build sch blocks index0 = factor.index_lvl[ind] sch = np.zeros((factor.index_lvl[ind].shape[0], sch_len),dtype=pr.dtype) tmp = 0 for ii in pb_ind: if ii in factor.elim_list: sch_tmp = schur(ind, ii , factor, ib_row='i', ib_col='b') if not sch_tmp is None: sch[:,tmp:tmp+sch_tmp.shape[1]] = sch_tmp tmp += sch_tmp.shape[1] else: if not factor.index_lvl[ii] is None: sch_tmp = schur(ind, ii , factor, ib_row='i', ib_col='i') if not sch_tmp is None: sch[:,tmp:tmp+sch_tmp.shape[1]] = sch_tmp tmp += sch_tmp.shape[1] else: print(f'Error: _node_buildmatrix0 ind: {ind}, factor.index_lvl[{ii}] is None!') raise KeyboardInterrupt # add proxy to matrix proxy_data = Data(tree.data.ndim, p, proxy, close_r=tree.data.close_r) proxy_mats0 = test_funcs.exp_distance_h2t(tree.data, index0, proxy_data, np.arange(p)) proxy_matd0 = test_funcs.double_layer(tree.data,index0,proxy_data,np.arange(p)) D = np.diag(factor.pr.wts[index0]) proxy_mat_s = D.dot(proxy_mats0) proxy_mat_d = D.dot(proxy_matd0) tmp = 0 matrix[:, tmp : tmp + p] = proxy_mats0 tmp += p matrix[:, tmp : tmp + p] = proxy_mat_s tmp += p matrix[:, tmp : tmp + p] = proxy_mat_d tmp += p matrix[:,tmp:tmp+sch_len] = sch tmp += sch_len if not pr.half_sym: sch = np.zeros((sch_len,factor.index_lvl[ind].shape[0]), dtype=pr.dtype) tmp1 = 0 for ii in pb_ind: if ii in factor.elim_list: sch_tmp = schur(ii, ind , factor, ib_row='b', ib_col='i') if not sch_tmp is None: sch[tmp1:tmp1+sch_tmp.shape[0]] = sch_tmp tmp1 += sch_tmp.shape[0] else: if not factor.index_lvl[ii] is None: sch_tmp = schur(ii, ind , factor, ib_row='i', ib_col='i') if not sch_tmp is None: sch[tmp1:tmp1+sch_tmp.shape[0]] = sch_tmp tmp1 += sch_tmp.shape[0] else: print(f'Error: _node_buildmatrix0 ind: {ind}, factor.index_lvl[{ii}] is None!') raise KeyboardInterrupt # if hasattr(tree.data, 'norms'): # proxy_data.norms = tree.data.norms matrix[:,tmp:tmp+sch_len] = sch.T # print(ind) # if ind == 10: # print (f'col sch: {np.linalg.norm(sch)}') tmp += sch_len return matrix def buildmatrix_new2(ind, factor, tau, l): pr = factor.pr tree = factor.tree ndim = tree.data.ndim pb_ind = [] sch_len = 0 for ii in factor.pr.schur_list[ind]: ban_ind = (ii in factor.pr.lvl_close[ind]) ban_ind = ban_ind or (tree.parent[ii] in factor.pr.lvl_close[ind]) if tree.child[ii]: for ii_ch in tree.child[ii]: ban_ind = ban_ind or (ii_ch in factor.pr.lvl_close[ind]) if not ban_ind: pb_ind += [ii] if not factor.basis[ii] is None: sch_len += factor.basis[ii].shape[0] else: if not factor.index_lvl[ii] is None: sch_len += factor.index_lvl[ii].shape[0] else: print(f'Error: buildmatrix0 ind: {ind}, factor.index_lvl[{ii}] is None!') raise KeyboardInterrupt # proxy build points: lvl = len(tree.level) - 3 p = factor.proxy_p[1]*(factor.proxy_p[0]**(lvl-l)) #print(lvl, l, p, factor.proxy_p[0],factor.proxy_p[1]) r = factor.proxy_r c = np.zeros(ndim) for i_ndim in range(ndim): c[i_ndim] = (factor.tree.aux[ind][:,i_ndim][0] + factor.tree.aux[ind][:,i_ndim][1])/2 box_size = np.linalg.norm(factor.tree.aux[ind][1] - factor.tree.aux[ind][0]) theta = np.linspace(0, 2*np.pi, p, endpoint=False) if ndim == 2: proxy = r * box_size * np.vstack((c[0] + np.cos(theta), c[1] + np.sin(theta))) proxy[0] -= (c * r * box_size - c)[0] proxy[1] -= (c * r * box_size - c)[1] elif ndim == 3: proxy = fibonacci_sphere(p, r * box_size, c) else: raise NameError('In progress') # zero matrix: if factor.symmetric_fun: matrix = np.zeros((factor.index_lvl[ind].shape[0], sch_len + p), dtype=pr.dtype) else: matrix = np.zeros((factor.index_lvl[ind].shape[0], sch_len * 2 + p * 2), dtype=pr.dtype) # build sch blocks index0 = factor.index_lvl[ind] sch = np.zeros((factor.index_lvl[ind].shape[0], sch_len),dtype=pr.dtype) tmp = 0 for ii in pb_ind: if ii in factor.elim_list: sch_tmp = schur(ind, ii , factor, ib_row='i', ib_col='b') if not sch_tmp is None: sch[:,tmp:tmp+sch_tmp.shape[1]] = sch_tmp tmp += sch_tmp.shape[1] else: if not factor.index_lvl[ii] is None: sch_tmp = schur(ind, ii , factor, ib_row='i', ib_col='i') if not sch_tmp is None: sch[:,tmp:tmp+sch_tmp.shape[1]] = sch_tmp tmp += sch_tmp.shape[1] else: print(f'Error: _node_buildmatrix0 ind: {ind}, factor.index_lvl[{ii}] is None!') raise KeyboardInterrupt # add proxy to matrix proxy_data = Data(tree.data.ndim, p, proxy, close_r=tree.data.close_r) proxy_mat0 = factor.pr._func(tree.data, index0, proxy_data, np.arange(p)) D = np.diag(factor.pr.wts[index0]) proxy_mat = D.dot(proxy_mat0) tmp = 0 matrix[:, tmp : tmp + p] = proxy_mat tmp += p matrix[:,tmp:tmp+sch_len] = sch tmp += sch_len if not pr.half_sym: sch = np.zeros((sch_len,factor.index_lvl[ind].shape[0]), dtype=pr.dtype) tmp1 = 0 for ii in pb_ind: if ii in factor.elim_list: sch_tmp = schur(ii, ind , factor, ib_row='b', ib_col='i') if not sch_tmp is None: sch[tmp1:tmp1+sch_tmp.shape[0]] = sch_tmp tmp1 += sch_tmp.shape[0] else: if not factor.index_lvl[ii] is None: sch_tmp = schur(ii, ind , factor, ib_row='i', ib_col='i') if not sch_tmp is None: sch[tmp1:tmp1+sch_tmp.shape[0]] = sch_tmp tmp1 += sch_tmp.shape[0] else: print(f'Error: _node_buildmatrix0 ind: {ind}, factor.index_lvl[{ii}] is None!') raise KeyboardInterrupt if hasattr(tree.data, 'k'): proxy_data.k = tree.data.k # if hasattr(tree.data, 'norms'): # proxy_data.norms = tree.data.norms test_mat2 = factor.pr._func(tree.data,index0, proxy_data, np.arange(p)) matrix[:, tmp : tmp + p] = test_mat2 tmp += p matrix[:,tmp:tmp+sch_len] = sch.T # print(ind) # if ind == 10: # print (f'col sch: {np.linalg.norm(sch)}') tmp += sch_len return matrix def buildmatrix(ind, factor, tau, l): pr = factor.pr tree = factor.tree ndim = tree.data.ndim pb_ind = [] sch_len = 0 for ii in factor.pr.schur_list[ind]: ban_ind = (ii in factor.pr.lvl_close[ind]) ban_ind = ban_ind or (tree.parent[ii] in factor.pr.lvl_close[ind]) if tree.child[ii]: for ii_ch in tree.child[ii]: ban_ind = ban_ind or (ii_ch in factor.pr.lvl_close[ind]) if not ban_ind: pb_ind += [ii] if not factor.basis[ii] is None: sch_len += factor.basis[ii].shape[0] else: if not factor.index_lvl[ii] is None: sch_len += factor.index_lvl[ii].shape[0] else: print(f'Error: buildmatrix0 ind: {ind}, factor.index_lvl[{ii}] is None!') raise KeyboardInterrupt # proxy build points: lvl = len(tree.level) - 3 p = factor.proxy_p[1]*(factor.proxy_p[0]**(lvl-l)) #print(lvl, l, p, factor.proxy_p[0],factor.proxy_p[1]) r = factor.proxy_r c = np.zeros(ndim) for i_ndim in range(ndim): c[i_ndim] = (factor.tree.aux[ind][:,i_ndim][0] + factor.tree.aux[ind][:,i_ndim][1])/2 box_size = np.linalg.norm(factor.tree.aux[ind][1] - factor.tree.aux[ind][0]) theta = np.linspace(0, 2*np.pi, p, endpoint=False) if ndim == 2: proxy = r * box_size * np.vstack((c[0] + np.cos(theta), c[1] + np.sin(theta))) proxy[0] -= (c * r * box_size - c)[0] proxy[1] -= (c * r * box_size - c)[1] elif ndim == 3: proxy = fibonacci_sphere(p, r * box_size, c) else: raise NameError('In progress') # zero matrix: if factor.symmetric_fun: matrix = np.zeros((factor.index_lvl[ind].shape[0], sch_len + p), dtype=pr.dtype) else: matrix = np.zeros((factor.index_lvl[ind].shape[0], sch_len * 2 + p * 2), dtype=pr.dtype) # build sch blocks index0 = factor.index_lvl[ind] sch = np.zeros((factor.index_lvl[ind].shape[0], sch_len),dtype=pr.dtype) tmp = 0 for ii in pb_ind: if ii in factor.elim_list: sch_tmp = schur(ind, ii , factor, ib_row='i', ib_col='b') if not sch_tmp is None: sch[:,tmp:tmp+sch_tmp.shape[1]] = sch_tmp tmp += sch_tmp.shape[1] else: if not factor.index_lvl[ii] is None: sch_tmp = schur(ind, ii , factor, ib_row='i', ib_col='i') if not sch_tmp is None: sch[:,tmp:tmp+sch_tmp.shape[1]] = sch_tmp tmp += sch_tmp.shape[1] else: print(f'Error: _node_buildmatrix0 ind: {ind}, factor.index_lvl[{ii}] is None!') raise KeyboardInterrupt # add proxy to matrix proxy_data = Data(tree.data.ndim, p, proxy, close_r=tree.data.close_r) proxy_mat = factor.pr._func(tree.data, index0, proxy_data, np.arange(p)) tmp = 0 matrix[:, tmp : tmp + p] = proxy_mat tmp += p matrix[:,tmp:tmp+sch_len] = sch tmp += sch_len if not pr.half_sym: sch = np.zeros((sch_len,factor.index_lvl[ind].shape[0]), dtype=pr.dtype) tmp1 = 0 for ii in pb_ind: if ii in factor.elim_list: sch_tmp = schur(ii, ind , factor, ib_row='b', ib_col='i') if not sch_tmp is None: sch[tmp1:tmp1+sch_tmp.shape[0]] = sch_tmp tmp1 += sch_tmp.shape[0] else: if not factor.index_lvl[ii] is None: sch_tmp = schur(ii, ind , factor, ib_row='i', ib_col='i') if not sch_tmp is None: sch[tmp1:tmp1+sch_tmp.shape[0]] = sch_tmp tmp1 += sch_tmp.shape[0] else: print(f'Error: _node_buildmatrix0 ind: {ind}, factor.index_lvl[{ii}] is None!') raise KeyboardInterrupt if hasattr(tree.data, 'k'): proxy_data.k = tree.data.k # if hasattr(tree.data, 'norms'): # proxy_data.norms = tree.data.norms test_mat2 = factor.pr._func(tree.data,index0, proxy_data, np.arange(p)) matrix[:, tmp : tmp + p] = test_mat2 tmp += p matrix[:,tmp:tmp+sch_len] = sch.T # print(ind) # if ind == 10: # print (f'col sch: {np.linalg.norm(sch)}') tmp += sch_len return matrix def block_schur(factor, ind, row_i, col_i, close, res, ib_row = 'i', ib_col = 'i',): if factor.off_diag[ind][close.index(col_i)].shape[0] == 0: return None if factor.symmetric_fun: if factor.off_diag[ind][close.index(row_i)].shape[0] == 0: return None else: if factor.off_diag_U[ind][close.index(row_i)].shape[0] == 0: return None if factor.symmetric_fun: col_mat = factor.off_diag[ind][close.index(row_i)].T else: col_mat = factor.off_diag_U[ind][close.index(row_i)] row_mat = factor.off_diag[ind][close.index(col_i)] upd_mat = col_mat.dot(row_mat) res = add_res_and_tmp(res, upd_mat, factor=factor, i_row=row_i, i_col=col_i) if ib_row == 'b': if res.shape[0] != factor.basis[row_i].shape[0]: return res[factor.local_basis[row_i]] if ib_col == 'b': if res.shape[1] != factor.basis[col_i].shape[0]: return res[:, factor.local_basis[col_i]] return res def level_schour(row_i, col_i, factor, ib_row = 'i', ib_col = 'i', lvl_type = 'row', ban_list=[]): close = factor.pr.lvl_close other_close = factor.pr.other_lvl_close pr = factor.pr res = None # if (row_i, col_i) in pr.schur_dict.keys(): # job = pr.schur_dict[(row_i, col_i)] # elif (col_i, row_i) in pr.schur_dict.keys(): # job = pr.schur_dict[(col_i, row_i)] # else: # print(f'Warning! level_schour: {row_i}, {col_i} are not in sch list, but shold be!') job = pr.schur_dict.get((row_i, col_i), None) if job is None: job = pr.schur_dict.get((col_i, row_i), None) if job is None: raise NameError(f'Error! level_schour: {row_i}, {col_i} are not in sch list, but shold be!') for ind in job: if (not ind in ban_list) and (ind in factor.elim_list): tmp = block_schur(factor, ind, row_i, col_i, close[ind]+other_close[ind], None, ib_row = ib_row, ib_col = ib_col) res = add_res_and_tmp(res, tmp, factor=factor, i_row=row_i, i_col=col_i) return res def add_res_and_tmp(res, tmp, factor=None, i_row=0, i_col=0): if res is None: if tmp is None: return None else: return tmp else: if tmp is None: return res else: if res.shape[0] == tmp.shape[0]: if res.shape[1] == tmp.shape[1]: return res + tmp elif res.shape[1] > tmp.shape[1]: return res[:, factor.local_basis[i_col]] + tmp elif res.shape[1] < tmp.shape[1]: return tmp[:, factor.local_basis[i_col]] + res elif res.shape[0] > tmp.shape[0]: if res.shape[1] == tmp.shape[1]: return res[factor.local_basis[i_row]] + tmp elif res.shape[1] > tmp.shape[1]: return res[np.ix_(factor.local_basis[i_row],factor.local_basis[i_col])] + tmp elif res.shape[0] < tmp.shape[0]: if res.shape[1] == tmp.shape[1]: return tmp[factor.local_basis[i_row]] + res elif res.shape[1] < tmp.shape[1]: return (tmp.ravel()[(factor.local_basis[i_col] + (factor.local_basis[i_row] * tmp.shape[1]).reshape((-1,1))).ravel()]).reshape(factor.local_basis[i_row].size, factor.local_basis[i_col].size) + res # return tmp[np.ix_(factor.local_basis[i_row],factor.local_basis[i_col])] + res print ('Warning! add_res_and_tmp') return res def schur_tail(row_i, col_i, factor, job, row_col = 'row'): res = schur(row_i, col_i, factor, ib_row = 'b', ib_col = 'b') for ind in job: if row_col == 'row': if ind == row_i: break else: if ind == col_i: break inv_L = np.linalg.inv(factor.tail_L[ind]) if factor.symmetric_fun: inv_U = np.linalg.inv(factor.tail_L[ind].T) else: inv_U = np.linalg.inv(factor.tail_U[ind]) row_mat = factor.tail_od[ind][col_i-ind-1] if factor.symmetric_fun: col_mat = factor.tail_od[ind][row_i-ind-1].T else: col_mat = factor.tail_od_U[ind][row_i-ind-1] if res is None: res = col_mat.dot(inv_U.dot(inv_L.dot(row_mat))) else: res += col_mat.dot(inv_U.dot(inv_L.dot(row_mat))) return res #@profile def factorize_lvl(factor, ind_l, tau = 1e-3, l = 0): pr = factor.pr close = pr.lvl_close other_close = factor.pr.other_lvl_close elim_list = factor.elim_list for ind in ind_l: # T: build_T(ind, factor, tau, l) if pr.wtd_T: build_T_wtd(ind, factor) T = factor.T[ind] if pr.wtd_T: T_T = factor.T_wtd[ind] else: T_T = T.T b = factor.basis[ind] abasis = factor.local_abasis[ind] basis = factor.local_basis[ind] if (set(factor.index_lvl[ind]) == set(b)): factor.L[ind] = np.zeros((0,0)) inv_L = np.zeros((0,0)) factor.off_diag[ind] = [] for i_cl in close[ind]: factor.off_diag[ind].append(np.zeros((b.shape[0],0))) if not factor.symmetric_fun: factor.U[ind] = np.zeros((0,0)) factor.off_diag_U[ind] = [] for i_cl in close[ind]: factor.off_diag_U[ind].append(np.zeros((b.shape[0],0)).T) inv_U = np.zeros((0,0)) continue # ============================== # compute L, U tmp_mat = factor.func(factor.index_lvl[ind], factor.index_lvl[ind]) sch_bl = schur(ind, ind, factor) if not sch_bl is None: try: tmp_mat -= sch_bl except: print (f'factorize_lvl:Warning! {ind, i_cl, sch_bl.shape, tmp_mat.shape}') if sch_bl.shape[0] < tmp_mat.shape[0]: tmp_mat[factor.local_basis[ind]] -= sch_bl else: print ('Warning! factorize_lvl Unexpected sizes!') matrix_diag = T.dot(tmp_mat).dot(T_T) if factor.symmetric_fun: factor.L[ind] = cholesky(matrix_diag[np.ix_(abasis,abasis)],lower=1) inv_L = np.linalg.inv(factor.L[ind]) inv_U = inv_L.T else: factor.L[ind], factor.U[ind] = lu(matrix_diag[np.ix_(abasis,abasis)], permute_l=True) inv_L = np.linalg.inv(factor.L[ind]) inv_U = np.linalg.inv(factor.U[ind]) #====================== # factorize: cl_offdiag = [] cl_offdiag_U = [] for i_cl in close[ind]+other_close[ind]: if not i_cl in elim_list: try: tmp_mat = factor.func(factor.index_lvl[ind], factor.index_lvl[i_cl]) except: raise NameError('err') sch_bl = schur(ind, i_cl, factor) if not sch_bl is None: try: tmp_mat -= sch_bl except: print (f'factorize_lvl:Warning! {ind, i_cl, sch_bl.shape, tmp_mat.shape}') if sch_bl.shape[0] < tmp_mat.shape[0]: tmp_mat[factor.local_basis[ind]] -= sch_bl else: print ('Warning! factorize_lvl Unexpected sizes!') if i_cl == ind: matrix_diag = T.dot(tmp_mat).dot(T_T) cl_offdiag.append(inv_L.dot(matrix_diag[np.ix_(abasis,basis)])) if not factor.symmetric_fun: cl_offdiag_U.append(matrix_diag[np.ix_(basis,abasis)].dot(inv_U)) else: matrix_offdiag = T.dot(tmp_mat) cl_offdiag.append(inv_L.dot(matrix_offdiag[abasis])) if not factor.symmetric_fun: tmp_mat_U = factor.func(factor.index_lvl[i_cl], factor.index_lvl[ind]) sch_bl = schur(i_cl, ind, factor) if not sch_bl is None: try: tmp_mat_U -= sch_bl except: print (f'factorize_lvl:Warning! {ind, i_cl, sch_bl.shape, tmp_mat_U.shape}') if sch_bl.shape[0] < tmp_mat_U.shape[0]: tmp_mat_U[factor.local_basis[ind]] -= sch_bl else: print ('Warning! factorize_lvl Unexpected sizes!') matrix_offdiag_U = (tmp_mat_U).dot(T_T) cl_offdiag_U.append(matrix_offdiag_U[:,abasis].dot(inv_U)) else: tmp_mat = factor.func(factor.index_lvl[ind], factor.basis[i_cl]) sch_bl = schur(ind, i_cl, factor) if not sch_bl is None: if tmp_mat.shape == sch_bl.shape: tmp_mat = tmp_mat - sch_bl else: try: tmp_mat = tmp_mat - sch_bl[:,factor.local_basis[i_cl]] except: raise KeyboardInterrupt(f'factorize_lvl: Err!sch_bl wrong size') matrix_offdiag = T.dot(tmp_mat) cl_offdiag.append(inv_L.dot(matrix_offdiag[abasis])) if not factor.symmetric_fun: tmp_mat_U = factor.func(factor.basis[i_cl], factor.index_lvl[ind]) sch_bl = schur(i_cl, ind, factor) if not sch_bl is None: if tmp_mat_U.shape == sch_bl.shape: tmp_mat_U = tmp_mat_U - sch_bl else: try: tmp_mat_U = tmp_mat_U - sch_bl[factor.local_basis[i_cl]] except: raise KeyboardInterrupt(f'factorize_lvl: Err!sch_bl wrong size') matrix_offdiag_U =(tmp_mat_U).dot(T_T) cl_offdiag_U.append(matrix_offdiag_U[:,abasis].dot(inv_U)) factor.off_diag[ind] = cl_offdiag if not factor.symmetric_fun: factor.off_diag_U[ind] = cl_offdiag_U elim_list.add(ind) if l > factor.tail_lvl: prep_next_lvl_schur(factor, l-1) return factor def build_T_old(ind,factor, tau): pr = factor.pr index_lvl = factor.index_lvl[ind] if pr.row_far[ind] == [] and not factor.tree.child[ind]: if factor.tree.child[ind]: print (f"Bad tree!!!!! {ind} has kids and has no far! ") b = factor.index_lvl[ind] T0 = np.identity(b.shape[0]) else: matrix = buildmatrix(ind, factor) if matrix.size: matrix = matrix.reshape(matrix.shape[0], -1) pivots, T0 = maxvol_svd(matrix, tau, 0., 1.05, job='R') result_basis = index_lvl[pivots] else: result_basis = np.zeros(0, dtype=np.uint64) T0 = np.zeros((basis.size, 0), dtype=matrix.dtype) factor.abasis[ind] = np.setdiff1d(index_lvl, result_basis, assume_unique=True) factor.basis[ind] = result_basis sorter = np.argsort(index_lvl) factor.local_abasis[ind] = sorter[np.searchsorted(index_lvl, factor.abasis[ind], sorter=sorter)] factor.local_basis[ind] = pivots T_1 = np.identity(T0.shape[0]) T0[factor.local_abasis[ind]] *= -1 T_1[:,pivots] = T0 factor.T[ind] = T_1 @jit(nopython=True) def inv(perm): inverse = [0] * len(perm) for i, p in enumerate(perm): inverse[p] = i return inverse def build_T(ind,factor, tau, l): pr = factor.pr index_lvl = factor.index_lvl[ind] if(pr.ibuild_matrix == 1): matrix = buildmatrix(ind, factor, tau, l) elif(pr.ibuild_matrix == 2): matrix = buildmatrix_new(ind, factor, tau, l) elif(pr.ibuild_matrix == 3): matrix = buildmatrix_new2(ind, factor, tau, l) elif(pr.ibuild_matrix == 4): matrix = buildmatrix_new3(ind, factor, tau, l) matrix = matrix.T #if matrix.T.shape[0] == 0 or matrix.T.shape[1] == 0: # print(ind, matrix.shape) if(matrix.shape[0] > 0 and matrix.shape[1] >0): # print(np.linalg.norm(matrix,2)) # matrix = np.linalg.qr(matrix, mode='r') # print(ind, matrix.shape) # print(ind,np.linalg.norm(matrix,2)) ss = np.sum(abs(matrix)**2,axis=0) smax = max(ss) # print(ind,np.sqrt(smax)) # # This part of the code needs to be reverted back # k, idx, proj = interp_decomp(matrix, tau) # print(ind,k,index_lvl.shape[0]) if k == index_lvl.shape[0]: factor.abasis[ind] = np.zeros(0) factor.basis[ind] = dc(index_lvl) factor.local_abasis[ind] = np.zeros(0) factor.local_basis[ind] = np.arange(k) factor.T[ind] = np.identity(index_lvl.shape[0], dtype=pr.dtype) else: factor.abasis[ind] = index_lvl[idx[k:]] factor.basis[ind] = index_lvl[idx[:k]] factor.local_abasis[ind] = idx[k:] factor.local_basis[ind] = idx[:k] T_1 = np.identity(index_lvl.shape[0], dtype=pr.dtype) if proj.T.shape[0] > 0: T_1[np.ix_(idx[k:],idx[:k])] = proj.T * -1 factor.T[ind] = T_1 def build_T_wtd(ind, factor): wts = factor.pr.wts D = np.diag(wts[factor.index_lvl[ind]]) inv_D = np.linalg.inv(D) factor.T_wtd[ind] = (inv_D).dot(factor.T[ind].T).dot(D) def factorize_tail(factor): print("in factorize tail") l = factor.tail_lvl n0 = 0 tree = factor.tree pr = factor.pr job = [j for j in range(tree.level[l], tree.level[l+1]) if not pr.row_notransition[j]] rem_job = dc(job) # print(job) # print(rem_job) for ind in job: # print(ind) tmp_mat = factor.func(factor.basis[ind], factor.basis[ind]) n0 = n0 + np.size(factor.basis[ind]) sch_bl = schur_tail(ind, ind, factor, job) if not sch_bl is None: tmp_mat -= sch_bl if factor.symmetric_fun: factor.tail_L[ind] = cholesky(tmp_mat, lower=1) else: if tmp_mat.shape[0] == 0 or tmp_mat.shape[1] == 0: factor.tail_L[ind], factor.tail_U[ind] = np.zeros(tmp_mat.shape),np.zeros(tmp_mat.shape) else: factor.tail_L[ind], factor.tail_U[ind] = lu(tmp_mat, permute_l=True) rem_job.remove(ind) for ind_od in rem_job: od_tmp = factor.func(factor.basis[ind], factor.basis[ind_od]) sch_bl = schur_tail(ind, ind_od, factor, job) if not sch_bl is None: od_tmp -= sch_bl factor.tail_od[ind].append(od_tmp) if not factor.symmetric_fun: od_tmp_U = factor.func(factor.basis[ind_od], factor.basis[ind]) sch_bl = schur_tail(ind_od, ind, factor, job, row_col = 'col') if not sch_bl is None: od_tmp_U -= sch_bl factor.tail_od_U[ind].append(od_tmp_U) return factor,n0 def build_cube_problem(func, n=15, ndim=2, block_size=28, symmetric=1, verbose=1,point_based_tree = True, close_r='1box',num_child_tree = 'hyper', random_points=0, zk=None): count = n**ndim if random_points: position = np.random.rand(ndim,n**ndim) else: if ndim == 1: raise NameError('In progress') elif ndim == 2: x0, x1 = np.meshgrid(np.arange(1,n+1)/(n),np.arange(1,n+1)/n) position = np.vstack((x0.reshape(1,n**ndim),x1.reshape(1,n**ndim))) elif ndim == 3: x0, x1, x2 = np.meshgrid(np.arange(1,n+1)/(n),np.arange(1,n+1)/n, np.arange(1,n+1)/(n)) position = np.vstack((x0.reshape(1,n**ndim),x1.reshape(1,n**ndim), x2.reshape(1,n**ndim))) data = Data(ndim, count, position, close_r=close_r) if func == test_funcs.exp_distance_h2t: data.k = zk tree = Tree(data, block_size, point_based_tree = point_based_tree, num_child_tree = num_child_tree) problem = Problem(func, tree, tree, symmetric, verbose%2) return problem def prep_next_lvl_schur(factor, lvl): tmp_scour_dict = {} tree = factor.tree pr = factor.pr level_count = len(tree.level)-2 if lvl >= level_count-1: print('Error! can not compute prep_next_lvl_schur for this level!') raise KeyboardInterrupt job = [j for j in range(tree.level[lvl], tree.level[lvl+1]) if not pr.row_notransition[j]] for row_i in job: for col_i in factor.pr.schur_list[row_i]: if tree.child[row_i] and tree.child[col_i]: res = None for ii in tree.child[row_i]: for jj in tree.child[col_i]: tmp = schur(ii, jj, factor, ib_row = 'b', ib_col='b') if not tmp is None: if res is None: res = 1 tmp_scour_dict[row_i, col_i] = {} tmp_scour_dict[row_i, col_i][ii,jj] = tmp elif not tree.child[row_i] and tree.child[col_i]: res = None for jj in tree.child[col_i]: tmp = schur(row_i, jj, factor, ib_col='b') if not tmp is None: if res is None: res = 1 tmp_scour_dict[row_i, col_i] = {} tmp_scour_dict[row_i, col_i]['r', jj] = tmp elif tree.child[row_i] and not tree.child[col_i]: res = None for jj in tree.child[row_i]: tmp = schur(jj, col_i, factor, ib_row='b') if not tmp is None: if res is None: res = 1 tmp_scour_dict[row_i, col_i] = {} tmp_scour_dict[row_i, col_i]['c', jj] = tmp factor.prev_lvl_schur = tmp_scour_dict def prep_next_lvl_schur_old(factor, lvl): tmp_scour_dict = {} tree = factor.tree pr = factor.pr level_count = len(tree.level)-2 if lvl >= level_count-1: print('Error! can not compute prep_next_lvl_schur for this level!') raise KeyboardInterrupt job = [j for j in range(tree.level[lvl], tree.level[lvl+1]) if not pr.row_notransition[j]] two_ch = 0 one_ch = 0 other_ch = 0 no_ch = 0 two_ch_nr = 0 one_ch_nr = 0 other_ch_nr = 0 no_ch_nr = 0 schur_n_tot = 0 avrg_nzb = 0 for row_i in job: for col_i in factor.pr.schur_list[row_i]: schur_n_tot += 1 if tree.child[row_i] and tree.child[col_i]: two_ch += 1 res = None pointer_row = 0 nzb = 0 for ii in tree.child[row_i]: pointer_col = 0 for jj in tree.child[col_i]: tmp = schur(ii, jj, factor, ib_row = 'b', ib_col='b') if not tmp is None: nzb += 1 if res is None: l_row = 0 l_col = 0 for i_tmp in tree.child[row_i]: l_row += factor.basis[i_tmp].shape[0] for i_tmp in tree.child[col_i]: l_col += factor.basis[i_tmp].shape[0] res = np.zeros((l_row,l_col), dtype=pr.dtype) res[pointer_row:pointer_row+tmp.shape[0],pointer_col:pointer_col+tmp.shape[1]] = tmp pointer_col += factor.basis[jj].shape[0] pointer_row += factor.basis[ii].shape[0] #print(nzb, nzb/64.) avrg_nzb += nzb/64. if not res is None: #print(nzb, nzb/64.) two_ch_nr += 1 tmp_scour_dict[row_i, col_i] = res elif not tree.child[row_i] and tree.child[col_i]: one_ch += 1 res = None pointer_col = 0 for jj in tree.child[col_i]: tmp = schur(row_i, jj, factor, ib_col='b') if not tmp is None: if res is None: l_col = 0 for i_tmp in tree.child[col_i]: l_col += factor.basis[i_tmp].shape[0] res = np.zeros((factor.index_lvl[row_i].shape[0],l_col)) res[:,pointer_col:pointer_col+tmp.shape[1]] = tmp pointer_col += factor.basis[jj].shape[0] if not res is None: one_ch_nr += 1 tmp_scour_dict[row_i, col_i] = res elif tree.child[row_i] and not tree.child[col_i]: other_ch += 1 res = None pointer_row = 0 for jj in tree.child[row_i]: tmp = schur(jj, col_i, factor, ib_row='b') if not tmp is None: if res is None: l_row = 0 for i_tmp in tree.child[row_i]: l_row += factor.basis[i_tmp].shape[0] res = np.zeros((l_row,factor.index_lvl[col_i].shape[0])) res[pointer_row:pointer_row+tmp.shape[0],:] = tmp pointer_row += factor.basis[jj].shape[0] if not res is None: other_ch_nr += 1 tmp_scour_dict[row_i, col_i] = res else: no_ch += 1 print(f'lvl: {lvl}') if two_ch_nr != 0: print(f'avrg_nzb: {avrg_nzb/two_ch_nr}') #print(f"dict: {sys.getsizeof(factor.prev_lvl_scour)}") print(f'tot: {schur_n_tot}, 2_ch: {two_ch}, 1_ch: {one_ch}, 1_ch:{other_ch}, 0_ch: {no_ch}') print(f'2_ch_nr: {two_ch_nr}, 1_ch_nr: {one_ch_nr}, 1_ch_nr:{other_ch_nr}, 0_ch_nr: {0}') factor.prev_lvl_scour = tmp_scour_dict a = dc(factor.prev_lvl_scour) def build_matrix_from_dict(factor, row_i, col_i): pr = factor.pr tree = factor.tree if tree.child[row_i] and tree.child[col_i]: l_row = 0 l_col = 0 for i_tmp in tree.child[row_i]: l_row += factor.basis[i_tmp].shape[0] for i_tmp in tree.child[col_i]: l_col += factor.basis[i_tmp].shape[0] res = np.zeros((l_row, l_col), dtype=pr.dtype) pointer_row = 0 for ii in tree.child[row_i]: pointer_col = 0 for jj in tree.child[col_i]: if (ii,jj) in factor.prev_lvl_schur[row_i, col_i]: tmp = factor.prev_lvl_schur[row_i, col_i][ii,jj] res[pointer_row:pointer_row+tmp.shape[0],pointer_col:pointer_col+tmp.shape[1]] = tmp pointer_col += factor.basis[jj].shape[0] pointer_row += factor.basis[ii].shape[0] return res elif not tree.child[row_i] and tree.child[col_i]: l_col = 0 for i_tmp in tree.child[col_i]: l_col += factor.basis[i_tmp].shape[0] res = np.zeros((factor.index_lvl[row_i].shape[0],l_col)) pointer_col = 0 for jj in tree.child[col_i]: if ('r', jj) in factor.prev_lvl_schur[row_i, col_i]: tmp = factor.prev_lvl_schur[row_i, col_i]['r',jj] res[:,pointer_col:pointer_col+tmp.shape[1]] = tmp pointer_col += factor.basis[jj].shape[0] return res elif tree.child[row_i] and not tree.child[col_i]: l_row = 0 for i_tmp in tree.child[row_i]: l_row += factor.basis[i_tmp].shape[0] res = np.zeros((l_row,factor.index_lvl[col_i].shape[0])) pointer_row = 0 for jj in tree.child[row_i]: if ('r', jj) in factor.prev_lvl_schur[row_i, col_i]: tmp = factor.prev_lvl_schur[row_i, col_i]['c',jj] res[pointer_row:pointer_row+tmp.shape[0],:] = tmp pointer_row += factor.basis[jj].shape[0] return res else: raise NameError('Error!') def schur(row_i, col_i, factor, ib_row = 'i', ib_col = 'i', ban_list=[]): if not col_i in factor.pr.schur_list[row_i] and not row_i in factor.pr.schur_list[col_i]: return None tree = factor.tree res = level_schour(row_i, col_i, factor, ib_row = ib_row, ib_col = ib_col, ban_list=ban_list) #if (row_i, col_i) in factor.prev_lvl_scour: # res = add_res_and_tmp(res, factor.prev_lvl_scour[row_i, col_i], factor=factor, i_row=row_i, i_col=col_i) if (row_i, col_i) in factor.prev_lvl_schur: bl = build_matrix_from_dict(factor, row_i, col_i) res = add_res_and_tmp(res, bl, factor=factor, i_row=row_i, i_col=col_i) del(bl) if ib_row == 'b' and not res is None: if res.shape[0] != factor.basis[row_i].shape[0]: res = res[factor.local_basis[row_i]] if ib_col == 'b' and not res is None: if res.shape[1] != factor.basis[col_i].shape[0]: res = res[:, factor.local_basis[col_i]] return res def build_problem_old(block_size=26, n=15, ndim = 2, func = test_funcs.log_distance, point_based_tree=1, close_r = '1box', num_child_tree='hyper', random_points=1): iters = 2 onfly = 1 symmetric_tree = 1 verbose = 0 random_init = 2 if (point_based_tree or num_child_tree == 2) and close_r == '1box': print("!!'1box' work only with space_based_tree num_child_tree = 'hyper'! \n !! close_r chanjed to 1.") close_r = 1. pr = build_cube_problem(func, n=n, ndim=ndim, block_size=block_size, symmetric=symmetric_tree, verbose=verbose,point_based_tree=point_based_tree, close_r=close_r,num_child_tree = num_child_tree,random_points = random_points) # pr.dtype = float if not pr.symmetric: raise NameError('Different row and column trees are not supported. Set symmetric=1') return pr def build_sphere_problem(func, n=15, block_size=28, symmetric=1, point_based_tree = True, close_r='1box',num_child_tree = 'hyper', random_points=0, zk=None): count = n position = fibonacci_sphere(n, 1, [0,0,0]) data = Data(3, count, position, close_r=close_r) tree = Tree(data, block_size, point_based_tree = point_based_tree, num_child_tree = num_child_tree) problem = Problem(func, tree, tree, symmetric, 0) return problem def build_sphere_problem_double(func, n=15, ndim=3, block_size=28, symmetric=1, verbose=1,point_based_tree = True, close_r='1box',num_child_tree = 'hyper', zk=None): if ndim == 2: raise NameError(f'ndim = 2 is in progress') r = 1. c = np.zeros(ndim) position = fibonacci_sphere(n, r, c) count = position.shape[1] print (f'Number of points is {count}') if (np.unique(position, axis=1)).shape[1] != count: raise NameError ('Duplocated points!') data = Data(ndim, count, position, close_r=close_r) if func == test_funcs.exp_distance_h2t: data.k = zk tree = Tree(data, block_size, point_based_tree = point_based_tree, num_child_tree = num_child_tree) problem = Problem(func, tree, tree, symmetric, verbose%2) return problem def build_problem_from_file(func, block_size=28, symmetric=1, verbose=1, point_based_tree=True, close_r='1box', num_child_tree='hyper',file=None, eps = 0.51e-6, zk = 1.1 + 1j*0, alpha = 3.0, beta = 0,csc_fun=0, ifwrite=0): x = np.loadtxt(file) ndim = 3 order = int(x[0]) # ndim npatches = int(x[1]) npols = int((order+1)*(order+2)/2) n = npatches*npols zpars = np.array([zk,alpha,beta],dtype=complex) # setup geometry in the correct format norders = order*np.ones(npatches) iptype = np.ones(npatches) srcvals = x[2::].reshape(12,n).copy(order='F') x0 = srcvals[0] x1 = srcvals[1] x2 = srcvals[2] position = np.vstack((x0.reshape(1,n),x1.reshape(1,n), x2.reshape(1,n))) data = Data(ndim, n, position, close_r=close_r) if func == test_funcs.exp_distance_h2t: data.k = zk elif func == test_funcs.double_layer: data.k = zk data.norms = srcvals[9:12] tree = Tree(data, block_size, point_based_tree = point_based_tree, num_child_tree = num_child_tree) problem = Problem(func, tree, tree, symmetric, verbose%2) problem.csc_fun = csc_fun problem.ndim = ndim problem.file = file problem.npatches = npatches problem.srcvals = srcvals problem.eps = eps problem.order = order problem.npatches = npatches ixyzs = np.arange(npatches+1)*npols+1 srccoefs = h3.surf_vals_to_coefs(norders,ixyzs,iptype, srcvals[0:9,:]) wts = h3.get_qwts(norders,ixyzs,iptype,srcvals) problem.wts = wts if csc_fun: nifds,nrfds,nzfds = h3.helm_comb_dir_fds_csc_mem(norders,ixyzs,iptype,srccoefs,srcvals, eps,zpars) ifds,rfds,zfds = h3.helm_comb_dir_fds_csc_init(norders,ixyzs,iptype,srccoefs,srcvals,eps, zpars,nifds,nrfds,nzfds) else: nifds,nrfds,nzfds = h3.helm_comb_dir_fds_block_mem(norders,ixyzs,iptype,srccoefs,srcvals,eps,zpars,ifwrite) ifds,zfds = h3.helm_comb_dir_fds_block_init(norders,ixyzs,iptype,srccoefs,srcvals,eps,zpars,nifds,nzfds) problem.ixyzs = ixyzs problem.srccoefs = srccoefs problem.ifds = ifds if csc_fun: problem.rfds = rfds problem.zfds = zfds problem.zpars = zpars problem.beta = beta problem.norders = np.ones(npatches)*order problem.npols = npols problem.npts = npols*npatches problem.iptype = np.ones(npatches) problem.ifwrite = ifwrite return problem def build_problem_wtorus(func, block_size=28, symmetric=1, verbose=1, point_based_tree=True, close_r='1.1', num_child_tree='hyper', eps = 0.51e-6, zk = 1.1 + 1j*0, alpha = 3.0, beta = 0, csc_fun=0, ifwrite=0, nu=10, order=3): radii = np.array([1.0,2.0,0.25]) scales = np.array([1.2,1.0,1.7]) nosc = 5 npatches = 2*nu*nu npols = int((order+1)*(order+2)/2) npts = int(npatches*npols) norders,ixyzs,iptype,srcvals,srccoefs,wts = h3.get_wtorus_geom(radii,scales, nosc,nu,nu,npatches,order,npts) # x = np.loadtxt(file) ndim = 3 # order = int(x[0]) # ndim # npatches = int(x[1]) # npols = int((order+1)*(order+2)/2) n = npatches*npols zpars = np.array([zk,alpha,beta],dtype=complex) # setup geometry in the correct format # norders = order*np.ones(npatches) iptype = np.ones(npatches) # srcvals = x[2::].reshape(12,n).copy(order='F') x0 = srcvals[0] x1 = srcvals[1] x2 = srcvals[2] position = np.vstack((x0.reshape(1,n),x1.reshape(1,n), x2.reshape(1,n))) data = Data(ndim, n, position, close_r=close_r) data.k = zk data.norms = srcvals[9:12] tree = Tree(data, block_size, point_based_tree = point_based_tree, num_child_tree = num_child_tree) problem = Problem(func, tree, tree, symmetric, verbose%2) problem.csc_fun = csc_fun problem.ndim = ndim problem.file = None problem.npatches = npatches problem.srcvals = srcvals problem.eps = eps problem.order = order problem.npatches = npatches ixyzs = np.arange(npatches+1)*npols+1 srccoefs = h3.surf_vals_to_coefs(norders,ixyzs,iptype, srcvals[0:9,:]) wts = h3.get_qwts(norders,ixyzs,iptype,srcvals) problem.wts = wts t0 = time() if csc_fun: nifds,nrfds,nzfds = h3.helm_comb_dir_fds_csc_mem(norders,ixyzs,iptype,srccoefs,srcvals, eps,zpars) ifds,rfds,zfds = h3.helm_comb_dir_fds_csc_init(norders,ixyzs,iptype,srccoefs,srcvals,eps, zpars,nifds,nrfds,nzfds) else: # print("eps=",eps) nifds,nrfds,nzfds = h3.helm_comb_dir_fds_block_mem(norders,ixyzs,iptype,srccoefs,srcvals,eps,zpars,ifwrite) # print("nifds=",nifds) # print("nzfds=",nzfds) ifds,zfds = h3.helm_comb_dir_fds_block_init(norders,ixyzs,iptype,srccoefs,srcvals,eps,zpars,nifds,nzfds) t1 = time() print("time taken for quadrature correction="+str(t1-t0)) problem.ixyzs = ixyzs problem.srccoefs = srccoefs problem.ifds = ifds if csc_fun: problem.rfds = rfds problem.zfds = zfds problem.zpars = zpars problem.beta = beta problem.norders = np.ones(npatches)*order problem.npols = npols problem.npts = npols*npatches problem.iptype = np.ones(npatches) problem.ifwrite = ifwrite return problem def build_problem(geom_type='qube',block_size=26, n=15, ndim = 2, func = test_funcs.log_distance, point_based_tree=0, close_r = 1., num_child_tree='hyper', random_points=1, file = None, eps = 0.51e-6, zk = 1.1 + 1j*0, alpha = 3.0, beta = 0, wtd_T=0, ibuild_matrix=1,add_up_level_close=0,half_sym=0,csc_fun=0,q_fun=0,ifwrite=0, nu=10, order=10): iters = 2 onfly = 1 symmetric_tree = 1 verbose = 0 random_init = 2 if point_based_tree and close_r == '1box': print("!!'1box' does not work with point_based_tree = 1, close_r chanjed to 1.") close_r = 1. if geom_type == 'qube': pr = build_cube_problem(func, n=n, ndim=ndim, block_size=block_size, symmetric=symmetric_tree, verbose=verbose, point_based_tree=point_based_tree, close_r=close_r,num_child_tree = num_child_tree,random_points = random_points,zk=zk) if geom_type == 'sphere_test': pr = build_sphere_problem(func, n=n, block_size=block_size, point_based_tree=point_based_tree, close_r=close_r, num_child_tree=num_child_tree) elif geom_type == 'sphere_double': pr = build_sphere_problem_double(func, n=n, ndim=ndim, block_size=block_size, symmetric=symmetric_tree, verbose=verbose, point_based_tree=point_based_tree, close_r=close_r,num_child_tree = num_child_tree,zk=zk) elif geom_type == 'from_file': if file is None: raise NameError(f"Geometry type '{geom_type}' should have nonepty file!") pr = build_problem_from_file(func, block_size=block_size,symmetric=symmetric_tree, verbose=verbose, point_based_tree=point_based_tree, close_r=close_r, num_child_tree=num_child_tree, file=file,eps=eps, zk=zk, alpha=alpha, beta=beta,csc_fun=csc_fun,ifwrite=ifwrite) elif geom_type == 'wtorus': pr = build_problem_wtorus(func, block_size=block_size,symmetric=symmetric_tree, verbose=verbose, point_based_tree=point_based_tree, close_r=close_r, num_child_tree=num_child_tree, eps=eps, zk=zk, alpha=alpha, beta=beta,csc_fun=csc_fun,ifwrite=ifwrite, nu=nu, order=order) else: raise NameError (f"Geometry type '{geom_type}' is not supported. Try 'qube/sphere/from_file/wtorus'") if not pr.symmetric: raise NameError('Different row and column trees are not supported. Set symmetric=1') pr.add_up_level_close = add_up_level_close if add_up_level_close: print('Warning! up-level close is not well-tested!') pr.csc_fun = csc_fun pr.wtd_T = wtd_T pr.ibuild_matrix = ibuild_matrix pr.half_sym = half_sym pr.q_fun = q_fun tree = pr.row_tree level_count = len(tree.level) - 2 for i in range(level_count-1, -1, -1): job = [j for j in range(tree.level[i], tree.level[i+1])] exist_no_trans_t = False exist_no_trans_f = False for ind in job: if pr.row_notransition[ind]: exist_no_trans_t = True else: exist_no_trans_f = True if exist_no_trans_t and exist_no_trans_f: print ('lvl', i, '+-') pr.tail_lvl = i for ind in job: pr.row_notransition[ind] = False elif exist_no_trans_t: pr.tail_lvl = i+1 break # print(tree.child[0:10]) return pr def fmm_lu_old(pr, proxy_p=1., proxy_r=1., symmetric_fun = 0, tau=1e-9): csc_fun = pr.csc_fun tree = pr.row_tree level_count = len(tree.level) - 2 pr.multilevel_close() pr.schur_precompute() factor = Factor(pr, proxy_p=proxy_p, proxy_r=proxy_r, symmetric_fun = symmetric_fun) ind_l = [] factor.tail_lvl = pr.tail_lvl for i in range(level_count-1, factor.tail_lvl-1, -1): job = [j for j in range(tree.level[i], tree.level[i+1])] for ind in job: factor.init_index_lvl(ind) for i in range(level_count-1, factor.tail_lvl-1, -1): job = [j for j in range(tree.level[i], tree.level[i+1])] for ind in job: factor.upd_index_lvl(ind) if csc_fun: factor.csc = pr.compute_csc(factor, i) ind_l += job factor = factorize_lvl(factor, job, tau=tau, l=i) if csc_fun: # factor.csc_fun = 0 factor.csc = pr.compute_csc_tail(factor) factor = factorize_tail(factor) return factor def fibonacci_sphere(numpts, k, c): ga = (3 - np.sqrt(5)) * np.pi # golden angle # Create a list of golden angle increments along tha range of number of points theta = ga * np.arange(numpts) # Z is a split into a range of -1 to 1 in order to create a unit circle z = np.linspace(1/numpts-1, 1-1/numpts, numpts) # a list of the radii at each height step of the unit circle radius = np.sqrt(1 - z * z) # Determine where xy fall on the sphere, given the azimuthal and polar angles x = radius * k * np.cos(theta) + c[0] y = radius * k * np.sin(theta) + c[1] z = z * k + c[2] return np.array((x, y, z)) # FMM-LU solver def build_csc(pr, row_ind, col_ptr): # npols = int((pr.ndim+1)*(pr.ndim+2)/2) # npts = pr.npatches*npols norders = pr.ndim*np.ones(pr.npatches) iptype = np.ones(pr.npatches) eps = pr.eps wts = h3.get_qwts(norders,pr.ixyzs,iptype,pr.srcvals) col_ptr = col_ptr + 1 row_ind = row_ind + 1 return h3.helm_comb_dir_fds_csc_matgen(norders,pr.ixyzs,iptype,pr.srccoefs,pr.srcvals, eps,pr.zpars,pr.ifds,pr.rfds,pr.zfds,col_ptr,row_ind) def compute_csc(factor, i, coef): pr = factor.pr tree = pr.row_tree # tmp_lil = identity(factor.n, dtype=bool, format='lil') tmp_lil = lil((factor.n,factor.n)) job = [j for j in range(tree.level[i], tree.level[i+1])] for ind in job: for cl in pr.lvl_close[ind]: tmp_lil[np.ix_(factor.index_lvl[ind], factor.index_lvl[cl])] = np.ones((factor.index_lvl[ind].shape[0], factor.index_lvl[cl].shape[0])) print (f'level: {i}, tmp_lil.nnz:{tmp_lil.nnz}, factor.n**2:{factor.n**2}, factor.n:{factor.n}, tmp_lil.nnz/factor.n:{tmp_lil.nnz/factor.n}') # factor.full_lil += tmp_lil tmp_csc = csc(tmp_lil) # print (tmp_csc.shape) row = tmp_csc.indices col = tmp_csc.indptr # print (tmp_csc.data.shape) # print ('---before csc_log_fun') data = build_csc(pr, row, col) # print ('---after csc_log_fun') # print(data.shape) npols = int((pr.ndim+1)*(pr.ndim+2)/2) npts = pr.npatches*npols addition = coef*2*np.pi*sps.identity(factor.n,format='csc')*pr.zpars[2] # print (2*np.pi*pr.zpars[2]) csc_mat = csc((data, row, col),shape=(factor.n,factor.n)) print (addition.shape, csc_mat.shape, factor.n) return csc_mat + addition def compute_csc_tail(factor, coef): print(' compute_csc_tail pass 0') pr = factor.pr tree = pr.row_tree tmp_lil = lil((factor.n,factor.n)) i = factor.tail_lvl job = [j for j in range(tree.level[i], tree.level[i+1])] for ind in job: for cl in job: tmp_lil[np.ix_(factor.basis[ind], factor.basis[cl])] = np.ones((factor.basis[ind].shape[0], factor.basis[cl].shape[0])) # print(' compute_csc_tail pass 1') print (f'tmp_lil.nnz:{tmp_lil.nnz}, factor.n**2:{factor.n**2}, factor.n:{factor.n}, tmp_lil.nnz/factor.n:{tmp_lil.nnz/factor.n}') # factor.full_lil += tmp_lil tmp_csc = csc(tmp_lil) # print(' compute_csc_tail pass 2') row = tmp_csc.indices col = tmp_csc.indptr # print(' compute_csc_tail pass 3') data = build_csc(pr, row, col) npols = int((pr.ndim+1)*(pr.ndim+2)/2) npts = pr.npatches*npols addition = coef*2*np.pi*sps.identity(factor.n,format='csc')*pr.zpars[2] csc_mat = csc((data, row, col),shape=(factor.n,factor.n)) return csc_mat + addition @profile def fmm_lu(pr, proxy_p=(1, 100), proxy_r=1., symmetric_fun = 0, tau=1e-9, out_f=0): coef = pr.coef if out_f: with open(out_f, 'a') as f: f.write('----- befor factor level: csc_fun: {pr.csc_fun}\n') else: print (f'----- befor factor level: csc_fun: {pr.csc_fun}') tree = pr.row_tree level_count = len(tree.level) - 2 pr.multilevel_close() pr.schur_precompute() t0 = time() factor = Factor(pr, proxy_p=proxy_p, proxy_r=proxy_r, symmetric_fun = symmetric_fun) ind_l = [] factor.tail_lvl = pr.tail_lvl for i in range(level_count-1, factor.tail_lvl-1, -1): job = [j for j in range(tree.level[i], tree.level[i+1])] for ind in job: factor.init_index_lvl(ind) for i in range(level_count-1, factor.tail_lvl-1, -1): job = [j for j in range(tree.level[i], tree.level[i+1])] for ind in job: factor.upd_index_lvl(ind) if pr.csc_fun: factor.csc = compute_csc(factor, i, coef) # print (f'------lvl {i}, CSC is done, start factor, csc[0,0]: {factor.csc[0,0]}') ind_l += job # print('level=',i) factor = factorize_lvl(factor, job, tau=tau, l=i) # if out_f: # with open(out_f, 'a') as f: # f.write(f'lvl {i} done!\n') # else: # print(f'lvl {i} done!') # if out_f: # with open(out_f, 'a') as f: # f.write(f'----- after factor level, t={time()-t0}\n') # else: # print (f'----- after factor level, t={time()-t0}') t0 = time() if pr.csc_fun: factor.csc = compute_csc_tail(factor, coef) factor,n0 = factorize_tail(factor) # if out_f: # with open(out_f, 'a') as f: # f.write(f'----- after factor tail: t={time() - t0}sec\n') # else: # print (f'----- after factor tail, t={time()-t0}') return factor,n0 def fmm_lu_no_print(pr, proxy_p=(1,100), proxy_r=1., symmetric_fun = 0, tau=1e-9): #print (f'----- befor factor level: csc_fun: {pr.csc_fun}') coef = pr.coef tree = pr.row_tree level_count = len(tree.level) - 2 pr.multilevel_close() pr.schur_precompute() t0 = time() factor = Factor(pr, proxy_p=proxy_p, proxy_r=proxy_r, symmetric_fun = symmetric_fun) ind_l = [] factor.tail_lvl = pr.tail_lvl for i in range(level_count-1, factor.tail_lvl-1, -1): job = [j for j in range(tree.level[i], tree.level[i+1])] for ind in job: factor.init_index_lvl(ind) for i in range(level_count-1, factor.tail_lvl-1, -1): job = [j for j in range(tree.level[i], tree.level[i+1])] for ind in job: factor.upd_index_lvl(ind) if pr.csc_fun: factor.csc = compute_csc(factor, i, coef) # print (f'------lvl {i}, CSC is done, start factor, csc[0,0]: {factor.csc[0,0]}') ind_l += job factor = factorize_lvl(factor, job, tau=tau, l=i) #print (f'----- after factor level, t={time()-t0}') t0 = time() if pr.csc_fun: factor.csc = compute_csc_tail(factor, coef) factor = factorize_tail(factor) #print (f'----- after factor tail, t={time()-t0}') return factor def factor_csc_to_full(factor): col_ptr = np.arange(factor.n+1)*factor.n row_ind = np.tile(np.arange(factor.n),factor.n) data = build_csc(factor.pr, row_ind, col_ptr) factor.csc = csc((data, row_ind, col_ptr)) def fmm_lu_solve(pr,eps,rhst,proxy_p,proxy_r,verbose=0): t0 = time() if verbose: factor,n0 = fmm_lu(pr, tau = eps, proxy_p=proxy_p, proxy_r=proxy_r, symmetric_fun=0) else: factor = fmm_lu_no_print(pr, tau = eps, proxy_p=proxy_p, proxy_r=proxy_r, symmetric_fun=0) t1 = time() # print(f'Fact time: {t1 - t0}') ans = factor.solve(rhst) # print(f'Sol time: {time() - t1}') return ans, factor, t1 - t0, time() - t1,n0