Arcane  v4.1.10.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
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#include <boost/multi_array.hpp>
24
25#include "arccore/alina/QRFactorizationImpl.h"
26#include "arccore/alina/ValueTypeInterface.h"
27#include "arccore/alina/ValueTypeComplex.h"
28#include "arccore/alina/StaticMatrix.h"
29
30using namespace Arcane;
31
32template <class T>
34{
35 static T get()
36 {
37 static std::mt19937 gen;
38 static std::uniform_real_distribution<T> rnd;
39
40 return rnd(gen);
41 }
42};
43
44template <class T>
45T random()
46{
47 return make_random<T>::get();
48}
49
50template <class T>
51struct make_random<std::complex<T>>
52{
53 static std::complex<T> get()
54 {
55 return std::complex<T>(random<T>(), random<T>());
56 }
57};
58
59template <class T, int N, int M>
60struct make_random<Alina::StaticMatrix<T, N, M>>
61{
62 typedef Alina::StaticMatrix<T, N, M> matrix;
63 static matrix get()
64 {
65 matrix A = Alina::math::zero<matrix>();
66 for (int i = 0; i < N; ++i)
67 for (int j = 0; j < M; ++j)
68 A(i, j) = make_random<T>::get();
69 return A;
70 }
71};
72
73template <class value_type, Alina::detail::storage_order order>
74void qr_factorize(int n, int m)
75{
76 std::cout << "factorize " << n << " " << m << std::endl;
77 typedef typename std::conditional<order == Alina::detail::row_major,
78 boost::c_storage_order,
79 boost::fortran_storage_order>::type ma_storage_order;
80
81 boost::multi_array<value_type, 2> A0(boost::extents[n][m], ma_storage_order());
82
83 for (int i = 0; i < n; ++i)
84 for (int j = 0; j < m; ++j)
85 A0[i][j] = random<value_type>();
86
87 boost::multi_array<value_type, 2> A = A0;
88
90
91 qr.factorize(n, m, A.data(), order);
92
93 // Check that A = QR
94 int p = std::min(n, m);
95 for (int i = 0; i < n; ++i) {
96 for (int j = 0; j < m; ++j) {
97 value_type sum = Alina::math::zero<value_type>();
98
99 for (int k = 0; k < p; ++k)
100 sum += qr.Q(i, k) * qr.R(k, j);
101
102 sum -= A0[i][j];
103
104 ASSERT_NEAR(Alina::math::norm(sum), 0.0, 1e-8);
105 }
106 }
107}
108
109template <class value_type, Alina::detail::storage_order order>
110void qr_solve(int n, int m)
111{
112 std::cout << "solve " << n << " " << m << std::endl;
113 typedef typename std::conditional<order == Alina::detail::row_major,
114 boost::c_storage_order,
115 boost::fortran_storage_order>::type ma_storage_order;
116
117 typedef typename Alina::math::rhs_of<value_type>::type rhs_type;
118
119 boost::multi_array<value_type, 2> A0(boost::extents[n][m], ma_storage_order());
120
121 for (int i = 0; i < n; ++i)
122 for (int j = 0; j < m; ++j)
123 A0[i][j] = random<value_type>();
124
125 boost::multi_array<value_type, 2> A = A0;
126
128
129 std::vector<rhs_type> f0(n, Alina::math::constant<rhs_type>(1));
130 std::vector<rhs_type> f = f0;
131
132 std::vector<rhs_type> x(m);
133
134 qr.solve(n, m, A.data(), f.data(), x.data(), order);
135
136 std::vector<rhs_type> Ax(n);
137 for (int i = 0; i < n; ++i) {
138 rhs_type sum = Alina::math::zero<rhs_type>();
139 for (int j = 0; j < m; ++j)
140 sum += A0[i][j] * x[j];
141
142 Ax[i] = sum;
143
144 if (n < m) {
145 ASSERT_NEAR(Alina::math::norm(sum - f0[i]), 0.0, 1e-8);
146 }
147 }
148
149 if (n >= m) {
150 for (int i = 0; i < m; ++i) {
151 rhs_type sumx = Alina::math::zero<rhs_type>();
152 rhs_type sumf = Alina::math::zero<rhs_type>();
153
154 for (int j = 0; j < n; ++j) {
155 sumx += Alina::math::adjoint(A0[j][i]) * Ax[j];
156 sumf += Alina::math::adjoint(A0[j][i]) * f0[j];
157 }
158
159 rhs_type delta = sumx - sumf;
160
161 ASSERT_NEAR(Alina::math::norm(delta), 0.0, 1e-8);
162 }
163 }
164}
165
166TEST(alina_test_qr, test_qr_factorize)
167{
168 const int shape[][2] = {
169 { 3, 3 },
170 { 3, 5 },
171 { 5, 3 },
172 { 5, 5 }
173 };
174
175 const int n = sizeof(shape) / sizeof(shape[0]);
176
177 for (int i = 0; i < n; ++i) {
178 qr_factorize<double, Alina::detail::row_major>(shape[i][0], shape[i][1]);
179 qr_factorize<double, Alina::detail::col_major>(shape[i][0], shape[i][1]);
180 qr_factorize<std::complex<double>, Alina::detail::row_major>(shape[i][0], shape[i][1]);
181 qr_factorize<std::complex<double>, Alina::detail::col_major>(shape[i][0], shape[i][1]);
182 qr_factorize<Alina::StaticMatrix<double, 2, 2>, Alina::detail::row_major>(shape[i][0], shape[i][1]);
183 qr_factorize<Alina::StaticMatrix<double, 2, 2>, Alina::detail::col_major>(shape[i][0], shape[i][1]);
184 }
185}
186
187TEST(alina_test_qr, test_qr_solve)
188{
189 const int shape[][2] = {
190 { 3, 3 },
191 { 3, 5 },
192 { 5, 3 },
193 { 5, 5 }
194 };
195
196 const int n = sizeof(shape) / sizeof(shape[0]);
197
198 for (int i = 0; i < n; ++i) {
199 qr_solve<double, Alina::detail::row_major>(shape[i][0], shape[i][1]);
200 qr_solve<double, Alina::detail::col_major>(shape[i][0], shape[i][1]);
201 qr_solve<std::complex<double>, Alina::detail::row_major>(shape[i][0], shape[i][1]);
202 qr_solve<std::complex<double>, Alina::detail::col_major>(shape[i][0], shape[i][1]);
203 qr_solve<Alina::StaticMatrix<double, 2, 2>, Alina::detail::row_major>(shape[i][0], shape[i][1]);
204 qr_solve<Alina::StaticMatrix<double, 2, 2>, Alina::detail::col_major>(shape[i][0], shape[i][1]);
205 }
206}
207
208TEST(alina_test_qr, qr_issue_39)
209{
210 boost::multi_array<double, 2> A0(boost::extents[2][2]);
211 A0[0][0] = 1e+0;
212 A0[0][1] = 1e+0;
213 A0[1][0] = 1e-8;
214 A0[1][1] = 1e+0;
215
216 boost::multi_array<double, 2> A = A0;
217
219
220 qr.factorize(2, 2, A.data());
221
222 // Check that A = QR
223 for (int i = 0; i < 2; ++i) {
224 for (int j = 0; j < 2; ++j) {
225 double sum = 0;
226 for (int k = 0; k < 2; ++k)
227 sum += qr.Q(i, k) * qr.R(k, j);
228
229 sum -= A0[i][j];
230
231 ASSERT_NEAR(sum, 0.0, 1e-8);
232 }
233 }
234}
-*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-