Ginkgo Generated from develop branch based on develop. Ginkgo version 1.8.0
A numerical linear algebra library targeting many-core architectures
Loading...
Searching...
No Matches
ilu.hpp
1// SPDX-FileCopyrightText: 2017 - 2024 The Ginkgo authors
2//
3// SPDX-License-Identifier: BSD-3-Clause
4
5#ifndef GKO_PUBLIC_CORE_PRECONDITIONER_ILU_HPP_
6#define GKO_PUBLIC_CORE_PRECONDITIONER_ILU_HPP_
7
8
9#include <memory>
10#include <type_traits>
11
12
13#include <ginkgo/core/base/abstract_factory.hpp>
14#include <ginkgo/core/base/composition.hpp>
15#include <ginkgo/core/base/exception.hpp>
16#include <ginkgo/core/base/exception_helpers.hpp>
17#include <ginkgo/core/base/lin_op.hpp>
18#include <ginkgo/core/base/precision_dispatch.hpp>
19#include <ginkgo/core/base/std_extensions.hpp>
20#include <ginkgo/core/factorization/par_ilu.hpp>
21#include <ginkgo/core/matrix/dense.hpp>
22#include <ginkgo/core/solver/solver_traits.hpp>
23#include <ginkgo/core/solver/triangular.hpp>
24#include <ginkgo/core/stop/combined.hpp>
25#include <ginkgo/core/stop/iteration.hpp>
26#include <ginkgo/core/stop/residual_norm.hpp>
27
28
29namespace gko {
30namespace preconditioner {
31
32
82template <typename LSolverType = solver::LowerTrs<>,
83 typename USolverType = solver::UpperTrs<>, bool ReverseApply = false,
84 typename IndexType = int32>
85class Ilu : public EnableLinOp<
86 Ilu<LSolverType, USolverType, ReverseApply, IndexType>>,
87 public Transposable {
88 friend class EnableLinOp<Ilu>;
89 friend class EnablePolymorphicObject<Ilu, LinOp>;
90
91public:
92 static_assert(
93 std::is_same<typename LSolverType::value_type,
94 typename USolverType::value_type>::value,
95 "Both the L- and the U-solver must use the same `value_type`!");
96 using value_type = typename LSolverType::value_type;
97 using l_solver_type = LSolverType;
98 using u_solver_type = USolverType;
99 static constexpr bool performs_reverse_apply = ReverseApply;
100 using index_type = IndexType;
101 using transposed_type =
102 Ilu<typename USolverType::transposed_type,
103 typename LSolverType::transposed_type, ReverseApply, IndexType>;
104
105 class Factory;
106
108 : public enable_parameters_type<parameters_type, Factory> {
112 std::shared_ptr<const typename l_solver_type::Factory>
114
118 std::shared_ptr<const typename u_solver_type::Factory>
120
124 std::shared_ptr<const LinOpFactory> factorization_factory{};
125
126 GKO_DEPRECATED("use with_l_solver instead")
127 parameters_type& with_l_solver_factory(
129 solver)
130 {
131 return with_l_solver(std::move(solver));
132 }
133
134 parameters_type& with_l_solver(
136 solver)
137 {
138 this->l_solver_generator = std::move(solver);
139 this->deferred_factories["l_solver"] = [](const auto& exec,
140 auto& params) {
141 if (!params.l_solver_generator.is_empty()) {
142 params.l_solver_factory =
143 params.l_solver_generator.on(exec);
144 }
145 };
146 return *this;
147 }
148
149 GKO_DEPRECATED("use with_u_solver instead")
150 parameters_type& with_u_solver_factory(
151 deferred_factory_parameter<const typename u_solver_type::Factory>
152 solver)
153 {
154 return with_u_solver(std::move(solver));
155 }
156
157 parameters_type& with_u_solver(
158 deferred_factory_parameter<const typename u_solver_type::Factory>
159 solver)
160 {
161 this->u_solver_generator = std::move(solver);
162 this->deferred_factories["u_solver"] = [](const auto& exec,
163 auto& params) {
164 if (!params.u_solver_generator.is_empty()) {
165 params.u_solver_factory =
166 params.u_solver_generator.on(exec);
167 }
168 };
169 return *this;
170 }
171
172 GKO_DEPRECATED("use with_factorization instead")
173 parameters_type& with_factorization_factory(
174 deferred_factory_parameter<const LinOpFactory> factorization)
175 {
176 return with_factorization(std::move(factorization));
177 }
178
179 parameters_type& with_factorization(
181 {
182 this->factorization_generator = std::move(factorization);
183 this->deferred_factories["factorization"] = [](const auto& exec,
184 auto& params) {
185 if (!params.factorization_generator.is_empty()) {
186 params.factorization_factory =
187 params.factorization_generator.on(exec);
188 }
189 };
190 return *this;
191 }
192
193 private:
194 deferred_factory_parameter<const typename l_solver_type::Factory>
195 l_solver_generator;
196
197 deferred_factory_parameter<const typename u_solver_type::Factory>
198 u_solver_generator;
199
201 };
202
205
211 std::shared_ptr<const l_solver_type> get_l_solver() const
212 {
213 return l_solver_;
214 }
215
221 std::shared_ptr<const u_solver_type> get_u_solver() const
222 {
223 return u_solver_;
224 }
225
226 std::unique_ptr<LinOp> transpose() const override
227 {
228 std::unique_ptr<transposed_type> transposed{
229 new transposed_type{this->get_executor()}};
230 transposed->set_size(gko::transpose(this->get_size()));
231 transposed->l_solver_ =
233 this->get_u_solver()->transpose()));
234 transposed->u_solver_ =
236 this->get_l_solver()->transpose()));
237
238 return std::move(transposed);
239 }
240
241 std::unique_ptr<LinOp> conj_transpose() const override
242 {
243 std::unique_ptr<transposed_type> transposed{
244 new transposed_type{this->get_executor()}};
245 transposed->set_size(gko::transpose(this->get_size()));
246 transposed->l_solver_ =
248 this->get_u_solver()->conj_transpose()));
249 transposed->u_solver_ =
251 this->get_l_solver()->conj_transpose()));
252
253 return std::move(transposed);
254 }
255
262 {
263 if (&other != this) {
265 auto exec = this->get_executor();
266 l_solver_ = other.l_solver_;
267 u_solver_ = other.u_solver_;
268 parameters_ = other.parameters_;
269 if (other.get_executor() != exec) {
270 l_solver_ = gko::clone(exec, l_solver_);
271 u_solver_ = gko::clone(exec, u_solver_);
272 }
273 }
274 return *this;
275 }
276
284 {
285 if (&other != this) {
287 auto exec = this->get_executor();
288 l_solver_ = std::move(other.l_solver_);
289 u_solver_ = std::move(other.u_solver_);
290 parameters_ = std::exchange(other.parameters_, parameters_type{});
291 if (other.get_executor() != exec) {
292 l_solver_ = gko::clone(exec, l_solver_);
293 u_solver_ = gko::clone(exec, u_solver_);
294 }
295 }
296 return *this;
297 }
298
303 Ilu(const Ilu& other) : Ilu{other.get_executor()} { *this = other; }
304
310 Ilu(Ilu&& other) : Ilu{other.get_executor()} { *this = std::move(other); }
311
312protected:
313 void apply_impl(const LinOp* b, LinOp* x) const override
314 {
315 // take care of real-to-complex apply
317 [&](auto dense_b, auto dense_x) {
318 this->set_cache_to(dense_b);
319 if (!ReverseApply) {
320 l_solver_->apply(dense_b, cache_.intermediate);
321 if (u_solver_->apply_uses_initial_guess()) {
322 dense_x->copy_from(cache_.intermediate);
323 }
324 u_solver_->apply(cache_.intermediate, dense_x);
325 } else {
326 u_solver_->apply(dense_b, cache_.intermediate);
327 if (l_solver_->apply_uses_initial_guess()) {
328 dense_x->copy_from(cache_.intermediate);
329 }
330 l_solver_->apply(cache_.intermediate, dense_x);
331 }
332 },
333 b, x);
334 }
335
336 void apply_impl(const LinOp* alpha, const LinOp* b, const LinOp* beta,
337 LinOp* x) const override
338 {
340 [&](auto dense_alpha, auto dense_b, auto dense_beta, auto dense_x) {
341 this->set_cache_to(dense_b);
342 if (!ReverseApply) {
343 l_solver_->apply(dense_b, cache_.intermediate);
344 u_solver_->apply(dense_alpha, cache_.intermediate,
346 } else {
347 u_solver_->apply(dense_b, cache_.intermediate);
348 l_solver_->apply(dense_alpha, cache_.intermediate,
350 }
351 },
352 alpha, b, beta, x);
353 }
354
355 explicit Ilu(std::shared_ptr<const Executor> exec)
356 : EnableLinOp<Ilu>(std::move(exec))
357 {}
358
359 explicit Ilu(const Factory* factory, std::shared_ptr<const LinOp> lin_op)
360 : EnableLinOp<Ilu>(factory->get_executor(), lin_op->get_size()),
361 parameters_{factory->get_parameters()}
362 {
363 auto comp =
364 std::dynamic_pointer_cast<const Composition<value_type>>(lin_op);
365 std::shared_ptr<const LinOp> l_factor;
366 std::shared_ptr<const LinOp> u_factor;
367
368 // build factorization if we weren't passed a composition
369 if (!comp) {
370 auto exec = lin_op->get_executor();
371 if (!parameters_.factorization_factory) {
372 parameters_.factorization_factory =
373 factorization::ParIlu<value_type, index_type>::build().on(
374 exec);
375 }
376 auto fact = std::shared_ptr<const LinOp>(
377 parameters_.factorization_factory->generate(lin_op));
378 // ensure that the result is a composition
379 comp =
380 std::dynamic_pointer_cast<const Composition<value_type>>(fact);
381 if (!comp) {
382 GKO_NOT_SUPPORTED(comp);
383 }
384 }
385 if (comp->get_operators().size() == 2) {
386 l_factor = comp->get_operators()[0];
387 u_factor = comp->get_operators()[1];
388 } else {
389 GKO_NOT_SUPPORTED(comp);
390 }
391 GKO_ASSERT_EQUAL_DIMENSIONS(l_factor, u_factor);
392
393 auto exec = this->get_executor();
394
395 // If no factories are provided, generate default ones
396 if (!parameters_.l_solver_factory) {
398 } else {
399 l_solver_ = parameters_.l_solver_factory->generate(l_factor);
400 }
401 if (!parameters_.u_solver_factory) {
403 } else {
404 u_solver_ = parameters_.u_solver_factory->generate(u_factor);
405 }
406 }
407
415 void set_cache_to(const LinOp* b) const
416 {
417 if (cache_.intermediate == nullptr) {
418 cache_.intermediate =
420 }
421 // Use b as the initial guess for the first triangular solve
422 cache_.intermediate->copy_from(b);
423 }
424
425
433 template <typename SolverType>
434 static std::enable_if_t<solver::has_with_criteria<SolverType>::value,
435 std::unique_ptr<SolverType>>
436 generate_default_solver(const std::shared_ptr<const Executor>& exec,
437 const std::shared_ptr<const LinOp>& mtx)
438 {
440 const unsigned int default_max_iters{
441 static_cast<unsigned int>(mtx->get_size()[0])};
442
443 return SolverType::build()
444 .with_criteria(
445 gko::stop::Iteration::build().with_max_iters(default_max_iters),
447 .with_reduction_factor(default_reduce_residual))
448 .on(exec)
449 ->generate(mtx);
450 }
451
455 template <typename SolverType>
456 static std::enable_if_t<!solver::has_with_criteria<SolverType>::value,
457 std::unique_ptr<SolverType>>
458 generate_default_solver(const std::shared_ptr<const Executor>& exec,
459 const std::shared_ptr<const LinOp>& mtx)
460 {
461 return SolverType::build().on(exec)->generate(mtx);
462 }
463
464private:
465 std::shared_ptr<const l_solver_type> l_solver_{};
466 std::shared_ptr<const u_solver_type> u_solver_{};
477 mutable struct cache_struct {
478 cache_struct() = default;
479 ~cache_struct() = default;
480 cache_struct(const cache_struct&) {}
481 cache_struct(cache_struct&&) {}
482 cache_struct& operator=(const cache_struct&) { return *this; }
483 cache_struct& operator=(cache_struct&&) { return *this; }
484 std::unique_ptr<LinOp> intermediate{};
485 } cache_;
486};
487
488
489} // namespace preconditioner
490} // namespace gko
491
492
493#endif // GKO_PUBLIC_CORE_PRECONDITIONER_ILU_HPP_
The EnableLinOp mixin can be used to provide sensible default implementations of the majority of the ...
Definition lin_op.hpp:880
This mixin inherits from (a subclass of) PolymorphicObject and provides a base implementation of a ne...
Definition polymorphic_object.hpp:663
Definition lin_op.hpp:118
std::shared_ptr< const Executor > get_executor() const noexcept
Returns the Executor of the object.
Definition polymorphic_object.hpp:235
Linear operators which support transposition should implement the Transposable interface.
Definition lin_op.hpp:434
Represents a factory parameter of factory type that can either initialized by a pre-existing factory ...
Definition abstract_factory.hpp:309
The enable_parameters_type mixin is used to create a base implementation of the factory parameters st...
Definition abstract_factory.hpp:211
static std::unique_ptr< Dense > create(std::shared_ptr< const Executor > exec, const dim< 2 > &size={}, size_type stride=0)
Creates an uninitialized Dense matrix of the specified size.
Definition ilu.hpp:203
The Incomplete LU (ILU) preconditioner solves the equation for a given lower triangular matrix L,...
Definition ilu.hpp:87
Ilu(Ilu &&other)
Move-constructs an ILU preconditioner.
Definition ilu.hpp:310
Ilu & operator=(Ilu &&other)
Move-assigns an ILU preconditioner.
Definition ilu.hpp:283
std::shared_ptr< const l_solver_type > get_l_solver() const
Returns the solver which is used for the provided L matrix.
Definition ilu.hpp:211
std::unique_ptr< LinOp > conj_transpose() const override
Returns a LinOp representing the conjugate transpose of the Transposable object.
Definition ilu.hpp:241
Ilu(const Ilu &other)
Copy-constructs an ILU preconditioner.
Definition ilu.hpp:303
std::shared_ptr< const u_solver_type > get_u_solver() const
Returns the solver which is used for the provided U matrix.
Definition ilu.hpp:221
std::unique_ptr< LinOp > transpose() const override
Returns a LinOp representing the transpose of the Transposable object.
Definition ilu.hpp:226
Ilu & operator=(const Ilu &other)
Copy-assigns an ILU preconditioner.
Definition ilu.hpp:261
The ResidualNorm class is a stopping criterion which stops the iteration process when the actual resi...
Definition residual_norm.hpp:110
#define GKO_ENABLE_BUILD_METHOD(_factory_name)
Defines a build method for the factory, simplifying its construction by removing the repetitive typin...
Definition abstract_factory.hpp:394
#define GKO_ENABLE_LIN_OP_FACTORY(_lin_op, _parameters_name, _factory_name)
This macro will generate a default implementation of a LinOpFactory for the LinOp subclass it is defi...
Definition lin_op.hpp:1018
@ factory
LinOpFactory events.
The Ginkgo namespace.
Definition abstract_factory.hpp:20
constexpr T one()
Returns the multiplicative identity for T.
Definition math.hpp:775
typename detail::remove_complex_s< T >::type remove_complex
Obtain the type which removed the complex of complex/scalar type or the template parameter of class b...
Definition math.hpp:326
detail::cloned_type< Pointer > clone(const Pointer &p)
Creates a unique clone of the object pointed to by p.
Definition utils_helper.hpp:175
batch_dim< 2, DimensionType > transpose(const batch_dim< 2, DimensionType > &input)
Returns a batch_dim object with its dimensions swapped for batched operators.
Definition batch_dim.hpp:120
detail::shared_type< OwningPointer > share(OwningPointer &&p)
Marks the object pointed to by p as shared.
Definition utils_helper.hpp:226
std::shared_ptr< const LinOpFactory > factorization_factory
Factory for the factorization.
Definition ilu.hpp:124
std::shared_ptr< const typename u_solver_type::Factory > u_solver_factory
Factory for the U solver.
Definition ilu.hpp:119
std::shared_ptr< const typename l_solver_type::Factory > l_solver_factory
Factory for the L solver.
Definition ilu.hpp:113