Arcane  4.2.2.0
Developer documentation
Loading...
Searching...
No Matches
BuiltinBackend.h
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2026 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com)
4// See the top-level COPYRIGHT file for details.
5// SPDX-License-Identifier: Apache-2.0
6//-----------------------------------------------------------------------------
7/*---------------------------------------------------------------------------*/
8/* BuiltinBackend.h (C) 2000-2026 */
9/* */
10/* Builtin backend using CSR matrix. */
11/*---------------------------------------------------------------------------*/
12#ifndef ARCCORE_ALINA_BUILTINBACKEND_H
13#define ARCCORE_ALINA_BUILTINBACKEND_H
14/*---------------------------------------------------------------------------*/
15/*---------------------------------------------------------------------------*/
16/*
17 * This file is based on the work on AMGCL library (version march 2026)
18 * which can be found at https://github.com/ddemidov/amgcl.
19 *
20 * Copyright (c) 2012-2022 Denis Demidov <dennis.demidov@gmail.com>
21 * SPDX-License-Identifier: MIT
22 */
23/*---------------------------------------------------------------------------*/
24/*---------------------------------------------------------------------------*/
25
26//#pragma GCC diagnostic ignored "-Wconversion"
27
28/*---------------------------------------------------------------------------*/
29/*---------------------------------------------------------------------------*/
30
31#include "arccore/alina/CSRMatrixOperations.h"
32#include "arccore/alina/SkylineLUSolver.h"
33#include "arccore/alina/MatrixOperationsImpl.h"
34
35#include "arccore/base/ConcurrencyBase.h"
36#include "arccore/common/SmallArray.h"
37
38#include <numeric>
39#include <random>
40
41/*---------------------------------------------------------------------------*/
42/*---------------------------------------------------------------------------*/
43
44namespace Arcane::Alina
45{
46
47/*---------------------------------------------------------------------------*/
48/*---------------------------------------------------------------------------*/
56template <typename ValueType,
57 typename ColumnType = AlinaDefaultColumnType,
58 typename PointerType = AlinaDefaultRowIndexType>
60{
61 typedef ValueType value_type;
62 typedef ColumnType index_type;
63 typedef ColumnType col_type;
64 typedef PointerType ptr_type;
65
66 typedef typename math::rhs_of<value_type>::type rhs_type;
67
68 struct provides_row_iterator : std::true_type
69 {};
70
72 typedef numa_vector<rhs_type> vector;
73 typedef numa_vector<value_type> matrix_diagonal;
74 typedef solver::SkylineLUSolver<value_type> direct_solver;
75
78
79 static std::string name() { return "builtin"; }
80
81 // Copy matrix. This is a noop for builtin backend.
82 static std::shared_ptr<matrix>
83 copy_matrix(std::shared_ptr<matrix> A, const params&)
84 {
85 return A;
86 }
87
88 // Copy vector to builtin backend.
89 template <class T>
90 static std::shared_ptr<numa_vector<T>>
91 copy_vector(const std::vector<T>& x, const params&)
92 {
93 return std::make_shared<numa_vector<T>>(x);
94 }
95
96 // Copy vector to builtin backend. This is a noop for builtin backend.
97 template <class T>
98 static std::shared_ptr<numa_vector<T>>
99 copy_vector(std::shared_ptr<numa_vector<T>> x, const params&)
100 {
101 return x;
102 }
103
104 // Create vector of the specified size.
105 static std::shared_ptr<vector>
106 create_vector(size_t size, const params&)
107 {
108 return std::make_shared<vector>(size);
109 }
110
111 struct gather
112 {
113 std::vector<col_type> I;
114
115 gather(size_t /*size*/, const std::vector<col_type>& I, const params&)
116 : I(I)
117 {}
118
119 template <class InVec, class OutVec>
120 void operator()(const InVec& vec, OutVec& vals) const
121 {
122 for (size_t i = 0; i < I.size(); ++i)
123 vals[i] = vec[I[i]];
124 }
125 };
126
127 struct scatter
128 {
129 std::vector<col_type> I;
130
131 scatter(size_t /*size*/, const std::vector<col_type>& I, const params&)
132 : I(I)
133 {}
134
135 template <class InVec, class OutVec>
136 void operator()(const InVec& vals, OutVec& vec) const
137 {
138 for (size_t i = 0; i < I.size(); ++i)
139 vec[I[i]] = vals[i];
140 }
141 };
142
143 // Create direct solver for coarse level
144 static std::shared_ptr<direct_solver>
145 create_solver(std::shared_ptr<matrix> A, const params&)
146 {
147 return std::make_shared<direct_solver>(*A);
148 }
149};
150
151/*---------------------------------------------------------------------------*/
152/*---------------------------------------------------------------------------*/
153
154} // namespace Arcane::Alina
155
156namespace Arcane::Alina::backend
157{
158
159/*---------------------------------------------------------------------------*/
160/*---------------------------------------------------------------------------*/
161
162template <class T>
163struct is_builtin_vector : std::false_type
164{};
165
166template <class V>
167struct is_builtin_vector<std::vector<V>> : std::is_arithmetic<V>
168{};
169
170template <class V>
171struct is_builtin_vector<UniqueArray<V>> : std::is_arithmetic<V>
172{};
173
174template <class V>
175struct is_builtin_vector<SmallSpan<V>> : std::true_type
176{};
177
178template <class V>
179struct is_builtin_vector<Span<V>> : std::true_type
180{};
181
182template <class V>
183struct is_builtin_vector<numa_vector<V>> : std::true_type
184{};
185
186//---------------------------------------------------------------------------
187// Specialization of backend interface
188//---------------------------------------------------------------------------
189template <typename T1, typename T2>
190struct backends_compatible<BuiltinBackend<T1>, BuiltinBackend<T2>> : std::true_type
191{};
192
193template <typename V, typename C, typename P>
194struct rows_impl<CSRMatrix<V, C, P>>
195{
196 static size_t get(const CSRMatrix<V, C, P>& A)
197 {
198 return A.nbRow();
199 }
200};
201
202template <typename V, typename C, typename P>
203struct cols_impl<CSRMatrix<V, C, P>>
204{
205 static size_t get(const CSRMatrix<V, C, P>& A)
206 {
207 return A.ncols;
208 }
209};
210
211template <class Vec>
212struct bytes_impl<Vec, typename std::enable_if<is_builtin_vector<Vec>::value>::type>
213{
214 static size_t get(const Vec& x)
215 {
216 typedef typename backend::value_type<Vec>::type V;
217 return x.size() * sizeof(V);
218 }
219};
220
221template <typename V, typename C, typename P>
222struct ptr_data_impl<CSRMatrix<V, C, P>>
223{
224 typedef const P* type;
225 static type get(const CSRMatrix<V, C, P>& A)
226 {
227 return &A.ptr[0];
228 }
229};
230
231template <typename V, typename C, typename P>
232struct col_data_impl<CSRMatrix<V, C, P>>
233{
234 typedef const C* type;
235 static type get(const CSRMatrix<V, C, P>& A)
236 {
237 return &A.col[0];
238 }
239};
240
241template <typename V, typename C, typename P>
242struct val_data_impl<CSRMatrix<V, C, P>>
243{
244 typedef const V* type;
245 static type get(const CSRMatrix<V, C, P>& A)
246 {
247 return &A.val[0];
248 }
249};
250
251template <typename V, typename C, typename P>
252struct nonzeros_impl<CSRMatrix<V, C, P>>
253{
254 static size_t get(const CSRMatrix<V, C, P>& A)
255 {
256 return A.nbRow() == 0 ? 0 : A.ptr[A.nbRow()];
257 }
258};
259
260template <typename V, typename C, typename P>
262{
263 static size_t get(const CSRMatrix<V, C, P>& A, size_t row)
264 {
265 return A.ptr[row + 1] - A.ptr[row];
266 }
267};
268
269template <class Vec>
270struct clear_impl<Vec, typename std::enable_if<is_builtin_vector<Vec>::value>::type>
271{
272 static void apply(Vec& x)
273 {
274 typedef typename backend::value_type<Vec>::type V;
275
276 const size_t n = x.size();
277 arccoreParallelFor(0, n, ForLoopRunInfo{}, [&](Int32 begin, Int32 size) {
278 for (ptrdiff_t i = begin; i < (begin + size); ++i) {
279 x[i] = math::zero<V>();
280 }
281 });
282 }
283};
284
285/*---------------------------------------------------------------------------*/
286/*---------------------------------------------------------------------------*/
287
288template <class Vec1, class Vec2>
289struct inner_product_impl<Vec1, Vec2,
290 typename std::enable_if<
291 is_builtin_vector<Vec1>::value &&
292 is_builtin_vector<Vec2>::value>::type>
293{
294 typedef typename value_type<Vec1>::type V;
295
296 typedef typename math::inner_product_impl<V>::return_type return_type;
297
298 static return_type get(const Vec1& x, const Vec2& y)
299 {
301 return parallel(x, y);
302 }
303 else {
304 return serial(x, y);
305 }
306 }
307
308 static return_type serial(const Vec1& x, const Vec2& y)
309 {
310 const size_t n = x.size();
311
312 return_type s = math::zero<return_type>();
313 return_type c = math::zero<return_type>();
314
315 for (ptrdiff_t i = 0; i < static_cast<ptrdiff_t>(n); ++i) {
316 return_type d = math::inner_product(x[i], y[i]) - c;
317 return_type t = s + d;
318 c = (t - s) - d;
319 s = t;
320 }
321
322 return s;
323 }
324
325 static return_type parallel(const Vec1& x, const Vec2& y)
326 {
327 const size_t n = x.size();
328 // TODO: Use padding to avoid sharing cache line between threads
331 const return_type zero = math::zero<return_type>();
332 sum_array.resize(nb_thread, zero);
333 SmallSpan<return_type> sum = sum_array.view();
334 for (Int32 i = 0; i < nb_thread; ++i)
335 sum[i] = zero;
336 // NOTE GG: NOT reproducible
337
338 arccoreParallelFor(0, n, ForLoopRunInfo{}, [&](Int32 begin, Int32 size) {
339 const int tid = TaskFactory::currentTaskThreadIndex();
340 return_type s = zero;
341 return_type c = zero;
342 for (ptrdiff_t i = begin; i < (begin + size); ++i) {
343 return_type d = math::inner_product(x[i], y[i]) - c;
344 return_type t = s + d;
345 c = (t - s) - d;
346 s = t;
347 }
348
349 sum[tid] += s;
350 });
351 return_type total = zero;
352 for (Int32 i = 0; i < nb_thread; ++i) {
353 total += sum[i];
354 }
355 return total;
356 }
357};
358
359/*---------------------------------------------------------------------------*/
360/*---------------------------------------------------------------------------*/
361
362template <class A, class Vec1, class B, class Vec2>
363struct axpby_impl<A, Vec1, B, Vec2, typename std::enable_if<is_builtin_vector<Vec1>::value && is_builtin_vector<Vec2>::value>::type>
364{
365 static void apply(A a, const Vec1& x, B b, Vec2& y)
366 {
367 const size_t n = x.size();
368 arccoreParallelFor(0, n, ForLoopRunInfo{}, [&](Int32 begin, Int32 size) {
369 if (!math::is_zero(b)) {
370 for (ptrdiff_t i = begin; i < (begin + size); ++i) {
371 y[i] = a * x[i] + b * y[i];
372 }
373 }
374 else {
375 for (ptrdiff_t i = begin; i < (begin + size); ++i) {
376 y[i] = a * x[i];
377 }
378 }
379 });
380 }
381};
382
383/*---------------------------------------------------------------------------*/
384/*---------------------------------------------------------------------------*/
385
386template <class A, class Vec1, class B, class Vec2, class C, class Vec3>
387struct axpbypcz_impl<A, Vec1, B, Vec2, C, Vec3,
388 typename std::enable_if<
389 is_builtin_vector<Vec1>::value &&
390 is_builtin_vector<Vec2>::value &&
391 is_builtin_vector<Vec3>::value>::type>
392{
393 static void apply(A a, const Vec1& x, B b, const Vec2& y, C c, Vec3& z)
394 {
395 const size_t n = x.size();
396 arccoreParallelFor(0, n, ForLoopRunInfo{}, [&](Int32 begin, Int32 size) {
397 if (!math::is_zero(c)) {
398 for (ptrdiff_t i = begin; i < (begin + size); ++i) {
399 z[i] = a * x[i] + b * y[i] + c * z[i];
400 }
401 }
402 else {
403 for (ptrdiff_t i = begin; i < (begin + size); ++i) {
404 z[i] = a * x[i] + b * y[i];
405 }
406 }
407 });
408 }
409};
410
411/*---------------------------------------------------------------------------*/
412/*---------------------------------------------------------------------------*/
413
414template <class Alpha, class Vec1, class Vec2, class Beta, class Vec3>
415struct vmul_impl<Alpha, Vec1, Vec2, Beta, Vec3,
416 typename std::enable_if<
417 is_builtin_vector<Vec1>::value &&
418 is_builtin_vector<Vec2>::value &&
419 is_builtin_vector<Vec3>::value &&
420 math::static_rows<typename value_type<Vec1>::type>::value == math::static_rows<typename value_type<Vec2>::type>::value &&
421 math::static_rows<typename value_type<Vec1>::type>::value == math::static_rows<typename value_type<Vec3>::type>::value>::type>
422{
423 static void apply(Alpha a, const Vec1& x, const Vec2& y, Beta b, Vec3& z)
424 {
425 const size_t n = x.size();
426 arccoreParallelFor(0, n, ForLoopRunInfo{}, [&](Int32 begin, Int32 size) {
427 if (!math::is_zero(b)) {
428 for (ptrdiff_t i = begin; i < (begin + size); ++i) {
429 z[i] = a * x[i] * y[i] + b * z[i];
430 }
431 }
432 else {
433 for (ptrdiff_t i = begin; i < (begin + size); ++i) {
434 z[i] = a * x[i] * y[i];
435 }
436 }
437 });
438 }
439};
440
441/*---------------------------------------------------------------------------*/
442/*---------------------------------------------------------------------------*/
443
444// Support for mixed scalar/nonscalar types
445template <class Alpha, class Vec1, class Vec2, class Beta, class Vec3>
446struct vmul_impl<Alpha, Vec1, Vec2, Beta, Vec3,
447 typename std::enable_if<is_builtin_vector<Vec1>::value &&
448 is_builtin_vector<Vec2>::value &&
449 is_builtin_vector<Vec3>::value &&
450 (math::static_rows<typename value_type<Vec1>::type>::value != math::static_rows<typename value_type<Vec2>::type>::value ||
451 math::static_rows<typename value_type<Vec1>::type>::value != math::static_rows<typename value_type<Vec3>::type>::value)>::type>
452{
453 static void apply(Alpha a, const Vec1& x, const Vec2& y, Beta b, Vec3& z)
454 {
455 typedef typename value_type<Vec1>::type M_type;
456 auto Y = backend::reinterpret_as_rhs<M_type>(y);
457 auto Z = backend::reinterpret_as_rhs<M_type>(z);
458
459 const size_t n = x.size();
460
461 arccoreParallelFor(0, n, ForLoopRunInfo{}, [&](Int32 begin, Int32 size) {
462 if (!math::is_zero(b)) {
463 for (ptrdiff_t i = begin; i < (begin + size); ++i) {
464 Z[i] = a * x[i] * Y[i] + b * Z[i];
465 }
466 }
467 else {
468 for (ptrdiff_t i = begin; i < (begin + size); ++i) {
469 Z[i] = a * x[i] * Y[i];
470 }
471 }
472 });
473 }
474};
475
476/*---------------------------------------------------------------------------*/
477/*---------------------------------------------------------------------------*/
478
479template <class Vec1, class Vec2>
480struct copy_impl<Vec1, Vec2,
481 typename std::enable_if<
482 is_builtin_vector<Vec1>::value &&
483 is_builtin_vector<Vec2>::value>::type>
484{
485 static void apply(const Vec1& x, Vec2& y)
486 {
487 const size_t n = x.size();
488 arccoreParallelFor(0, n, ForLoopRunInfo{}, [&](Int32 begin, Int32 size) {
489 for (ptrdiff_t i = begin; i < (begin + size); ++i) {
490 y[i] = x[i];
491 }
492 });
493 }
494};
495
496template <class MatrixValue, class Vector, bool IsConst>
497struct reinterpret_as_rhs_impl<MatrixValue, Vector, IsConst,
498 typename std::enable_if<is_builtin_vector<Vector>::value>::type>
499{
500 typedef typename backend::value_type<Vector>::type src_type;
501 typedef typename math::scalar_of<src_type>::type scalar_type;
502 typedef typename math::rhs_of<MatrixValue>::type rhs_type;
503 typedef typename math::replace_scalar<rhs_type, scalar_type>::type dst_type;
504 typedef typename std::conditional<IsConst, const dst_type*, dst_type*>::type ptr_type;
505 typedef typename std::conditional<IsConst, const dst_type, dst_type>::type return_value_type;
506 typedef Span<return_value_type> return_type;
507
508 template <class V>
509 static return_type get(V&& x)
510 {
511 auto ptr = reinterpret_cast<ptr_type>(&x[0]);
512 const size_t n = x.size() * sizeof(src_type) / sizeof(dst_type);
513 return Span<return_value_type>(ptr, n);
514 }
515};
516
517/*---------------------------------------------------------------------------*/
518/*---------------------------------------------------------------------------*/
519
520namespace detail
521{
522
523 template <typename V, typename C, typename P>
525 : std::true_type
526 {};
527
528} // namespace detail
529
530} // namespace Arcane::Alina::backend
531
532namespace Arcane::Alina::detail
533{
534
535// Backend with scalar value_type of highest precision.
536template <class V1, class V2>
538 typename std::enable_if<math::static_rows<V1>::value != 1 || math::static_rows<V2>::value != 1>::type>
539{
540 typedef typename math::scalar_of<V1>::type S1;
541 typedef typename math::scalar_of<V2>::type S2;
542
543 typedef typename std::conditional<(sizeof(S1) > sizeof(S2)), BuiltinBackend<S1>, BuiltinBackend<S2>>::type type;
544};
545
546} // namespace Arcane::Alina::detail
547
548#endif
Class to handle empty parameter list.
Definition AlinaUtils.h:91
NUMA-aware vector container.
Definition NumaVector.h:42
Direct solver that uses Skyline LU factorization.
void resize(Int64 s)
Changes the number of elements in the array to s.
ArrayView< T > view() const
Mutable view of this array.
static Int32 maxAllowedThread()
Maximum number of allowed threads for multi-threading.
Loop execution information.
1D data array with pre-allocated stack buffer.
View of an array of elements of type T.
Definition Span.h:803
constexpr __host__ __device__ SizeType size() const noexcept
Returns the size of the array.
Definition Span.h:325
View of an array of elements of type T.
Definition Span.h:633
static Int32 currentTaskThreadIndex()
Index (between 0 and nbAllowedThread()-1) of the thread executing the current task.
1D data vector with value semantics (STL style).
Vector class, to be used by user.
void arccoreParallelFor(const ComplexForLoopRanges< RankValue, IndexType_ > &loop_ranges, const ForLoopRunInfo &run_info, const LambdaType &lambda_function, const ReducerArgs &... reducer_args)
Applies the lambda function lambda_function concurrently over the iteration interval given by loop_ra...
Definition ParallelFor.h:86
std::int32_t Int32
Signed integer type of 32 bits.
Sparse matrix stored in CSR (Compressed Sparse Row) format.
Definition CSRMatrix.h:98
Implementation for linear combination of two vectors.
Implementation for linear combination of three vectors.
Metafunction that checks if two backends are compatible.
Implementation for function returning number of bytes allocated for a matrix/vector.
Implementation for zeroing out a vector.
Implementation for function returning the number of columns in a matrix.
Implementation for vector copy.
Implementation for inner product.
Implementation for function returning the number of nonzeros in a matrix.
Reinterpret the vector to be compatible with the matrix value type.
Implementation for function returning the number of nonzeros in a matrix row.
Implementation for function returning the number of rows in a matrix.
Implementation for element-wise vector product.