CLogDetEstimator::CLogDetEstimator(SGSparseMatrix<float64_t> sparse_mat) : CSGObject() { init(); m_computation_engine=new CSerialComputationEngine(); SG_REF(m_computation_engine); CSparseMatrixOperator<float64_t>* op= new CSparseMatrixOperator<float64_t>(sparse_mat); float64_t accuracy=1E-5; CLanczosEigenSolver* eig_solver=new CLanczosEigenSolver(op); CCGMShiftedFamilySolver* linear_solver=new CCGMShiftedFamilySolver(); m_operator_log=new CLogRationalApproximationCGM(op,m_computation_engine, eig_solver,linear_solver,accuracy); SG_REF(m_operator_log); #ifdef HAVE_COLPACK m_trace_sampler=new CProbingSampler(op,1,NATURAL,DISTANCE_TWO); #else m_trace_sampler=new CNormalSampler(op->get_dimension()); #endif SG_REF(m_trace_sampler); SG_INFO("LogDetEstimator:Using %s, %s with 1E-5 accuracy, %s as default\n", m_computation_engine->get_name(), m_operator_log->get_name(), m_trace_sampler->get_name()); }
template<class ST> bool CDenseFeatures<ST>::apply_preprocessor(bool force_preprocessing) { if (m_subset_stack->has_subsets()) SG_ERROR("A subset is set, cannot call apply_preproc\n"); SG_DEBUG( "force: %d\n", force_preprocessing); if (feature_matrix.matrix && get_num_preprocessors()) { for (int32_t i = 0; i < get_num_preprocessors(); i++) { if ((!is_preprocessed(i) || force_preprocessing)) { set_preprocessed(i); CDensePreprocessor<ST>* p = (CDensePreprocessor<ST>*) get_preprocessor(i); SG_INFO( "preprocessing using preproc %s\n", p->get_name()); if (p->apply_to_feature_matrix(this).matrix == NULL) { SG_UNREF(p); return false; } SG_UNREF(p); } } return true; } else { if (!feature_matrix.matrix) SG_ERROR( "no feature matrix\n"); if (!get_num_preprocessors()) SG_ERROR( "no preprocessors available\n"); return false; } }
SGVector<complex128_t> CCGMShiftedFamilySolver::solve_shifted_weighted( CLinearOperator<SGVector<float64_t>, SGVector<float64_t> >* A, SGVector<float64_t> b, SGVector<complex128_t> shifts, SGVector<complex128_t> weights) { SG_DEBUG("Entering\n"); // sanity check REQUIRE(A, "Operator is NULL!\n"); REQUIRE(A->get_dimension()==b.vlen, "Dimension mismatch! [%d vs %d]\n", A->get_dimension(), b.vlen); REQUIRE(shifts.vector,"Shifts are not initialized!\n"); REQUIRE(weights.vector,"Weights are not initialized!\n"); REQUIRE(shifts.vlen==weights.vlen, "Number of shifts and number of " "weights are not equal! [%d vs %d]\n", shifts.vlen, weights.vlen); // the solution matrix, one column per shift, initial guess 0 for all MatrixXcd x_sh=MatrixXcd::Zero(b.vlen, shifts.vlen); MatrixXcd p_sh=MatrixXcd::Zero(b.vlen, shifts.vlen); // non-shifted direction SGVector<float64_t> p_(b.vlen); // the rest of the part hinges on eigen3 for computing norms Map<VectorXd> b_map(b.vector, b.vlen); Map<VectorXd> p(p_.vector, p_.vlen); // residual r_i=b-Ax_i, here x_0=[0], so r_0=b VectorXd r=b_map; // initial direction is same as residual p=r; p_sh=r.replicate(1, shifts.vlen).cast<complex128_t>(); // non shifted initializers float64_t r_norm2=r.dot(r); float64_t beta_old=1.0; float64_t alpha=1.0; // shifted quantities SGVector<complex128_t> alpha_sh(shifts.vlen); SGVector<complex128_t> beta_sh(shifts.vlen); SGVector<complex128_t> zeta_sh_old(shifts.vlen); SGVector<complex128_t> zeta_sh_cur(shifts.vlen); SGVector<complex128_t> zeta_sh_new(shifts.vlen); // shifted initializers zeta_sh_old.set_const(1.0); zeta_sh_cur.set_const(1.0); // the iterator for this iterative solver IterativeSolverIterator<float64_t> it(r, m_max_iteration_limit, m_relative_tolerence, m_absolute_tolerence); // start the timer CTime time; time.start(); // set the residuals to zero if (m_store_residuals) m_residuals.set_const(0.0); // CG iteration begins for (it.begin(r); !it.end(r); ++it) { SG_DEBUG("CG iteration %d, residual norm %f\n", it.get_iter_info().iteration_count, it.get_iter_info().residual_norm); if (m_store_residuals) { m_residuals[it.get_iter_info().iteration_count] =it.get_iter_info().residual_norm; } // apply linear operator to the direction vector SGVector<float64_t> Ap_=A->apply(p_); Map<VectorXd> Ap(Ap_.vector, Ap_.vlen); // compute p^{T}Ap, if zero, failure float64_t p_dot_Ap=p.dot(Ap); if (p_dot_Ap==0.0) break; // compute the beta parameter of CG_M float64_t beta=-r_norm2/p_dot_Ap; // compute the zeta-shifted parameter of CG_M compute_zeta_sh_new(zeta_sh_old, zeta_sh_cur, shifts, beta_old, beta, alpha, zeta_sh_new); // compute beta-shifted parameter of CG_M compute_beta_sh(zeta_sh_new, zeta_sh_cur, beta, beta_sh); // update the solution vector and residual for (index_t i=0; i<shifts.vlen; ++i) x_sh.col(i)-=beta_sh[i]*p_sh.col(i); // r_{i}=r_{i-1}+\beta_{i}Ap r+=beta*Ap; // compute new ||r||_{2}, if zero, converged float64_t r_norm2_i=r.dot(r); if (r_norm2_i==0.0) break; // compute the alpha parameter of CG_M alpha=r_norm2_i/r_norm2; // update ||r||_{2} r_norm2=r_norm2_i; // update direction p=r+alpha*p; compute_alpha_sh(zeta_sh_new, zeta_sh_cur, beta_sh, beta, alpha, alpha_sh); for (index_t i=0; i<shifts.vlen; ++i) { p_sh.col(i)*=alpha_sh[i]; p_sh.col(i)+=zeta_sh_new[i]*r; } // update parameters for (index_t i=0; i<shifts.vlen; ++i) { zeta_sh_old[i]=zeta_sh_cur[i]; zeta_sh_cur[i]=zeta_sh_new[i]; } beta_old=beta; } float64_t elapsed=time.cur_time_diff(); if (!it.succeeded(r)) SG_WARNING("Did not converge!\n"); SG_INFO("Iteration took %d times, residual norm=%.20lf, time elapsed=%f\n", it.get_iter_info().iteration_count, it.get_iter_info().residual_norm, elapsed); // compute the final result vector multiplied by weights SGVector<complex128_t> result(b.vlen); result.set_const(0.0); Map<VectorXcd> x(result.vector, result.vlen); for (index_t i=0; i<x_sh.cols(); ++i) x+=x_sh.col(i)*weights[i]; SG_DEBUG("Leaving\n"); return result; }
SGVector<float64_t> CConjugateGradientSolver::solve( CLinearOperator<float64_t>* A, SGVector<float64_t> b) { SG_DEBUG("CConjugateGradientSolve::solve(): Entering..\n"); // sanity check REQUIRE(A, "Operator is NULL!\n"); REQUIRE(A->get_dimension()==b.vlen, "Dimension mismatch!\n"); // the final solution vector, initial guess is 0 SGVector<float64_t> result(b.vlen); result.set_const(0.0); // the rest of the part hinges on eigen3 for computing norms Map<VectorXd> x(result.vector, result.vlen); Map<VectorXd> b_map(b.vector, b.vlen); // direction vector SGVector<float64_t> p_(result.vlen); Map<VectorXd> p(p_.vector, p_.vlen); // residual r_i=b-Ax_i, here x_0=[0], so r_0=b VectorXd r=b_map; // initial direction is same as residual p=r; // the iterator for this iterative solver IterativeSolverIterator<float64_t> it(b_map, m_max_iteration_limit, m_relative_tolerence, m_absolute_tolerence); // CG iteration begins float64_t r_norm2=r.dot(r); // start the timer CTime time; time.start(); // set the residuals to zero if (m_store_residuals) m_residuals.set_const(0.0); for (it.begin(r); !it.end(r); ++it) { SG_DEBUG("CG iteration %d, residual norm %f\n", it.get_iter_info().iteration_count, it.get_iter_info().residual_norm); if (m_store_residuals) { m_residuals[it.get_iter_info().iteration_count] =it.get_iter_info().residual_norm; } // apply linear operator to the direction vector SGVector<float64_t> Ap_=A->apply(p_); Map<VectorXd> Ap(Ap_.vector, Ap_.vlen); // compute p^{T}Ap, if zero, failure float64_t p_dot_Ap=p.dot(Ap); if (p_dot_Ap==0.0) break; // compute the alpha parameter of CG float64_t alpha=r_norm2/p_dot_Ap; // update the solution vector and residual // x_{i}=x_{i-1}+\alpha_{i}p x+=alpha*p; // r_{i}=r_{i-1}-\alpha_{i}p r-=alpha*Ap; // compute new ||r||_{2}, if zero, converged float64_t r_norm2_i=r.dot(r); if (r_norm2_i==0.0) break; // compute the beta parameter of CG float64_t beta=r_norm2_i/r_norm2; // update direction, and ||r||_{2} r_norm2=r_norm2_i; p=r+beta*p; } float64_t elapsed=time.cur_time_diff(); if (!it.succeeded(r)) SG_WARNING("Did not converge!\n"); SG_INFO("Iteration took %ld times, residual norm=%.20lf, time elapsed=%lf\n", it.get_iter_info().iteration_count, it.get_iter_info().residual_norm, elapsed); SG_DEBUG("CConjugateGradientSolve::solve(): Leaving..\n"); return result; }
SGVector<float64_t> CLogDetEstimator::sample(index_t num_estimates) { SG_DEBUG("Entering\n"); SG_INFO("Computing %d log-det estimates\n", num_estimates); REQUIRE(m_operator_log, "Operator function is NULL\n"); // call the precompute of operator function to compute the prerequisites m_operator_log->precompute(); REQUIRE(m_trace_sampler, "Trace sampler is NULL\n"); // call the precompute of the sampler m_trace_sampler->precompute(); REQUIRE(m_operator_log->get_operator()->get_dimension()\ ==m_trace_sampler->get_dimension(), "Mismatch in dimensions of the operator and trace-sampler, %d vs %d!\n", m_operator_log->get_operator()->get_dimension(), m_trace_sampler->get_dimension()); // for storing the aggregators that submit_jobs return CDynamicObjectArray* aggregators=new CDynamicObjectArray(); index_t num_trace_samples=m_trace_sampler->get_num_samples(); for (index_t i=0; i<num_estimates; ++i) { for (index_t j=0; j<num_trace_samples; ++j) { SG_INFO("Computing log-determinant trace sample %d/%d\n", j, num_trace_samples); SG_DEBUG("Creating job for estimate %d, trace sample %d/%d\n", i, j, num_trace_samples); // get the trace sampler vector SGVector<float64_t> s=m_trace_sampler->sample(j); // create jobs with the sample vector and store the aggregator CJobResultAggregator* agg=m_operator_log->submit_jobs(s); aggregators->append_element(agg); SG_UNREF(agg); } } REQUIRE(m_computation_engine, "Computation engine is NULL\n"); // wait for all the jobs to be completed SG_INFO("Waiting for jobs to finish\n"); m_computation_engine->wait_for_all(); SG_INFO("All jobs finished, aggregating results\n"); // the samples vector which stores the estimates with averaging SGVector<float64_t> samples(num_estimates); samples.zero(); // use the aggregators to find the final result // use the same order as job submission to combine results int32_t num_aggregates=aggregators->get_num_elements(); index_t idx_row=0; index_t idx_col=0; for (int32_t i=0; i<num_aggregates; ++i) { // this cast is safe due to above way of building the array CJobResultAggregator* agg=dynamic_cast<CJobResultAggregator*> (aggregators->get_element(i)); ASSERT(agg); // call finalize on all the aggregators, cast is safe again agg->finalize(); CScalarResult<float64_t>* r=dynamic_cast<CScalarResult<float64_t>*> (agg->get_final_result()); ASSERT(r); // iterate through indices, group results in the same way as jobs samples[idx_col]+=r->get_result(); idx_row++; if (idx_row>=num_trace_samples) { idx_row=0; idx_col++; } SG_UNREF(agg); } // clear all aggregators SG_UNREF(aggregators) SG_INFO("Finished computing %d log-det estimates\n", num_estimates); SG_DEBUG("Leaving\n"); return samples; }