108 using lno_t =
typename Adapter::lno_t;
109 using gno_t =
typename Adapter::gno_t;
115 using graph_t = Tpetra::CrsGraph<lno_t, gno_t, node_t>;
116 using matrix_t = Tpetra::CrsMatrix<scalar_t, lno_t, gno_t, node_t>;
117 using mvector_t = Tpetra::MultiVector<scalar_t, lno_t, gno_t, node_t>;
118 using op_t = Tpetra::Operator<scalar_t, lno_t, gno_t, node_t>;
127 Sphynx(
const RCP<const Environment> &env,
128 const RCP<Teuchos::ParameterList> ¶ms,
129 const RCP<Teuchos::ParameterList> &sphynxParams,
130 const RCP<
const Comm<int> > &comm,
132 env_(env), params_(params), sphynxParams_(sphynxParams), comm_(comm), adapter_(adapter)
136 const Teuchos::ParameterEntry *pe = params_->getEntryPtr(
"num_global_parts");
137 numGlobalParts_ = pe->getValue<
int>(&numGlobalParts_);
138 if(numGlobalParts_ > 1){
140 Teuchos::TimeMonitor t(*Teuchos::TimeMonitor::getNewTimer(
"Sphynx::Laplacian"));
143 pe = sphynxParams_->getEntryPtr(
"sphynx_verbosity");
145 verbosity_ = pe->getValue<
int>(&verbosity_);
148 pe = sphynxParams_->getEntryPtr(
"sphynx_skip_preprocessing");
150 skipPrep_ = pe->getValue<
bool>(&skipPrep_);
155 graph_ = adapter_->getUserGraph();
157 throw std::runtime_error(
"\nSphynx Error: Preprocessing has not been implemented yet.\n");
183 template<
typename problem_t>
186 template<
typename problem_t>
189 template<
typename problem_t>
192 template<
typename problem_t>
200 std::vector<int> strides);
203 std::vector<const weight_t *>
weights,
204 std::vector<int> strides,
222 auto rowOffsets = graph_->getLocalGraphDevice().row_map;
223 auto rowOffsets_h = Kokkos::create_mirror_view(rowOffsets);
224 Kokkos::deep_copy(rowOffsets_h, rowOffsets);
227 const size_t numGlobalEntries = graph_->getGlobalNumEntries();
228 const size_t numLocalRows = graph_->getLocalNumRows();
229 const size_t numGlobalRows = graph_->getGlobalNumRows();
233 for(
size_t i = 0; i < numLocalRows; i++){
234 if(rowOffsets_h(i+1) - rowOffsets_h(i) - 1 > localMax)
235 localMax = rowOffsets_h(i+1) - rowOffsets_h(i) - 1;
239 size_t globalMax = 0;
240 Teuchos::reduceAll<int, size_t> (*comm_, Teuchos::REDUCE_MAX, 1, &localMax, &globalMax);
242 double avg =
static_cast<double>(numGlobalEntries-numGlobalRows)/numGlobalRows;
243 double maxOverAvg =
static_cast<double>(globalMax)/avg;
247 if(maxOverAvg > 10) {
253 if(comm_->getRank() == 0) {
254 std::cout <<
"Determining Regularity -- max degree: " << globalMax
255 <<
", avg degree: " << avg <<
", max/avg: " << globalMax/avg << std::endl
256 <<
"Determined Regularity -- regular: " << !irregular_ << std::endl;
277 precType_ =
"jacobi";
278#ifdef HAVE_ZOLTAN2SPHYNX_MUELU
283 const Teuchos::ParameterEntry *pe = sphynxParams_->getEntryPtr(
"sphynx_preconditioner_type");
285 precType_ = pe->getValue<std::string>(&precType_);
286 if(precType_ !=
"muelu" && precType_ !=
"jacobi" && precType_ !=
"polynomial")
287 throw std::runtime_error(
"\nSphynx Error: " + precType_ +
" is not recognized as a preconditioner.\n"
288 +
" Possible values: muelu (if enabled), jacobi, and polynomial\n");
291 solverType_ = sphynxParams_->get(
"sphynx_eigensolver",
"LOBPCG");
292 TEUCHOS_TEST_FOR_EXCEPTION(!(solverType_ ==
"LOBPCG" || solverType_ ==
"randomized"),
293 std::invalid_argument,
"Sphynx: sphynx_eigensolver must be set to LOBPCG or randomized.");
298 if(precType_ ==
"polynomial")
305 pe = sphynxParams_->getEntryPtr(
"sphynx_problem_type");
307 std::string probType =
"";
308 probType = pe->getValue<std::string>(&probType);
310 if(probType ==
"combinatorial")
312 else if(probType ==
"generalized")
314 else if(probType ==
"normalized")
317 throw std::runtime_error(
"\nSphynx Error: " + probType +
" is not recognized as a problem type.\n"
318 +
" Possible values: combinatorial, generalized, and normalized.\n");
324 if(!irregular_ && (precType_ ==
"jacobi" || precType_ ==
"polynomial"))
329 pe = sphynxParams_->getEntryPtr(
"sphynx_tolerance");
331 tolerance_ = pe->getValue<
scalar_t>(&tolerance_);
340 pe = sphynxParams_->getEntryPtr(
"sphynx_initial_guess");
342 std::string initialGuess =
"";
343 initialGuess = pe->getValue<std::string>(&initialGuess);
345 if(initialGuess ==
"random")
347 else if(initialGuess ==
"constants")
350 throw std::runtime_error(
"\nSphynx Error: " + initialGuess +
" is not recognized as an option for initial guess.\n"
351 +
" Possible values: random and constants.\n");
363 if(solverType_ ==
"randomized")
377 auto rowOffsets = graph_->getLocalGraphHost().row_map;
380 Teuchos::RCP<matrix_t> degMat(
new matrix_t (graph_->getRowMap(),
386 lno_t numRows =
static_cast<lno_t>(graph_->getLocalNumRows());
389 for (
lno_t i = 0; i < numRows; ++i) {
390 val[0] = rowOffsets(i+1) - rowOffsets(i) - 1;
392 degMat->insertLocalValues(i, 1, val, ind);
397 degMat->fillComplete(graph_->getDomainMap(), graph_->getRangeMap());
409 using range_policy = Kokkos::RangePolicy<
410 typename node_t::device_type::execution_space, Kokkos::IndexType<lno_t>>;
411 using values_view_t = Kokkos::View<scalar_t*, typename node_t::device_type>;
412 using offset_view_t = Kokkos::View<size_t*, typename node_t::device_type>;
414 const size_t numEnt = graph_->getLocalNumEntries();
415 const size_t numRows = graph_->getLocalNumRows();
418 values_view_t newVal (Kokkos::view_alloc(
"CombLapl::val", Kokkos::WithoutInitializing), numEnt);
419 Kokkos::deep_copy(newVal, -1);
422 offset_view_t diagOffsets(Kokkos::view_alloc(
"Diag Offsets", Kokkos::WithoutInitializing), numRows);
423 graph_->getLocalDiagOffsets(diagOffsets);
426 auto rowOffsets = graph_->getLocalGraphDevice().row_map;
429 Kokkos::parallel_for(
"Combinatorial Laplacian", range_policy(0, numRows),
430 KOKKOS_LAMBDA(
const lno_t i){
431 newVal(rowOffsets(i) + diagOffsets(i)) = rowOffsets(i+1) - rowOffsets(i) - 1;
437 Teuchos::RCP<matrix_t> laplacian (
new matrix_t(graph_, newVal));
438 laplacian->fillComplete (graph_->getDomainMap(), graph_->getRangeMap());
456 using range_policy = Kokkos::RangePolicy<
457 typename node_t::device_type::execution_space, Kokkos::IndexType<lno_t>>;
458 using values_view_t = Kokkos::View<scalar_t*, typename node_t::device_type>;
459 using offset_view_t = Kokkos::View<size_t*, typename node_t::device_type>;
460 using vector_t = Tpetra::Vector<scalar_t, lno_t, gno_t, node_t>;
461 using dual_view_t =
typename vector_t::dual_view_type;
462 using KAT = Kokkos::ArithTraits<scalar_t>;
464 const size_t numEnt = graph_->getLocalNumEntries();
465 const size_t numRows = graph_->getLocalNumRows();
468 values_view_t newVal (Kokkos::view_alloc(
"NormLapl::val", Kokkos::WithoutInitializing), numEnt);
470 Kokkos::deep_copy(newVal, 1);
473 Kokkos::deep_copy(newVal, -1);
477 dual_view_t dv (
"MV::DualView", numRows, 1);
478 auto deginvsqrt = dv.d_view;
481 offset_view_t diagOffsets(Kokkos::view_alloc(
"Diag Offsets", Kokkos::WithoutInitializing), numRows);
482 graph_->getLocalDiagOffsets(diagOffsets);
485 auto rowOffsets = graph_->getLocalGraphDevice().row_map;
489 Kokkos::parallel_for(
"Combinatorial Laplacian", range_policy(0, numRows),
490 KOKKOS_LAMBDA(
const lno_t i){
491 newVal(rowOffsets(i) + diagOffsets(i)) = rowOffsets(i+1) - rowOffsets(i) - 1;
492 deginvsqrt(i,0) = 1.0/KAT::sqrt(rowOffsets(i+1) - rowOffsets(i) - 1);
499 Kokkos::parallel_for(
"Zero Diagonal", range_policy(0, numRows),
500 KOKKOS_LAMBDA(
const lno_t i){
501 newVal(rowOffsets(i) + diagOffsets(i)) = 1.0;
502 deginvsqrt(i,0) = 1.0/KAT::sqrt(rowOffsets(i+1) - rowOffsets(i) - 1);
509 Teuchos::RCP<matrix_t> laplacian (
new matrix_t(graph_, newVal));
510 laplacian->fillComplete (graph_->getDomainMap(), graph_->getRangeMap());
513 vector_t degInvSqrt(graph_->getRowMap(), dv);
516 laplacian->leftScale(degInvSqrt);
517 laplacian->rightScale(degInvSqrt);
529 const Teuchos::RCP<const Environment> env_;
530 Teuchos::RCP<Teuchos::ParameterList> params_;
531 Teuchos::RCP<Teuchos::ParameterList> sphynxParams_;
532 const Teuchos::RCP<const Teuchos::Comm<int> > comm_;
533 const Teuchos::RCP<const Adapter> adapter_;
537 Teuchos::RCP<const graph_t> graph_;
538 Teuchos::RCP<matrix_t> laplacian_;
539 Teuchos::RCP<const matrix_t> degMatrix_;
540 Teuchos::RCP<mvector_t> eigenVectors_;
543 std::string precType_;
544 std::string solverType_;
589 if(numGlobalParts_ == 1) {
591 size_t numRows =adapter_->getUserGraph()->getLocalNumRows();
592 Teuchos::ArrayRCP<part_t> parts(numRows,0);
593 solution->setParts(parts);
600 int numEigenVectors = (int) log2(numGlobalParts_)+1;
603 if(eigenVectors_ == Teuchos::null){
608 if(computedNumEv <= 1 && solverType_ ==
"LOBPCG") {
610 std::runtime_error(
"\nAnasazi Error: LOBPCGSolMgr::solve() returned unconverged.\n"
611 "Sphynx Error: LOBPCG could not compute any eigenvectors.\n"
612 " Increase either max iters or tolerance.\n");
617 computedNumEv = (int) eigenVectors_->getNumVectors();
618 if(computedNumEv <= numEigenVectors) {
620 std::runtime_error(
"\nSphynx Error: Number of eigenvectors given by user\n"
621 " is less than number of Eigenvectors needed for partition." );
631 std::vector<const weight_t *>
weights;
632 std::vector<int> wstrides;
648 Teuchos::TimeMonitor t(*Teuchos::TimeMonitor::getNewTimer(
"Sphynx::Anasazi"));
652 std::string which = (solverType_ ==
"randomized" ?
"LM" :
"SR");
653 std::string ortho =
"SVQB";
654 bool relConvTol =
false;
655 int maxIterations = sphynxParams_->get(
"sphynx_max_iterations",1000);
656 int blockSize = sphynxParams_->get(
"sphynx_block_size",numEigenVectors);
657 bool isHermitian =
true;
658 bool relLockTol =
false;
660 bool useFullOrtho = sphynxParams_->get(
"sphynx_use_full_ortho",
true);
664 double solvetime = 0;
667 int anasaziVerbosity = Anasazi::Errors + Anasazi::Warnings;
669 anasaziVerbosity += Anasazi::FinalSummary + Anasazi::TimingDetails;
671 anasaziVerbosity += Anasazi::IterationDetails;
673 anasaziVerbosity += Anasazi::StatusTestDetails + Anasazi::OrthoDetails
677 Teuchos::ParameterList anasaziParams;
678 anasaziParams.set(
"Verbosity", anasaziVerbosity);
679 anasaziParams.set(
"Which", which);
680 anasaziParams.set(
"Convergence Tolerance", tolerance_);
681 anasaziParams.set(
"Maximum Iterations", maxIterations);
682 anasaziParams.set(
"Block Size", blockSize);
683 anasaziParams.set(
"Relative Convergence Tolerance", relConvTol);
684 anasaziParams.set(
"Orthogonalization", ortho);
685 anasaziParams.set(
"Use Locking", lock);
686 anasaziParams.set(
"Relative Locking Tolerance", relLockTol);
687 anasaziParams.set(
"Full Ortho", useFullOrtho);
690 Teuchos::RCP<mvector_t> ivec(
new mvector_t(laplacian_->getRangeMap(), numEigenVectors));
694 Anasazi::MultiVecTraits<scalar_t, mvector_t>::MvRandom(*ivec);
695 ivec->getVectorNonConst(0)->putScalar(1.);
702 ivec->getVectorNonConst(0)->putScalar(1.);
703 for (
int j = 1; j < numEigenVectors; j++)
704 ivec->getVectorNonConst(j)->putScalar(0.);
706 auto map = laplacian_->getRangeMap();
707 gno_t blkSize =
map->getGlobalNumElements() / numEigenVectors;
708 TEUCHOS_TEST_FOR_EXCEPTION(blkSize <= 0, std::runtime_error,
"Blocksize too small for \"constants\" initial guess. Try \"random\".");
710 for (
size_t lid = 0; lid < ivec->getLocalLength(); lid++) {
711 gno_t gid =
map->getGlobalElement(lid);
712 for (
int j = 1; j < numEigenVectors; j++){
713 if (((j-1)*blkSize <= gid) && (j*blkSize > gid))
714 ivec->replaceLocalValue(lid,j,1.);
720 using problem_t = Anasazi::BasicEigenproblem<scalar_t, mvector_t, op_t>;
721 Teuchos::RCP<problem_t> problem (
new problem_t(laplacian_, ivec));
722 problem->setHermitian(isHermitian);
723 problem->setNEV(numEigenVectors);
725 if(solverType_ ==
"LOBPCG"){
731 problem->setM(degMatrix_);
735 bool boolret = problem->setProblem();
736 if (boolret !=
true) {
737 throw std::runtime_error(
"\nAnasazi::BasicEigenproblem::setProblem() returned with error.\n");
740 Teuchos::RCP<Anasazi::SolverManager<scalar_t, mvector_t, op_t>> solver;
742 if(solverType_ ==
"LOBPCG"){
743 solver = Teuchos::rcp(
new Anasazi::LOBPCGSolMgr<scalar_t, mvector_t, op_t>(problem, anasaziParams));
748 throw std::runtime_error(
"\nInvalid solver type.\n");
751 if (verbosity_ > 0 && comm_->getRank() == 0)
752 anasaziParams.print(std::cout);
755 if (verbosity_ > 0 && comm_->getRank() == 0)
756 std::cout <<
"Beginning the Anasazi solve..." << std::endl;
757 Anasazi::ReturnType returnCode = solver->solve();
760 if (returnCode != Anasazi::Converged) {
763 iter = solver->getNumIters();
764 solvetime = (solver->getTimers()[0])->totalElapsedTime();
768 using solution_t = Anasazi::Eigensolution<scalar_t, mvector_t>;
769 solution_t sol = problem->getSolution();
770 eigenVectors_ = sol.Evecs;
771 int numev = sol.numVecs;
774 if (verbosity_ > 0 && comm_->getRank() == 0) {
775 std::cout << std::endl;
776 std::cout <<
"ANASAZI SUMMARY" << std::endl;
777 std::cout <<
"Failed to converge: " << numfailed << std::endl;
778 std::cout <<
"No of iterations : " << iter << std::endl;
779 std::cout <<
"Solve time: " << solvetime << std::endl;
780 std::cout <<
"No of comp. vecs. : " << numev << std::endl;
782 std::cout <<
"Returning from Anasazi Wrapper." << std::endl;
813#ifdef HAVE_ZOLTAN2SPHYNX_MUELU
814 Teuchos::ParameterList paramList;
816 paramList.set(
"verbosity",
"none");
817 else if(verbosity_ == 1)
818 paramList.set(
"verbosity",
"low");
819 else if(verbosity_ == 2)
820 paramList.set(
"verbosity",
"medium");
821 else if(verbosity_ == 3)
822 paramList.set(
"verbosity",
"high");
823 else if(verbosity_ >= 4)
824 paramList.set(
"verbosity",
"extreme");
826 paramList.set(
"smoother: type",
"CHEBYSHEV");
827 Teuchos::ParameterList smootherParamList;
828 smootherParamList.set(
"chebyshev: degree", 3);
829 smootherParamList.set(
"chebyshev: ratio eigenvalue", 7.0);
830 smootherParamList.set(
"chebyshev: eigenvalue max iterations", irregular_ ? 100 : 10);
831 paramList.set(
"smoother: params", smootherParamList);
832 paramList.set(
"use kokkos refactor",
true);
833 paramList.set(
"transpose: use implicit",
true);
837 paramList.set(
"multigrid algorithm",
"unsmoothed");
839 paramList.set(
"coarse: type",
"CHEBYSHEV");
840 Teuchos::ParameterList coarseParamList;
841 coarseParamList.set(
"chebyshev: degree", 3);
842 coarseParamList.set(
"chebyshev: ratio eigenvalue", 7.0);
843 paramList.set(
"coarse: params", coarseParamList);
845 paramList.set(
"max levels", 5);
846 paramList.set(
"aggregation: drop tol", 0.40);
849 using prec_t = MueLu::TpetraOperator<scalar_t, lno_t, gno_t, node_t>;
850 Teuchos::RCP<prec_t> prec = MueLu::CreateTpetraPreconditioner<
853 problem->setPrec(prec);
856 throw std::runtime_error(
"\nSphynx Error: MueLu requested but not compiled into Trilinos.\n");
865 int verbosity2 = Belos::Errors;
867 verbosity2 += Belos::Warnings;
868 else if(verbosity_ == 2)
869 verbosity2 += Belos::Warnings + Belos::FinalSummary;
870 else if(verbosity_ == 3)
871 verbosity2 += Belos::Warnings + Belos::FinalSummary + Belos::TimingDetails;
872 else if(verbosity_ >= 4)
873 verbosity2 += Belos::Warnings + Belos::FinalSummary + Belos::TimingDetails
874 + Belos::StatusTestDetails;
876 Teuchos::ParameterList paramList;
877 paramList.set(
"Polynomial Type",
"Roots");
878 paramList.set(
"Orthogonalization",
"ICGS");
879 paramList.set(
"Maximum Degree", laplacian_->getGlobalNumRows() > 100 ? 25 : 5);
880 paramList.set(
"Polynomial Tolerance", 1.0e-6 );
881 paramList.set(
"Verbosity", verbosity2 );
882 paramList.set(
"Random RHS",
false );
883 paramList.set(
"Outer Solver",
"");
884 paramList.set(
"Timer Label",
"Belos Polynomial Solve" );
887 using lproblem_t = Belos::LinearProblem<scalar_t, mvector_t, op_t>;
888 Teuchos::RCP<lproblem_t> innerPolyProblem(
new lproblem_t());
889 innerPolyProblem->setOperator(laplacian_);
891 using btop_t = Belos::TpetraOperator<scalar_t, lno_t, gno_t, node_t>;
892 Teuchos::RCP<btop_t> polySolver(
new btop_t(innerPolyProblem,
893 Teuchos::rcpFromRef(paramList),
895 problem->setPrec(polySolver);
945 std::vector<int> strides)
948 int numWeights = adapter_->getNumWeightsPerVertex();
949 int numConstraints = numWeights > 0 ? numWeights : 1;
951 size_t myNumVertices = adapter_->getLocalNumVertices();
953 for(
int j = 0; j < numConstraints; j++)
958 const gno_t *columnId;
961 if(numWeights == 0) {
964 adapter_->getEdgesView(offset, columnId);
965 for (
size_t i = 0; i < myNumVertices; i++)
966 weights[0][i] = offset[i+1] - offset[i] - 1;
968 vecweights.push_back(
weights[0]);
969 strides.push_back(1);
974 for(
int j = 0; j < numConstraints; j++) {
976 if(adapter_->useDegreeAsVertexWeight(j)) {
978 adapter_->getEdgesView(offset, columnId);
979 for (
size_t i = 0; i < myNumVertices; i++)
980 weights[j][i] = offset[i+1] - offset[i];
985 adapter_->getVertexWeightsView(wgt, stride, j);
987 for (
size_t i = 0; i < myNumVertices; i++)
991 vecweights.push_back(
weights[j]);
992 strides.push_back(1);
1004 std::vector<const weight_t *>
weights,
1005 std::vector<int> strides,
1009 Teuchos::TimeMonitor t(*Teuchos::TimeMonitor::getNewTimer(
"Sphynx::MJ"));
1012 using base_adapter_t =
typename mvector_adapter_t::base_adapter_t;
1016 size_t myNumVertices =
coordinates->getLocalLength();
1019 Teuchos::RCP<mvector_adapter_t> adapcoordinates(
new mvector_adapter_t(
coordinates,
1022 Teuchos::RCP<const base_adapter_t> baseAdapter =
1023 Teuchos::rcp(
dynamic_cast<const base_adapter_t *
>(adapcoordinates.get()),
false);
1029 Teuchos::RCP<const Comm<int>> comm2 = comm_;
1030 Teuchos::RCP<mj_t> mj(
new mj_t(env_, comm2, baseAdapter));
1033 Teuchos::RCP<solution_t> vectorsolution(
new solution_t(env_, comm2, 1, mj));
1034 mj->partition(vectorsolution);
1037 Teuchos::ArrayRCP<part_t> parts(myNumVertices);
1038 for(
size_t i = 0; i < myNumVertices; i++) {
1039 parts[i] = vectorsolution->getPartListView()[i];
1041 solution->setParts(parts);