Ginkgo Generated from branch based on master. Ginkgo version 1.7.0
A numerical linear algebra library targeting many-core architectures
Loading...
Searching...
No Matches
ilu.hpp
1/*******************************<GINKGO LICENSE>******************************
2Copyright (c) 2017-2023, the Ginkgo authors
3All rights reserved.
4
5Redistribution and use in source and binary forms, with or without
6modification, are permitted provided that the following conditions
7are met:
8
91. Redistributions of source code must retain the above copyright
10notice, this list of conditions and the following disclaimer.
11
122. Redistributions in binary form must reproduce the above copyright
13notice, this list of conditions and the following disclaimer in the
14documentation and/or other materials provided with the distribution.
15
163. Neither the name of the copyright holder nor the names of its
17contributors may be used to endorse or promote products derived from
18this software without specific prior written permission.
19
20THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
21IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31******************************<GINKGO LICENSE>*******************************/
32
33#ifndef GKO_PUBLIC_CORE_PRECONDITIONER_ILU_HPP_
34#define GKO_PUBLIC_CORE_PRECONDITIONER_ILU_HPP_
35
36
37#include <memory>
38#include <type_traits>
39
40
41#include <ginkgo/core/base/abstract_factory.hpp>
42#include <ginkgo/core/base/composition.hpp>
43#include <ginkgo/core/base/exception.hpp>
44#include <ginkgo/core/base/exception_helpers.hpp>
45#include <ginkgo/core/base/lin_op.hpp>
46#include <ginkgo/core/base/precision_dispatch.hpp>
47#include <ginkgo/core/base/std_extensions.hpp>
48#include <ginkgo/core/factorization/par_ilu.hpp>
49#include <ginkgo/core/matrix/dense.hpp>
50#include <ginkgo/core/solver/solver_traits.hpp>
51#include <ginkgo/core/solver/triangular.hpp>
52#include <ginkgo/core/stop/combined.hpp>
53#include <ginkgo/core/stop/iteration.hpp>
54#include <ginkgo/core/stop/residual_norm.hpp>
55
56
57namespace gko {
58namespace preconditioner {
59
60
110template <typename LSolverType = solver::LowerTrs<>,
111 typename USolverType = solver::UpperTrs<>, bool ReverseApply = false,
112 typename IndexType = int32>
113class Ilu : public EnableLinOp<
114 Ilu<LSolverType, USolverType, ReverseApply, IndexType>>,
115 public Transposable {
116 friend class EnableLinOp<Ilu>;
117 friend class EnablePolymorphicObject<Ilu, LinOp>;
118
119public:
120 static_assert(
121 std::is_same<typename LSolverType::value_type,
122 typename USolverType::value_type>::value,
123 "Both the L- and the U-solver must use the same `value_type`!");
124 using value_type = typename LSolverType::value_type;
125 using l_solver_type = LSolverType;
126 using u_solver_type = USolverType;
127 static constexpr bool performs_reverse_apply = ReverseApply;
128 using index_type = IndexType;
129 using transposed_type =
130 Ilu<typename USolverType::transposed_type,
131 typename LSolverType::transposed_type, ReverseApply, IndexType>;
132
133 class Factory;
134
136 : public enable_parameters_type<parameters_type, Factory> {
140 std::shared_ptr<const typename l_solver_type::Factory>
142
146 std::shared_ptr<const typename u_solver_type::Factory>
148
152 std::shared_ptr<const LinOpFactory> factorization_factory{};
153
154 GKO_DEPRECATED("use with_l_solver instead")
155 parameters_type& with_l_solver_factory(
157 solver)
158 {
159 return with_l_solver(std::move(solver));
160 }
161
162 parameters_type& with_l_solver(
164 solver)
165 {
166 this->l_solver_generator = std::move(solver);
167 this->deferred_factories["l_solver"] = [](const auto& exec,
168 auto& params) {
169 if (!params.l_solver_generator.is_empty()) {
170 params.l_solver_factory =
171 params.l_solver_generator.on(exec);
172 }
173 };
174 return *this;
175 }
176
177 GKO_DEPRECATED("use with_u_solver instead")
178 parameters_type& with_u_solver_factory(
179 deferred_factory_parameter<const typename u_solver_type::Factory>
180 solver)
181 {
182 return with_u_solver(std::move(solver));
183 }
184
185 parameters_type& with_u_solver(
186 deferred_factory_parameter<const typename u_solver_type::Factory>
187 solver)
188 {
189 this->u_solver_generator = std::move(solver);
190 this->deferred_factories["u_solver"] = [](const auto& exec,
191 auto& params) {
192 if (!params.u_solver_generator.is_empty()) {
193 params.u_solver_factory =
194 params.u_solver_generator.on(exec);
195 }
196 };
197 return *this;
198 }
199
200 GKO_DEPRECATED("use with_factorization instead")
201 parameters_type& with_factorization_factory(
202 deferred_factory_parameter<const LinOpFactory> factorization)
203 {
204 return with_factorization(std::move(factorization));
205 }
206
207 parameters_type& with_factorization(
209 {
210 this->factorization_generator = std::move(factorization);
211 this->deferred_factories["factorization"] = [](const auto& exec,
212 auto& params) {
213 if (!params.factorization_generator.is_empty()) {
214 params.factorization_factory =
215 params.factorization_generator.on(exec);
216 }
217 };
218 return *this;
219 }
220
221 private:
222 deferred_factory_parameter<const typename l_solver_type::Factory>
223 l_solver_generator;
224
225 deferred_factory_parameter<const typename u_solver_type::Factory>
226 u_solver_generator;
227
229 };
230
233
239 std::shared_ptr<const l_solver_type> get_l_solver() const
240 {
241 return l_solver_;
242 }
243
249 std::shared_ptr<const u_solver_type> get_u_solver() const
250 {
251 return u_solver_;
252 }
253
254 std::unique_ptr<LinOp> transpose() const override
255 {
256 std::unique_ptr<transposed_type> transposed{
257 new transposed_type{this->get_executor()}};
258 transposed->set_size(gko::transpose(this->get_size()));
259 transposed->l_solver_ =
261 this->get_u_solver()->transpose()));
262 transposed->u_solver_ =
264 this->get_l_solver()->transpose()));
265
266 return std::move(transposed);
267 }
268
269 std::unique_ptr<LinOp> conj_transpose() const override
270 {
271 std::unique_ptr<transposed_type> transposed{
272 new transposed_type{this->get_executor()}};
273 transposed->set_size(gko::transpose(this->get_size()));
274 transposed->l_solver_ =
276 this->get_u_solver()->conj_transpose()));
277 transposed->u_solver_ =
279 this->get_l_solver()->conj_transpose()));
280
281 return std::move(transposed);
282 }
283
290 {
291 if (&other != this) {
293 auto exec = this->get_executor();
294 l_solver_ = other.l_solver_;
295 u_solver_ = other.u_solver_;
296 parameters_ = other.parameters_;
297 if (other.get_executor() != exec) {
298 l_solver_ = gko::clone(exec, l_solver_);
299 u_solver_ = gko::clone(exec, u_solver_);
300 }
301 }
302 return *this;
303 }
304
312 {
313 if (&other != this) {
315 auto exec = this->get_executor();
316 l_solver_ = std::move(other.l_solver_);
317 u_solver_ = std::move(other.u_solver_);
318 parameters_ = std::exchange(other.parameters_, parameters_type{});
319 if (other.get_executor() != exec) {
320 l_solver_ = gko::clone(exec, l_solver_);
321 u_solver_ = gko::clone(exec, u_solver_);
322 }
323 }
324 return *this;
325 }
326
331 Ilu(const Ilu& other) : Ilu{other.get_executor()} { *this = other; }
332
338 Ilu(Ilu&& other) : Ilu{other.get_executor()} { *this = std::move(other); }
339
340protected:
341 void apply_impl(const LinOp* b, LinOp* x) const override
342 {
343 // take care of real-to-complex apply
345 [&](auto dense_b, auto dense_x) {
346 this->set_cache_to(dense_b);
347 if (!ReverseApply) {
348 l_solver_->apply(dense_b, cache_.intermediate);
349 if (u_solver_->apply_uses_initial_guess()) {
350 dense_x->copy_from(cache_.intermediate);
351 }
352 u_solver_->apply(cache_.intermediate, dense_x);
353 } else {
354 u_solver_->apply(dense_b, cache_.intermediate);
355 if (l_solver_->apply_uses_initial_guess()) {
356 dense_x->copy_from(cache_.intermediate);
357 }
358 l_solver_->apply(cache_.intermediate, dense_x);
359 }
360 },
361 b, x);
362 }
363
364 void apply_impl(const LinOp* alpha, const LinOp* b, const LinOp* beta,
365 LinOp* x) const override
366 {
368 [&](auto dense_alpha, auto dense_b, auto dense_beta, auto dense_x) {
369 this->set_cache_to(dense_b);
370 if (!ReverseApply) {
371 l_solver_->apply(dense_b, cache_.intermediate);
372 u_solver_->apply(dense_alpha, cache_.intermediate,
374 } else {
375 u_solver_->apply(dense_b, cache_.intermediate);
376 l_solver_->apply(dense_alpha, cache_.intermediate,
378 }
379 },
380 alpha, b, beta, x);
381 }
382
383 explicit Ilu(std::shared_ptr<const Executor> exec)
384 : EnableLinOp<Ilu>(std::move(exec))
385 {}
386
387 explicit Ilu(const Factory* factory, std::shared_ptr<const LinOp> lin_op)
388 : EnableLinOp<Ilu>(factory->get_executor(), lin_op->get_size()),
389 parameters_{factory->get_parameters()}
390 {
391 auto comp =
392 std::dynamic_pointer_cast<const Composition<value_type>>(lin_op);
393 std::shared_ptr<const LinOp> l_factor;
394 std::shared_ptr<const LinOp> u_factor;
395
396 // build factorization if we weren't passed a composition
397 if (!comp) {
398 auto exec = lin_op->get_executor();
399 if (!parameters_.factorization_factory) {
400 parameters_.factorization_factory =
401 factorization::ParIlu<value_type, index_type>::build().on(
402 exec);
403 }
404 auto fact = std::shared_ptr<const LinOp>(
405 parameters_.factorization_factory->generate(lin_op));
406 // ensure that the result is a composition
407 comp =
408 std::dynamic_pointer_cast<const Composition<value_type>>(fact);
409 if (!comp) {
410 GKO_NOT_SUPPORTED(comp);
411 }
412 }
413 if (comp->get_operators().size() == 2) {
414 l_factor = comp->get_operators()[0];
415 u_factor = comp->get_operators()[1];
416 } else {
417 GKO_NOT_SUPPORTED(comp);
418 }
419 GKO_ASSERT_EQUAL_DIMENSIONS(l_factor, u_factor);
420
421 auto exec = this->get_executor();
422
423 // If no factories are provided, generate default ones
424 if (!parameters_.l_solver_factory) {
426 } else {
427 l_solver_ = parameters_.l_solver_factory->generate(l_factor);
428 }
429 if (!parameters_.u_solver_factory) {
431 } else {
432 u_solver_ = parameters_.u_solver_factory->generate(u_factor);
433 }
434 }
435
443 void set_cache_to(const LinOp* b) const
444 {
445 if (cache_.intermediate == nullptr) {
446 cache_.intermediate =
447 matrix::Dense<value_type>::create(this->get_executor());
448 }
449 // Use b as the initial guess for the first triangular solve
450 cache_.intermediate->copy_from(b);
451 }
452
453
461 template <typename SolverType>
462 static std::enable_if_t<solver::has_with_criteria<SolverType>::value,
463 std::unique_ptr<SolverType>>
464 generate_default_solver(const std::shared_ptr<const Executor>& exec,
465 const std::shared_ptr<const LinOp>& mtx)
466 {
468 const unsigned int default_max_iters{
469 static_cast<unsigned int>(mtx->get_size()[0])};
470
471 return SolverType::build()
472 .with_criteria(
473 gko::stop::Iteration::build().with_max_iters(default_max_iters),
475 .with_reduction_factor(default_reduce_residual))
476 .on(exec)
477 ->generate(mtx);
478 }
479
483 template <typename SolverType>
484 static std::enable_if_t<!solver::has_with_criteria<SolverType>::value,
485 std::unique_ptr<SolverType>>
486 generate_default_solver(const std::shared_ptr<const Executor>& exec,
487 const std::shared_ptr<const LinOp>& mtx)
488 {
489 return SolverType::build().on(exec)->generate(mtx);
490 }
491
492private:
493 std::shared_ptr<const l_solver_type> l_solver_{};
494 std::shared_ptr<const u_solver_type> u_solver_{};
505 mutable struct cache_struct {
506 cache_struct() = default;
507 ~cache_struct() = default;
508 cache_struct(const cache_struct&) {}
509 cache_struct(cache_struct&&) {}
510 cache_struct& operator=(const cache_struct&) { return *this; }
511 cache_struct& operator=(cache_struct&&) { return *this; }
512 std::unique_ptr<LinOp> intermediate{};
513 } cache_;
514};
515
516
517} // namespace preconditioner
518} // namespace gko
519
520
521#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:908
This mixin inherits from (a subclass of) PolymorphicObject and provides a base implementation of a ne...
Definition polymorphic_object.hpp:691
Definition lin_op.hpp:146
std::shared_ptr< const Executor > get_executor() const noexcept
Returns the Executor of the object.
Definition polymorphic_object.hpp:263
Linear operators which support transposition should implement the Transposable interface.
Definition lin_op.hpp:462
Represents a factory parameter of factory type that can either initialized by a pre-existing factory ...
Definition abstract_factory.hpp:337
The enable_parameters_type mixin is used to create a base implementation of the factory parameters st...
Definition abstract_factory.hpp:239
Definition ilu.hpp:231
The Incomplete LU (ILU) preconditioner solves the equation for a given lower triangular matrix L,...
Definition ilu.hpp:115
Ilu(Ilu &&other)
Move-constructs an ILU preconditioner.
Definition ilu.hpp:338
Ilu & operator=(Ilu &&other)
Move-assigns an ILU preconditioner.
Definition ilu.hpp:311
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:239
std::unique_ptr< LinOp > conj_transpose() const override
Returns a LinOp representing the conjugate transpose of the Transposable object.
Definition ilu.hpp:269
Ilu(const Ilu &other)
Copy-constructs an ILU preconditioner.
Definition ilu.hpp:331
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:249
std::unique_ptr< LinOp > transpose() const override
Returns a LinOp representing the transpose of the Transposable object.
Definition ilu.hpp:254
Ilu & operator=(const Ilu &other)
Copy-assigns an ILU preconditioner.
Definition ilu.hpp:289
The ResidualNorm class is a stopping criterion which stops the iteration process when the actual resi...
Definition residual_norm.hpp:138
#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:422
#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:1046
@ factory
LinOpFactory events.
The Ginkgo namespace.
Definition abstract_factory.hpp:48
constexpr T one()
Returns the multiplicative identity for T.
Definition math.hpp:803
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:354
detail::cloned_type< Pointer > clone(const Pointer &p)
Creates a unique clone of the object pointed to by p.
Definition utils_helper.hpp:203
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:148
detail::shared_type< OwningPointer > share(OwningPointer &&p)
Marks the object pointed to by p as shared.
Definition utils_helper.hpp:254
std::shared_ptr< const LinOpFactory > factorization_factory
Factory for the factorization.
Definition ilu.hpp:152
std::shared_ptr< const typename u_solver_type::Factory > u_solver_factory
Factory for the U solver.
Definition ilu.hpp:147
std::shared_ptr< const typename l_solver_type::Factory > l_solver_factory
Factory for the L solver.
Definition ilu.hpp:141