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
ic.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_IC_HPP_
34#define GKO_PUBLIC_CORE_PRECONDITIONER_IC_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_ic.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
106template <typename LSolverType = solver::LowerTrs<>, typename IndexType = int32>
107class Ic : public EnableLinOp<Ic<LSolverType, IndexType>>, public Transposable {
108 friend class EnableLinOp<Ic>;
109 friend class EnablePolymorphicObject<Ic, LinOp>;
110
111public:
112 static_assert(
113 std::is_same<typename LSolverType::transposed_type::transposed_type,
114 LSolverType>::value,
115 "LSolverType::transposed_type must be symmetric");
116 using value_type = typename LSolverType::value_type;
117 using l_solver_type = LSolverType;
118 using lh_solver_type = typename LSolverType::transposed_type;
119 using index_type = IndexType;
121
122 class Factory;
123
125 : public enable_parameters_type<parameters_type, Factory> {
129 std::shared_ptr<const typename l_solver_type::Factory>
131
135 std::shared_ptr<const LinOpFactory> factorization_factory{};
136
137 GKO_DEPRECATED("use with_l_solver instead")
138 parameters_type& with_l_solver_factory(
140 solver)
141 {
142 return with_l_solver(std::move(solver));
143 }
144
145 parameters_type& with_l_solver(
147 solver)
148 {
149 this->l_solver_generator = std::move(solver);
150 this->deferred_factories["l_solver"] = [](const auto& exec,
151 auto& params) {
152 if (!params.l_solver_generator.is_empty()) {
153 params.l_solver_factory =
154 params.l_solver_generator.on(exec);
155 }
156 };
157 return *this;
158 }
159
160 GKO_DEPRECATED("use with_factorization instead")
161 parameters_type& with_factorization_factory(
162 deferred_factory_parameter<const LinOpFactory> factorization)
163 {
164 return with_factorization(std::move(factorization));
165 }
166
167 parameters_type& with_factorization(
169 {
170 this->factorization_generator = std::move(factorization);
171 this->deferred_factories["factorization"] = [](const auto& exec,
172 auto& params) {
173 if (!params.factorization_generator.is_empty()) {
174 params.factorization_factory =
175 params.factorization_generator.on(exec);
176 }
177 };
178 return *this;
179 }
180
181 private:
182 deferred_factory_parameter<const typename l_solver_type::Factory>
183 l_solver_generator;
184
186 };
187
190
196 std::shared_ptr<const l_solver_type> get_l_solver() const
197 {
198 return l_solver_;
199 }
200
206 std::shared_ptr<const lh_solver_type> get_lh_solver() const
207 {
208 return lh_solver_;
209 }
210
211 std::unique_ptr<LinOp> transpose() const override
212 {
213 std::unique_ptr<transposed_type> transposed{
214 new transposed_type{this->get_executor()}};
215 transposed->set_size(gko::transpose(this->get_size()));
216 transposed->l_solver_ =
218 this->get_lh_solver()->transpose()));
219 transposed->lh_solver_ =
221 this->get_l_solver()->transpose()));
222
223 return std::move(transposed);
224 }
225
226 std::unique_ptr<LinOp> conj_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_lh_solver()->conj_transpose()));
234 transposed->lh_solver_ =
236 this->get_l_solver()->conj_transpose()));
237
238 return std::move(transposed);
239 }
240
247 {
248 if (&other != this) {
250 auto exec = this->get_executor();
251 l_solver_ = other.l_solver_;
252 lh_solver_ = other.lh_solver_;
253 parameters_ = other.parameters_;
254 if (other.get_executor() != exec) {
255 l_solver_ = gko::clone(exec, l_solver_);
256 lh_solver_ = gko::clone(exec, lh_solver_);
257 }
258 }
259 return *this;
260 }
261
269 {
270 if (&other != this) {
272 auto exec = this->get_executor();
273 l_solver_ = std::move(other.l_solver_);
274 lh_solver_ = std::move(other.lh_solver_);
275 parameters_ = std::exchange(other.parameters_, parameters_type{});
276 if (other.get_executor() != exec) {
277 l_solver_ = gko::clone(exec, l_solver_);
278 lh_solver_ = gko::clone(exec, lh_solver_);
279 }
280 }
281 return *this;
282 }
283
288 Ic(const Ic& other) : Ic{other.get_executor()} { *this = other; }
289
295 Ic(Ic&& other) : Ic{other.get_executor()} { *this = std::move(other); }
296
297protected:
298 void apply_impl(const LinOp* b, LinOp* x) const override
299 {
300 // take care of real-to-complex apply
302 [&](auto dense_b, auto dense_x) {
303 this->set_cache_to(dense_b);
304 l_solver_->apply(dense_b, cache_.intermediate);
305 if (lh_solver_->apply_uses_initial_guess()) {
306 dense_x->copy_from(cache_.intermediate);
307 }
308 lh_solver_->apply(cache_.intermediate, dense_x);
309 },
310 b, x);
311 }
312
313 void apply_impl(const LinOp* alpha, const LinOp* b, const LinOp* beta,
314 LinOp* x) const override
315 {
317 [&](auto dense_alpha, auto dense_b, auto dense_beta, auto dense_x) {
318 this->set_cache_to(dense_b);
319 l_solver_->apply(dense_b, cache_.intermediate);
320 lh_solver_->apply(dense_alpha, cache_.intermediate, dense_beta,
321 dense_x);
322 },
323 alpha, b, beta, x);
324 }
325
326 explicit Ic(std::shared_ptr<const Executor> exec)
327 : EnableLinOp<Ic>(std::move(exec))
328 {}
329
330 explicit Ic(const Factory* factory, std::shared_ptr<const LinOp> lin_op)
331 : EnableLinOp<Ic>(factory->get_executor(), lin_op->get_size()),
332 parameters_{factory->get_parameters()}
333 {
334 auto comp =
335 std::dynamic_pointer_cast<const Composition<value_type>>(lin_op);
336 std::shared_ptr<const LinOp> l_factor;
337
338 // build factorization if we weren't passed a composition
339 if (!comp) {
340 auto exec = lin_op->get_executor();
341 if (!parameters_.factorization_factory) {
342 parameters_.factorization_factory =
343 factorization::ParIc<value_type, index_type>::build()
344 .with_both_factors(false)
345 .on(exec);
346 }
347 auto fact = std::shared_ptr<const LinOp>(
348 parameters_.factorization_factory->generate(lin_op));
349 // ensure that the result is a composition
350 comp =
351 std::dynamic_pointer_cast<const Composition<value_type>>(fact);
352 if (!comp) {
353 GKO_NOT_SUPPORTED(comp);
354 }
355 }
356 // comp must contain one or two factors
357 if (comp->get_operators().size() > 2 || comp->get_operators().empty()) {
358 GKO_NOT_SUPPORTED(comp);
359 }
360 l_factor = comp->get_operators()[0];
361 GKO_ASSERT_IS_SQUARE_MATRIX(l_factor);
362
363 auto exec = this->get_executor();
364
365 // If no factories are provided, generate default ones
366 if (!parameters_.l_solver_factory) {
368 // If comp contains both factors: use the transposed factor to avoid
369 // transposing twice
370 if (comp->get_operators().size() == 2) {
371 auto lh_factor = comp->get_operators()[1];
372 GKO_ASSERT_EQUAL_DIMENSIONS(l_factor, lh_factor);
373 lh_solver_ = as<lh_solver_type>(l_solver_->conj_transpose());
374 } else {
375 lh_solver_ = as<lh_solver_type>(l_solver_->conj_transpose());
376 }
377 } else {
378 l_solver_ = parameters_.l_solver_factory->generate(l_factor);
379 lh_solver_ = as<lh_solver_type>(l_solver_->conj_transpose());
380 }
381 }
382
390 void set_cache_to(const LinOp* b) const
391 {
392 if (cache_.intermediate == nullptr) {
393 cache_.intermediate =
394 matrix::Dense<value_type>::create(this->get_executor());
395 }
396 // Use b as the initial guess for the first triangular solve
397 cache_.intermediate->copy_from(b);
398 }
399
400
408 template <typename SolverType>
409 static std::enable_if_t<solver::has_with_criteria<SolverType>::value,
410 std::unique_ptr<SolverType>>
411 generate_default_solver(const std::shared_ptr<const Executor>& exec,
412 const std::shared_ptr<const LinOp>& mtx)
413 {
415 const unsigned int default_max_iters{
416 static_cast<unsigned int>(mtx->get_size()[0])};
417
418 return SolverType::build()
419 .with_criteria(
420 gko::stop::Iteration::build().with_max_iters(default_max_iters),
422 .with_reduction_factor(default_reduce_residual))
423 .on(exec)
424 ->generate(mtx);
425 }
426
430 template <typename SolverType>
431 static std::enable_if_t<!solver::has_with_criteria<SolverType>::value,
432 std::unique_ptr<SolverType>>
433 generate_default_solver(const std::shared_ptr<const Executor>& exec,
434 const std::shared_ptr<const LinOp>& mtx)
435 {
436 return SolverType::build().on(exec)->generate(mtx);
437 }
438
439private:
440 std::shared_ptr<const l_solver_type> l_solver_{};
441 std::shared_ptr<const lh_solver_type> lh_solver_{};
452 mutable struct cache_struct {
453 cache_struct() = default;
454 ~cache_struct() = default;
455 cache_struct(const cache_struct&) {}
456 cache_struct(cache_struct&&) {}
457 cache_struct& operator=(const cache_struct&) { return *this; }
458 cache_struct& operator=(cache_struct&&) { return *this; }
459 std::unique_ptr<LinOp> intermediate{};
460 } cache_;
461};
462
463
464} // namespace preconditioner
465} // namespace gko
466
467
468#endif // GKO_PUBLIC_CORE_PRECONDITIONER_IC_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
The Incomplete Cholesky (IC) preconditioner solves the equation for a given lower triangular matrix ...
Definition ic.hpp:107
std::shared_ptr< const lh_solver_type > get_lh_solver() const
Returns the solver which is used for the L^H matrix.
Definition ic.hpp:206
std::unique_ptr< LinOp > transpose() const override
Returns a LinOp representing the transpose of the Transposable object.
Definition ic.hpp:211
Ic(const Ic &other)
Copy-constructs an IC preconditioner.
Definition ic.hpp:288
Ic & operator=(Ic &&other)
Move-assigns an IC preconditioner.
Definition ic.hpp:268
Ic(Ic &&other)
Move-constructs an IC preconditioner.
Definition ic.hpp:295
std::shared_ptr< const l_solver_type > get_l_solver() const
Returns the solver which is used for the provided L matrix.
Definition ic.hpp:196
Ic & operator=(const Ic &other)
Copy-assigns an IC preconditioner.
Definition ic.hpp:246
std::unique_ptr< LinOp > conj_transpose() const override
Returns a LinOp representing the conjugate transpose of the Transposable object.
Definition ic.hpp:226
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 typename l_solver_type::Factory > l_solver_factory
Factory for the L solver.
Definition ic.hpp:130
std::shared_ptr< const LinOpFactory > factorization_factory
Factory for the factorization.
Definition ic.hpp:135