def solve(A, b, method, tol=1e-3): """ General sparse solver interface. method can be one of - spsolve_umfpack_mmd_ata - spsolve_umfpack_colamd - spsolve_superlu_mmd_ata - spsolve_superlu_colamd - bicg - bicgstab - cg - cgs - gmres - lgmres - minres - qmr - lsqr - lsmr """ if method == 'spsolve_umfpack_mmd_ata': return spla.spsolve(A, b, use_umfpack=True, permc_spec='MMD_ATA') elif method == 'spsolve_umfpack_colamd': return spla.spsolve(A, b, use_umfpack=True, permc_spec='COLAMD') elif method == 'spsolve_superlu_mmd_ata': return spla.spsolve(A, b, use_umfpack=False, permc_spec='MMD_ATA') elif method == 'spsolve_superlu_colamd': return spla.spsolve(A, b, use_umfpack=False, permc_spec='COLAMD') elif method == 'bicg': res = spla.bicg(A, b, tol=tol) return res[0] elif method == 'bicgstab': res = spla.bicgstab(A, b, tol=tol) return res[0] elif method == 'cg': res = spla.cg(A, b, tol=tol) return res[0] elif method == 'cgs': res = spla.cgs(A, b, tol=tol) return res[0] elif method == 'gmres': res = spla.gmres(A, b, tol=tol) return res[0] elif method == 'lgmres': res = spla.lgmres(A, b, tol=tol) return res[0] elif method == 'minres': res = spla.minres(A, b, tol=tol) return res[0] elif method == 'qmr': res = spla.qmr(A, b, tol=tol) return res[0] elif method == 'lsqr': res = spla.lsqr(A, b, atol=tol, btol=tol) return res[0] elif method == 'lsmr': res = spla.lsmr(A, b, atol=tol, btol=tol) return res[0] else: raise Exception('UnknownSolverType')
def solve(self): A, b = list( zip(self.triangle_consistency(), self.vertex_consistency(), self.wheel_consistency())) A, b = sps.vstack(A), np.concatenate(b) W = sps.diags(self.preprocess_angles()) A = A * W x, success = qmr(A * A.T, b) delta = W * A.T * x error = np.linalg.norm(delta) / (3 * self.num_faces) return (self.preprocess_angles() + delta).reshape( self.faces.shape), True if not success else False, error
def qmr_solve(A, u, b, tol=1e-08): print("Solving system using QMR solver") """ Solves the linear system A*u = b Input A: numpy array of NxN components (LHS) b: numpy array of Nx1 components (RHS) u: numpy array of Nx1 components (Solution) """ # Change RHS representation A = sp.csr_matrix(A) # Solve system u[:] = spla.qmr(A, b, tol=tol)[0]
def iterative_solver_list(self, which, rhs, *args): """Solves the linear problem Ab = x using the sparse matrix Parameters ---------- rhs : ndarray the right hand side which : string choose which solver is used bicg(A, b[, x0, tol, maxiter, xtype, M, ...]) Use BIConjugate Gradient iteration to solve A x = b bicgstab(A, b[, x0, tol, maxiter, xtype, M, ...]) Use BIConjugate Gradient STABilized iteration to solve A x = b cg(A, b[, x0, tol, maxiter, xtype, M, callback]) Use Conjugate Gradient iteration to solve A x = b cgs(A, b[, x0, tol, maxiter, xtype, M, callback]) Use Conjugate Gradient Squared iteration to solve A x = b gmres(A, b[, x0, tol, restart, maxiter, ...]) Use Generalized Minimal RESidual iteration to solve A x = b. lgmres(A, b[, x0, tol, maxiter, M, ...]) Solve a matrix equation using the LGMRES algorithm. minres(A, b[, x0, shift, tol, maxiter, ...]) Use MINimum RESidual iteration to solve Ax=b qmr(A, b[, x0, tol, maxiter, xtype, M1, M2, ...]) Use Quasi-Minimal Residual iteration to solve A x = b """ if which == 'bicg': return spla.bicg(self.sp_matrix, rhs, args) elif which == "cg": return spla.cg(self.sp_matrix, rhs, args) elif which == "bicgstab": return spla.bicgstab(self.sp_matrix, rhs, args) elif which == "cgs": return spla.cgs(self.sp_matrix, rhs, args) elif which == "gmres": return spla.gmres(self.sp_matrix, rhs, args) elif which == "lgmres": return spla.lgmres(self.sp_matrix, rhs, args) elif which == "qmr": return spla.qmr(self.sp_matrix, rhs, args) else: raise NotImplementedError("this solver is unknown")
def runFastSinkSource(P, positives, negatives=None, max_iters=1000, eps=0.0001, a=0.8, tol=1e-5, solver=None, Milu=None, verbose=False): """ *P*: Network ags a scipy sparse matrix. Should already be normalized *positives*: numpy array of node ids to be used as positives *negatives*: numpy array of node ids to be used as negatives. If not given, will be run as FastSinkSourcePlus. For FastSinkSourcePlus, if the lambda parameter is desired, it should already have been included in the graph normalization process. See the function normalizeGraphEdgeWeights in alg_utils.py *max_iters*: max # of iterations to run SinkSource. If 0, use spsolve to solve the equation directly """ num_nodes = P.shape[0] if len(positives) == 0: print("WARNING: No positive examples given. Skipping.") return np.zeros(num_nodes), 0, 0, 0 # remove the positive and negative nodes from the graph # and setup the f vector which contains the influence from positive and negative nodes newP, f, = alg_utils.setup_fixed_scores(P, positives, negatives, a=a, remove_nonreachable=False) if solver is None: s, process_time, wall_time, num_iters = FastSinkSource( newP, f, max_iters=max_iters, eps=eps, a=a, verbose=verbose) else: # Solve for s directly. Scipy uses the form Ax=b to solve for x # SinkSource equation: (I - aP)s = f #solvers = ['bicg', 'bicgstab', 'cg', 'cgs', 'gmres', 'lgmres', 'minres', 'qmr', 'gcrotmk']#, 'lsmr'] # eye is the identity matrix #M = eye(P.shape[0]) - a*P M = eye(newP.shape[0]) - a * newP # keep track of the number of iterations def callback(xk): # keep the reference to the variable within the callback function (Python 3) nonlocal num_iters num_iters += 1 # this measures the amount of time taken by all processors start_process_time = time.process_time() # this measures the amount of time that has passed start_wall_time = time.time() num_iters = 0 # spsolve basically stalls for large or dense networks (e.g., e-value cutoff 0.1) if solver == 'spsolve': s = linalg.spsolve(M, f) elif solver == 'bicg': s, info = linalg.bicg(M, f, tol=tol, maxiter=max_iters, M=Milu, callback=callback) elif solver == 'bicgstab': s, info = linalg.bicgstab(M, f, tol=tol, maxiter=max_iters, M=Milu, callback=callback) elif solver == 'cg': s, info = linalg.cg(M, f, tol=tol, maxiter=max_iters, M=Milu, callback=callback) elif solver == 'cgs': s, info = linalg.cgs(M, f, tol=tol, maxiter=max_iters, M=Milu, callback=callback) elif solver == 'gmres': s, info = linalg.gmres(M, f, tol=tol, maxiter=max_iters, M=Milu, callback=callback) elif solver == 'lgmres': s, info = linalg.lgmres(M, f, tol=tol, maxiter=max_iters, M=Milu, callback=callback) elif solver == 'minres': s, info = linalg.minres(M, f, tol=tol, maxiter=max_iters, M=Milu, callback=callback) elif solver == 'qmr': s, info = linalg.qmr(M, f, tol=tol, maxiter=max_iters, M=Milu, callback=callback) elif solver == 'gcrotmk': s, info = linalg.gcrotmk(M, f, tol=tol, maxiter=max_iters, M=Milu, callback=callback) #elif solver == 'lsmr': # s, info = linalg.lsmr(M, f, maxiter=max_iters, callback=callback) process_time = time.process_time() - start_process_time wall_time = time.time() - start_wall_time if verbose: print("Solved SS using %s (%0.3f sec, %0.3f process time). %s" % (solver, wall_time, process_time, "iters: %d, max_iters: %d, info: %s" % (num_iters, 1000, info) if solver != 'spsolve' else '')) # keep the positive examples at 1 s[positives] = 1 return s, process_time, wall_time, num_iters
def __init__(self, **kwargs): self.resource_pool = kwargs Y = kwargs[TRAIN_LABELS] self.label_row_inds = np.array(kwargs["label_row_inds"], dtype = np.int32) self.label_col_inds = np.array(kwargs["label_col_inds"], dtype = np.int32) self.Y = Y self.trained = False if "regparam" in kwargs: self.regparam = kwargs["regparam"] else: self.regparam = 1.0 if CALLBACK_FUNCTION in kwargs: self.callbackfun = kwargs[CALLBACK_FUNCTION] else: self.callbackfun = None if "compute_risk" in kwargs: self.compute_risk = kwargs["compute_risk"] else: self.compute_risk = False regparam = self.regparam if not 'K1' in self.resource_pool: self.regparam = regparam X1 = self.resource_pool['X1'] X2 = self.resource_pool['X2'] self.X1, self.X2 = X1, X2 if 'maxiter' in self.resource_pool: maxiter = int(self.resource_pool['maxiter']) else: maxiter = 1000 if 'inneriter' in self.resource_pool: inneriter = int(self.resource_pool['inneriter']) else: inneriter = 50 x1tsize, x1fsize = X1.shape #m, d x2tsize, x2fsize = X2.shape #q, r label_row_inds = np.array(self.label_row_inds, dtype = np.int32) label_col_inds = np.array(self.label_col_inds, dtype = np.int32) Y = self.Y rowind = label_row_inds colind = label_col_inds lamb = self.regparam rowind = np.array(rowind, dtype = np.int32) colind = np.array(colind, dtype = np.int32) fdim = X1.shape[1]*X2.shape[1] w = np.zeros(fdim) #np.random.seed(1) #w = np.random.random(fdim) self.bestloss = float("inf") def mv(v): return hessian(w, v, X1, X2, Y, rowind, colind, lamb) for i in range(maxiter): g = gradient(w, X1, X2, Y, rowind, colind, lamb) G = LinearOperator((fdim, fdim), matvec=mv, rmatvec=mv, dtype=np.float64) self.best_residual = float("inf") self.w_new = qmr(G, g, tol=1e-10, maxiter=inneriter)[0] if np.all(w == w - self.w_new): break w = w - self.w_new if self.compute_risk: P = sampled_kronecker_products.sampled_vec_trick(w, X1, X2, rowind, colind) z = (1. - Y*P) z = np.where(z>0, z, 0) loss = 0.5*(np.dot(z,z)+lamb*np.dot(w,w)) if loss < self.bestloss: self.W = w.reshape((x1fsize, x2fsize), order='F') self.bestloss = loss else: self.W = w.reshape((x1fsize, x2fsize), order='F') if self.callbackfun is not None: self.callbackfun.callback(self) self.predictor = LinearPairwisePredictor(self.W) else: K1 = self.resource_pool['K1'] K2 = self.resource_pool['K2'] if 'maxiter' in self.resource_pool: maxiter = int(self.resource_pool['maxiter']) else: maxiter = 100 if 'inneriter' in self.resource_pool: inneriter = int(self.resource_pool['inneriter']) else: inneriter = 1000 label_row_inds = np.array(self.label_row_inds, dtype = np.int32) label_col_inds = np.array(self.label_col_inds, dtype = np.int32) Y = self.Y rowind = label_row_inds colind = label_col_inds lamb = self.regparam rowind = np.array(rowind, dtype = np.int32) colind = np.array(colind, dtype = np.int32) ddim = len(rowind) a = np.zeros(ddim) self.bestloss = float("inf") def func(a): P = sampled_kronecker_products.sampled_vec_trick(a, K2, K1, colind, rowind, colind, rowind) z = (1. - Y*P) z = np.where(z>0, z, 0) Ka = sampled_kronecker_products.sampled_vec_trick(a, K2, K1, colind, rowind, colind, rowind) return 0.5*(np.dot(z,z)+lamb*np.dot(a, Ka)) def mv(v): rows = rowind[sv] cols = colind[sv] p = np.zeros(len(rowind)) A = sampled_kronecker_products.sampled_vec_trick(v, K2, K1, cols, rows, colind, rowind) p[sv] = A return p + lamb * v def rv(v): rows = rowind[sv] cols = colind[sv] p = sampled_kronecker_products.sampled_vec_trick(v[sv], K2, K1, colind, rowind, cols, rows) return p + lamb * v for i in range(maxiter): P = sampled_kronecker_products.sampled_vec_trick(a, K2, K1, colind, rowind, colind, rowind) z = (1. - Y*P) z = np.where(z>0, z, 0) sv = np.nonzero(z)[0] B = np.zeros(P.shape) B[sv] = P[sv]-Y[sv] B = B + lamb*a #solve Ax = B A = LinearOperator((ddim, ddim), matvec=mv, rmatvec=rv, dtype=np.float64) self.a_new = qmr(A, B, tol=1e-10, maxiter=inneriter)[0] if np.all(a == a - self.a_new): break a = a - self.a_new if self.compute_risk: loss = func(a) if loss < self.bestloss: self.A = a self.bestloss = loss else: self.A = a self.predictor = KernelPairwisePredictor(a, rowind, colind) if self.callbackfun is not None: self.callbackfun.callback(self) self.predictor = KernelPairwisePredictor(a, rowind, colind) if self.callbackfun is not None: self.callbackfun.finished(self)
def _action(self, act=1): if QSMODE == MODE_MPMATH: args = {} if act==0: self.typeStr = "mpmath_qr_solve_dps"+getArgDesc(mpmath.qr_solve, args)+" DPS"+str(DPS) self.matrixType = 1 self.indexType = 1 else: self.coeffVec = mpmath.qr_solve(self.sysMat, self.resVec, **args) self.printCalStr() else: if PYTYPE_COEFF_SOLVE_METHOD == "numpy_solve": args = {} if act==0: self.typeStr = "numpy_solve"+getArgDesc(np.linalg.solve, args) self.matrixType = 0 self.indexType = 0 else: self.coeffVec = np.linalg.solve(self.sysMat, self.resVec, **args) self.printCalStr() elif PYTYPE_COEFF_SOLVE_METHOD == "numpy_lstsq": args = {} if act==0: self.typeStr = "numpy_lstsq"+getArgDesc(np.linalg.lstsq, args) self.matrixType = 0 self.indexType = 0 else: self.coeffVec = np.linalg.lstsq(self.sysMat, self.resVec, **args)[0] self.printCalStr() elif PYTYPE_COEFF_SOLVE_METHOD == "numpy_sparse_bicg": args = {} if act==0: self.typeStr = "numpy_sparse_bicg"+getArgDesc(sp_sparse_linalg.bicg, args) self.matrixType = 0 self.indexType = 1 else: self.coeffVec = self._sparseRet(sp_sparse_linalg.bicg(self.sysMat, self.resVec, **args))#, tol=1e-05, maxiter=10*len(self.resVec) elif PYTYPE_COEFF_SOLVE_METHOD == "numpy_sparse_bicgstab": args = {} if act==0: self.typeStr = "numpy_sparse_bicgstab"+getArgDesc(sp_sparse_linalg.bicgstab, args) self.matrixType = 0 self.indexType = 1 else: self.coeffVec = self._sparseRet(sp_sparse_linalg.bicgstab(self.sysMat, self.resVec, **args))#, tol=1e-05, maxiter=10*len(self.resVec) elif PYTYPE_COEFF_SOLVE_METHOD == "numpy_sparse_lgmres": args = {} if act==0: self.typeStr = "numpy_sparse_lgmres"+getArgDesc(sp_sparse_linalg.lgmres, args) self.matrixType = 0 self.indexType = 1 else: self.coeffVec = self._sparseRet(sp_sparse_linalg.lgmres(self.sysMat, self.resVec, **args))#, tol=1e-05, maxiter=1000 elif PYTYPE_COEFF_SOLVE_METHOD == "numpy_sparse_minres": args = {} if act==0: self.typeStr = "numpy_sparse_minres"+getArgDesc(sp_sparse_linalg.minres, args) self.matrixType = 0 self.indexType = 1 else: self.coeffVec = self._sparseRet(sp_sparse_linalg.minres(self.sysMat, self.resVec, **args))#, tol=1e-05, maxiter=5*self.sysMat.shape[0] elif PYTYPE_COEFF_SOLVE_METHOD == "numpy_sparse_qmr": args = {} if act==0: self.typeStr = "numpy_sparse_qmr"+getArgDesc(sp_sparse_linalg.qmr, args) self.matrixType = 0 self.indexType = 1 else: self.coeffVec = self._sparseRet(sp_sparse_linalg.qmr(self.sysMat, self.resVec, **args))#, tol=1e-05, maxiter=10*len(self.resVec) elif PYTYPE_COEFF_SOLVE_METHOD == "numpy_qr": args_qr = {} args_s = {} if act==0: self.typeStr = "numpy_qr"+getArgDesc(np.linalg.qr, args_qr)+",numpy_solve"+getArgDesc(np.linalg.solve, args_s) self.matrixType = 0 self.indexType = 0 else: Q,R = np.linalg.qr(self.sysMat, **args_qr) y = np.dot(Q.T,self.resVec) self.coeffVec = np.linalg.solve(R,y, **args_s) self.printCalStr()
import numpy as np from scipy.sparse.linalg import qmr A = np.arange(1, 10).reshape((3, 3)) A[2, 2] = 0 b = np.arange(1, 4).reshape((3, 1)) x = np.zeros(()) x = np.linalg.inv(A) @ b qmr_x = qmr(A, b, np.zeros((3, 1)))
elif ALGORITHM=="biconjugate-gradient-stabilized": x=la.bicgstab(A,y) elif ALGORITHM=="conjugate-gradient-iter": x=la.cg(A,y) elif ALGORITHM == "conjugate-gradient-squared": x = la.cgs(A, y) elif ALGORITHM == "conjugate-gradient-squared": x = la.cgs(A, y) elif ALGORITHM == "generalized-min-res": x = la.gmres(A, y) elif ALGORITHM == "improved-generalized-min-res": x = la.lgmres(A, y) elif ALGORITHM =="min-res": x=la.minres(A,y) elif ALGORITHM =="quasi-min-res": x=la.qmr(A,y) endT=time.process_time() '''print(x) print(xCorrect)''' residue=np.average(np.average(np.abs(x-xCorrect)))/np.average(np.average(np.abs(xCorrect))) print("Algorith: "+ALGORITHM+"\tMat Size: "+str(N)+"\tTime: "+str(endT-startT)+"\t Residue: "+str(residue)) TIME[n]=endT-startT RESIDUE[n]=residue print("Time List:") for n in range(len(NN)):
def __init__(self, **kwargs): self.resource_pool = kwargs Y = kwargs[TRAIN_LABELS] self.label_row_inds = np.array(kwargs["label_row_inds"], dtype = np.int32) self.label_col_inds = np.array(kwargs["label_col_inds"], dtype = np.int32) self.Y = Y self.trained = False if "regparam" in kwargs: self.regparam = kwargs["regparam"] else: self.regparam = 1.0 if CALLBACK_FUNCTION in kwargs: self.callbackfun = kwargs[CALLBACK_FUNCTION] else: self.callbackfun = None if "compute_risk" in kwargs: self.compute_risk = kwargs["compute_risk"] else: self.compute_risk = False regparam = self.regparam if not 'K1' in self.resource_pool: self.regparam = regparam X1 = self.resource_pool['X1'] X2 = self.resource_pool['X2'] self.X1, self.X2 = X1, X2 if 'maxiter' in self.resource_pool: maxiter = int(self.resource_pool['maxiter']) else: maxiter = 1000 if 'inneriter' in self.resource_pool: inneriter = int(self.resource_pool['inneriter']) else: inneriter = 50 x1tsize, x1fsize = X1.shape #m, d x2tsize, x2fsize = X2.shape #q, r label_row_inds = np.array(self.label_row_inds, dtype = np.int32) label_col_inds = np.array(self.label_col_inds, dtype = np.int32) Y = self.Y rowind = label_row_inds colind = label_col_inds lamb = self.regparam rowind = np.array(rowind, dtype = np.int32) colind = np.array(colind, dtype = np.int32) fdim = X1.shape[1]*X2.shape[1] w = np.zeros(fdim) #np.random.seed(1) #w = np.random.random(fdim) self.bestloss = float("inf") def mv(v): return hessian(w, v, X1, X2, Y, rowind, colind, lamb) for i in range(maxiter): g = gradient(w, X1, X2, Y, rowind, colind, lamb) G = LinearOperator((fdim, fdim), matvec=mv, rmatvec=mv, dtype=np.float64) self.best_residual = float("inf") self.w_new = qmr(G, g, tol=1e-10, maxiter=inneriter)[0] if np.all(w == w - self.w_new): break w = w - self.w_new if self.compute_risk: P = sampled_kronecker_products.sampled_vec_trick(w, X1, X2, rowind, colind) z = (1. - Y*P) z = np.where(z>0, z, 0) loss = 0.5*(np.dot(z,z)+lamb*np.dot(w,w)) if loss < self.bestloss: self.W = w.reshape((x1fsize, x2fsize), order='F') self.bestloss = loss else: self.W = w.reshape((x1fsize, x2fsize), order='F') if self.callbackfun is not None: self.callbackfun.callback(self) self.predictor = LinearPairwisePredictor(self.W) else: K1 = self.resource_pool['K1'] K2 = self.resource_pool['K2'] if 'maxiter' in self.resource_pool: maxiter = int(self.resource_pool['maxiter']) else: maxiter = 100 if 'inneriter' in self.resource_pool: inneriter = int(self.resource_pool['inneriter']) else: inneriter = 1000 label_row_inds = np.array(self.label_row_inds, dtype = np.int32) label_col_inds = np.array(self.label_col_inds, dtype = np.int32) Y = self.Y rowind = label_row_inds colind = label_col_inds lamb = self.regparam rowind = np.array(rowind, dtype = np.int32) colind = np.array(colind, dtype = np.int32) ddim = len(rowind) a = np.zeros(ddim) self.bestloss = float("inf") def func(a): P = sampled_kronecker_products.sampled_vec_trick(a, K2, K1, colind, rowind, colind, rowind) z = (1. - Y*P) z = np.where(z>0, z, 0) Ka = sampled_kronecker_products.sampled_vec_trick(a, K2, K1, colind, rowind, colind, rowind) return 0.5*(np.dot(z,z)+lamb*np.dot(a, Ka)) def mv(v): rows = rowind[sv] cols = colind[sv] p = np.zeros(len(rowind)) A = sampled_kronecker_products.sampled_vec_trick(v, K2, K1, cols, rows, colind, rowind) p[sv] = A return p + lamb * v def mv_mk(v): rows = rowind[sv] cols = colind[sv] p = np.zeros(len(rowind)) skpsum = np.zeros(len(sv)) for i in range(len(K1)): K1i = K1[i] K2i = K2[i] skpsum += weights[i] * sampled_kronecker_products.sampled_vec_trick(v, K2i, K1i, cols, rows, colind, rowind) p[sv] = skpsum return p + lamb * v def rv(v): rows = rowind[sv] cols = colind[sv] p = sampled_kronecker_products.sampled_vec_trick(v[sv], K2, K1, colind, rowind, cols, rows) return p + lamb * v def rv_mk(v): rows = rowind[sv] cols = colind[sv] psum = np.zeros(len(v)) for i in range(len(K1)): K1i = K1[i] K2i = K2[i] psum += weights[i] * sampled_kronecker_products.sampled_vec_trick(v[sv], K2i, K1i, colind, rowind, cols, rows) return psum + lamb * v for i in range(maxiter): if isinstance(K1, (list, tuple)): if 'weights' in kwargs: weights = kwargs['weights'] else: weights = np.ones((len(K1))) A = LinearOperator((ddim, ddim), matvec = mv_mk, rmatvec = rv_mk, dtype = np.float64) P = np.zeros(ddim) for i in range(len(K1)): K1i = K1[i] K2i = K2[i] prod_i = weights[i] * sampled_kronecker_products.sampled_vec_trick(a, K2i, K1i, colind, rowind, colind, rowind) P += prod_i else: weights = None A = LinearOperator((ddim, ddim), matvec=mv, rmatvec=rv, dtype=np.float64) P = sampled_kronecker_products.sampled_vec_trick(a, K2, K1, colind, rowind, colind, rowind) z = (1. - Y*P) z = np.where(z>0, z, 0) sv = np.nonzero(z)[0] B = np.zeros(P.shape) B[sv] = P[sv]-Y[sv] B = B + lamb*a #solve Ax = B self.a_new = qmr(A, B, tol=1e-10, maxiter=inneriter)[0] if np.all(a == a - self.a_new): break a = a - self.a_new if self.compute_risk: loss = func(a) if loss < self.bestloss: self.A = a self.bestloss = loss else: self.A = a self.predictor = KernelPairwisePredictor(a, rowind, colind) if self.callbackfun is not None: self.callbackfun.callback(self) self.predictor = KernelPairwisePredictor(a, rowind, colind) if self.callbackfun is not None: self.callbackfun.finished(self)