void Tikhonov ( Orientation orientation, const SparseMatrix<F>& A, const Matrix<F>& B, const SparseMatrix<F>& G, Matrix<F>& X, const LeastSquaresCtrl<Base<F>>& ctrl ) { DEBUG_CSE // Explicitly form W := op(A) // ========================== SparseMatrix<F> W; if( orientation == NORMAL ) W = A; else if( orientation == TRANSPOSE ) Transpose( A, W ); else Adjoint( A, W ); const Int m = W.Height(); const Int n = W.Width(); const Int numRHS = B.Width(); // Embed into a higher-dimensional problem via appending regularization // ==================================================================== SparseMatrix<F> WEmb; if( m >= n ) VCat( W, G, WEmb ); else HCat( W, G, WEmb ); Matrix<F> BEmb; Zeros( BEmb, WEmb.Height(), numRHS ); if( m >= n ) { auto BEmbT = BEmb( IR(0,m), IR(0,numRHS) ); BEmbT = B; } else BEmb = B; // Solve the higher-dimensional problem // ==================================== Matrix<F> XEmb; LeastSquares( NORMAL, WEmb, BEmb, XEmb, ctrl ); // Extract the solution // ==================== if( m >= n ) X = XEmb; else X = XEmb( IR(0,n), IR(0,numRHS) ); }
void StackedRuizEquil ( SparseMatrix<Field>& A, SparseMatrix<Field>& B, Matrix<Base<Field>>& dRowA, Matrix<Base<Field>>& dRowB, Matrix<Base<Field>>& dCol, bool progress ) { EL_DEBUG_CSE typedef Base<Field> Real; const Int mA = A.Height(); const Int mB = B.Height(); const Int n = A.Width(); Ones( dRowA, mA, 1 ); Ones( dRowB, mB, 1 ); Ones( dCol, n, 1 ); // TODO(poulson): Expose these as control parameters // For now, simply hard-code the number of iterations const Int maxIter = 4; Matrix<Real> scales, maxAbsValsB; const Int indent = PushIndent(); for( Int iter=0; iter<maxIter; ++iter ) { // Rescale the columns // ------------------- ColumnMaxNorms( A, scales ); ColumnMaxNorms( B, maxAbsValsB ); for( Int j=0; j<n; ++j ) scales(j) = Max(scales(j),maxAbsValsB(j)); EntrywiseMap( scales, MakeFunction(DampScaling<Real>) ); DiagonalScale( LEFT, NORMAL, scales, dCol ); DiagonalSolve( RIGHT, NORMAL, scales, A ); DiagonalSolve( RIGHT, NORMAL, scales, B ); // Rescale the rows // ---------------- RowMaxNorms( A, scales ); EntrywiseMap( scales, MakeFunction(DampScaling<Real>) ); DiagonalScale( LEFT, NORMAL, scales, dRowA ); DiagonalSolve( LEFT, NORMAL, scales, A ); RowMaxNorms( B, scales ); EntrywiseMap( scales, MakeFunction(DampScaling<Real>) ); DiagonalScale( LEFT, NORMAL, scales, dRowB ); DiagonalSolve( LEFT, NORMAL, scales, B ); } SetIndent( indent ); }
void ShiftDiagonal ( SparseMatrix<T>& A, S alphaPre, Int offset, bool existingDiag ) { EL_DEBUG_CSE const Int m = A.Height(); const Int n = A.Width(); const T alpha = T(alphaPre); if( existingDiag ) { T* valBuf = A.ValueBuffer(); for( Int i=Max(0,-offset); i<Min(m,n-offset); ++i ) { const Int e = A.Offset( i, i+offset ); valBuf[e] += alpha; } } else { const Int diagLength = Min(m,n-offset) - Max(0,-offset); A.Reserve( diagLength ); for( Int i=Max(0,-offset); i<Min(m,n-offset); ++i ) A.QueueUpdate( i, i+offset, alpha ); A.ProcessQueues(); } }
void LAV ( const SparseMatrix<Real>& A, const Matrix<Real>& b, Matrix<Real>& x, const lp::affine::Ctrl<Real>& ctrl ) { EL_DEBUG_CSE const Int m = A.Height(); const Int n = A.Width(); const Range<Int> xInd(0,n), uInd(n,n+m), vInd(n+m,n+2*m); SparseMatrix<Real> AHat, G; Matrix<Real> c, h; // c := [0;1;1] // ============ Zeros( c, n+2*m, 1 ); auto cuv = c( IR(n,n+2*m), ALL ); Fill( cuv, Real(1) ); // \hat A := [A, I, -I] // ==================== Zeros( AHat, m, n+2*m ); const Int numEntriesA = A.NumEntries(); AHat.Reserve( numEntriesA + 2*m ); for( Int e=0; e<numEntriesA; ++e ) AHat.QueueUpdate( A.Row(e), A.Col(e), A.Value(e) ); for( Int i=0; i<m; ++i ) { AHat.QueueUpdate( i, i+n, Real( 1) ); AHat.QueueUpdate( i, i+n+m, Real(-1) ); } AHat.ProcessQueues(); // G := | 0 -I 0 | // | 0 0 -I | // ================ Zeros( G, 2*m, n+2*m ); G.Reserve( G.Height() ); for( Int i=0; i<2*m; ++i ) G.QueueUpdate( i, i+n, Real(-1) ); G.ProcessQueues(); // h := | 0 | // | 0 | // ========== Zeros( h, 2*m, 1 ); // Solve the affine linear program // =============================== Matrix<Real> xHat, y, z, s; LP( AHat, G, b, c, h, xHat, y, z, s, ctrl ); // Extract x // ========= x = xHat( xInd, ALL ); }
void Fill( SparseMatrix<T>& A, T alpha ) { EL_DEBUG_CSE const Int m = A.Height(); const Int n = A.Width(); A.Resize( m, n ); Zero( A ); if( alpha != T(0) ) { A.Reserve( m*n ); for( Int i=0; i<m; ++i ) for( Int j=0; j<n; ++j ) A.QueueUpdate( i, j, alpha ); A.ProcessQueues(); } }
void MatrixMarket( const SparseMatrix<T>& A, string basename="matrix" ) { EL_DEBUG_CSE string filename = basename + "." + FileExtension(MATRIX_MARKET); ofstream file( filename.c_str(), std::ios::binary ); if( !file.is_open() ) RuntimeError("Could not open ",filename); // Write the header // ================ { ostringstream os; os << "%%MatrixMarket matrix coordinate "; if( IsComplex<T>::value ) os << "complex "; else os << "real "; os << "general\n"; file << os.str(); } // Write the size line // =================== const Int m = A.Height(); const Int n = A.Width(); const Int numNonzeros = A.NumEntries(); file << BuildString(m," ",n," ",numNonzeros,"\n"); // Write the entries // ================= for( Int e=0; e<numNonzeros; ++e ) { const Int i = A.Row(e); const Int j = A.Col(e); const T value = A.Value(e); if( IsComplex<T>::value ) { file << BuildString(i," ",j," ",RealPart(value)," ",ImagPart(value),"\n"); } else { file << BuildString(i," ",j," ",RealPart(value),"\n"); } } }
void Lanczos ( const SparseMatrix<F>& A, Matrix<Base<F>>& T, Int basisSize ) { DEBUG_CSE const Int n = A.Height(); if( n != A.Width() ) LogicError("A was not square"); auto applyA = [&]( const Matrix<F>& X, Matrix<F>& Y ) { Zeros( Y, n, X.Width() ); Multiply( NORMAL, F(1), A, X, F(0), Y ); }; Lanczos<F>( n, applyA, T, basisSize ); }
bool WriteMatrixMarketFile(const std::string& file_path, const SparseMatrix<T>& A, const unsigned int precision) { // Write a MatrixMarket file with no comments. Note that the // MatrixMarket format uses 1-based indexing for rows and columns. std::ofstream outfile(file_path); if (!outfile) return false; unsigned int height = A.Height(); unsigned int width = A.Width(); unsigned int nnz = A.Size(); // write the 'banner' outfile << MM_BANNER << " matrix coordinate real general" << std::endl; // write matrix dimensions and number of nonzeros outfile << height << " " << width << " " << nnz << std::endl; outfile << std::fixed; outfile.precision(precision); const unsigned int* cols_a = A.LockedColBuffer(); const unsigned int* rows_a = A.LockedRowBuffer(); const T* data_a = A.LockedDataBuffer(); unsigned int width_a = A.Width(); for (unsigned int c=0; c != width_a; ++c) { unsigned int start = cols_a[c]; unsigned int end = cols_a[c+1]; for (unsigned int offset=start; offset != end; ++offset) { unsigned int r = rows_a[offset]; T val = data_a[offset]; outfile << r+1 << " " << c+1 << " " << val << std::endl; } } outfile.close(); return true; }
void RowMaxNorms( const SparseMatrix<F>& A, Matrix<Base<F>>& norms ) { DEBUG_CSE typedef Base<F> Real; const Int m = A.Height(); const F* valBuf = A.LockedValueBuffer(); const Int* offsetBuf = A.LockedOffsetBuffer(); norms.Resize( m, 1 ); for( Int i=0; i<m; ++i ) { Real rowMax = 0; const Int offset = offsetBuf[i]; const Int numConn = offsetBuf[i+1] - offset; for( Int e=offset; e<offset+numConn; ++e ) rowMax = Max(rowMax,Abs(valBuf[e])); norms(i) = rowMax; } }
Base<Field> ProductLanczosDecomp ( const SparseMatrix<Field>& A, Matrix<Field>& V, Matrix<Base<Field>>& T, Matrix<Field>& v, Int basisSize ) { EL_DEBUG_CSE const Int m = A.Height(); const Int n = A.Width(); Matrix<Field> S; // Cache the adjoint // ----------------- SparseMatrix<Field> AAdj; Adjoint( A, AAdj ); if( m >= n ) { auto applyA = [&]( const Matrix<Field>& X, Matrix<Field>& Y ) { Zeros( S, m, X.Width() ); Multiply( NORMAL, Field(1), A, X, Field(0), S ); Zeros( Y, n, X.Width() ); Multiply( NORMAL, Field(1), AAdj, S, Field(0), Y ); }; return LanczosDecomp( n, applyA, V, T, v, basisSize ); } else { auto applyA = [&]( const Matrix<Field>& X, Matrix<Field>& Y ) { Zeros( S, n, X.Width() ); Multiply( NORMAL, Field(1), AAdj, X, Field(0), S ); Zeros( Y, m, X.Width() ); Multiply( NORMAL, Field(1), A, S, Field(0), Y ); }; return LanczosDecomp( m, applyA, V, T, v, basisSize ); } }
Base<Field> LanczosDecomp ( const SparseMatrix<Field>& A, Matrix<Field>& V, Matrix<Base<Field>>& T, Matrix<Field>& v, Int basisSize ) { EL_DEBUG_CSE const Int n = A.Height(); if( n != A.Width() ) LogicError("A was not square"); auto applyA = [&]( const Matrix<Field>& X, Matrix<Field>& Y ) { Zeros( Y, n, X.Width() ); Multiply( NORMAL, Field(1), A, X, Field(0), Y ); }; return LanczosDecomp( n, applyA, V, T, v, basisSize ); }
void RowTwoNorms( const SparseMatrix<F>& A, Matrix<Base<F>>& norms ) { DEBUG_CSE typedef Base<F> Real; const Int m = A.Height(); const F* valBuf = A.LockedValueBuffer(); const Int* offsetBuf = A.LockedOffsetBuffer(); norms.Resize( m, 1 ); for( Int i=0; i<m; ++i ) { Real scale = 0; Real scaledSquare = 1; const Int offset = offsetBuf[i]; const Int numConn = offsetBuf[i+1] - offset; for( Int e=offset; e<offset+numConn; ++e ) UpdateScaledSquare( valBuf[e], scale, scaledSquare ); norms(i) = scale*Sqrt(scaledSquare); } }
void GetMappedDiagonal ( const SparseMatrix<T>& A, Matrix<S>& d, function<S(const T&)> func, Int offset ) { EL_DEBUG_CSE const Int m = A.Height(); const Int n = A.Width(); const T* valBuf = A.LockedValueBuffer(); const Int* colBuf = A.LockedTargetBuffer(); const Int iStart = Max(-offset,0); const Int jStart = Max( offset,0); const Int diagLength = El::DiagonalLength(m,n,offset); d.Resize( diagLength, 1 ); Zero( d ); S* dBuf = d.Buffer(); for( Int k=0; k<diagLength; ++k ) { const Int i = iStart + k; const Int j = jStart + k; const Int thisOff = A.RowOffset(i); const Int nextOff = A.RowOffset(i+1); auto it = std::lower_bound( colBuf+thisOff, colBuf+nextOff, j ); if( *it == j ) { const Int e = it-colBuf; dBuf[Min(i,j)] = func(valBuf[e]); } else dBuf[Min(i,j)] = func(0); } }
void SymmetricRuizEquil ( SparseMatrix<F>& A, Matrix<Base<F>>& d, Int maxIter, bool progress ) { DEBUG_CSE typedef Base<F> Real; const Int n = A.Height(); Ones( d, n, 1 ); Matrix<Real> scales; const Int indent = PushIndent(); for( Int iter=0; iter<maxIter; ++iter ) { // Rescale the columns (and rows) // ------------------------------ ColumnMaxNorms( A, scales ); EntrywiseMap( scales, function<Real(Real)>(DampScaling<Real>) ); EntrywiseMap( scales, function<Real(Real)>(SquareRootScaling<Real>) ); DiagonalScale( LEFT, NORMAL, scales, d ); SymmetricDiagonalSolve( scales, A ); } SetIndent( indent ); }
int main(int argc, char *argv[]) { // 1. Parse command-line options. const char *mesh_file = "../data/beam-tri.mesh"; int order = 1; bool static_cond = false; bool visualization = 1; OptionsParser args(argc, argv); args.AddOption(&mesh_file, "-m", "--mesh", "Mesh file to use."); args.AddOption(&order, "-o", "--order", "Finite element order (polynomial degree)."); args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc", "--no-static-condensation", "Enable static condensation."); args.AddOption(&visualization, "-vis", "--visualization", "-no-vis", "--no-visualization", "Enable or disable GLVis visualization."); args.Parse(); if (!args.Good()) { args.PrintUsage(cout); return 1; } args.PrintOptions(cout); // 2. Read the mesh from the given mesh file. We can handle triangular, // quadrilateral, tetrahedral or hexahedral elements with the same code. Mesh *mesh = new Mesh(mesh_file, 1, 1); int dim = mesh->Dimension(); if (mesh->attributes.Max() < 2 || mesh->bdr_attributes.Max() < 2) { cerr << "\nInput mesh should have at least two materials and " << "two boundary attributes! (See schematic in ex2.cpp)\n" << endl; return 3; } // 3. Select the order of the finite element discretization space. For NURBS // meshes, we increase the order by degree elevation. if (mesh->NURBSext) { mesh->DegreeElevate(order, order); } // 4. Refine the mesh to increase the resolution. In this example we do // 'ref_levels' of uniform refinement. We choose 'ref_levels' to be the // largest number that gives a final mesh with no more than 5,000 // elements. { int ref_levels = (int)floor(log(5000./mesh->GetNE())/log(2.)/dim); for (int l = 0; l < ref_levels; l++) { mesh->UniformRefinement(); } } // 5. Define a finite element space on the mesh. Here we use vector finite // elements, i.e. dim copies of a scalar finite element space. The vector // dimension is specified by the last argument of the FiniteElementSpace // constructor. For NURBS meshes, we use the (degree elevated) NURBS space // associated with the mesh nodes. FiniteElementCollection *fec; FiniteElementSpace *fespace; if (mesh->NURBSext) { fec = NULL; fespace = mesh->GetNodes()->FESpace(); } else { fec = new H1_FECollection(order, dim); fespace = new FiniteElementSpace(mesh, fec, dim); } cout << "Number of finite element unknowns: " << fespace->GetTrueVSize() << endl << "Assembling: " << flush; // 6. Determine the list of true (i.e. conforming) essential boundary dofs. // In this example, the boundary conditions are defined by marking only // boundary attribute 1 from the mesh as essential and converting it to a // list of true dofs. Array<int> ess_tdof_list, ess_bdr(mesh->bdr_attributes.Max()); ess_bdr = 0; ess_bdr[0] = 1; fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list); // 7. Set up the linear form b(.) which corresponds to the right-hand side of // the FEM linear system. In this case, b_i equals the boundary integral // of f*phi_i where f represents a "pull down" force on the Neumann part // of the boundary and phi_i are the basis functions in the finite element // fespace. The force is defined by the VectorArrayCoefficient object f, // which is a vector of Coefficient objects. The fact that f is non-zero // on boundary attribute 2 is indicated by the use of piece-wise constants // coefficient for its last component. VectorArrayCoefficient f(dim); for (int i = 0; i < dim-1; i++) { f.Set(i, new ConstantCoefficient(0.0)); } { Vector pull_force(mesh->bdr_attributes.Max()); pull_force = 0.0; pull_force(1) = -1.0e-2; f.Set(dim-1, new PWConstCoefficient(pull_force)); } LinearForm *b = new LinearForm(fespace); b->AddBoundaryIntegrator(new VectorBoundaryLFIntegrator(f)); cout << "r.h.s. ... " << flush; b->Assemble(); // 8. Define the solution vector x as a finite element grid function // corresponding to fespace. Initialize x with initial guess of zero, // which satisfies the boundary conditions. GridFunction x(fespace); x = 0.0; // 9. Set up the bilinear form a(.,.) on the finite element space // corresponding to the linear elasticity integrator with piece-wise // constants coefficient lambda and mu. Vector lambda(mesh->attributes.Max()); lambda = 1.0; lambda(0) = lambda(1)*50; PWConstCoefficient lambda_func(lambda); Vector mu(mesh->attributes.Max()); mu = 1.0; mu(0) = mu(1)*50; PWConstCoefficient mu_func(mu); BilinearForm *a = new BilinearForm(fespace); a->AddDomainIntegrator(new ElasticityIntegrator(lambda_func,mu_func)); // 10. Assemble the bilinear form and the corresponding linear system, // applying any necessary transformations such as: eliminating boundary // conditions, applying conforming constraints for non-conforming AMR, // static condensation, etc. cout << "matrix ... " << flush; if (static_cond) { a->EnableStaticCondensation(); } a->Assemble(); SparseMatrix A; Vector B, X; a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B); cout << "done." << endl; cout << "Size of linear system: " << A.Height() << endl; #ifndef MFEM_USE_SUITESPARSE // 11. Define a simple symmetric Gauss-Seidel preconditioner and use it to // solve the system Ax=b with PCG. GSSmoother M(A); PCG(A, M, B, X, 1, 500, 1e-8, 0.0); #else // 11. If MFEM was compiled with SuiteSparse, use UMFPACK to solve the system. UMFPackSolver umf_solver; umf_solver.Control[UMFPACK_ORDERING] = UMFPACK_ORDERING_METIS; umf_solver.SetOperator(A); umf_solver.Mult(B, X); #endif // 12. Recover the solution as a finite element grid function. a->RecoverFEMSolution(X, *b, x); // 13. For non-NURBS meshes, make the mesh curved based on the finite element // space. This means that we define the mesh elements through a fespace // based transformation of the reference element. This allows us to save // the displaced mesh as a curved mesh when using high-order finite // element displacement field. We assume that the initial mesh (read from // the file) is not higher order curved mesh compared to the chosen FE // space. if (!mesh->NURBSext) { mesh->SetNodalFESpace(fespace); } // 14. Save the displaced mesh and the inverted solution (which gives the // backward displacements to the original grid). This output can be // viewed later using GLVis: "glvis -m displaced.mesh -g sol.gf". { GridFunction *nodes = mesh->GetNodes(); *nodes += x; x *= -1; ofstream mesh_ofs("displaced.mesh"); mesh_ofs.precision(8); mesh->Print(mesh_ofs); ofstream sol_ofs("sol.gf"); sol_ofs.precision(8); x.Save(sol_ofs); } // 15. Send the above data by socket to a GLVis server. Use the "n" and "b" // keys in GLVis to visualize the displacements. if (visualization) { char vishost[] = "localhost"; int visport = 19916; socketstream sol_sock(vishost, visport); sol_sock.precision(8); sol_sock << "solution\n" << *mesh << x << flush; } // 16. Free the used memory. delete a; delete b; if (fec) { delete fespace; delete fec; } delete mesh; return 0; }
void IPM ( const SparseMatrix<Real>& A, const Matrix<Real>& b, Real lambda, Matrix<Real>& x, const qp::affine::Ctrl<Real>& ctrl ) { DEBUG_CSE const Int m = A.Height(); const Int n = A.Width(); const Range<Int> uInd(0,n), vInd(n,2*n), rInd(2*n,2*n+m); SparseMatrix<Real> Q, AHat, G; Matrix<Real> c, h; // Q := | 0 0 0 | // | 0 0 0 | // | 0 0 I | // ============== Zeros( Q, 2*n+m, 2*n+m ); Q.Reserve( m ); for( Int e=0; e<m; ++e ) Q.QueueUpdate( 2*n+e, 2*n+e, Real(1) ); Q.ProcessQueues(); // c := lambda*[1;1;0] // =================== Zeros( c, 2*n+m, 1 ); auto cuv = c( IR(0,2*n), ALL ); Fill( cuv, lambda ); // \hat A := [A, -A, I] // ==================== const Int numEntriesA = A.NumEntries(); Zeros( AHat, m, 2*n+m ); AHat.Reserve( 2*numEntriesA+m ); for( Int e=0; e<numEntriesA; ++e ) { AHat.QueueUpdate( A.Row(e), A.Col(e), A.Value(e) ); AHat.QueueUpdate( A.Row(e), A.Col(e)+n, -A.Value(e) ); } for( Int e=0; e<m; ++e ) AHat.QueueUpdate( e, e+2*n, Real(1) ); AHat.ProcessQueues(); // G := | -I 0 0 | // | 0 -I 0 | // ================ Zeros( G, 2*n, 2*n+m ); G.Reserve( 2*m ); for( Int e=0; e<2*m; ++e ) G.QueueUpdate( e, e, Real(-1) ); G.ProcessQueues(); // h := 0 // ====== Zeros( h, 2*n, 1 ); // Solve the affine QP // =================== Matrix<Real> xHat, y, z, s; QP( Q, AHat, G, b, c, h, xHat, y, z, s, ctrl ); // x := u - v // ========== x = xHat( uInd, ALL ); x -= xHat( vInd, ALL ); }
//----------------------------------------------------------------------------- void Nmf(const unsigned int kval, const Algorithm algorithm, const std::string& csv_file_w, const std::string& csv_file_h) { if (!matrix_loaded) throw std::logic_error("smallk error (NMF): no matrix has been loaded."); if (max_iter < min_iter) throw std::logic_error("smallk error (NMF): min_iterations exceeds max_iterations."); if (0 == kval) throw std::logic_error("smallk error (NMF): k must be greater than 0."); // Check the sizes of matrix W(m, k) and matrix H(k, n) and make sure // they don't overflow Elemental's default signed int index type. if (!SizeCheck<int>(m, kval)) throw std::logic_error("smallk error (Nmf): mxk matrix W is too large."); if (!SizeCheck<int>(kval, n)) throw std::logic_error("smallk error (Nmf): kxn matrix H is too large."); k = kval; // convert to the 'NmfAlgorithm' type in nmf.hpp switch (algorithm) { case Algorithm::MU: nmf_opts.algorithm = NmfAlgorithm::MU; break; case Algorithm::HALS: nmf_opts.algorithm = NmfAlgorithm::HALS; break; case Algorithm::RANK2: nmf_opts.algorithm = NmfAlgorithm::RANK2; break; case Algorithm::BPP: nmf_opts.algorithm = NmfAlgorithm::BPP; break; default: throw std::logic_error("smallk error (NMF): unknown NMF algorithm."); } // set k == 2 for Rank2 algorithm if (NmfAlgorithm::RANK2 == nmf_opts.algorithm) k = 2; ldim_w = m; ldim_h = k; if (buf_w.size() < m*k) buf_w.resize(m*k); if (buf_h.size() < k*n) buf_h.resize(k*n); // initialize matrices W and H bool ok; unsigned int height_w = m, width_w = k, height_h = k, width_h = n; cout << "Initializing matrix W..." << endl; if (csv_file_w.empty()) ok = RandomMatrix(&buf_w[0], ldim_w, m, k, rng); else ok = LoadDelimitedFile(buf_w, height_w, width_w, csv_file_w); if (!ok) { std::ostringstream msg; msg << "smallk error (Nmf): load failed for file "; msg << "\"" << csv_file_w << "\""; throw std::runtime_error(msg.str()); } if ( (height_w != m) || (width_w != k)) { cerr << "\tdimensions of matrix W are " << height_w << " x " << width_w << endl; cerr << "\texpected " << m << " x " << k << endl; throw std::logic_error("smallk error (Nmf): non-conformant matrix W."); } cout << "Initializing matrix H..." << endl; if (csv_file_h.empty()) ok = RandomMatrix(&buf_h[0], ldim_h, k, n, rng); else ok = LoadDelimitedFile(buf_h, height_h, width_h, csv_file_h); if (!ok) { std::ostringstream msg; msg << "smallk error (Nmf): load failed for file "; msg << "\"" << csv_file_h << "\""; throw std::runtime_error(msg.str()); } if ( (height_h != k) || (width_h != n)) { cerr << "\tdimensions of matrix H are " << height_h << " x " << width_h << endl; cerr << "\texpected " << k << " x " << n << endl; throw std::logic_error("smallk error (Nmf): non-conformant matrix H."); } // The ratio of projected gradient norms doesn't seem to work very well // with MU. We frequently observe a 'leveling off' behavior and the // convergence is even slower than usual. So for MU use the relative // change in the Frobenius norm of W as the stopping criterion, which // always seems to behave well, even though it is on shaky theoretical // ground. if (NmfAlgorithm::MU == nmf_opts.algorithm) nmf_opts.prog_est_algorithm = NmfProgressAlgorithm::DELTA_FNORM; else nmf_opts.prog_est_algorithm = NmfProgressAlgorithm::PG_RATIO; nmf_opts.tol = nmf_tolerance; nmf_opts.height = m; nmf_opts.width = n; nmf_opts.k = k; nmf_opts.min_iter = min_iter; nmf_opts.max_iter = max_iter; nmf_opts.tolcount = 1; nmf_opts.max_threads = max_threads; nmf_opts.verbose = true; nmf_opts.normalize = true; // display all params to user PrintNmfOpts(nmf_opts); NmfStats stats; Result result; if (is_sparse) { result = NmfSparse(nmf_opts, A.Height(), A.Width(), A.Size(), A.LockedColBuffer(), A.LockedRowBuffer(), A.LockedDataBuffer(), &buf_w[0], ldim_w, &buf_h[0], ldim_h, stats); } else { result = Nmf(nmf_opts, &buf_a[0], ldim_a, &buf_w[0], ldim_w, &buf_h[0], ldim_h, stats); } cout << "Elapsed wall clock time: "; cout << ElapsedTime(stats.elapsed_us) << endl; cout << endl; if (Result::OK != result) throw std::runtime_error("smallk error (Nmf): NMF solver failure."); // write the computed W and H factors to disk std::string outfile_w, outfile_h; if (outdir.empty()) { outfile_w = DEFAULT_FILENAME_W; outfile_h = DEFAULT_FILENAME_H; } else { outfile_w = outdir + DEFAULT_FILENAME_W; outfile_h = outdir + DEFAULT_FILENAME_H; } cout << "Writing output files..." << endl; if (!WriteDelimitedFile(&buf_w[0], ldim_w, m, k, outfile_w, outprecision)) throw std::runtime_error("smallk error (Nmf): could not write W result."); if (!WriteDelimitedFile(&buf_h[0], ldim_h, k, n, outfile_h, outprecision)) throw std::runtime_error("smallk error (Nmf): could not write H result."); }
void SparseMatrix<T>::SubMatrixColsCompact(SparseMatrix<T>& result, const std::vector<unsigned int>& col_indices, std::vector<unsigned int>& old_to_new_rows, std::vector<unsigned int>& new_to_old_rows) const { const unsigned int UNUSED_ROW = 0xFFFFFFFF; // extract entire columns from the source matrix to form the dest matrix unsigned int new_width = col_indices.size(); if (0u == new_width) throw std::logic_error("SparseMatrix::SubMatrixColsCompact: empty column set"); // need one entry per original row in the row_map if (old_to_new_rows.size() < height_) old_to_new_rows.resize(height_); std::fill(old_to_new_rows.begin(), old_to_new_rows.begin() + height_, UNUSED_ROW); // no need to fill 'new_to_old_rows' // check the column indices for validty and count nonzeros unsigned int new_size = 0; for (auto it=col_indices.begin(); it != col_indices.end(); ++it) { // index of next source column unsigned int c = *it; if (c >= width_) throw std::logic_error("SparseMatrix::SubMatrixColsCompact: column index out of range"); // number of nonzeros in source column c new_size += (col_offsets_[c+1] - col_offsets_[c]); } if (0u == new_size) throw std::logic_error("SparseMatrix::SubMatrixColsCompact: submatrix is the zero matrix"); // allocate memory in the result; won't allocate if sufficient memory available result.Reserve(height_, new_width, new_size); unsigned int* cols_b = result.ColBuffer(); unsigned int* rows_b = result.RowBuffer(); T* data_b = result.DataBuffer(); unsigned int c_dest = 0; unsigned int elt_count = 0; for (auto it=col_indices.begin(); it != col_indices.end(); ++it) { // index of the next source column unsigned int c = *it; // set element offset for the next dest column cols_b[c_dest] = elt_count; unsigned int start = col_offsets_[c]; unsigned int end = col_offsets_[c+1]; for (unsigned int offset = start; offset != end; ++offset) { unsigned int row = row_indices_[offset]; old_to_new_rows[row] = row; rows_b[elt_count] = row; data_b[elt_count] = data_[offset]; ++elt_count; } // have now completed another column ++c_dest; } cols_b[new_width] = elt_count; assert(new_width == c_dest); // set the size of the new matrix explicitly, since Load() has been bypassed result.SetSize(elt_count); // determine the new height of the submatrix unsigned int new_height = 0; for (unsigned int r=0; r != height_; ++r) { if (UNUSED_ROW != old_to_new_rows[r]) ++new_height; } new_to_old_rows.resize(new_height); // renumber the rows in the submatrix unsigned int new_r = 0; for (unsigned int r=0; r<height_; ++r) { if (UNUSED_ROW != old_to_new_rows[r]) { old_to_new_rows[r] = new_r; new_to_old_rows[new_r] = r; ++new_r; } } // set the height of the new matrix explicitly assert(new_r == new_height); result.SetHeight(new_height); // re-index the rows in the submatrix for (unsigned int s=0; s != elt_count; ++s) { unsigned int old_row_index = rows_b[s]; rows_b[s] = old_to_new_rows[old_row_index]; } assert(result.Height() == new_height); assert(new_to_old_rows.size() == new_height); assert(old_to_new_rows.size() == height_); }
//----------------------------------------------------------------------------- int main(int argc, char* argv[]) { Timer timer; double elapsed_s; // print usage info if no command line args were specified std::string prog_name(argv[0]); if (1 == argc) { PrintUsage(prog_name); return 0; } CommandLineOptions opts; ParseCommandLine(argc, argv, opts); if (!IsValid(opts)) return -1; // // Check to see if the specified directories exist. // if (!DirectoryExists(opts.indir)) { cerr << "\npreprocessor: the specified input directory " << opts.indir << " does not exist." << endl; return -1; } if (!opts.outdir.empty()) { if (!DirectoryExists(opts.outdir)) { cerr << "\npreprocessor: the specified output directory " << opts.outdir << " does not exist." << endl; return -1; } } // setup paths and filenames std::string inputdir = EnsureTrailingPathSep(opts.indir); std::string infile = inputdir + std::string("matrix.mtx"); std::string indict = inputdir + std::string("dictionary.txt"); std::string indocs = inputdir + std::string("documents.txt"); std::string outputdir, outfile, outdict, outdocs; if (!opts.outdir.empty()) { outputdir = EnsureTrailingPathSep(opts.outdir); outfile = outputdir + std::string("reduced_matrix.mtx"); outdict = outputdir + std::string("reduced_dictionary.txt"); outdocs = outputdir + std::string("reduced_documents.txt"); } else { outfile = std::string("reduced_matrix.mtx"); outdict = std::string("reduced_dictionary.txt"); outdocs = std::string("reduced_documents.txt"); } // // load the input dictionary and documents // std::vector<std::string> dictionary, documents; if (!LoadStringsFromFile(indict, dictionary)) { cerr << "\npreprocessor: could not open dictionary file " << indict << endl; return -1; } unsigned int num_terms = dictionary.size(); if (!LoadStringsFromFile(indocs, documents)) { cerr << "\npreprocessor: could not open documents file " << indocs << endl; return -1; } unsigned int num_docs = documents.size(); // print options to screen prior to run opts.indir = inputdir; if (outputdir.empty()) opts.outdir = std::string("current directory"); else opts.outdir = outputdir; PrintOpts(opts); bool boolean_mode = (0 != opts.boolean_mode); SparseMatrix<double> A; unsigned int height, width, nonzeros; // // load the input matrix // cout << "Loading input matrix " << infile << endl; timer.Start(); if (!LoadMatrixMarketFile(infile, A, height, width, nonzeros)) { cerr << "\npreprocessor: could not load file " << infile << endl; return -1; } timer.Stop(); elapsed_s = static_cast<double>(timer.ReportMilliseconds() * 0.001); cout << "\tInput file load time: " << elapsed_s << "s." << endl; // // check num_terms and num_docs // if (num_terms < A.Height()) { cerr << "\npreprocessor error: expected " << A.Height() << " terms in the dictionary; found " << num_terms << "." << endl; return -1; } if (num_docs < A.Width()) { cerr << "\npreprocessor error: expected " << A.Width() << " strings in the documents file; found " << num_docs << "." << endl; return -1; } // // do the preprocessing // timer.Start(); TermFrequencyMatrix M(A, boolean_mode); // allocate the index sets for the terms and docs std::vector<unsigned int> term_indices(height); std::vector<unsigned int> doc_indices(width); std::vector<double> scores; bool ok = preprocess_tf(M, term_indices, doc_indices, scores, opts.max_iter, opts.docs_per_term, opts.terms_per_doc); timer.Stop(); elapsed_s = static_cast<double>(timer.ReportMilliseconds() * 0.001); cout << "Processing time: " << elapsed_s << "s." << endl; cout << endl; if (!ok) { cerr << "\npreprocessor: matrix has dimension zero." << endl; cerr << "no output files will be written" << endl; return false; } // // write the result matrix to disk // cout << "Writing output matrix " << outfile << endl; timer.Start(); if (!M.WriteMtxFile(outfile, &scores[0], opts.precision)) { cerr << "\npreprocessor: could not write file " << outfile << endl; return -1; } timer.Stop(); elapsed_s = static_cast<double>(timer.ReportMilliseconds() * 0.001); cout << "Output file write time: " << elapsed_s << "s." << endl; // // write the reduced dictionary and documents to disk // cout << "Writing dictionary file " << outdict << endl; timer.Start(); if (!WriteStringsToFile(outdict, dictionary, term_indices, M.Height())) { cerr << "\npreprocessor: could not write file " << outdict << endl; } timer.Stop(); elapsed_s = static_cast<double>(timer.ReportMilliseconds() * 0.001); cout << "Writing documents file " << outdocs << endl; timer.Start(); if (!WriteStringsToFile(outdocs, documents, doc_indices, M.Width())) { cerr << "\npreprocessor: could not write file " << outdocs << endl; } timer.Stop(); elapsed_s += static_cast<double>(timer.ReportMilliseconds() * 0.001); cout << "Dictionary + documents write time: " << elapsed_s << "s." << endl; return 0; }
int main(int argc, char *argv[]) { // 1. Parse command-line options. const char *mesh_file = "../../data/fichera.mesh"; int order = sol_p; bool static_cond = false; bool visualization = 1; bool perf = true; OptionsParser args(argc, argv); args.AddOption(&mesh_file, "-m", "--mesh", "Mesh file to use."); args.AddOption(&order, "-o", "--order", "Finite element order (polynomial degree) or -1 for" " isoparametric space."); args.AddOption(&perf, "-perf", "--hpc-version", "-std", "--standard-version", "Enable high-performance, tensor-based, assembly."); args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc", "--no-static-condensation", "Enable static condensation."); args.AddOption(&visualization, "-vis", "--visualization", "-no-vis", "--no-visualization", "Enable or disable GLVis visualization."); args.Parse(); if (!args.Good()) { args.PrintUsage(cout); return 1; } args.PrintOptions(cout); // 2. Read the mesh from the given mesh file. We can handle triangular, // quadrilateral, tetrahedral, hexahedral, surface and volume meshes with // the same code. Mesh *mesh = new Mesh(mesh_file, 1, 1); int dim = mesh->Dimension(); // 3. Check if the optimized version matches the given mesh if (perf) { cout << "High-performance version using integration rule with " << int_rule_t::qpts << " points ..." << endl; if (!mesh_t::MatchesGeometry(*mesh)) { cout << "The given mesh does not match the optimized 'geom' parameter.\n" << "Recompile with suitable 'geom' value." << endl; delete mesh; return 3; } else if (!mesh_t::MatchesNodes(*mesh)) { cout << "Switching the mesh curvature to match the " << "optimized value (order " << mesh_p << ") ..." << endl; mesh->SetCurvature(mesh_p, false, -1, Ordering::byNODES); } } // 4. Refine the mesh to increase the resolution. In this example we do // 'ref_levels' of uniform refinement. We choose 'ref_levels' to be the // largest number that gives a final mesh with no more than 50,000 // elements. { int ref_levels = (int)floor(log(50000./mesh->GetNE())/log(2.)/dim); for (int l = 0; l < ref_levels; l++) { mesh->UniformRefinement(); } } // 5. Define a finite element space on the mesh. Here we use continuous // Lagrange finite elements of the specified order. If order < 1, we // instead use an isoparametric/isogeometric space. FiniteElementCollection *fec; if (order > 0) { fec = new H1_FECollection(order, dim); } else if (mesh->GetNodes()) { fec = mesh->GetNodes()->OwnFEC(); cout << "Using isoparametric FEs: " << fec->Name() << endl; } else { fec = new H1_FECollection(order = 1, dim); } FiniteElementSpace *fespace = new FiniteElementSpace(mesh, fec); cout << "Number of finite element unknowns: " << fespace->GetTrueVSize() << endl; // 6. Check if the optimized version matches the given space if (perf && !sol_fes_t::Matches(*fespace)) { cout << "The given order does not match the optimized parameter.\n" << "Recompile with suitable 'sol_p' value." << endl; delete fespace; delete fec; delete mesh; return 4; } // 7. Determine the list of true (i.e. conforming) essential boundary dofs. // In this example, the boundary conditions are defined by marking all // the boundary attributes from the mesh as essential (Dirichlet) and // converting them to a list of true dofs. Array<int> ess_tdof_list; if (mesh->bdr_attributes.Size()) { Array<int> ess_bdr(mesh->bdr_attributes.Max()); ess_bdr = 1; fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list); } // 8. Set up the linear form b(.) which corresponds to the right-hand side of // the FEM linear system, which in this case is (1,phi_i) where phi_i are // the basis functions in the finite element fespace. LinearForm *b = new LinearForm(fespace); ConstantCoefficient one(1.0); b->AddDomainIntegrator(new DomainLFIntegrator(one)); b->Assemble(); // 9. Define the solution vector x as a finite element grid function // corresponding to fespace. Initialize x with initial guess of zero, // which satisfies the boundary conditions. GridFunction x(fespace); x = 0.0; // 10. Set up the bilinear form a(.,.) on the finite element space that will // hold the matrix corresponding to the Laplacian operator -Delta. BilinearForm *a = new BilinearForm(fespace); // 11. Assemble the bilinear form and the corresponding linear system, // applying any necessary transformations such as: eliminating boundary // conditions, applying conforming constraints for non-conforming AMR, // static condensation, etc. if (static_cond) { a->EnableStaticCondensation(); } cout << "Assembling the matrix ..." << flush; tic_toc.Clear(); tic_toc.Start(); // Pre-allocate sparsity assuming dense element matrices a->UsePrecomputedSparsity(); if (!perf) { // Standard assembly using a diffusion domain integrator a->AddDomainIntegrator(new DiffusionIntegrator(one)); a->Assemble(); } else { // High-performance assembly using the templated operator type oper_t a_oper(integ_t(coeff_t(1.0)), *fespace); a_oper.AssembleBilinearForm(*a); } tic_toc.Stop(); cout << " done, " << tic_toc.RealTime() << "s." << endl; SparseMatrix A; Vector B, X; a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B); cout << "Size of linear system: " << A.Height() << endl; #ifndef MFEM_USE_SUITESPARSE // 12. Define a simple symmetric Gauss-Seidel preconditioner and use it to // solve the system A X = B with PCG. GSSmoother M(A); PCG(A, M, B, X, 1, 500, 1e-12, 0.0); #else // 12. If MFEM was compiled with SuiteSparse, use UMFPACK to solve the system. UMFPackSolver umf_solver; umf_solver.Control[UMFPACK_ORDERING] = UMFPACK_ORDERING_METIS; umf_solver.SetOperator(A); umf_solver.Mult(B, X); #endif // 13. Recover the solution as a finite element grid function. a->RecoverFEMSolution(X, *b, x); // 14. Save the refined mesh and the solution. This output can be viewed later // using GLVis: "glvis -m refined.mesh -g sol.gf". ofstream mesh_ofs("refined.mesh"); mesh_ofs.precision(8); mesh->Print(mesh_ofs); ofstream sol_ofs("sol.gf"); sol_ofs.precision(8); x.Save(sol_ofs); // 15. Send the solution by socket to a GLVis server. if (visualization) { char vishost[] = "localhost"; int visport = 19916; socketstream sol_sock(vishost, visport); sol_sock.precision(8); sol_sock << "solution\n" << *mesh << x << flush; } // 16. Free the used memory. delete a; delete b; delete fespace; if (order > 0) { delete fec; } delete mesh; return 0; }
void RLS ( const SparseMatrix<Real>& A, const Matrix<Real>& b, Real rho, Matrix<Real>& x, const socp::affine::Ctrl<Real>& ctrl ) { DEBUG_CSE const Int m = A.Height(); const Int n = A.Width(); Matrix<Int> orders, firstInds; Zeros( orders, m+n+3, 1 ); Zeros( firstInds, m+n+3, 1 ); for( Int i=0; i<m+1; ++i ) { orders.Set( i, 0, m+1 ); firstInds.Set( i, 0, 0 ); } for( Int i=0; i<n+2; ++i ) { orders.Set( i+m+1, 0, n+2 ); firstInds.Set( i+m+1, 0, m+1 ); } // G := | -1 0 0 | // | 0 0 A | // | 0 -1 0 | // | 0 0 -I | // | 0 0 0 | SparseMatrix<Real> G; { const Int numEntriesA = A.NumEntries(); Zeros( G, m+n+3, n+2 ); G.Reserve( numEntriesA+n+2 ); G.QueueUpdate( 0, 0, -1 ); for( Int e=0; e<numEntriesA; ++e ) G.QueueUpdate( A.Row(e)+1, A.Col(e)+2, A.Value(e) ); G.QueueUpdate( m+1, 1, -1 ); for( Int j=0; j<n; ++j ) G.QueueUpdate( j+m+2, j+2, -1 ); G.ProcessQueues(); } // h := | 0 | // | b | // | 0 | // | 0 | // | 1 | Matrix<Real> h; Zeros( h, m+n+3, 1 ); auto hb = h( IR(1,m+1), ALL ); hb = b; h.Set( END, 0, 1 ); // c := [1; rho; 0] Matrix<Real> c; Zeros( c, n+2, 1 ); c.Set( 0, 0, 1 ); c.Set( 1, 0, rho ); SparseMatrix<Real> AHat; Zeros( AHat, 0, n+2 ); Matrix<Real> bHat; Zeros( bHat, 0, 1 ); Matrix<Real> xHat, y, z, s; SOCP( AHat, G, bHat, c, h, orders, firstInds, xHat, y, z, s, ctrl ); x = xHat( IR(2,END), ALL ); }
void IPM ( const SparseMatrix<Real>& A, const Matrix<Real>& d, Real lambda, Matrix<Real>& x, const qp::affine::Ctrl<Real>& ctrl ) { EL_DEBUG_CSE const Int m = A.Height(); const Int n = A.Width(); const Range<Int> wInd(0,n), betaInd(n,n+1), zInd(n+1,n+m+1); SparseMatrix<Real> Q, AHat, G; Matrix<Real> c, b, h; // Q := | I 0 0 | // | 0 0 0 | // | 0 0 0 | // ============== Zeros( Q, n+m+1, n+m+1 ); Q.Reserve( n ); for( Int e=0; e<n; ++e ) Q.QueueUpdate( e, e, Real(1) ); Q.ProcessQueues(); // c := [0;0;lambda] // ================= Zeros( c, n+m+1, 1 ); auto cz = c( zInd, ALL ); Fill( cz, lambda ); // AHat = [] // ========= Zeros( AHat, 0, n+m+1 ); // b = [] // ====== Zeros( b, 0, 1 ); // G := |-diag(d) A, -d, -I| // | 0, 0, -I| // ========================= Zeros( G, 2*m, n+m+1 ); const Int numEntriesA = A.NumEntries(); G.Reserve( numEntriesA+3*m ); for( Int e=0; e<numEntriesA; ++e ) G.QueueUpdate( A.Row(e), A.Col(e), -d(A.Row(e))*A.Value(e) ); for( Int e=0; e<m; ++e ) G.QueueUpdate( e, n, -d(e) ); for( Int e=0; e<m; ++e ) { G.QueueUpdate( e, e+n+1, Real(-1) ); G.QueueUpdate( e+m, e+n+1, Real(-1) ); } G.ProcessQueues(); // h := [-ones(m,1); zeros(m,1)] // ============================= Zeros( h, 2*m, 1 ); auto h0 = h( IR(0,m), ALL ); Fill( h0, Real(-1) ); // Solve the affine QP // =================== Matrix<Real> y, z, s; QP( Q, AHat, G, b, c, h, x, y, z, s, ctrl ); }