void QP ( const SparseMatrix<Real>& A, const Matrix<Real>& B, Matrix<Real>& X, const qp::direct::Ctrl<Real>& ctrl ) { DEBUG_CSE const Int n = A.Width(); const Int k = B.Width(); SparseMatrix<Real> Q, AHat; Matrix<Real> bHat, c; Herk( LOWER, ADJOINT, Real(1), A, Q ); MakeHermitian( LOWER, Q ); Zeros( AHat, 0, n ); Zeros( bHat, 0, 1 ); Zeros( X, n, k ); Matrix<Real> y, z; for( Int j=0; j<k; ++j ) { auto x = X( ALL, IR(j) ); auto b = B( ALL, IR(j) ); Zeros( c, n, 1 ); Multiply( ADJOINT, Real(-1), A, b, Real(0), c ); El::QP( Q, AHat, bHat, c, x, y, z, ctrl ); } }
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(); } }
T OneNorm(const SparseMatrix<T>& A) { // compute the max absolute column sum const unsigned int* cols_a = A.LockedColBuffer(); const T* data_a = A.LockedDataBuffer(); const unsigned int width_a = A.Width(); T max_col_sum = T(0), col_sum; for (unsigned int c=0; c != width_a; ++c) { unsigned int start = cols_a[c]; unsigned int end = cols_a[c+1]; col_sum = T(0); for (unsigned int offset=start; offset != end; ++offset) { T val = fabs(data_a[offset]); col_sum += val; } if (col_sum > max_col_sum) max_col_sum = col_sum; } return max_col_sum; }
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 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 Print(const SparseMatrix<T>& M) { // Print a SparseMatrix to the screen. const unsigned int* col_buf = M.LockedColBuffer(); const unsigned int* row_buf = M.LockedRowBuffer(); const T* buf = M.LockedDataBuffer(); if (0 == M.Size()) { std::cout << "Matrix is empty." << std::endl; return; } for (unsigned int c=0; c != M.Width(); ++c) { unsigned int start = col_buf[c]; unsigned int end = col_buf[c+1]; for (unsigned int offset=start; offset != end; ++offset) { assert(offset >= 0); assert(offset < M.Size()); unsigned int row_index = row_buf[offset]; T data = buf[offset]; std::cout << "(" << row_index << ", " << c << "): " << data << std::endl; } } std::cout << "Col indices: "; std::cout.flush(); for (unsigned int i=0; i != M.Width(); ++i) std::cout << col_buf[i] << ", "; std::cout << col_buf[M.Width()] << std::endl; std::cout << "Row indices: "; std::cout.flush(); for (unsigned int i=0; i != M.Size(); ++i) std::cout << row_buf[i] << ", "; std::cout << std::endl; std::cout << "Data: "; std::cout.flush(); for (unsigned int i=0; i != M.Size(); ++i) std::cout << buf[i] << ", "; std::cout << std::endl; }
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 KKT ( const SparseMatrix<Real>& A, const SparseMatrix<Real>& G, const Matrix<Real>& s, const Matrix<Real>& z, SparseMatrix<Real>& J, bool onlyLower ) { EL_DEBUG_CSE const Int n = A.Width(); SparseMatrix<Real> Q; Q.Resize( n, n ); qp::affine::KKT( Q, A, G, s, z, J, onlyLower ); }
void AugmentedKKT ( const SparseMatrix<Real>& A, Real gamma, Real delta, const Matrix<Real>& x, const Matrix<Real>& z, SparseMatrix<Real>& J, bool onlyLower ) { EL_DEBUG_CSE const Int n = A.Width(); SparseMatrix<Real> Q; Zeros( Q, n, n ); qp::direct::AugmentedKKT( Q, A, gamma, delta, x, z, J, onlyLower ); }
void KKT ( const SparseMatrix<Real>& A, Real gamma, Real delta, Real beta, const Matrix<Real>& x, const Matrix<Real>& z, SparseMatrix<Real>& J, bool onlyLower ) { EL_DEBUG_CSE const Int n = A.Width(); SparseMatrix<Real> Q; Q.Resize( n, n ); qp::direct::KKT( Q, A, gamma, delta, beta, x, z, J, onlyLower ); }
void StaticKKT ( const SparseMatrix<Real>& A, const SparseMatrix<Real>& G, Real gamma, Real delta, Real beta, SparseMatrix<Real>& J, bool onlyLower ) { EL_DEBUG_CSE const Int n = A.Width(); SparseMatrix<Real> Q; Q.Resize( n, n ); qp::affine::StaticKKT( Q, A, G, gamma, delta, beta, J, onlyLower ); }
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 ); }
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 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 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."); }
/** Bi-conjugate gradient method. */ MATHLIB_API int BiConjugateGradientSolve( const SparseMatrix &A, const DenseVector &b, DenseVector &x, float epsilon ) { piDebugCheck( A.IsSquare() ); piDebugCheck( A.Width() == b.Dim() ); piDebugCheck( A.Width() == x.Dim() ); int i = 0; const int D = A.Width(); const int i_max = 4 * D; float resid; float rho_1 = 0; float rho_2 = 0; float alpha; float beta; DenseVector r(D); DenseVector rtilde(D); DenseVector p(D); DenseVector ptilde(D); DenseVector q(D); DenseVector qtilde(D); DenseVector tmp(D); // temporal vector. // r = b - A·x; A.Product( x, tmp ); r.Sub( b, tmp ); // rtilde = r rtilde.Set( r ); // p = r; p.Set( r ); // ptilde = rtilde ptilde.Set( rtilde ); float normb = b.Norm(); if( normb == 0.0 ) normb = 1; // test convergence resid = r.Norm() / normb; if( resid < epsilon ) { // method converges? return 0; } while( i < i_max ) { i++; rho_1 = DenseVectorDotProduct( r, rtilde ); if( rho_1 == 0 ) { // method fails. return -i; } if (i == 1) { p.Set( r ); ptilde.Set( rtilde ); } else { beta = rho_1 / rho_2; // p = r + beta * p; p.Mad( r, p, beta ); // ptilde = ztilde + beta * ptilde; ptilde.Mad( rtilde, ptilde, beta ); } // q = A * p; A.Product( p, q ); // qtilde = A^t * ptilde; A.TransProduct( ptilde, qtilde ); alpha = rho_1 / DenseVectorDotProduct( ptilde, q ); // x += alpha * p; x.Mad( x, p, alpha ); // r -= alpha * q; r.Mad( r, q, -alpha ); // rtilde -= alpha * qtilde; rtilde.Mad( rtilde, qtilde, -alpha ); rho_2 = rho_1; // test convergence resid = r.Norm() / normb; if( resid < epsilon ) { // method converges return i; } } return i; }
//----------------------------------------------------------------------------- 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; }
/** Bi-conjugate gradient stabilized method. */ int BiCGSTABPrecondSolve( const SparseMatrix &A, const DenseVector &b, DenseVector &x, const IPreconditioner &M, float epsilon ) { piDebugCheck( A.IsSquare() ); piDebugCheck( A.Width() == b.Dim() ); piDebugCheck( A.Width() == x.Dim() ); int i = 0; const int D = A.Width(); const int i_max = D; // const int i_max = 1000; float resid; float rho_1 = 0; float rho_2 = 0; float alpha = 0; float beta = 0; float omega = 0; DenseVector p(D); DenseVector phat(D); DenseVector s(D); DenseVector shat(D); DenseVector t(D); DenseVector v(D); DenseVector r(D); DenseVector rtilde(D); DenseVector tmp(D); // r = b - A·x; A.Product( x, tmp ); r.Sub( b, tmp ); // rtilde = r rtilde.Set( r ); float normb = b.Norm(); if( normb == 0.0 ) normb = 1; // test convergence resid = r.Norm() / normb; if( resid < epsilon ) { // method converges? return 0; } while( i<i_max ) { i++; rho_1 = DenseVectorDotProduct( rtilde, r ); if( rho_1 == 0 ) { // method fails return -i; } if( i == 1 ) { p.Set( r ); } else { beta = (rho_1 / rho_2) * (alpha / omega); // p = r + beta * (p - omega * v); p.Mad( p, v, -omega ); p.Mad( r, p, beta ); } //phat = M.solve(p); //phat.Set( p ); M.Precond( &phat, p ); //v = A * phat; A.Product( phat, v ); alpha = rho_1 / DenseVectorDotProduct( rtilde, v ); // s = r - alpha * v; s.Mad( r, v, -alpha ); resid = s.Norm() / normb; //printf( "--- Iteration %d: residual = %f\n", i, resid ); if( resid < epsilon ) { // x += alpha * phat; x.Mad( x, phat, alpha ); return i; } //shat = M.solve(s); //shat.Set( s ); M.Precond( &shat, s ); //t = A * shat; A.Product( shat, t ); omega = DenseVectorDotProduct( t, s ) / DenseVectorDotProduct( t, t ); // x += alpha * phat + omega * shat; x.Mad( x, shat, omega ); x.Mad( x, phat, alpha ); //r = s - omega * t; r.Mad( s, t, -omega ); rho_2 = rho_1; resid = r.Norm() / normb; if( resid < epsilon ) { return i; } if( omega == 0 ) { return -i; // ??? } } return i; }
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 ); }