5 #ifndef GKO_PUBLIC_CORE_SOLVER_SOLVER_BASE_HPP_
6 #define GKO_PUBLIC_CORE_SOLVER_SOLVER_BASE_HPP_
11 #include <type_traits>
15 #include <ginkgo/core/base/exception.hpp>
16 #include <ginkgo/core/base/lin_op.hpp>
17 #include <ginkgo/core/base/math.hpp>
18 #include <ginkgo/core/base/name_demangling.hpp>
19 #include <ginkgo/core/log/logger.hpp>
20 #include <ginkgo/core/matrix/dense.hpp>
21 #include <ginkgo/core/matrix/identity.hpp>
22 #include <ginkgo/core/preconditioner/nullspace_projection.hpp>
23 #include <ginkgo/core/solver/nullspace.hpp>
24 #include <ginkgo/core/solver/workspace.hpp>
25 #include <ginkgo/core/stop/combined.hpp>
26 #include <ginkgo/core/stop/criterion.hpp>
29 GKO_BEGIN_DISABLE_DEPRECATION_WARNINGS
76 friend class multigrid::detail::MultigridState;
91 virtual void apply_with_initial_guess(
const LinOp* b,
LinOp* x,
97 apply_with_initial_guess(b.
get(), x.
get(), guess);
112 virtual void apply_with_initial_guess(
const LinOp* alpha,
const LinOp* b,
123 apply_with_initial_guess(alpha.
get(), b.
get(), beta.
get(), x.
get(),
169 template <
typename DerivedType>
172 friend class multigrid::detail::MultigridState;
183 void apply_with_initial_guess(
const LinOp* b,
LinOp* x,
186 self()->
template log<log::Logger::linop_apply_started>(
self(), b, x);
187 auto exec =
self()->get_executor();
188 GKO_ASSERT_CONFORMANT(
self(), b);
189 GKO_ASSERT_EQUAL_ROWS(
self(), x);
190 GKO_ASSERT_EQUAL_COLS(b, x);
194 self()->
template log<log::Logger::linop_apply_completed>(
self(), b, x);
201 void apply_with_initial_guess(
const LinOp* alpha,
const LinOp* b,
205 self()->
template log<log::Logger::linop_advanced_apply_started>(
206 self(), alpha, b, beta, x);
207 auto exec =
self()->get_executor();
208 GKO_ASSERT_CONFORMANT(
self(), b);
209 GKO_ASSERT_EQUAL_ROWS(
self(), x);
210 GKO_ASSERT_EQUAL_COLS(b, x);
211 GKO_ASSERT_EQUAL_DIMENSIONS(alpha,
dim<2>(1, 1));
212 GKO_ASSERT_EQUAL_DIMENSIONS(beta,
dim<2>(1, 1));
213 this->apply_with_initial_guess_impl(
218 self()->
template log<log::Logger::linop_advanced_apply_completed>(
219 self(), alpha, b, beta, x);
227 virtual void apply_with_initial_guess_impl(
234 virtual void apply_with_initial_guess_impl(
238 GKO_ENABLE_SELF(DerivedType);
246 template <
typename Solver>
249 static int num_vectors(
const Solver&) {
return 0; }
251 static int num_arrays(
const Solver&) {
return 0; }
253 static std::vector<std::string> op_names(
const Solver&) {
return {}; }
255 static std::vector<std::string> array_names(
const Solver&) {
return {}; }
257 static std::vector<int> scalars(
const Solver&) {
return {}; }
259 static std::vector<int> vectors(
const Solver&) {
return {}; }
278 template <
typename DerivedType>
289 auto exec =
self()->get_executor();
291 GKO_ASSERT_EQUAL_DIMENSIONS(
self(), new_precond);
292 GKO_ASSERT_IS_SQUARE_MATRIX(new_precond);
293 if (new_precond->get_executor() != exec) {
306 if (&other !=
this) {
319 if (&other !=
this) {
321 other.set_preconditioner(
nullptr);
347 *
this = std::move(other);
351 DerivedType*
self() {
return static_cast<DerivedType*>(
this); }
353 const DerivedType*
self()
const
355 return static_cast<const DerivedType*>(
this);
371 class SolverBaseLinOp {
373 SolverBaseLinOp(std::shared_ptr<const Executor> exec)
374 : workspace_{std::move(exec)}
377 virtual ~SolverBaseLinOp() =
default;
384 std::shared_ptr<const LinOp> get_system_matrix()
const
386 return system_matrix_;
389 const LinOp* get_workspace_op(
int vector_id)
const
391 return workspace_.get_op(vector_id);
394 virtual int get_num_workspace_ops()
const {
return 0; }
396 virtual std::vector<std::string> get_workspace_op_names()
const
405 virtual std::vector<int> get_workspace_scalars()
const {
return {}; }
411 virtual std::vector<int> get_workspace_vectors()
const {
return {}; }
414 void set_system_matrix_base(std::shared_ptr<const LinOp> system_matrix)
416 system_matrix_ = std::move(system_matrix);
419 void set_workspace_size(
int num_operators,
int num_arrays)
const
421 workspace_.set_size(num_operators, num_arrays);
424 template <
typename LinOpType>
425 LinOpType* create_workspace_op(
int vector_id,
gko::dim<2> size)
const
427 return workspace_.template create_or_get_op<LinOpType>(
430 return LinOpType::create(this->workspace_.get_executor(), size);
432 typeid(LinOpType), size, size[1]);
435 template <
typename LinOpType>
436 LinOpType* create_workspace_op_with_config_of(
int vector_id,
437 const LinOpType* vec)
const
439 return workspace_.template create_or_get_op<LinOpType>(
440 vector_id, [&] {
return LinOpType::create_with_config_of(vec); },
441 typeid(*vec), vec->get_size(), vec->get_stride());
444 template <
typename LinOpType>
445 LinOpType* create_workspace_op_with_type_of(
int vector_id,
446 const LinOpType* vec,
449 return workspace_.template create_or_get_op<LinOpType>(
452 return LinOpType::create_with_type_of(
453 vec, workspace_.get_executor(), size, size[1]);
455 typeid(*vec), size, size[1]);
458 template <
typename LinOpType>
459 LinOpType* create_workspace_op_with_type_of(
int vector_id,
460 const LinOpType* vec,
462 dim<2> local_size)
const
464 return workspace_.template create_or_get_op<LinOpType>(
467 return LinOpType::create_with_type_of(
468 vec, workspace_.get_executor(), global_size, local_size,
471 typeid(*vec), global_size, local_size[1]);
474 template <
typename ValueType>
475 matrix::Dense<ValueType>* create_workspace_scalar(
int vector_id,
478 return workspace_.template create_or_get_op<matrix::Dense<ValueType>>(
482 workspace_.get_executor(), dim<2>{1, size});
484 typeid(matrix::Dense<ValueType>),
gko::dim<2>{1, size}, size);
487 template <
typename ValueType>
488 const matrix::Dense<ValueType>* create_workspace_fixed_scalar(
489 int vector_id,
size_type size, ValueType val)
const
491 return workspace_.template create_or_get_op<matrix::Dense<ValueType>>(
495 workspace_.get_executor(), dim<2>{1, size});
499 typeid(matrix::Dense<ValueType>),
gko::dim<2>{1, size}, size);
502 template <
typename ValueType>
503 array<ValueType>& create_workspace_array(
int array_id,
size_type size)
const
505 return workspace_.template create_or_get_array<ValueType>(array_id,
509 template <
typename ValueType>
510 array<ValueType>& create_workspace_array(
int array_id)
const
512 return workspace_.template init_or_get_array<ValueType>(array_id);
516 mutable detail::workspace workspace_;
518 std::shared_ptr<const LinOp> system_matrix_;
525 template <
typename MatrixType>
528 GKO_DEPRECATED(
"This class will be replaced by the template-less detail::SolverBaseLinOp in a future release")
SolverBase
530 : public detail::SolverBaseLinOp {
532 using detail::SolverBaseLinOp::SolverBaseLinOp;
543 return std::dynamic_pointer_cast<const MatrixType>(
544 SolverBaseLinOp::get_system_matrix());
548 void set_system_matrix_base(std::shared_ptr<const MatrixType> system_matrix)
550 SolverBaseLinOp::set_system_matrix_base(std::move(system_matrix));
564 template <
typename DerivedType,
typename MatrixType = LinOp>
573 if (&other !=
this) {
585 if (&other !=
this) {
586 set_system_matrix(other.get_system_matrix());
587 other.set_system_matrix(
nullptr);
594 EnableSolverBase(std::shared_ptr<const MatrixType> system_matrix)
595 : SolverBase<MatrixType>{
self()->get_executor()}
597 set_system_matrix(std::move(system_matrix));
604 :
SolverBase<MatrixType>{other.self()->get_executor()}
614 :
SolverBase<MatrixType>{other.self()->get_executor()}
616 *
this = std::move(other);
619 int get_num_workspace_ops()
const override
621 using traits = workspace_traits<DerivedType>;
622 return traits::num_vectors(*
self());
625 std::vector<std::string> get_workspace_op_names()
const override
627 using traits = workspace_traits<DerivedType>;
628 return traits::op_names(*
self());
638 return traits::scalars(*
self());
648 return traits::vectors(*
self());
652 void set_system_matrix(std::shared_ptr<const MatrixType> new_system_matrix)
654 auto exec =
self()->get_executor();
655 if (new_system_matrix) {
656 GKO_ASSERT_EQUAL_DIMENSIONS(
self(), new_system_matrix);
657 GKO_ASSERT_IS_SQUARE_MATRIX(new_system_matrix);
658 if (new_system_matrix->get_executor() != exec) {
659 new_system_matrix =
gko::clone(exec, new_system_matrix);
662 this->set_system_matrix_base(new_system_matrix);
665 void setup_workspace()
const
667 using traits = workspace_traits<DerivedType>;
668 this->set_workspace_size(traits::num_vectors(*
self()),
669 traits::num_arrays(*
self()));
673 DerivedType*
self() {
return static_cast<DerivedType*>(
this); }
675 const DerivedType*
self()
const
677 return static_cast<const DerivedType*>(
this);
700 return stop_factory_;
709 std::shared_ptr<const stop::CriterionFactory> new_stop_factory)
711 stop_factory_ = new_stop_factory;
715 std::shared_ptr<const stop::CriterionFactory> stop_factory_;
728 template <
typename DerivedType>
737 if (&other !=
this) {
750 if (&other !=
this) {
752 other.set_stop_criterion_factory(
nullptr);
760 std::shared_ptr<const stop::CriterionFactory> stop_factory)
776 *
this = std::move(other);
780 std::shared_ptr<const stop::CriterionFactory> new_stop_factory)
override
782 auto exec =
self()->get_executor();
783 if (new_stop_factory && new_stop_factory->get_executor() != exec) {
785 new_stop_factory =
gko::clone(exec, new_stop_factory);
791 DerivedType*
self() {
return static_cast<DerivedType*>(
this); }
793 const DerivedType*
self()
const
795 return static_cast<const DerivedType*>(
this);
807 template <
typename Solver>
841 template <
typename ValueType,
typename DerivedType>
850 std::shared_ptr<const LinOp> system_matrix,
851 std::shared_ptr<const stop::CriterionFactory> stop_factory,
852 std::shared_ptr<const LinOp> preconditioner)
858 template <
typename FactoryParameters>
860 std::shared_ptr<const LinOp> system_matrix,
861 const FactoryParameters& params)
864 generate_preconditioner(system_matrix, params)}
867 if ((params.nullspace || params.left_nullspace) &&
868 !traits::is_supported) {
870 __FILE__, __LINE__,
"nullspace projection",
871 name_demangling::get_type_name(
typeid(DerivedType)));
874 auto exec = get_solver_executor();
875 nullspace_ = detail::prepare_nullspace<ValueType>(
876 params.nullspace,
"nullspace", system_matrix.get(),
877 system_matrix->get_size()[1], exec);
878 left_nullspace_ = detail::prepare_nullspace<ValueType>(
879 params.left_nullspace,
"left_nullspace", system_matrix.get(),
880 system_matrix->get_size()[0], exec);
882 if (traits::requires_hermitian) {
883 if (!left_nullspace_) {
884 left_nullspace_ = nullspace_;
887 nullspace_ = left_nullspace_;
909 if (&other !=
this) {
910 nullspace_ = on_executor(other.nullspace_);
911 left_nullspace_ = on_executor(other.left_nullspace_);
926 if (&other !=
this) {
927 nullspace_ = on_executor(std::exchange(other.nullspace_,
nullptr));
929 on_executor(std::exchange(other.left_nullspace_,
nullptr));
951 return left_nullspace_;
962 if (new_precond && nullspace_ &&
963 !removes_nullspaces(new_precond.get())) {
964 new_precond = project_preconditioner(std::move(new_precond));
967 std::move(new_precond));
981 if (
auto projection = std::dynamic_pointer_cast<
982 const ::gko::preconditioner::NullspaceProjection<
983 ValueType>>(precond)) {
984 return projection->get_preconditioner();
1000 nullspace_->project(v);
1015 template <
typename VectorType>
1016 const VectorType* get_consistent_rhs(
const VectorType* b,
1017 int workspace_id)
const
1019 if (!left_nullspace_) {
1022 auto rhs = this->create_workspace_op_with_config_of(workspace_id, b);
1024 left_nullspace_->project(
rhs);
1032 std::shared_ptr<const LinOp> get_transposed_nullspace(
bool conjugate)
const
1034 assert_nullspace_transposable(conjugate);
1035 return left_nullspace_;
1042 std::shared_ptr<const LinOp> get_transposed_left_nullspace(
1043 bool conjugate)
const
1045 assert_nullspace_transposable(conjugate);
1051 bool removes_nullspaces(
const LinOp* precond)
const
1053 auto projection =
dynamic_cast<
1054 const ::gko::preconditioner::NullspaceProjection<ValueType>*
>(
1056 return projection && projection->get_nullspace() &&
1058 !left_nullspace_ || projection->get_left_nullspace());
1064 void assert_nullspace_transposable(
bool conjugate)
const
1066 if (!conjugate && is_complex<ValueType>() &&
1067 (nullspace_ || left_nullspace_)) {
1069 __FILE__, __LINE__,
"transpose with nullspace",
1070 name_demangling::get_type_name(
typeid(DerivedType)));
1074 std::shared_ptr<const Executor> get_solver_executor()
const
1076 return static_cast<const DerivedType*>(
this)->get_executor();
1079 std::shared_ptr<const Nullspace<ValueType>> on_executor(
1080 std::shared_ptr<
const Nullspace<ValueType>> ns)
const
1082 auto exec = get_solver_executor();
1083 if (ns && ns->get_executor() != exec) {
1090 std::shared_ptr<const LinOp> project_preconditioner(
1091 std::shared_ptr<const LinOp> precond)
const
1093 auto projection_params =
1095 .with_generated_preconditioner(std::move(precond))
1096 .with_nullspace(nullspace_);
1098 projection_params.with_left_nullspace(left_nullspace_);
1100 return projection_params.on(get_solver_executor())
1104 template <
typename FactoryParameters>
1105 static std::shared_ptr<const LinOp> generate_preconditioner(
1106 std::shared_ptr<const LinOp> system_matrix,
1107 const FactoryParameters& params)
1109 if (params.generated_preconditioner) {
1110 return params.generated_preconditioner;
1111 }
else if (params.preconditioner) {
1112 return params.preconditioner->generate(system_matrix);
1115 system_matrix->get_executor(), system_matrix->get_size());
1119 std::shared_ptr<const Nullspace<ValueType>> nullspace_{};
1120 std::shared_ptr<const Nullspace<ValueType>> left_nullspace_{};
1124 template <
typename Parameters,
typename Factory>
1130 std::vector<std::shared_ptr<const stop::CriterionFactory>>
1135 template <
typename Parameters,
typename Factory>
1142 std::shared_ptr<const LinOpFactory> GKO_DEFERRED_FACTORY_PARAMETER(
1201 GKO_END_DISABLE_DEPRECATION_WARNINGS
1204 #endif // GKO_PUBLIC_CORE_SOLVER_SOLVER_BASE_HPP_