Ginkgo Generated from develop branch based on develop. Ginkgo version 1.10.0
A numerical linear algebra library targeting many-core architectures
 
Loading...
Searching...
No Matches
precision_dispatch.hpp
1// SPDX-FileCopyrightText: 2017 - 2025 The Ginkgo authors
2//
3// SPDX-License-Identifier: BSD-3-Clause
4
5#ifndef GKO_PUBLIC_CORE_BASE_PRECISION_DISPATCH_HPP_
6#define GKO_PUBLIC_CORE_BASE_PRECISION_DISPATCH_HPP_
7
8
9#include <ginkgo/config.hpp>
10#include <ginkgo/core/base/math.hpp>
11#include <ginkgo/core/base/temporary_conversion.hpp>
12#include <ginkgo/core/distributed/vector.hpp>
13#include <ginkgo/core/matrix/dense.hpp>
14
15
16namespace gko {
17
18
43template <typename ValueType, typename Ptr>
44detail::temporary_conversion<std::conditional_t<
45 std::is_const<detail::pointee<Ptr>>::value, const matrix::Dense<ValueType>,
48{
49 using Pointee = detail::pointee<Ptr>;
50 using Dense = matrix::Dense<ValueType>;
54 using MaybeConstDense =
55 std::conditional_t<std::is_const<Pointee>::value, const Dense, Dense>;
56 auto result =
57 detail::temporary_conversion<MaybeConstDense>::template create<
58 NextDense, Next2Dense, Next3Dense>(matrix);
59 if (!result) {
60 GKO_NOT_SUPPORTED(matrix);
61 }
62 return result;
63}
64
65
80template <typename ValueType, typename Function, typename... Args>
81void precision_dispatch(Function fn, Args*... linops)
82{
83 fn(make_temporary_conversion<ValueType>(linops).get()...);
84}
85
86
96template <typename ValueType, typename Function>
97void precision_dispatch_real_complex(Function fn, const LinOp* in, LinOp* out)
98{
99 // do we need to convert complex Dense to real Dense?
100 // all real dense vectors are intra-convertible, thus by casting to
101 // ConvertibleTo<matrix::Dense<>>, we can check whether a LinOp is a real
102 // dense matrix:
103 auto complex_to_real =
105 dynamic_cast<const ConvertibleTo<matrix::Dense<>>*>(in));
106 if (complex_to_real) {
109 using Dense = matrix::Dense<ValueType>;
110 // These dynamic_casts are only needed to make the code compile
111 // If ValueType is complex, this branch will never be taken
112 // If ValueType is real, the cast is a no-op
113 fn(dynamic_cast<const Dense*>(dense_in->create_real_view().get()),
114 dynamic_cast<Dense*>(dense_out->create_real_view().get()));
115 } else {
117 }
118}
119
120
130template <typename ValueType, typename Function>
131void precision_dispatch_real_complex(Function fn, const LinOp* alpha,
132 const LinOp* in, LinOp* out)
133{
134 // do we need to convert complex Dense to real Dense?
135 // all real dense vectors are intra-convertible, thus by casting to
136 // ConvertibleTo<matrix::Dense<>>, we can check whether a LinOp is a real
137 // dense matrix:
138 auto complex_to_real =
140 dynamic_cast<const ConvertibleTo<matrix::Dense<>>*>(in));
141 if (complex_to_real) {
144 auto dense_alpha = make_temporary_conversion<ValueType>(alpha);
145 using Dense = matrix::Dense<ValueType>;
146 // These dynamic_casts are only needed to make the code compile
147 // If ValueType is complex, this branch will never be taken
148 // If ValueType is real, the cast is a no-op
149 fn(dense_alpha.get(),
150 dynamic_cast<const Dense*>(dense_in->create_real_view().get()),
151 dynamic_cast<Dense*>(dense_out->create_real_view().get()));
152 } else {
153 precision_dispatch<ValueType>(fn, alpha, in, out);
154 }
155}
156
157
167template <typename ValueType, typename Function>
168void precision_dispatch_real_complex(Function fn, const LinOp* alpha,
169 const LinOp* in, const LinOp* beta,
170 LinOp* out)
171{
172 // do we need to convert complex Dense to real Dense?
173 // all real dense vectors are intra-convertible, thus by casting to
174 // ConvertibleTo<matrix::Dense<>>, we can check whether a LinOp is a real
175 // dense matrix:
176 auto complex_to_real =
178 dynamic_cast<const ConvertibleTo<matrix::Dense<>>*>(in));
179 if (complex_to_real) {
182 auto dense_alpha = make_temporary_conversion<ValueType>(alpha);
183 auto dense_beta = make_temporary_conversion<ValueType>(beta);
184 using Dense = matrix::Dense<ValueType>;
185 // These dynamic_casts are only needed to make the code compile
186 // If ValueType is complex, this branch will never be taken
187 // If ValueType is real, the cast is a no-op
188 fn(dense_alpha.get(),
189 dynamic_cast<const Dense*>(dense_in->create_real_view().get()),
190 dense_beta.get(),
191 dynamic_cast<Dense*>(dense_out->create_real_view().get()));
192 } else {
193 precision_dispatch<ValueType>(fn, alpha, in, beta, out);
194 }
195}
196
197
227template <typename ValueType, typename Function>
228void mixed_precision_dispatch(Function fn, const LinOp* in, LinOp* out)
229{
230#ifdef GINKGO_MIXED_PRECISION
231 using fst_type = matrix::Dense<ValueType>;
235 auto dispatch_out_vector = [&](auto dense_in) {
236 if (auto dense_out = dynamic_cast<fst_type*>(out)) {
237 fn(dense_in, dense_out);
238 } else if (auto dense_out = dynamic_cast<snd_type*>(out)) {
239 fn(dense_in, dense_out);
240 } else if (auto dense_out = dynamic_cast<trd_type*>(out)) {
241 fn(dense_in, dense_out);
242 } else if (auto dense_out = dynamic_cast<fth_type*>(out)) {
243 fn(dense_in, dense_out);
244 } else {
245 GKO_NOT_SUPPORTED(out);
246 }
247 };
248 if (auto dense_in = dynamic_cast<const fst_type*>(in)) {
249 dispatch_out_vector(dense_in);
250 } else if (auto dense_in = dynamic_cast<const snd_type*>(in)) {
251 dispatch_out_vector(dense_in);
252 } else if (auto dense_in = dynamic_cast<const trd_type*>(in)) {
253 dispatch_out_vector(dense_in);
254 } else if (auto dense_in = dynamic_cast<const fth_type*>(in)) {
255 dispatch_out_vector(dense_in);
256 } else {
257 GKO_NOT_SUPPORTED(in);
258 }
259#else
261#endif
262}
263
264
274template <typename ValueType, typename Function,
275 std::enable_if_t<is_complex<ValueType>()>* = nullptr>
277 LinOp* out)
278{
279#ifdef GINKGO_MIXED_PRECISION
281#else
283#endif
284}
285
286
287template <typename ValueType, typename Function,
288 std::enable_if_t<!is_complex<ValueType>()>* = nullptr>
289void mixed_precision_dispatch_real_complex(Function fn, const LinOp* in,
290 LinOp* out)
291{
292#ifdef GINKGO_MIXED_PRECISION
293 if (!dynamic_cast<const ConvertibleTo<matrix::Dense<>>*>(in)) {
295 [&fn](auto dense_in, auto dense_out) {
296 fn(dense_in->create_real_view().get(),
297 dense_out->create_real_view().get());
298 },
299 in, out);
300 } else {
302 }
303#else
305#endif
306}
307
308
309namespace experimental {
310
311
312#if GINKGO_BUILD_MPI
313
314
315namespace distributed {
316
317
343template <typename ValueType>
344gko::detail::temporary_conversion<Vector<ValueType>> make_temporary_conversion(
345 LinOp* matrix)
346{
347 auto result =
348 gko::detail::temporary_conversion<Vector<ValueType>>::template create<
352 if (!result) {
353 GKO_NOT_SUPPORTED(matrix);
354 }
355 return result;
356}
357
358
362template <typename ValueType>
363gko::detail::temporary_conversion<const Vector<ValueType>>
365{
366 auto result = gko::detail::temporary_conversion<const Vector<ValueType>>::
367 template create<Vector<next_precision<ValueType>>,
370 if (!result) {
371 GKO_NOT_SUPPORTED(matrix);
372 }
373 return result;
374}
375
376
391template <typename ValueType, typename Function, typename... Args>
392void precision_dispatch(Function fn, Args*... linops)
393{
395}
396
397
407template <typename ValueType, typename Function>
408void precision_dispatch_real_complex(Function fn, const LinOp* in, LinOp* out)
409{
410 auto complex_to_real = !(
413 in));
414 if (complex_to_real) {
415 auto dense_in =
417 auto dense_out =
420 // These dynamic_casts are only needed to make the code compile
421 // If ValueType is complex, this branch will never be taken
422 // If ValueType is real, the cast is a no-op
423 fn(dynamic_cast<const Vector*>(dense_in->create_real_view().get()),
424 dynamic_cast<Vector*>(dense_out->create_real_view().get()));
425 } else {
427 }
428}
429
430
434template <typename ValueType, typename Function>
435void precision_dispatch_real_complex(Function fn, const LinOp* alpha,
436 const LinOp* in, LinOp* out)
437{
438 auto complex_to_real = !(
441 in));
442 if (complex_to_real) {
443 auto dense_in =
445 auto dense_out =
447 auto dense_alpha = gko::make_temporary_conversion<ValueType>(alpha);
449 // These dynamic_casts are only needed to make the code compile
450 // If ValueType is complex, this branch will never be taken
451 // If ValueType is real, the cast is a no-op
452 fn(dense_alpha.get(),
453 dynamic_cast<const Vector*>(dense_in->create_real_view().get()),
454 dynamic_cast<Vector*>(dense_out->create_real_view().get()));
455 } else {
459 }
460}
461
462
466template <typename ValueType, typename Function>
467void precision_dispatch_real_complex(Function fn, const LinOp* alpha,
468 const LinOp* in, const LinOp* beta,
469 LinOp* out)
470{
471 auto complex_to_real = !(
474 in));
475 if (complex_to_real) {
476 auto dense_in =
478 auto dense_out =
480 auto dense_alpha = gko::make_temporary_conversion<ValueType>(alpha);
481 auto dense_beta = gko::make_temporary_conversion<ValueType>(beta);
483 // These dynamic_casts are only needed to make the code compile
484 // If ValueType is complex, this branch will never be taken
485 // If ValueType is real, the cast is a no-op
486 fn(dense_alpha.get(),
487 dynamic_cast<const Vector*>(dense_in->create_real_view().get()),
488 dense_beta.get(),
489 dynamic_cast<Vector*>(dense_out->create_real_view().get()));
490 } else {
495 }
496}
497
498
499} // namespace distributed
500
501
515template <typename ValueType, typename Function>
516void precision_dispatch_real_complex_distributed(Function fn, const LinOp* in,
517 LinOp* out)
518{
519 if (dynamic_cast<const experimental::distributed::DistributedBase*>(in)) {
521 fn, in, out);
522 } else {
524 }
525}
526
527
532template <typename ValueType, typename Function>
533void precision_dispatch_real_complex_distributed(Function fn,
534 const LinOp* alpha,
535 const LinOp* in, LinOp* out)
536{
537 if (dynamic_cast<const experimental::distributed::DistributedBase*>(in)) {
539 fn, alpha, in, out);
540 } else {
542 }
543}
544
545
550template <typename ValueType, typename Function>
551void precision_dispatch_real_complex_distributed(Function fn,
552 const LinOp* alpha,
553 const LinOp* in,
554 const LinOp* beta, LinOp* out)
555{
556 if (dynamic_cast<const experimental::distributed::DistributedBase*>(in)) {
558 fn, alpha, in, beta, out);
559
560 } else {
562 out);
563 }
564}
565
566
567#else
568
569
580template <typename ValueType, typename Function, typename... Args>
581void precision_dispatch_real_complex_distributed(Function fn, Args*... args)
582{
584}
585
586
587#endif
588
589
590} // namespace experimental
591} // namespace gko
592
593
594#endif // GKO_PUBLIC_CORE_BASE_PRECISION_DISPATCH_HPP_
ConvertibleTo interface is used to mark that the implementer can be converted to the object of Result...
Definition polymorphic_object.hpp:479
Definition lin_op.hpp:117
A base class for distributed objects.
Definition base.hpp:32
Vector is a format which explicitly stores (multiple) distributed column vectors in a dense storage f...
Definition vector.hpp:77
Dense is a matrix format which explicitly stores all values of the matrix.
Definition dense.hpp:120
The distributed namespace.
Definition polymorphic_object.hpp:19
gko::detail::temporary_conversion< Vector< ValueType > > make_temporary_conversion(LinOp *matrix)
Convert the given LinOp from experimental::distributed::Vector<...> to experimental::distributed::Vec...
Definition precision_dispatch.hpp:344
void precision_dispatch_real_complex(Function fn, const LinOp *in, LinOp *out)
Calls the given function with the given LinOps temporarily converted to experimental::distributed::Ve...
Definition precision_dispatch.hpp:408
void precision_dispatch(Function fn, Args *... linops)
Calls the given function with each given argument LinOp temporarily converted into experimental::dist...
Definition precision_dispatch.hpp:392
The matrix namespace.
Definition dense_cache.hpp:15
The Ginkgo namespace.
Definition abstract_factory.hpp:20
void mixed_precision_dispatch(Function fn, const LinOp *in, LinOp *out)
Calls the given function with each given argument LinOp converted into matrix::Dense<ValueType> as pa...
Definition precision_dispatch.hpp:228
void mixed_precision_dispatch_real_complex(Function fn, const LinOp *in, LinOp *out)
Calls the given function with the given LinOps cast to their dynamic type matrix::Dense<ValueType>* a...
Definition precision_dispatch.hpp:276
void precision_dispatch(Function fn, Args *... linops)
Calls the given function with each given argument LinOp temporarily converted into matrix::Dense<Valu...
Definition precision_dispatch.hpp:81
detail::temporary_conversion< std::conditional_t< std::is_const< detail::pointee< Ptr > >::value, const matrix::Dense< ValueType >, matrix::Dense< ValueType > > > make_temporary_conversion(Ptr &&matrix)
Convert the given LinOp from matrix::Dense<...> to matrix::Dense<ValueType>.
Definition precision_dispatch.hpp:47
void precision_dispatch_real_complex(Function fn, const LinOp *in, LinOp *out)
Calls the given function with the given LinOps temporarily converted to matrix::Dense<ValueType>* as ...
Definition precision_dispatch.hpp:97
constexpr bool is_complex()
Checks if T is a complex type.
Definition math.hpp:225