def devfun(theta): LambdatZtW = csc_matrix(Lambdat @ ZtW) L = cholesky_AAt(LambdatZtW, beta=1) L.L().todense().tofile('L-py.bin') # deviance function calculations Lambdat.data[:] = thfun(theta) Lambdat.todense().tofile('Lambdat-new-py.bin') LambdatZtW = csc_matrix(Lambdat @ ZtW) L = cholesky_AAt(LambdatZtW, beta=1) L.L().todense().tofile('L-new-py.bin') cu = L.solve_L(L.apply_P(Lambdat @ ZtWy), use_LDLt_decomposition=False) cu.tofile('cu-py.bin') RZX = L.solve_L(L.apply_P(Lambdat @ ZtWX), use_LDLt_decomposition=False) RZX.tofile('RZX-py.bin') DD = XtWX - RZX.T @ RZX DD.tofile('DD-py.bin') # ran into an issue with using CHOLMOD here, fall back to scipy.sparse DD = csc_matrix(DD) betab = XtWy - RZX.T @ cu beta = spsolve(DD, betab) u = L.apply_Pt( L.solve_Lt((cu.T - RZX @ beta)[0], use_LDLt_decomposition=False)) b = Lambdat.T @ u mu = Z.T @ b + X @ beta + offset # remember to do this in sparse mode wtres = Whalf * (y - mu) pwrss = (wtres * wtres).sum() + (u * u).sum() fn = float(len(mu)) ld = L.logdet() REML = True if REML: ld += cholesky(DD).logdet() fn -= len(beta) deviance = ld + fn * (1. + np.log(2. * np.pi * pwrss) - np.log(fn)) np.array([deviance]).tofile('deviance-py.bin') return deviance
def normal_equation_projections(A, m, n, orth_tol, max_refin, tol): """Return linear operators for matrix A using ``NormalEquation`` approach. """ # Cholesky factorization factor = cholesky_AAt(A) # z = x - A.T inv(A A.T) A x def null_space(x): v = factor(A.dot(x)) z = x - A.T.dot(v) # Iterative refinement to improve roundoff # errors described in [2]_, algorithm 5.1. k = 0 while orthogonality(A, z) > orth_tol: if k >= max_refin: break # z_next = z - A.T inv(A A.T) A z v = factor(A.dot(z)) z = z - A.T.dot(v) k += 1 return z # z = inv(A A.T) A x def least_squares(x): return factor(A.dot(x)) # z = A.T inv(A A.T) x def row_space(x): return A.T.dot(factor(x)) return null_space, least_squares, row_space
def spsolve(sparse_X, dense_b): # wrap the cholesky call in a context manager that swallows the # low-level std-out to stop it from swamping our stdout (these low-level # prints come from METIS, but the solution behaves as normal) with stdout_redirected(): factor = cholesky_AAt(sparse_X.T) return factor(sparse_X.T.dot(dense_b)).toarray()
def __init__(self, At, b, c, K, options): # x: lagrange multipliers self.x = np.zeros(shape=(c.shape[0], 1)) # y: free variables self.y = np.ones(shape=(b.shape[0], 1)) # z: conic variables zeroCones = np.zeros(shape=(K.f, 1)) # Equality: 0s nnOrthants = np.zeros(shape=(K.l, 1)) # Inequality: 1s PSDs = [np.identity(size).reshape((size**2, 1)) for size in K.s] # PSD: identity self.z = vstack([zeroCones, nnOrthants, *PSDs]) # Stack up the vectors # Primal and dual residuals self.pres = np.linalg.norm(c - At*self.y - self.z) self.dres = float('inf') # Cost self.cost = b.transpose() * self.y # Time self.time = CPUTime() # Factorization of system matrix self.KKT = cholesky_AAt( At.transpose(), 0.0 )
def projectionls(neighbors, smp, Xsmp2D): #n = len(X) rows = len(neighbors) + len(smp) cols = len(neighbors) sA = SparseM2D() for i in range(len(neighbors)): sA.append(i, i, 1.0) maxv = -float('inf') minv = float('inf') for nv in neighbors[i]: j = nv[0] w = nv[1] if maxv < w: maxv = w if minv > w: minv = w sumv = 0.0 for nv in neighbors[i]: w = nv[1] if maxv > minv: d = (((w - minv) / (maxv - minv)) * (0.9)) + 0.1 sumv += (1 / d) for nv in neighbors[i]: j = nv[0] w = nv[1] if maxv > minv: d = (((w - minv) / (maxv - minv)) * (0.9)) + 0.1 sA.append(i, j, (-((1.0 / d) / sumv))) else: sA.append(i, j, (-(1.0 / len(neighbors[i])))) # add samples for i in range(len(smp)): sA.append(len(neighbors) + i, smp[i], 1.0) sB = SparseM2D() for i in range(len(Xsmp2D)): sB.append(len(neighbors) + i, 0, Xsmp2D[i][0]) sB.append(len(neighbors) + i, 1, Xsmp2D[i][1]) A = sA.makeScipySparse(rows, cols) B = sB.makeScipySparse(rows, 2) # ATA = (A.T*A) # ATB = (A.T*B) # factor = cholesky(ATA, beta=1.0) # x2 = factor(ATB).toarray() factor = cholesky_AAt(A.T) x2 = factor(A.T * B).toarray() # print(ATA) # print(ATB) #print(x2) return x2
def spsolve(sparse_X, dense_b): # wrap the cholesky call in a context manager that swallows the # low-level std-out to stop it from swamping our stdout (these low-level # prints come from METIS, but the solution behaves as normal) # fileno doesnt seem to work when called by Jupyter # comment by Thanos # try: # __IPYTHON__ # except NameError: with stdout_redirected(): factor = cholesky_AAt(sparse_X.T) # else: # factor = cholesky_AAt(sparse_X.T) return factor(sparse_X.T.dot(dense_b)).toarray()
def computeExactComponent(self, omega): print 'dAlpha' print 'build LHS...' t0 = time.time() # #LHS = np.dot(self.hodge1,self.d0.todense()) #ss = np.shape(omega)[0] #LHS = csc_matrix(LHS) #LHS = self.d0T.dot(LHS) #LHS = LHS #+ (1.e-8 * csc_matrix(np.identity(ss,float))) ## LHS = self.d0T.dot(self.hodge1) ss = np.shape(LHS)[0] LHS = csc_matrix(LHS) LHS = LHS.dot(self.d0) LHS = LHS #- (1.e-8 * csc_matrix(np.identity(ss,float))) #LHS = LHS + (1.e-8 * np.identity(ss,float)) #LHS = csc_matrix(LHS) # tSolve = time.time() - t0 print("...sparse alpha LHS completed.") print("alpha LHS build took {:.5f} seconds.".format(tSolve)) print 'build RHS...' t0 = time.time() RHS = self.d0T.dot(self.hodge1.dot(omega)) #RHS = self.d0T.dot(omega) tSolve = time.time() - t0 print("...sparse alpha RHS completed.") print("alpha RHS build took {:.5f} seconds.".format(tSolve)) print 'solve dAlpha' #dAlpha = dsolve.spsolve(LHS, RHS , use_umfpack=True) #dAlpha = scipy.sparse.linalg.cg(LHS, RHS)[0] #sparse LU solve: #DLU = scipy.sparse.linalg.splu(LHS) #dAlpha = DLU.solve(RHS) #sparse Cholesky solve: llt = skchol.cholesky_AAt(LHS) #factor dAlpha = llt(RHS) # now push alpha to a 1 form using d: dAlpha = self.d0.dot(dAlpha) #alpha = np.dot(self.d0.todense(), # alpha) return dAlpha
def fit(self): n = self.X.shape[0] self.mphi = self.phi(self.X) dphi = self.mphi.shape[1] self.factor = spch.cholesky_AAt(self.mphi.T, beta=self.variance) # precompute some useful quantities z = self.mphi.T.dot(self.y) self.theta = self.factor(z) # compute nll ssqr = self.variance ll = 0.5 * (z.T.dot(self.theta) / ssqr - self.factor.logdet() - self.y.T.dot(self.y) / ssqr - np.log(2 * np.pi) * n - np.log(ssqr) * (n - dphi)) self._nll = -ll[0, 0]
def spsolve(sparse_X, dense_b): # wrap the cholesky call in a context manager that swallows the # low-level std-out to stop it from swamping our stdout (these low-level # prints come from METIS, but the solution behaves as normal) with stdout_redirected(): try: factor = cholesky_AAt(sparse_X.T) X = factor(sparse_X.T.dot(dense_b)).toarray() except CholmodError: warnings.warn("Matrix not positive definite." "cholesky decomposition not available, using " "scipy solver instead") #scipy.io.savemat('/data/tmp16', {'A_s': sparse_X}) #exit(0) X = scipy_spsolve(sparse_X.T.dot(sparse_X), sparse_X.T.dot(dense_b)).toarray() return X
def test_cholesky_matrix_market(): for problem in ("well1033", "illc1033", "well1850", "illc1850"): X = mm_matrix(problem) y = mm_matrix(problem + "_rhs1") answer = np.linalg.lstsq(X.todense(), y)[0] XtX = (X.T * X).tocsc() Xty = X.T * y for mode in ("auto", "simplicial", "supernodal"): assert_allclose(cholesky(XtX, mode=mode)(Xty), answer) assert_allclose(cholesky_AAt(X.T, mode=mode)(Xty), answer) assert_allclose(cholesky(XtX, mode=mode).solve_A(Xty), answer) assert_allclose(cholesky_AAt(X.T, mode=mode).solve_A(Xty), answer) f1 = analyze(XtX, mode=mode) f2 = f1.cholesky(XtX) assert_allclose(f2(Xty), answer) assert_raises(CholmodError, f1, Xty) assert_raises(CholmodError, f1.solve_A, Xty) assert_raises(CholmodError, f1.solve_LDLt, Xty) assert_raises(CholmodError, f1.solve_LD, Xty) assert_raises(CholmodError, f1.solve_DLt, Xty) assert_raises(CholmodError, f1.solve_L, Xty) assert_raises(CholmodError, f1.solve_D, Xty) assert_raises(CholmodError, f1.apply_P, Xty) assert_raises(CholmodError, f1.apply_Pt, Xty) f1.P() assert_raises(CholmodError, f1.L) assert_raises(CholmodError, f1.LD) assert_raises(CholmodError, f1.L_D) assert_raises(CholmodError, f1.L_D) f1.cholesky_inplace(XtX) assert_allclose(f1(Xty), answer) f3 = analyze_AAt(X.T, mode=mode) f4 = f3.cholesky(XtX) assert_allclose(f4(Xty), answer) assert_raises(CholmodError, f3, Xty) f3.cholesky_AAt_inplace(X.T) assert_allclose(f3(Xty), answer) print(problem, mode) for f in (f1, f2, f3, f4): pXtX = XtX.todense()[f.P()[:, np.newaxis], f.P()[np.newaxis, :]] assert_allclose(np.prod(f.D()), np.linalg.det(XtX.todense())) assert_allclose((f.L() * f.L().T).todense(), pXtX) L, D = f.L_D() assert_allclose((L * D * L.T).todense(), pXtX) b = np.arange(XtX.shape[0])[:, np.newaxis] assert_allclose(f.solve_A(b), np.dot(XtX.todense().I, b)) assert_allclose(f(b), np.dot(XtX.todense().I, b)) assert_allclose(f.solve_LDLt(b), np.dot((L * D * L.T).todense().I, b)) assert_allclose(f.solve_LD(b), np.dot((L * D).todense().I, b)) assert_allclose(f.solve_DLt(b), np.dot((D * L.T).todense().I, b)) assert_allclose(f.solve_L(b), np.dot(L.todense().I, b)) assert_allclose(f.solve_Lt(b), np.dot(L.T.todense().I, b)) assert_allclose(f.solve_D(b), np.dot(D.todense().I, b)) assert_allclose(f.apply_P(b), b[f.P(), :]) assert_allclose(f.apply_P(b), b[f.P(), :]) # Pt is the inverse of P, and argsort inverts permutation # vectors: assert_allclose(f.apply_Pt(b), b[np.argsort(f.P()), :]) assert_allclose(f.apply_Pt(b), b[np.argsort(f.P()), :])
def solve_linear_system(M, C, backend="all", check=True, backend_error_tol=1e-4, verbose=0): """ **Description:** Solves the sparse linear system M*x+C=0. **Arguments:** - `M` *(scipy.sparse.csr_matrix)*: A scipy csr_matrix. - `C` *(array_like)*: A vector of floats. - `backend` *(str, optional, default="all")*: The sparse linear solver to use. Options are "all", "sksparse" and "scipy". When set to "all" it tries all available backends. - `check` *(bool, optional, default=True)*: Whether to explicitly check the solution to the linear system. - `backend_error_tol` *(float, optional, default=1e-4)*: Error tolerance for the solution of the linear system. - `verbose` *(int, optional, default=0)*: The verbosity level. - verbose = 0: Do not print anything. - verbose = 1: Print warnings when backends fail. **Returns:** *(numpy.ndarray)* Floating-point solution to the linear system. **Example:** We solve a very simple linear equation. ```python {5} from cytools.utils import to_sparse, solve_linear_system id_array = [[0,0,1],[1,1,1],[2,2,1],[3,3,1],[4,4,1]] M = to_sparse(id_array, sparse_type="csr") C = [1,1,1,1,1] solve_linear_system(M, C) # array([-1., -1., -1., -1., -1.]) ``` """ backends = ["all", "sksparse", "scipy"] if backend not in backends: raise Exception("Invalid linear system backend. " f"The options are: {backends}.") system_solved = False if backend == "all": for s in backends[1:]: solution = solve_linear_system(M, C, backend=s, check=check, backend_error_tol=backend_error_tol, verbose=verbose) if solution is not None: return solution elif backend == "sksparse": try: from sksparse.cholmod import cholesky_AAt factor = cholesky_AAt(M.transpose()) CC = -M.transpose() * C solution = factor(CC) system_solved = True except: if verbose >= 1: print("Linear backend error: sksparse failed.") system_solved = False elif backend == "scipy": try: from scipy.sparse.linalg import dsolve MM = M.transpose() * M CC = -M.transpose() * C solution = dsolve.spsolve(MM, CC).tolist() system_solved = True except: if verbose >= 1: print("Linear backend error: scipy failed.") system_solved = False if system_solved and check: res = M.dot(solution) + C max_error = max(abs(s) for s in res.flat) if max_error > backend_error_tol: system_solved = False if verbose >= 1: print("Linear backend error: Large numerical error.") if system_solved: return solution else: return None
def execute(self,context): path='/home/student/Documents/codeFiles/'#bpy.utils.resource_path('USER') SourceInpt=np.loadtxt(path+'source_vertz.txt',delimiter=',') TrgtInpt=np.loadtxt(path+'target_vertz.txt',delimiter=',') if int(np.size(TrgtInpt)/len(TrgtInpt))==1: TrgtInpt=np.reshape(TrgtInpt,(len(TrgtInpt),1)) SF=ReadFaces(path+'source_facez.txt') TF=ReadFaces(path+'target_facez.txt') if context.scene.CorrPath!='Default': CrT,CrS=ReadCorrespondences(context.scene.CorrPath,TF) else: CrT=list(range(len(TF))) CrS=[i for i in CrT] NVrt=len(TrgtInpt)//3 NPs=len(SourceInpt[0,:]) if self.seqType=='DTSumnerPopovic': strttime=time.time() X=ConnectionMatrices(CrT,TF,NVrt) factor=chmd.cholesky(((X[:,:3*(NVrt-1)].transpose().dot(X[:,:3*(NVrt-1)]))).tocsc()) Vref=X.dot(TrgtInpt[:,0]) print("Preprocessing....",time.time()-strttime) strttime=time.time() Vdef=DTSumAndPop(SourceInpt[:,0:2],Vref,SF,CrS) Pose=factor(X[:,:3*(NVrt-1)].transpose().dot(Vdef)) Pose=np.append(Pose,np.zeros(3)) print("Pose Computation .....",time.time()-strttime) CreateMesh(np.reshape(Pose,(NVrt,3)),TF,1) else: strttime=time.time() A=sp.lil_matrix((2*len(CrT),NVrt)) i=0 for t in CrT: A[2*i:2*i+2,TF[t]]=np.array([[-1,1,0],[-1,0,1]]) i+=1 A=A.tocsc() factor=chmd.cholesky_AAt((A[:,0:(NVrt-1)].transpose()).tocsc()) print("Preprocessing....",time.time()-strttime) strttime=time.time() Crrs=[] Crrt=[] for i in range(len(CrT)): Crrt=Crrt+TF[CrT[i]] Crrs=Crrs+SF[CrS[i]] Y=DTManifold(SourceInpt[:,0:2],TrgtInpt[:,0],Crrt,Crrs) P1=np.zeros([NVrt,3]) P1[:NVrt-1]=factor(A[:,0:NVrt-1].transpose().dot(Y)) print("Pose Computation .....",time.time()-strttime) CreateMesh(P1,TF,1) return {'FINISHED'}
def execute(self, context): global Phi, path, FilePath ################# Input from user ############### Rigname = context.scene.RigName if path[len(path) - len(Rigname) - 1:len(path) - 1] != Rigname: path = FilePath + Rigname + '/' ################################################ Vrt = np.loadtxt(path + '/' + 'vertz.txt', delimiter=',') Fcs = ReadTxt(path + '/' + Rigname + '_facz.txt') Nrml = np.loadtxt(path + '/' + 'Normal.txt', delimiter=',') NPs, NV = np.shape(Vrt) NPs = NPs // 3 NF = len(Fcs) AA = ConnectionMatrices(Fcs, NV, NF) factor = chmd.cholesky_AAt(AA[:(NV - 1), :].tocsc()) ########################## Comute Skeleton Frames ########################################### Joints = ReadTxt(path + '/' + Rigname + '_Joints.txt') Links = ReadTxt(path + '/' + Rigname + '_SkelEdgz.txt') VecIndx = [] for ln in Links: VecIndx.append(ln) print("Computing Skeleton Frames.....") NJ = len(Joints) NFrm = len(VecIndx) SFrm = np.zeros([3, 3]) SrFrm = np.zeros([3, 3 * NFrm]) A = np.zeros([NJ, 3]) RS = np.zeros((3 * NFrm, NPs - 1)) AS = np.zeros((NFrm, NPs - 1)) for ps in range(NPs): X = Vrt[3 * ps:3 * ps + 3, :].T for r in range(NJ): A[r] = np.mean(X[Joints[r]], axis=0) if ps == 0: np.savetxt(path + '/' + Rigname + '_RefSkel.txt', A, delimiter=',') t = 0 for r in range(NFrm): V = (A[VecIndx[r][0]] - A[VecIndx[r][1]] ) / np.linalg.norm(A[VecIndx[r][0]] - A[VecIndx[r][1]]) tmp = X[Joints[VecIndx[r][0]][0]] - A[VecIndx[r][0]] B = np.cross(V, tmp) / np.linalg.norm(np.cross(V, tmp)) N = np.cross(B, V) / np.linalg.norm(np.cross(B, V)) SFrm[:, 0] = V SFrm[:, 1] = B SFrm[:, 2] = N if ps != 0: Axs, Angl = RotMatToAnglAxis( np.dot(SFrm, SrFrm[:, 3 * r:3 * r + 3].T)) RS[3 * r:3 * r + 3, ps - 1] = Axs AS[r, ps - 1] = Angl else: SrFrm[:, 3 * r:3 * r + 3] = SFrm np.savetxt(path + '/' + Rigname + '_RefFrames.txt', SrFrm, delimiter=',') ################### Clustering ################### C = ReadTxt(path + '/' + 'ClusterKmeans.txt') Ncl = max(C[0]) + 1 Cls = [[]] * Ncl t = 0 for i in C[0]: Cls[i] = Cls[i] + [t] t += 1 Vbar = np.zeros((6 * (NPs - 1), NF)) Vref = np.zeros((6, NF)) for i in range(NF): f = Fcs[i] for ps in range(NPs): tmp = Vrt[3 * ps:3 * ps + 3, f[1:]].T - Vrt[3 * ps:3 * ps + 3, f[0]] if ps != 0: Vbar[6 * (ps - 1):6 * (ps - 1) + 6, i] = np.ravel(tmp) else: Vref[:, i] = np.ravel(tmp) ############ initialize Dl################## Dl = np.zeros((3 * (NPs - 1), 3 * Ncl)) for j in range(Ncl): c = Cls[j] for ps in range(1, NPs): RefFrm = np.reshape(Vref[:, c], (3, 2 * len(c)), 'F') DefFrm = np.reshape(Vbar[6 * (ps - 1):6 * (ps - 1) + 6, c], (3, 2 * len(c)), 'F') X = Multiply(RefFrm, RefFrm.T) Y = Multiply(DefFrm, RefFrm.T) Dl[3 * (ps - 1):3 * (ps - 1) + 3, 3 * j:3 * j + 3] = Y.dot(np.linalg.inv(X)) ###### Compute Weights ##################### Q = np.zeros((3, 2 * (NPs - 1))) Bt = np.zeros(NF) t = 0 for c in Cls: for f in c: for ps in range(NPs - 1): tmp = np.reshape(Vref[:, f], (3, 2), 'F') Q[:, 2 * ps:2 * ps + 2] = Dl[3 * ps:3 * ps + 3, 3 * t:3 * t + 3].dot(tmp) Vc = np.reshape(Vbar[:, f], (3, 2 * (NPs - 1)), 'F') Bt[f] = np.mean( np.linalg.norm(Vc, axis=0) / np.linalg.norm(Q, axis=0)) t += 1 ################################################################################## # Connect Meshes ################################################################################## print("Computing Mesh Frames.....") RM = np.zeros((3 * Ncl, NPs - 1)) AM = np.zeros((Ncl, NPs - 1)) Sc = np.zeros((9 * Ncl, NPs - 1)) ####################################### JntPrFace = 2 W = np.zeros((3 * Ncl, 3 * JntPrFace)) H = np.zeros((9 * Ncl, 3 * JntPrFace + 1)) JntInd = [] Wgts = np.zeros((Ncl, JntPrFace)) ####################################### Wtmp = np.zeros((3, 3 * NFrm)) Theta = np.ones((3 * JntPrFace + 1, NPs - 1)) #Dl=np.zeros((3*(NPs-1),3*Ncl)) #Bt=np.zeros(NF) for c in range(Ncl): for ps in range(NPs - 1): Q = Dl[3 * ps:3 * ps + 3, 3 * c:3 * c + 3] R, S = scla.polar(Q) Axs, Angl = RotMatToAnglAxis(R) RM[3 * c:3 * c + 3, ps] = Axs AM[c, ps] = Angl Sc[9 * c:9 * c + 9, ps] = np.ravel(S) Err = [] for r in range(NFrm): U, Lmda, V = np.linalg.svd( (RS[3 * r:3 * r + 3]).dot(RM[3 * c:3 * c + 3].T)) Wtmp[:, 3 * r:3 * r + 3] = (V.T).dot(U.T) Err.append( np.linalg.norm((Wtmp[:, 3 * r:3 * r + 3].dot(RS[3 * r:3 * r + 3])) - RM[3 * c:3 * c + 3])) IndSort = np.argsort(Err) JntInd.append(list(IndSort[0:JntPrFace])) TotalErr = sum([(1 / Err[i]) for i in IndSort[0:JntPrFace]]) for i in range(JntPrFace): r = IndSort[i] u = 0 l = 0 for j in range(NPs - 1): if AS[r, j] != 0: u += AM[c, j] / AS[r, j] l += 1 u = u / l W[3 * c:3 * c + 3, 3 * i:3 * i + 3] = u * Wtmp[:, 3 * r:3 * r + 3] Wgts[c, i] = 1 / (Err[r] * TotalErr) Theta[3 * i:3 * i + 3] = RS[3 * r:3 * r + 3] * AS[r] H[9 * c:9 * c + 9] = Sc[9 * c:9 * c + 9].dot(np.linalg.pinv(Theta)) ################################################################ # Forming matrix for Editing ################################################################ B = sp.lil_matrix((3 * Ncl, 2 * NF)) for c in range(Ncl): for f in Cls[c]: B[3 * c:3 * c + 3, 2 * f:2 * f + 2] = Bt[f] * np.reshape(Vref[:, f], (3, 2), 'F') L = (factor((AA[:(NV - 1), :].dot(B.transpose())).tocsc())).transpose() np.savetxt(path + Rigname + '_L.txt', L.toarray(), delimiter=',') np.savetxt(path + Rigname + '_RRWght.txt', W, delimiter=',') np.savetxt(path + Rigname + '_HRWght.txt', H, delimiter=',') np.savetxt(path + Rigname + '_JointClsWeights.txt', Wgts, delimiter=',') WriteAsTxt(path + Rigname + '_JointClsRl.txt', JntInd) return {'FINISHED'}
def choleskySolve(M, b): factor = cholesky_AAt(M.T) return factor(M.T.dot(b)).toarray()
def spsolve_chol(sparse_X, dense_b): factor = cholesky_AAt(sparse_X.T) return factor(sparse_X.T.dot(dense_b)).toarray()
def solvePoisson(mesh, densityValues): """ Solve a Poisson problem on the mesh. The results should be stored on the vertices in a variable named 'solutionVal'. You will want to make use of your buildLaplaceMatrix_dense() function from above. densityValues is a dictionary mapping {vertex ==> value} that specifies densities. The density is implicitly zero at every vertex not in this dictionary. When you run this program with 'python Assignment3.py part1 path/to/your/mesh.obj', you will get to click on vertices to specify density conditions. See the assignment document for more details. """ index_map = mesh.enumerateVertices L = buildLaplaceMatrix_sparse(mesh, index_map) M = buildMassMatrix_dense(mesh, index_map) #M <= 2D totalArea = mesh.totalArea rho = np.zeros((len(mesh.verts), 1), float) for key in densityValues: #index_val = index_map[key] print 'key dual area = ', key.barycentricDualArea rho[index_map[key]] = densityValues[key] #*key.dualArea nRows, nCols = np.shape(M) totalRho = sum(M.dot(rho)) #rhoBar = np.ones((nRows,1),float)*(totalRho/totalArea) rhoBar = totalRho / totalArea rhs = M.dot(rhoBar - rho) #rhs = np.matmul(M,(rho-rhoBar) ) #rhs = np.dot(M,rho) # # SwissArmyLaplacian, # page 179 Cu = Mf is better conditioned # assert(Cu == L) ?? #sol_vec = np.linalg.solve(L, np.dot(M,rho) ) #sparse: #sol_vec = dsolve.spsolve(L, np.dot(M,rho) , use_umfpack=True) # standard: #sol_vec = dsolve.spsolve(L, rhs , use_umfpack=True) #sparse Cholesky solve: llt = skchol.cholesky_AAt(L) #factor sol_vec = llt(rhs) #eigen: #sol_vec = np.zeros((nRows),float) #scipy.sparse.linalg.lobpcg(L,sol_vec,rhs) #@eigensolver #sol_vec = dsolve.spsolve(L, rho , use_umfpack=True) vert_sol = {} for vert in mesh.verts: key = index_map[vert] #print 'TLM sol_vec = ',sol_vec[key] vert.solutionVal = sol_vec[key] vert_sol[vert] = sol_vec[key] if rho[key]: vert.densityVal = rho[key] else: vert.densityVal = 0. return vert_sol
Lk = sp.random(3, 3, 0.5, format='csc') + sp.eye(3, 3, format='csc') K = Lk * Lk.T assert np.allclose(K.toarray(), K.T.toarray(), 1e-10), 'K not symmetric.' assert all(np.linalg.eigvals(K.toarray()) > 0), 'K is not positive definite.' # Lumped mass matrix m = np.array([1, 2, 3]) M = sp.diags(m, format='csc') assert np.allclose(M.toarray(), M.T.toarray(), 1e-10), 'M not symmetric.' # # alpha = 1 # Q1 = K f_Q1 = cholesky(K) fs_Q1 = cholesky_AAt(Lk) assert factor_of(f_Q1, K), 'Cannot use cholesky factor to reconstruct matrix.' assert factor_of(fs_Q1, K), 'Cannot use cholesky factor to reconstruct matrix.' assert np.allclose(f_Q1.L().toarray(),fs_Q1.L().toarray(),1e-10), \ 'Cholesky factors differ' # # alpha = 2 # Q2 = K * spla.inv(M) * K f_Q2 = cholesky(Q2) fs_Q2 = cholesky_AAt(K * sp.diags(1 / np.sqrt(m))) assert factor_of(f_Q2, Q2), 'Cannot use cholesky factor to reconstruct matrix.'
def main(): ###################### # Config ###################### # Choose least-squares solver to use: # # lsq_solver = "dense" # LAPACK DGELSD, direct, good for small problems # lsq_solver = "sparse" # SciPy LSQR, iterative, asymptotically faster, good for large problems # lsq_solver = "optimize" # general nonlinear optimizer using Trust Region Reflective (trf) algorithm # lsq_solver = "qr" # lsq_solver = "cholesky" # lsq_solver = "sparse_qr" lsq_solver = "sparse_qr_solve" ###################### # Load multiscale data ###################### print("Loading measurement data...") # measurements are provided on a meshgrid over (Hx, sigxx) # data2.mat contains virtual measurements, generated from a multiscale model. # data2 = scipy.io.loadmat("data2.mat") # Hx = np.squeeze(data2["Hx"]) # 1D array, (M,) # sigxx = np.squeeze(data2["sigxx"]) # 1D array, (N,) # Bx = data2["Bx"] # 2D array, (M, N) # lamxx = data2["lamxx"] # --"-- ## lamyy = data2["lamyy"] # --"-- ## lamzz = data2["lamzz"] # --"-- data2 = scipy.io.loadmat("umair_gal_denoised.mat") sigxx = -1e6 * np.array([ 0, 1, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80 ][::-1], dtype=np.float64) assert sigxx.shape[0] == 18 Hx = data2["Hval"][0, :] # same for all sigma, just take the first row Bx = data2["Bval"].T lamxx = data2["LHval"].T * 1e-6 Bx = Bx[::-1, :] lamxx = lamxx[::-1, :] # HACK, fix later (must decouple number of knots from number of data sites) ii = np.arange(Hx.shape[0]) n_newi = 401 newii = np.linspace(0, ii[-1], n_newi) nsigma = sigxx.shape[0] fH = scipy.interpolate.interp1d(ii, Hx) newB = np.empty((n_newi, Bx.shape[1]), dtype=np.float64) newlam = np.empty((n_newi, lamxx.shape[1]), dtype=np.float64) for j in range(nsigma): fB = scipy.interpolate.interp1d(ii, Bx[:, j]) newB[:, j] = fB(newii) flam = scipy.interpolate.interp1d(ii, lamxx[:, j]) newlam[:, j] = flam(newii) Hx = fH(newii) Bx = newB lamxx = newlam # Order of spline (as-is! 3 = cubic) ordr = 3 # Auxiliary variables (H, sig_xx, sig_xy) Hscale = np.max(Hx) sscale = np.max(np.abs(sigxx)) x = Hx / Hscale y = sigxx / sscale nx = x.shape[0] # number of grid points, x axis ny = y.shape[0] # number of grid points, y axis # Partial derivatives (B, lam_xx, lam_xy) from multiscale model # # In the magnetostriction components, the multiscale model produces nonzero lamxx at zero stress. # We normalize this away for purposes of performing the curve fit. # dpsi_dx = Bx * Hscale dpsi_dy = (lamxx - lamxx[0, :]) * sscale ###################### # Set up splines ###################### print("Setting up splines...") # The evaluation algorithm used in bspline.py uses half-open intervals t_i <= x < t_{i+1}. # # This causes havoc for evaluation at the end of each interval, because it is actually the start # of the next interval. # # Especially, the end of the last interval is the start of the next (non-existent) interval. # # We work around this by using a small epsilon to avoid evaluation exactly at t_{i+1} (for the last interval). # def marginize_end(x): out = x.copy() out[-1] += 1e-10 * (x[-1] - x[0]) return out # create knots and spline basis xknots = splinelab.aptknt(marginize_end(x), ordr) yknots = splinelab.aptknt(marginize_end(y), ordr) splx = bspline.Bspline(xknots, ordr) sply = bspline.Bspline(yknots, ordr) # get number of basis functions (perform dummy evaluation and count) nxb = len(splx(0.)) nyb = len(sply(0.)) # TODO Check if we need to convert input Bx and sigxx to u,v (what is actually stored in the data files?) # Create collocation matrices: # # A[i,j] = d**deriv_order B_j(tau[i]) # # where d denotes differentiation and B_j is the jth basis function. # # We place the collocation sites at the points where we have measurements. # Au = splx.collmat(x) Av = sply.collmat(y) Du = splx.collmat(x, deriv_order=1) Dv = sply.collmat(y, deriv_order=1) ###################### # Assemble system ###################### print("Assembling system...") # Assemble the equation system for fitting against data on the partial derivatives of psi. # # By writing psi in the spline basis, # # psi_{ij} = A^{u}_{ik} A^{v}_{jl} c_{kl} # # the quantities to be fitted, which are the partial derivatives of psi, become # # B_{ij} = D^{u}_{ik} A^{v}_{jl} c_{kl} # lambda_{xx,ij} = A^{u}_{ik} D^{v}_{jl} c_{kl} # # Repeated indices are summed over. # # Column: kl converted to linear index (k = 0,1,...,nxb-1, l = 0,1,...,nyb-1) # Row: ij converted to linear index (i = 0,1,...,nx-1, j = 0,1,...,ny-1) # # (Paavo's notes, Stresses4.pdf) nf = 2 # number of unknown fields nr = nx * ny # equation system rows per unknown field A = np.empty((nf * nr, nxb * nyb), dtype=np.float64) # global matrix b = np.empty((nf * nr), dtype=np.float64) # global RHS # zero array element detection tolerance tol = 1e-6 I, J, IJ = util.index.genidx((nx, ny)) K, L, KL = util.index.genidx((nxb, nyb)) # loop only over rows of the equation system for i, j, ij in zip(I, J, IJ): A[nf * ij, KL] = Du[i, K] * Av[j, L] A[nf * ij + 1, KL] = Au[i, K] * Dv[j, L] b[nf * IJ] = dpsi_dx[I, J] # RHS for B_x b[nf * IJ + 1] = dpsi_dy[I, J] # RHS for lambda_xx # # the above is equivalent to this much slower version: # # # # equation system row # for j in range(ny): # for i in range(nx): # ij = np.ravel_multi_index( (i,j), (nx,ny) ) # # # equation system column # for l in range(nyb): # for k in range(nxb): # kl = np.ravel_multi_index( (k,l), (nxb,nyb) ) # A[nf*ij, kl] = Du[i,k] * Av[j,l] # A[nf*ij+1,kl] = Au[i,k] * Dv[j,l] # # b[nf*ij] = dpsi_dx[i,j] if abs(dpsi_dx[i,j]) > tol else 0. # RHS for B_x # b[nf*ij+1] = dpsi_dy[i,j] if abs(dpsi_dy[i,j]) > tol else 0. # RHS for lambda_xx ###################### # Solve ###################### # Solve the optimal coefficients. # Note that we are constructing a potential function from partial derivatives only, # so the solution is unique only up to a global additive shift term. # # Under the hood, numpy.linalg.lstsq uses LAPACK DGELSD: # # http://stackoverflow.com/questions/29372559/what-is-the-difference-between-numpy-linalg-lstsq-and-scipy-linalg-lstsq # # DGELSD accepts also rank-deficient input (rank(A) < min(nrows,ncols)), returning arg min( ||x||_2 ) , # so we don't need to do anything special to account for this. # # Same goes for the sparse LSQR. # equilibrate row and column norms # # See documentation of scipy.sparse.linalg.lsqr, it requires this to work properly. # # https://github.com/Technologicat/python-wlsqm # print("Equilibrating...") S = A.copy(order='F') # the rescaler requires Fortran memory layout A = scipy.sparse.csr_matrix(A) # save memory (dense "A" no longer needed) # eps = 7./3. - 4./3. - 1 # http://stackoverflow.com/questions/19141432/python-numpy-machine-epsilon # print( S.max() * max(S.shape) * eps ) # default zero singular value detection tolerance in np.linalg.matrix_rank() # import wlsqm.utils.lapackdrivers as wul # rs,cs = wul.do_rescale( S, wul.ScalingAlgo.ALGO_DGEEQU ) # # row scaling only (for weighting) # with np.errstate(divide='ignore', invalid='ignore'): # rs = np.where( np.abs(b) > tol, 1./b, 1. ) # for i in range(S.shape[0]): # S[i,:] *= rs[i] # cs = 1. # scale rows corresponding to Bx # rs = np.ones_like(b) rs[nf * IJ] = 2 for i in range(S.shape[0]): S[i, :] *= rs[i] cs = 1. # # It seems this is not needed in the 2D problem (fitting error is slightly smaller without it). # # # Additional row scaling. # # # # This equilibrates equation weights, but deteriorates the condition number of the matrix. # # # # Note that in a least-squares problem the row weighting *does* matter, because it affects # # the fitting error contribution from the rows. # # # with np.errstate(divide='ignore', invalid='ignore'): # rs2 = np.where( np.abs(b) > tol, 1./b, 1. ) # for i in range(S.shape[0]): # S[i,:] *= rs2[i] # rs *= rs2 # a = np.abs(rs2) # print( np.min(a), np.mean(a), np.max(a) ) # rs = np.asanyarray(rs) # cs = np.asanyarray(cs) # a = np.abs(rs) # print( np.min(a), np.mean(a), np.max(a) ) b *= rs # scale RHS accordingly # colnorms = np.linalg.norm(S, ord=np.inf, axis=0) # sum over rows -> column norms # rownorms = np.linalg.norm(S, ord=np.inf, axis=1) # sum over columns -> row norms # print( " rescaled column norms min = %g, avg = %g, max = %g" % (np.min(colnorms), np.mean(colnorms), np.max(colnorms)) ) # print( " rescaled row norms min = %g, avg = %g, max = %g" % (np.min(rownorms), np.mean(rownorms), np.max(rownorms)) ) print("Solving with algorithm = '%s'..." % (lsq_solver)) if lsq_solver == "dense": print(" matrix shape %s = %d elements" % (S.shape, np.prod(S.shape))) ret = numpy.linalg.lstsq(S, b) # c,residuals,rank,singvals c = ret[0] elif lsq_solver == "sparse": S = scipy.sparse.coo_matrix(S) print(" matrix shape %s = %d elements; %d nonzeros (%g%%)" % (S.shape, np.prod( S.shape), S.nnz, 100. * S.nnz / np.prod(S.shape))) ret = scipy.sparse.linalg.lsqr(S, b) c, exit_reason, iters = ret[:3] if exit_reason != 2: # 2 = least-squares solution found print("WARNING: solver did not converge (exit_reason = %d)" % (exit_reason)) print(" sparse solver iterations taken: %d" % (iters)) elif lsq_solver == "optimize": # make sparse matrix (faster for dot products) S = scipy.sparse.coo_matrix(S) print(" matrix shape %s = %d elements; %d nonzeros (%g%%)" % (S.shape, np.prod( S.shape), S.nnz, 100. * S.nnz / np.prod(S.shape))) def fitting_error(c): return S.dot(c) - b ret = scipy.optimize.least_squares(fitting_error, np.ones(S.shape[1], dtype=np.float64), method="trf", loss="linear") c = ret.x if ret.status < 1: # status codes: https://docs.scipy.org/doc/scipy-0.18.1/reference/generated/scipy.optimize.least_squares.html print("WARNING: solver did not converge (status = %d)" % (ret.status)) elif lsq_solver == "qr": print(" matrix shape %s = %d elements" % (S.shape, np.prod(S.shape))) # http://glowingpython.blogspot.fi/2012/03/solving-overdetermined-systems-with-qr.html Q, R = np.linalg.qr(S) # qr decomposition of A Qb = (Q.T).dot(b) # computing Q^T*b (project b onto the range of A) # c = np.linalg.solve(R,Qb) # solving R*x = Q^T*b c = scipy.linalg.solve_triangular(R, Qb, check_finite=False) elif lsq_solver == "cholesky": # S is rank-deficient by one, because we are solving a potential based on data on its partial derivatives. # # Before solving, force S to have full rank by fixing one coefficient. # S[0, :] = 0. S[0, 0] = 1. b[0] = 1. rs[0] = 1. S = scipy.sparse.csr_matrix(S) print(" matrix shape %s = %d elements; %d nonzeros (%g%%)" % (S.shape, np.prod( S.shape), S.nnz, 100. * S.nnz / np.prod(S.shape))) # Be sure to use the new sksparse from # # https://github.com/scikit-sparse/scikit-sparse # # instead of the old scikits.sparse (which will fail with an error). # # Requires libsuitesparse-dev for CHOLMOD headers. # from sksparse.cholmod import cholesky_AAt # Notice that CHOLMOD computes AA' and we want M'M, so we must set A = M'! factor = cholesky_AAt(S.T) c = factor.solve_A(S.T * b) elif lsq_solver == "sparse_qr": # S is rank-deficient by one, because we are solving a potential based on data on its partial derivatives. # # Before solving, force S to have full rank by fixing one coefficient; # otherwise the linear solve step will fail because R will be exactly singular. # S[0, :] = 0. S[0, 0] = 1. b[0] = 1. rs[0] = 1. S = scipy.sparse.coo_matrix(S) print(" matrix shape %s = %d elements; %d nonzeros (%g%%)" % (S.shape, np.prod( S.shape), S.nnz, 100. * S.nnz / np.prod(S.shape))) # pip install sparseqr # or https://github.com/yig/PySPQR # # Works like MATLAB's [Q,R,e] = qr(...): # # https://se.mathworks.com/help/matlab/ref/qr.html # # [Q,R,E] = qr(A) or [Q,R,E] = qr(A,'matrix') produces unitary Q, upper triangular R and a permutation matrix E # so that A*E = Q*R. The column permutation E is chosen to reduce fill-in in R. # # [Q,R,e] = qr(A,'vector') returns the permutation information as a vector instead of a matrix. # That is, e is a row vector such that A(:,e) = Q*R. # import sparseqr print(" performing sparse QR decomposition...") Q, R, E, rank = sparseqr.qr(S) # produce reduced QR (for least-squares fitting) # # - cut away bottom part of R (zeros!) # - cut away the corresponding far-right part of Q # # see # np.linalg.qr # https://andreask.cs.illinois.edu/cs357-s15/public/demos/06-qr-applications/Solving%20Least-Squares%20Problems.html # # # inefficient way: # k = min(S.shape) # R = scipy.sparse.csr_matrix( R.A[:k,:] ) # Q = scipy.sparse.csr_matrix( Q.A[:,:k] ) print(" reducing matrices...") # somewhat more efficient way: k = min(S.shape) R = R.tocsr()[:k, :] Q = Q.tocsc()[:, :k] # # maybe somewhat efficient way: manipulate data vectors, create new coo matrix # # # # (incomplete, needs work; need to shift indices of rows/cols after the removed ones) # # # k = min(S.shape) # mask = np.nonzero( R.row < k )[0] # R = scipy.sparse.coo_matrix( ( R.data[mask], (R.row[mask], R.col[mask]) ), shape=(k,k) ) # mask = np.nonzero( Q.col < k )[0] # Q = scipy.sparse.coo_matrix( ( Q.data[mask], (Q.row[mask], Q.col[mask]) ), shape=(k,k) ) print(" solving...") Qb = (Q.T).dot(b) x = scipy.sparse.linalg.spsolve(R, Qb) c = np.empty_like(x) c[E] = x[:] # apply inverse permutation elif lsq_solver == "sparse_qr_solve": S[0, :] = 0. S[0, 0] = 1. b[0] = 1. rs[0] = 1. S = scipy.sparse.coo_matrix(S) print(" matrix shape %s = %d elements; %d nonzeros (%g%%)" % (S.shape, np.prod( S.shape), S.nnz, 100. * S.nnz / np.prod(S.shape))) import sparseqr c = sparseqr.solve(S, b) else: raise ValueError("unknown solver '%s'; valid: 'dense', 'sparse'" % (lsq_solver)) c *= cs # undo column scaling in solution # now c contains the spline coefficients, c_{kl}, where kl has been raveled into a linear index. ###################### # Save ###################### filename = "tmp_s2d.mat" L = locals() data = { key: L[key] for key in ["ordr", "xknots", "yknots", "c", "Hscale", "sscale"] } scipy.io.savemat(filename, data, format='5', oned_as='row') ###################### # Plot ###################### print("Visualizing...") # unpack results onto meshgrid # fitted = A.dot( c ) # function values corresponding to each row in the global equation system X, Y = np.meshgrid( Hx, sigxx, indexing='ij') # indexed like X[i,j] (i is x index, j is y index) Z_Bx = np.empty_like(X) Z_lamxx = np.empty_like(X) Z_Bx[I, J] = fitted[nf * IJ] Z_lamxx[I, J] = fitted[nf * IJ + 1] # # the above is equivalent to: # for ij in range(nr): # i,j = np.unravel_index( ij, (nx,ny) ) # Z_Bx[i,j] = fitted[nf*ij] # Z_lamxx[i,j] = fitted[nf*ij+1] data_Bx = { "x": (X, r"$H_{x}$"), "y": (Y, r"$\sigma_{xx}$"), "z": (Z_Bx / Hscale, r"$B_{x}$") } data_lamxx = { "x": (X, r"$H_{x}$"), "y": (Y, r"$\sigma_{xx}$"), "z": (Z_lamxx / sscale, r"$\lambda_{xx}$") } def relerr(data, refdata): refdata_linview = refdata.reshape(-1) return 100. * np.linalg.norm(refdata_linview - data.reshape(-1) ) / np.linalg.norm(refdata_linview) plt.figure(1) plt.clf() ax = util.plot.plot_wireframe(data_Bx, legend_label="Spline", figno=1) ax.plot_wireframe(X, Y, dpsi_dx / Hscale, label="Multiscale", color="r") plt.legend(loc="best") print("B_x relative error %g%%" % (relerr(Z_Bx, dpsi_dx))) plt.figure(2) plt.clf() ax = util.plot.plot_wireframe(data_lamxx, legend_label="Spline", figno=2) ax.plot_wireframe(X, Y, dpsi_dy / sscale, label="Multiscale", color="r") plt.legend(loc="best") print("lambda_{xx} relative error %g%%" % (relerr(Z_lamxx, dpsi_dy))) # match the grid point numbering used in MATLAB version of this script # def t(A): return np.transpose(A, [1, 0]) dpsi_dx = t(dpsi_dx) Z_Bx = t(Z_Bx) dpsi_dy = t(dpsi_dy) Z_lamxx = t(Z_lamxx) plt.figure(3) plt.clf() ax = plt.subplot(1, 1, 1) ax.plot(dpsi_dx.reshape(-1) / Hscale, 'ro', markersize='2', label="Multiscale") ax.plot(Z_Bx.reshape(-1) / Hscale, 'ko', markersize='2', label="Spline") ax.set_xlabel("Grid point number") ax.set_ylabel(r"$B_{x}$") plt.legend(loc="best") plt.figure(4) plt.clf() ax = plt.subplot(1, 1, 1) ax.plot(dpsi_dy.reshape(-1) / sscale, 'ro', markersize='2', label="Multiscale") ax.plot(Z_lamxx.reshape(-1) / sscale, 'ko', markersize='2', label="Spline") ax.set_xlabel("Grid point number") ax.set_ylabel(r"$\lambda_{xx}$") plt.legend(loc="best") print("All done.")
def projections(A, method=None, orth_tol=1e-12, max_refin=3): """Return three linear operators related with a given matrix A. Parameters ---------- A : sparse matrix (or ndarray), shape (m, n) Matrix ``A`` used in the projection. method : string, optional Method used for compute the given linear operators. Should be one of: - 'NormalEquation': The operators will be computed using the so-called normal equation approach explained in [1]_. In order to do so the Cholesky factorization of ``(A A.T)`` is computed. Exclusive for sparse matrices. - 'AugmentedSystem': The operators will be computed using the so-called augmented system approach explained in [1]_. Exclusive for sparse matrices. - 'QRFactorization': Compute projections using QR factorization. Exclusive for dense matrices. orth_tol : float, optional Tolerance for iterative refinements. max_refin : int, optional Maximum number of iterative refinements Returns ------- Z : LinearOperator, shape (n, n) Null-space operator. For a given vector ``x``, the null space operator is equivalent to apply a projection matrix ``P = I - A.T inv(A A.T) A`` to the vector. It can be shown that this is equivalent to project ``x`` into the null space of A. LS : LinearOperator, shape (m, n) Least-Square operator. For a given vector ``x``, the least-square operator is equivalent to apply a pseudoinverse matrix ``pinv(A.T) = inv(A A.T) A`` to the vector. It can be shown that this vector ``pinv(A.T) x`` is the least_square solution to ``A.T y = x``. Y : LinearOperator, shape (n, m) Row-space operator. For a given vector ``x``, the row-space operator is equivalent to apply a projection matrix ``Q = A.T inv(A A.T)`` to the vector. It can be shown that this vector ``y = Q x`` the minimum norm solution of ``A y = x``. Notes ----- Uses iterative refinements described in [1] during the computation of ``Z`` in order to cope with the possibility of large roundoff errors. References ---------- .. [1] Gould, Nicholas IM, Mary E. Hribar, and Jorge Nocedal. "On the solution of equality constrained quadratic programming problems arising in optimization." SIAM Journal on Scientific Computing 23.4 (2001): 1376-1395. """ m, n = np.shape(A) # Check Argument if issparse(A): if method is None: method = "AugmentedSystem" if method not in ("NormalEquation", "AugmentedSystem"): raise ValueError("Method not allowed for the given matrix.") else: if method is None: method = "QRFactorization" if method != "QRFactorization": raise ValueError("Method not allowed for the given matrix.") if method == 'NormalEquation': # Cholesky factorization factor = cholesky_AAt(A) # z = x - A.T inv(A A.T) A x def null_space(x): v = factor(A.dot(x)) z = x - A.T.dot(v) # Iterative refinement to improve roundoff # errors described in [2]_, algorithm 5.1. k = 0 while orthogonality(A, z) > orth_tol: if k >= max_refin: break # z_next = z - A.T inv(A A.T) A z v = factor(A.dot(z)) z = z - A.T.dot(v) k += 1 return z # z = inv(A A.T) A x def least_squares(x): return factor(A.dot(x)) # z = A.T inv(A A.T) x def row_space(x): return A.T.dot(factor(x)) elif method == 'AugmentedSystem': # Form augmented system K = csc_matrix(bmat([[eye(n), A.T], [A, None]])) # LU factorization # TODO: Use a symmetric indefinite factorization # to solve the system twice as fast (because # of the symmetry). factor = linalg.splu(K) # z = x - A.T inv(A A.T) A x # is computed solving the extended system: # [I A.T] * [ z ] = [x] # [A O ] [aux] [0] def null_space(x): # v = [x] # [0] v = np.hstack([x, np.zeros(m)]) # lu_sol = [ z ] # [aux] lu_sol = factor.solve(v) z = lu_sol[:n] # Iterative refinement to improve roundoff # errors described in [2]_, algorithm 5.2. k = 0 while orthogonality(A, z) > orth_tol: if k >= max_refin: break # new_v = [x] - [I A.T] * [ z ] # [0] [A O ] [aux] new_v = v - K.dot(lu_sol) # [I A.T] * [delta z ] = new_v # [A O ] [delta aux] lu_update = factor.solve(new_v) # [ z ] += [delta z ] # [aux] [delta aux] lu_sol += lu_update z = lu_sol[:n] k += 1 # return z = x - A.T inv(A A.T) A x return z # z = inv(A A.T) A x # is computed solving the extended system: # [I A.T] * [aux] = [x] # [A O ] [ z ] [0] def least_squares(x): # v = [x] # [0] v = np.hstack([x, np.zeros(m)]) # lu_sol = [aux] # [ z ] lu_sol = factor.solve(v) # return z = inv(A A.T) A x return lu_sol[n:m + n] # z = A.T inv(A A.T) x # is computed solving the extended system: # [I A.T] * [ z ] = [0] # [A O ] [aux] [x] def row_space(x): # v = [0] # [x] v = np.hstack([np.zeros(n), x]) # lu_sol = [ z ] # [aux] lu_sol = factor.solve(v) # return z = A.T inv(A A.T) x return lu_sol[:n] elif method == "QRFactorization": # QRFactorization Q, R, P = scipy.linalg.qr(A.T, pivoting=True, mode='economic') # z = x - A.T inv(A A.T) A x def null_space(x): # v = P inv(R) Q.T x aux1 = Q.T.dot(x) aux2 = scipy.linalg.solve_triangular(R, aux1, lower=False) v = np.zeros(m) v[P] = aux2 z = x - A.T.dot(v) # Iterative refinement to improve roundoff # errors described in [2]_, algorithm 5.1. k = 0 while orthogonality(A, z) > orth_tol: if k >= max_refin: break # v = P inv(R) Q.T x aux1 = Q.T.dot(z) aux2 = scipy.linalg.solve_triangular(R, aux1, lower=False) v[P] = aux2 # z_next = z - A.T v z = z - A.T.dot(v) k += 1 return z # z = inv(A A.T) A x def least_squares(x): # z = P inv(R) Q.T x aux1 = Q.T.dot(x) aux2 = scipy.linalg.solve_triangular(R, aux1, lower=False) z = np.zeros(m) z[P] = aux2 return z # z = A.T inv(A A.T) x def row_space(x): # z = Q inv(R.T) P.T x aux1 = x[P] aux2 = scipy.linalg.solve_triangular(R, aux1, lower=False, trans='T') z = Q.dot(aux2) return z Z = LinearOperator((n, n), null_space) LS = LinearOperator((m, n), least_squares) Y = LinearOperator((n, m), row_space) return Z, LS, Y
def execute(self, context): global Phi, path,FilePath ################# Input from user ############### Rigname=context.scene.RigName if path[len(path)-len(Rigname)-1:len(path)-1]!=Rigname: path=FilePath+Rigname+'/' num_JntPrVec=context.scene.JointPrVec FrmPrBn=context.scene.FrmPrBone ################################################ Vrt=np.loadtxt(path+Rigname+'_vertz.txt',delimiter=',') Fcs=ReadTxt(path+Rigname+'_Halffacz.txt') Nrml=np.loadtxt(path+Rigname+'_Normal.txt',delimiter=',') Joints=ReadTxt(path+Rigname+'_Joints.txt') Links=ReadTxt(path+Rigname+'_SkelEdgz.txt') NPs,NV=np.shape(Vrt) NPs=NPs//3 NVec=sum([len(f) for f in Fcs]) CnsVrt=ReadTxt(path+Rigname+'_LBSVrt.txt')[0] FrVrt=[] for i in range(NV): if i not in CnsVrt: FrVrt.append(i) WriteAsTxt(path+Rigname+'_FrVrt.txt',FrVrt) np.savetxt(path+Rigname+'_RefMesh.txt',Vrt[0:3,:].T,delimiter=',') ########################## Commpute Incident Matrices ########################################### print("Computing Incident Matrices.....") strtTime=time.time() AB,ABc=ConnectionMatrices(Fcs,NV,NVec,CnsVrt,FrVrt) Vecs=((AB.transpose()).dot(Vrt[:,FrVrt].T)).T+((ABc.transpose()).dot(Vrt[:,CnsVrt].T)).T factor=chmd.cholesky_AAt(AB.tocsc()) ########################## Comute Skeleton Frames ########################################### VecIndx=[] for ln in Links: if FrmPrBn==1: VecIndx.append(ln) else: VecIndx.append(ln) VecIndx.append([ln[1],ln[0]]) print("Computing Skeleton Frames.....") NJ=len(Joints) NFrm=len(VecIndx) SFrm=np.zeros([3,3]) SrFrm=np.zeros([3,4*NFrm]) SFrmLbs=np.eye(4) SrFrmLbs=np.zeros([4,4*NFrm]) RSLbs=np.zeros((3*(NPs-1),4*NFrm)) A=np.zeros([NJ,3]) RS=np.zeros((3*(NPs-1),3*NFrm)) for ps in range(NPs): X=Vrt[3*ps:3*ps+3,:].T for r in range(NJ): A[r]=np.mean(X[Joints[r]],axis=0) if ps==0: np.savetxt(path+Rigname+'_RefSkel.txt',A,delimiter=',') t=0 for r in range(NFrm): V=(A[VecIndx[r][0]]-A[VecIndx[r][1]])/np.linalg.norm(A[VecIndx[r][0]]-A[VecIndx[r][1]]) tmp=X[Joints[VecIndx[r][0]][0]]-A[VecIndx[r][0]] B=np.cross(V,tmp)/np.linalg.norm(np.cross(V,tmp)) N=np.cross(B,V)/np.linalg.norm(np.cross(B,V)) SFrm[:,0]=V SFrm[:,1]=B SFrm[:,2]=N SFrmLbs[0:3,0]=V SFrmLbs[0:3,1]=B SFrmLbs[0:3,2]=N SFrmLbs[0:3,3]=A[VecIndx[r][0]] if ps!=0: RS[3*(ps-1):3*(ps-1)+3,3*r:3*r+3]=np.dot(SFrm,SrFrm[:,4*r:4*r+3].T) RSLbs[3*(ps-1):3*(ps-1)+3,4*r:4*r+4]=SFrmLbs[0:3,:].dot(np.linalg.inv(SrFrmLbs[:,4*r:4*r+4])) else: SrFrm[:,4*r:4*r+3]=SFrm SrFrm[:,4*r+3]=A[VecIndx[r][0]] SrFrmLbs[:,4*r:4*r+4]=SFrmLbs np.savetxt(path+Rigname+'_RefFrames.txt',SrFrm,delimiter=',') ############################## LBS on Constrain Vertices ########################################## print("Computing Mesh Frames for Constraint vertices .....") LBSPhi=np.zeros((4*NFrm,len(CnsVrt))) Vn=0 for v in CnsVrt: v0=np.append(Vrt[0:3,v],[1]) Err=[] H=np.zeros((3*(NPs-1),NFrm)) for f in range(NFrm): for p in range(NPs-1): H[3*p:3*p+3,f]=RSLbs[3*p:3*p+3,4*f:4*f+4].dot(v0) Err.append(np.linalg.norm(Vrt[3:,v]-H[:,f])) num_JntPrVrt=3 IndSort=np.argsort(Err) SmlH=H[:,IndSort[0:num_JntPrVrt]] wghts=np.linalg.inv(np.dot(SmlH.T,SmlH)).dot(np.dot(SmlH.T,Vrt[3:,v])) #print(wghts) for i in range(num_JntPrVrt): if wghts[i]<0.0: wghts[i]=0.0 wghts=wghts/np.sum(wghts) for i in range(num_JntPrVrt): r=IndSort[i] Xr=SrFrmLbs[:,4*r:4*r+4] LBSPhi[4*r:4*r+4,Vn]=wghts[i]*(np.linalg.inv(Xr).dot(v0)) Vn+=1 del Vrt, Fcs,A,H ########################## Compute Mesh Frames ########################################### print("Computing Mesh Frames.....") RM=np.zeros((3*(NPs-1),3)) W=sp.lil_matrix((4*NFrm,NVec)) Wtmp=np.zeros([3,3*NFrm]) t=0 MRFrm=np.zeros((3,3)) MFrm=np.zeros((3,3)) WghtMtrx=np.zeros((3*(NPs-1),num_JntPrVec)) for vc in range(NVec): Err=[] MRFrm[:,2]=Nrml[3*vc:3*vc+3,0] MRFrm[:,0]=Vecs[0:3,vc] MRFrm[:,1]=np.cross(MRFrm[:,0],MRFrm[:,2]) MRFrm=MRFrm/np.linalg.norm(MRFrm,axis=0) for ps in range(1,NPs): MFrm[:,2]=Nrml[3*vc:3*vc+3,ps] MFrm[:,0]=Vecs[3*ps:3*ps+3,vc] MFrm[:,1]=np.cross(MFrm[:,0],MFrm[:,2]) MFrm=MFrm/np.linalg.norm(MFrm,axis=0) RM[3*(ps-1):3*(ps-1)+3]=MFrm.dot(MRFrm.T) for r in range(NFrm): U,Lmda,V=np.linalg.svd((RM.T).dot(RS[:,3*r:3*r+3])) Wtmp[:,3*r:3*r+3]=(V.T).dot(U.T) tmp=(RS[:,3*r:3*r+3].dot(Wtmp[:,3*r:3*r+3]))-RM Err.append(np.linalg.norm(tmp)) IndSort=np.argsort(Err) TotalErr=sum([(1/Err[i]) for i in IndSort[0:num_JntPrVec]]) for ps in range(NPs-1): for i in range(num_JntPrVec): r=IndSort[i] WghtMtrx[3*ps:3*ps+3,i]=(RS[3*ps:3*ps+3,3*r:3*r+3].dot(Wtmp[:,3*r:3*r+3])).dot(Vecs[0:3,vc]) wghts=ComputeWeights(WghtMtrx,Vecs[3:,vc]) for i in range(num_JntPrVec): r=IndSort[i] tmp=wghts[i]*((SrFrm[:,4*r:4*r+3].T).dot(Wtmp[:,3*r:3*r+3])) W[4*r:4*r+3,vc]=np.reshape(tmp.dot(Vecs[0:3,vc]),(3,1)) print("Computing Matrix.....") del RM, RS, SrFrm, Vecs, Nrml ##### New Phi=(factor((AB.dot(W.transpose())).tocsc())).transpose() K=(factor((AB.dot(ABc.transpose())).tocsc())).transpose() print(time.time()-strtTime) del W tmp=Phi.toarray()-LBSPhi.dot(K.toarray()) Phi=np.zeros((4*NFrm,NV)) t=0 for i in range(NV): if i in CnsVrt: Phi[:,i]=LBSPhi[:,t] t+=1 else: Phi[:,i]=tmp[:,FrVrt.index(i)] np.savetxt(path+Rigname+'_PhiSingle.txt',Phi,delimiter=',') return{'FINISHED'}