Ginkgo  Generated from pipelines/1330831941 branch based on master. Ginkgo version 1.8.0
A numerical linear algebra library targeting many-core architectures
precision_dispatch.hpp
1 // SPDX-FileCopyrightText: 2017 - 2024 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 
16 namespace gko {
17 
18 
43 template <typename ValueType, typename Ptr>
44 detail::temporary_conversion<std::conditional_t<
45  std::is_const<detail::pointee<Ptr>>::value, const matrix::Dense<ValueType>,
46  matrix::Dense<ValueType>>>
48 {
49  using Pointee = detail::pointee<Ptr>;
50  using Dense = matrix::Dense<ValueType>;
51  using NextDense = matrix::Dense<next_precision<ValueType>>;
52  using MaybeConstDense =
53  std::conditional_t<std::is_const<Pointee>::value, const Dense, Dense>;
54  auto result = detail::temporary_conversion<
55  MaybeConstDense>::template create<NextDense>(matrix);
56  if (!result) {
57  GKO_NOT_SUPPORTED(*matrix);
58  }
59  return result;
60 }
61 
62 
77 template <typename ValueType, typename Function, typename... Args>
78 void precision_dispatch(Function fn, Args*... linops)
79 {
80  fn(make_temporary_conversion<ValueType>(linops).get()...);
81 }
82 
83 
93 template <typename ValueType, typename Function>
94 void precision_dispatch_real_complex(Function fn, const LinOp* in, LinOp* out)
95 {
96  // do we need to convert complex Dense to real Dense?
97  // all real dense vectors are intra-convertible, thus by casting to
98  // ConvertibleTo<matrix::Dense<>>, we can check whether a LinOp is a real
99  // dense matrix:
100  auto complex_to_real =
101  !(is_complex<ValueType>() ||
102  dynamic_cast<const ConvertibleTo<matrix::Dense<>>*>(in));
103  if (complex_to_real) {
104  auto dense_in = make_temporary_conversion<to_complex<ValueType>>(in);
105  auto dense_out = make_temporary_conversion<to_complex<ValueType>>(out);
106  using Dense = matrix::Dense<ValueType>;
107  // These dynamic_casts are only needed to make the code compile
108  // If ValueType is complex, this branch will never be taken
109  // If ValueType is real, the cast is a no-op
110  fn(dynamic_cast<const Dense*>(dense_in->create_real_view().get()),
111  dynamic_cast<Dense*>(dense_out->create_real_view().get()));
112  } else {
113  precision_dispatch<ValueType>(fn, in, out);
114  }
115 }
116 
117 
127 template <typename ValueType, typename Function>
128 void precision_dispatch_real_complex(Function fn, const LinOp* alpha,
129  const LinOp* in, LinOp* out)
130 {
131  // do we need to convert complex Dense to real Dense?
132  // all real dense vectors are intra-convertible, thus by casting to
133  // ConvertibleTo<matrix::Dense<>>, we can check whether a LinOp is a real
134  // dense matrix:
135  auto complex_to_real =
136  !(is_complex<ValueType>() ||
137  dynamic_cast<const ConvertibleTo<matrix::Dense<>>*>(in));
138  if (complex_to_real) {
139  auto dense_in = make_temporary_conversion<to_complex<ValueType>>(in);
140  auto dense_out = make_temporary_conversion<to_complex<ValueType>>(out);
141  auto dense_alpha = make_temporary_conversion<ValueType>(alpha);
142  using Dense = matrix::Dense<ValueType>;
143  // These dynamic_casts are only needed to make the code compile
144  // If ValueType is complex, this branch will never be taken
145  // If ValueType is real, the cast is a no-op
146  fn(dense_alpha.get(),
147  dynamic_cast<const Dense*>(dense_in->create_real_view().get()),
148  dynamic_cast<Dense*>(dense_out->create_real_view().get()));
149  } else {
150  precision_dispatch<ValueType>(fn, alpha, in, out);
151  }
152 }
153 
154 
164 template <typename ValueType, typename Function>
165 void precision_dispatch_real_complex(Function fn, const LinOp* alpha,
166  const LinOp* in, const LinOp* beta,
167  LinOp* out)
168 {
169  // do we need to convert complex Dense to real Dense?
170  // all real dense vectors are intra-convertible, thus by casting to
171  // ConvertibleTo<matrix::Dense<>>, we can check whether a LinOp is a real
172  // dense matrix:
173  auto complex_to_real =
174  !(is_complex<ValueType>() ||
175  dynamic_cast<const ConvertibleTo<matrix::Dense<>>*>(in));
176  if (complex_to_real) {
177  auto dense_in = make_temporary_conversion<to_complex<ValueType>>(in);
178  auto dense_out = make_temporary_conversion<to_complex<ValueType>>(out);
179  auto dense_alpha = make_temporary_conversion<ValueType>(alpha);
180  auto dense_beta = make_temporary_conversion<ValueType>(beta);
181  using Dense = matrix::Dense<ValueType>;
182  // These dynamic_casts are only needed to make the code compile
183  // If ValueType is complex, this branch will never be taken
184  // If ValueType is real, the cast is a no-op
185  fn(dense_alpha.get(),
186  dynamic_cast<const Dense*>(dense_in->create_real_view().get()),
187  dense_beta.get(),
188  dynamic_cast<Dense*>(dense_out->create_real_view().get()));
189  } else {
190  precision_dispatch<ValueType>(fn, alpha, in, beta, out);
191  }
192 }
193 
194 
224 template <typename ValueType, typename Function>
225 void mixed_precision_dispatch(Function fn, const LinOp* in, LinOp* out)
226 {
227 #ifdef GINKGO_MIXED_PRECISION
228  using fst_type = matrix::Dense<ValueType>;
229  using snd_type = matrix::Dense<next_precision<ValueType>>;
230  if (auto dense_in = dynamic_cast<const fst_type*>(in)) {
231  if (auto dense_out = dynamic_cast<fst_type*>(out)) {
232  fn(dense_in, dense_out);
233  } else if (auto dense_out = dynamic_cast<snd_type*>(out)) {
234  fn(dense_in, dense_out);
235  } else {
236  GKO_NOT_SUPPORTED(out);
237  }
238  } else if (auto dense_in = dynamic_cast<const snd_type*>(in)) {
239  if (auto dense_out = dynamic_cast<fst_type*>(out)) {
240  fn(dense_in, dense_out);
241  } else if (auto dense_out = dynamic_cast<snd_type*>(out)) {
242  fn(dense_in, dense_out);
243  } else {
244  GKO_NOT_SUPPORTED(out);
245  }
246  } else {
247  GKO_NOT_SUPPORTED(in);
248  }
249 #else
250  precision_dispatch<ValueType>(fn, in, out);
251 #endif
252 }
253 
254 
264 template <typename ValueType, typename Function,
265  std::enable_if_t<is_complex<ValueType>()>* = nullptr>
266 void mixed_precision_dispatch_real_complex(Function fn, const LinOp* in,
267  LinOp* out)
268 {
269 #ifdef GINKGO_MIXED_PRECISION
270  mixed_precision_dispatch<ValueType>(fn, in, out);
271 #else
272  precision_dispatch<ValueType>(fn, in, out);
273 #endif
274 }
275 
276 
277 template <typename ValueType, typename Function,
278  std::enable_if_t<!is_complex<ValueType>()>* = nullptr>
279 void mixed_precision_dispatch_real_complex(Function fn, const LinOp* in,
280  LinOp* out)
281 {
282 #ifdef GINKGO_MIXED_PRECISION
283  if (!dynamic_cast<const ConvertibleTo<matrix::Dense<>>*>(in)) {
284  mixed_precision_dispatch<to_complex<ValueType>>(
285  [&fn](auto dense_in, auto dense_out) {
286  fn(dense_in->create_real_view().get(),
287  dense_out->create_real_view().get());
288  },
289  in, out);
290  } else {
291  mixed_precision_dispatch<ValueType>(fn, in, out);
292  }
293 #else
294  precision_dispatch_real_complex<ValueType>(fn, in, out);
295 #endif
296 }
297 
298 
299 namespace experimental {
300 
301 
302 #if GINKGO_BUILD_MPI
303 
304 
305 namespace distributed {
306 
307 
333 template <typename ValueType>
334 detail::temporary_conversion<experimental::distributed::Vector<ValueType>>
336 {
337  auto result = detail::temporary_conversion<
339  template create<
341  matrix);
342  if (!result) {
343  GKO_NOT_SUPPORTED(matrix);
344  }
345  return result;
346 }
347 
348 
352 template <typename ValueType>
353 detail::temporary_conversion<const experimental::distributed::Vector<ValueType>>
355 {
356  auto result = detail::temporary_conversion<
358  template create<
360  matrix);
361  if (!result) {
362  GKO_NOT_SUPPORTED(matrix);
363  }
364  return result;
365 }
366 
367 
382 template <typename ValueType, typename Function, typename... Args>
383 void precision_dispatch(Function fn, Args*... linops)
384 {
385  fn(distributed::make_temporary_conversion<ValueType>(linops).get()...);
386 }
387 
388 
398 template <typename ValueType, typename Function>
399 void precision_dispatch_real_complex(Function fn, const LinOp* in, LinOp* out)
400 {
401  auto complex_to_real = !(
402  is_complex<ValueType>() ||
404  in));
405  if (complex_to_real) {
406  auto dense_in =
407  distributed::make_temporary_conversion<to_complex<ValueType>>(in);
408  auto dense_out =
409  distributed::make_temporary_conversion<to_complex<ValueType>>(out);
411  // These dynamic_casts are only needed to make the code compile
412  // If ValueType is complex, this branch will never be taken
413  // If ValueType is real, the cast is a no-op
414  fn(dynamic_cast<const Vector*>(dense_in->create_real_view().get()),
415  dynamic_cast<Vector*>(dense_out->create_real_view().get()));
416  } else {
417  distributed::precision_dispatch<ValueType>(fn, in, out);
418  }
419 }
420 
421 
425 template <typename ValueType, typename Function>
426 void precision_dispatch_real_complex(Function fn, const LinOp* alpha,
427  const LinOp* in, LinOp* out)
428 {
429  auto complex_to_real = !(
430  is_complex<ValueType>() ||
432  in));
433  if (complex_to_real) {
434  auto dense_in =
435  distributed::make_temporary_conversion<to_complex<ValueType>>(in);
436  auto dense_out =
437  distributed::make_temporary_conversion<to_complex<ValueType>>(out);
438  auto dense_alpha = gko::make_temporary_conversion<ValueType>(alpha);
440  // These dynamic_casts are only needed to make the code compile
441  // If ValueType is complex, this branch will never be taken
442  // If ValueType is real, the cast is a no-op
443  fn(dense_alpha.get(),
444  dynamic_cast<const Vector*>(dense_in->create_real_view().get()),
445  dynamic_cast<Vector*>(dense_out->create_real_view().get()));
446  } else {
447  fn(gko::make_temporary_conversion<ValueType>(alpha).get(),
448  distributed::make_temporary_conversion<ValueType>(in).get(),
449  distributed::make_temporary_conversion<ValueType>(out).get());
450  }
451 }
452 
453 
457 template <typename ValueType, typename Function>
458 void precision_dispatch_real_complex(Function fn, const LinOp* alpha,
459  const LinOp* in, const LinOp* beta,
460  LinOp* out)
461 {
462  auto complex_to_real = !(
463  is_complex<ValueType>() ||
465  in));
466  if (complex_to_real) {
467  auto dense_in =
468  distributed::make_temporary_conversion<to_complex<ValueType>>(in);
469  auto dense_out =
470  distributed::make_temporary_conversion<to_complex<ValueType>>(out);
471  auto dense_alpha = gko::make_temporary_conversion<ValueType>(alpha);
472  auto dense_beta = gko::make_temporary_conversion<ValueType>(beta);
474  // These dynamic_casts are only needed to make the code compile
475  // If ValueType is complex, this branch will never be taken
476  // If ValueType is real, the cast is a no-op
477  fn(dense_alpha.get(),
478  dynamic_cast<const Vector*>(dense_in->create_real_view().get()),
479  dense_beta.get(),
480  dynamic_cast<Vector*>(dense_out->create_real_view().get()));
481  } else {
482  fn(gko::make_temporary_conversion<ValueType>(alpha).get(),
483  distributed::make_temporary_conversion<ValueType>(in).get(),
484  gko::make_temporary_conversion<ValueType>(beta).get(),
485  distributed::make_temporary_conversion<ValueType>(out).get());
486  }
487 }
488 
489 
490 } // namespace distributed
491 
492 
506 template <typename ValueType, typename Function>
507 void precision_dispatch_real_complex_distributed(Function fn, const LinOp* in,
508  LinOp* out)
509 {
510  if (dynamic_cast<const experimental::distributed::DistributedBase*>(in)) {
511  experimental::distributed::precision_dispatch_real_complex<ValueType>(
512  fn, in, out);
513  } else {
514  gko::precision_dispatch_real_complex<ValueType>(fn, in, out);
515  }
516 }
517 
518 
523 template <typename ValueType, typename Function>
524 void precision_dispatch_real_complex_distributed(Function fn,
525  const LinOp* alpha,
526  const LinOp* in, LinOp* out)
527 {
528  if (dynamic_cast<const experimental::distributed::DistributedBase*>(in)) {
529  experimental::distributed::precision_dispatch_real_complex<ValueType>(
530  fn, alpha, in, out);
531  } else {
532  gko::precision_dispatch_real_complex<ValueType>(fn, alpha, in, out);
533  }
534 }
535 
536 
541 template <typename ValueType, typename Function>
542 void precision_dispatch_real_complex_distributed(Function fn,
543  const LinOp* alpha,
544  const LinOp* in,
545  const LinOp* beta, LinOp* out)
546 {
547  if (dynamic_cast<const experimental::distributed::DistributedBase*>(in)) {
548  experimental::distributed::precision_dispatch_real_complex<ValueType>(
549  fn, alpha, in, beta, out);
550  } else {
551  gko::precision_dispatch_real_complex<ValueType>(fn, alpha, in, beta,
552  out);
553  }
554 }
555 
556 
557 #else
558 
559 
570 template <typename ValueType, typename Function, typename... Args>
571 void precision_dispatch_real_complex_distributed(Function fn, Args*... args)
572 {
573  precision_dispatch_real_complex<ValueType>(fn, args...);
574 }
575 
576 
577 #endif
578 
579 
580 } // namespace experimental
581 } // namespace gko
582 
583 
584 #endif // GKO_PUBLIC_CORE_BASE_PRECISION_DISPATCH_HPP_
gko::LinOp
Definition: lin_op.hpp:118
gko::matrix::Dense
Dense is a matrix format which explicitly stores all values of the matrix.
Definition: dense_cache.hpp:20
gko::experimental::distributed::Vector
Vector is a format which explicitly stores (multiple) distributed column vectors in a dense storage f...
Definition: matrix.hpp:138
gko::mixed_precision_dispatch_real_complex
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:266
gko::experimental::distributed::precision_dispatch_real_complex
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:399
gko
The Ginkgo namespace.
Definition: abstract_factory.hpp:20
gko::precision_dispatch
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:78
gko::experimental::distributed::precision_dispatch
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:383
gko::mixed_precision_dispatch
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:225
gko::experimental::distributed::make_temporary_conversion
detail::temporary_conversion< experimental::distributed::Vector< ValueType > > make_temporary_conversion(LinOp *matrix)
Convert the given LinOp from experimental::distributed::Vector<...> to experimental::distributed::Vec...
Definition: precision_dispatch.hpp:335
gko::precision_dispatch_real_complex
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:94
gko::make_temporary_conversion
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
gko::ConvertibleTo
ConvertibleTo interface is used to mark that the implementer can be converted to the object of Result...
Definition: polymorphic_object.hpp:471