Arcane  4.2.1.0
Developer documentation
Loading...
Searching...
No Matches
TestQR.cc
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/*---------------------------------------------------------------------------*/
9/*
10 * This file is based on the work on AMGCL library (version march 2026)
11 * which can be found at https://github.com/ddemidov/amgcl.
12 *
13 * Copyright (c) 2012-2022 Denis Demidov <dennis.demidov@gmail.com>
14 * SPDX-License-Identifier: MIT
15 */
16/*---------------------------------------------------------------------------*/
17/*---------------------------------------------------------------------------*/
18
19#include <gtest/gtest.h>
20
21#include <vector>
22#include <random>
23
24#include "arccore/common/NumArray.h"
25
26#include "arccore/alina/QRFactorizationImpl.h"
27#include "arccore/alina/ValueTypeInterface.h"
28#include "arccore/alina/ValueTypeComplex.h"
29#include "arccore/alina/StaticMatrix.h"
30
31using namespace Arcane;
32
33template <class T>
35{
36 static T get()
37 {
38 static std::mt19937 gen;
39 static std::uniform_real_distribution<T> rnd;
40
41 return rnd(gen);
42 }
43};
44
45template <class T>
46T random()
47{
48 return make_random<T>::get();
49}
50
51template <class T>
52struct make_random<std::complex<T>>
53{
54 static std::complex<T> get()
55 {
56 return std::complex<T>(random<T>(), random<T>());
57 }
58};
59
60template <class T, int N, int M>
61struct make_random<Alina::StaticMatrix<T, N, M>>
62{
63 typedef Alina::StaticMatrix<T, N, M> matrix;
64 static matrix get()
65 {
66 matrix A = Alina::math::zero<matrix>();
67 for (int i = 0; i < N; ++i)
68 for (int j = 0; j < M; ++j)
69 A(i, j) = make_random<T>::get();
70 return A;
71 }
72};
73
74template <class value_type, Alina::detail::storage_order order>
75void qr_factorize(int n, int m)
76{
77 std::cout << "factorize " << n << " " << m << std::endl;
78 typedef typename std::conditional<order == Alina::detail::row_major,
80 LeftLayout>::type WantedLayout;
81
83
84 for (int i = 0; i < n; ++i)
85 for (int j = 0; j < m; ++j)
86 A0(i, j) = random<value_type>();
87
89
91
92 qr.factorize(n, m, A.data(), order);
93
94 // Check that A = QR
95 int p = std::min(n, m);
96 for (int i = 0; i < n; ++i) {
97 for (int j = 0; j < m; ++j) {
98 value_type sum = Alina::math::zero<value_type>();
99
100 for (int k = 0; k < p; ++k)
101 sum += qr.Q(i, k) * qr.R(k, j);
102
103 sum -= A0(i, j);
104
105 ASSERT_NEAR(Alina::math::norm(sum), 0.0, 1e-8);
106 }
107 }
108}
109
110template <class value_type, Alina::detail::storage_order order>
111void qr_solve(int n, int m)
112{
113 std::cout << "solve " << n << " " << m << std::endl;
114 typedef typename std::conditional<order == Alina::detail::row_major,
116 LeftLayout>::type WantedLayout;
117
118 typedef typename Alina::math::rhs_of<value_type>::type rhs_type;
119
121
122 for (int i = 0; i < n; ++i)
123 for (int j = 0; j < m; ++j)
124 A0(i, j) = random<value_type>();
125
127
129
130 std::vector<rhs_type> f0(n, Alina::math::constant<rhs_type>(1));
131 std::vector<rhs_type> f = f0;
132
133 std::vector<rhs_type> x(m);
134
135 qr.solve(n, m, A.data(), f.data(), x.data(), order);
136
137 std::vector<rhs_type> Ax(n);
138 for (int i = 0; i < n; ++i) {
139 rhs_type sum = Alina::math::zero<rhs_type>();
140 for (int j = 0; j < m; ++j)
141 sum += A0(i, j) * x[j];
142
143 Ax[i] = sum;
144
145 if (n < m) {
146 ASSERT_NEAR(Alina::math::norm(sum - f0[i]), 0.0, 1e-8);
147 }
148 }
149
150 if (n >= m) {
151 for (int i = 0; i < m; ++i) {
152 rhs_type sumx = Alina::math::zero<rhs_type>();
153 rhs_type sumf = Alina::math::zero<rhs_type>();
154
155 for (int j = 0; j < n; ++j) {
156 sumx += Alina::math::adjoint(A0(j, i)) * Ax[j];
157 sumf += Alina::math::adjoint(A0(j, i)) * f0[j];
158 }
159
160 rhs_type delta = sumx - sumf;
161
162 ASSERT_NEAR(Alina::math::norm(delta), 0.0, 1e-8);
163 }
164 }
165}
166
167TEST(alina_test_qr, test_qr_factorize)
168{
169 const int shape[][2] = {
170 { 3, 3 },
171 { 3, 5 },
172 { 5, 3 },
173 { 5, 5 }
174 };
175
176 const int n = sizeof(shape) / sizeof(shape[0]);
177
178 for (int i = 0; i < n; ++i) {
179 qr_factorize<double, Alina::detail::row_major>(shape[i][0], shape[i][1]);
180 qr_factorize<double, Alina::detail::col_major>(shape[i][0], shape[i][1]);
181 qr_factorize<std::complex<double>, Alina::detail::row_major>(shape[i][0], shape[i][1]);
182 qr_factorize<std::complex<double>, Alina::detail::col_major>(shape[i][0], shape[i][1]);
183 qr_factorize<Alina::StaticMatrix<double, 2, 2>, Alina::detail::row_major>(shape[i][0], shape[i][1]);
184 qr_factorize<Alina::StaticMatrix<double, 2, 2>, Alina::detail::col_major>(shape[i][0], shape[i][1]);
185 }
186}
187
188TEST(alina_test_qr, test_qr_solve)
189{
190 const int shape[][2] = {
191 { 3, 3 },
192 { 3, 5 },
193 { 5, 3 },
194 { 5, 5 }
195 };
196
197 const int n = sizeof(shape) / sizeof(shape[0]);
198
199 for (int i = 0; i < n; ++i) {
200 qr_solve<double, Alina::detail::row_major>(shape[i][0], shape[i][1]);
201 qr_solve<double, Alina::detail::col_major>(shape[i][0], shape[i][1]);
202 qr_solve<std::complex<double>, Alina::detail::row_major>(shape[i][0], shape[i][1]);
203 qr_solve<std::complex<double>, Alina::detail::col_major>(shape[i][0], shape[i][1]);
204 qr_solve<Alina::StaticMatrix<double, 2, 2>, Alina::detail::row_major>(shape[i][0], shape[i][1]);
205 qr_solve<Alina::StaticMatrix<double, 2, 2>, Alina::detail::col_major>(shape[i][0], shape[i][1]);
206 }
207}
208
209TEST(alina_test_qr, qr_issue_39)
210{
212 A0(0, 0) = 1e+0;
213 A0(0, 1) = 1e+0;
214 A0(1, 0) = 1e-8;
215 A0(1, 1) = 1e+0;
216
218
220
221 qr.factorize(2, 2, A.data());
222
223 // Check that A = QR
224 for (int i = 0; i < 2; ++i) {
225 for (int j = 0; j < 2; ++j) {
226 double sum = 0;
227 for (int k = 0; k < 2; ++k)
228 sum += qr.Q(i, k) * qr.R(k, j);
229
230 sum -= A0(i, j);
231
232 ASSERT_NEAR(sum, 0.0, 1e-8);
233 }
234 }
235}
Multi-dimensional arrays for numerical types accessible on accelerators.
DataType * data()
Base pointer of the array.
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --