Arcane  4.2.1.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
NonScalarSearch.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 * Ce fichier est basé sur le travail effectué sur la bibliothèque AMGCL (version mars 2026)
11 * qui peut être trouvé à 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 "arccore/alina/BuiltinBackend.h"
20#include "arccore/alina/RelaxationRuntime.h"
21#include "arccore/alina/CoarseningRuntime.h"
22#include "arccore/alina/SolverRuntime.h"
23#include "arccore/alina/PreconditionerRuntime.h"
24#include "arccore/alina/DeflatedSolver.h"
25#include "arccore/alina/AMG.h"
26#include "arccore/alina/Adapters.h"
27#include "arccore/alina/IO.h"
28#include "arccore/alina/Profiler.h"
29
30#include "arccore/common/internal/ProgramOptions.h"
31
32#include <iostream>
33#include <string>
34
35using namespace Arcane;
36
37using Alina::precondition;
38
39//---------------------------------------------------------------------------
40int main(int argc, char* argv[])
41{
42 auto& prof = Alina::Profiler::globalProfiler();
43
44 namespace po = Arcane::ProgramOptions;
45 namespace io = Alina::IO;
46
47 using std::string;
48 using std::vector;
49
50 po::options_description desc("Options");
51
52 desc.add_options()("help,h", "Affiche cette aide.")("prm-file,P",
53 po::value<string>(),
54 "Fichier de paramètres au format json. ")(
55 "prm,p",
56 po::value<vector<string>>()->multitoken(),
57 "Paramètres spécifiés sous forme de paires nom=valeur. "
58 "Peut être fourni plusieurs fois. Exemples:\n"
59 " -p solver.tol=1e-3\n"
60 " -p precond.coarse_enough=300")("matrix,A",
61 po::value<string>()->required(),
62 "Matrice du système au format MatrixMarket.")(
63 "rhs,f",
64 po::value<string>(),
65 "Le vecteur du membre de droite (RHS) au format MatrixMarket. "
66 "Lorsqu'il est omis, un vecteur de uns est utilisé par défaut. "
67 "Ne doit être fourni qu'avec une matrice de système. ")(
68 "scale,s",
69 po::bool_switch()->default_value(false),
70 "Mettre à l'échelle la matrice de sorte que la diagonale soit unitaire. ")(
71 "null,N",
72 po::value<string>(),
73 "Vecteurs nuls de départ au format MatrixMarket. ")(
74 "numvec,n",
75 po::value<int>()->default_value(3),
76 "Le nombre de vecteurs proches de l'espace nul à rechercher. ")(
77 "binary,B",
78 po::bool_switch()->default_value(false),
79 "Lorsqu'il est spécifié, traiter les fichiers d'entrée comme binaires au lieu de MatrixMarket. "
80 "Il est supposé que les fichiers ont été convertis au format binaire avec l'utilitaire mm2bin. ")(
81 "output,o",
82 po::value<string>(),
83 "Sortir l'espace nul calculé dans le fichier MatrixMarket.");
84
86 p.add("prm", -1);
87
89 po::store(po::command_line_parser(argc, argv).options(desc).positional(p).run(), vm);
90 po::notify(vm);
91
92 if (vm.count("help")) {
93 std::cout << desc << std::endl;
94 return 0;
95 }
96
97 for (int i = 0; i < argc; ++i) {
98 if (i)
99 std::cout << " ";
100 std::cout << argv[i];
101 }
102 std::cout << std::endl;
103
105 if (vm.count("prm-file")) {
106 prm.read_json(vm["prm-file"].as<string>());
107 }
108
109 if (vm.count("prm")) {
110 for (const string& v : vm["prm"].as<vector<string>>()) {
111 prm.putKeyValue(v);
112 }
113 }
114
115 ptrdiff_t rows, nv = 0, numvec = vm["numvec"].as<int>();
116 vector<ptrdiff_t> ptr, col;
117 vector<double> val, rhs;
118 std::list<std::vector<double>> Z;
119
120 {
121 auto t = prof.scoped_tic("read");
122
123 string Afile = vm["matrix"].as<string>();
124 bool binary = vm["binary"].as<bool>();
125
126 if (binary) {
127 io::read_crs(Afile, rows, ptr, col, val);
128 }
129 else {
130 ptrdiff_t cols;
131 std::tie(rows, cols) = io::mm_reader(Afile)(ptr, col, val);
132 precondition(rows == cols, "Matrice de système non carrée");
133 }
134
135 if (vm.count("rhs")) {
136 string bfile = vm["rhs"].as<string>();
137
138 ptrdiff_t n, m;
139
140 if (binary) {
141 io::read_dense(bfile, n, m, rhs);
142 }
143 else {
144 std::tie(n, m) = io::mm_reader(bfile)(rhs);
145 }
146
147 precondition(n == rows && m == 1, "Le vecteur RHS a la mauvaise taille");
148 }
149 else {
150 rhs.resize(rows, 1.0);
151 }
152
153 if (vm.count("null")) {
154 string nfile = vm["null"].as<string>();
155
156 std::vector<double> null;
157 ptrdiff_t m;
158
159 if (binary) {
160 io::read_dense(nfile, m, nv, null);
161 }
162 else {
163 std::tie(m, nv) = io::mm_reader(nfile)(null);
164 }
165
166 precondition(m == rows, "Les vecteurs proches de l'espace nul ont la mauvaise taille");
167
168 for (ptrdiff_t i = 0; i < nv; ++i) {
169 Z.emplace_back(rows);
170 for (ptrdiff_t j = 0; j < rows; ++j) {
171 Z.back()[j] = null[j * nv + i];
172 }
173 }
174 }
175 }
176
177 if (vm["scale"].as<bool>()) {
178 auto t = prof.scoped_tic("scaling");
179 std::vector<double> dia(rows, 1.0);
180
181 for (ptrdiff_t i = 0; i < static_cast<ptrdiff_t>(rows); ++i) {
182 double d = 1.0;
183 for (ptrdiff_t j = ptr[i], e = ptr[i + 1]; j < e; ++j) {
184 if (col[j] == i) {
185 d = 1 / sqrt(val[j]);
186 }
187 }
188 if (!std::isnan(d))
189 dia[i] = d;
190 }
191
192 for (ptrdiff_t i = 0; i < static_cast<ptrdiff_t>(rows); ++i) {
193 rhs[i] *= dia[i];
194 for (ptrdiff_t j = ptr[i], e = ptr[i + 1]; j < e; ++j) {
195 val[j] *= dia[i] * dia[col[j]];
196 }
197 }
198 }
199
200 using Backend = Alina::BuiltinBackend<double>;
203
204 std::mt19937 rng;
205 std::uniform_real_distribution<double> rnd(-1, 1);
206 std::vector<double> x(rows), zero(rows, 0.0);
207
208 auto A = std::tie(rows, ptr, col, val);
209
210 prm.put("solver.ns_search", true);
211
212 prof.tic("search");
213 for (int k = nv; k < numvec; ++k) {
214 auto t = prof.scoped_tic(std::string("vector ") + std::to_string(k));
215 std::vector<double> N;
216
217 if (k) {
218 N.resize(k * rows);
219 int j = 0;
220 for (const auto& z : Z) {
221 for (ptrdiff_t i = 0; i < rows; ++i) {
222 N[i * k + j] = z[i];
223 }
224 ++j;
225 }
226
227 prm.put("precond.coarsening.nullspace.rows", rows);
228 prm.put("precond.coarsening.nullspace.cols", k);
229 prm.put("precond.coarsening.nullspace.B", N.data());
230 }
231
232 prof.tic("setup");
233 Solver S(A, prm);
234 prof.toc("setup");
235
236 std::cout << std::endl
237 << "-------------------------" << std::endl
238 << "-- Recherche du vecteur " << k << std::endl
239 << "-------------------------" << std::endl
240 << S << std::endl;
241
242 for (auto& v : x)
243 v = rnd(rng);
244
245 prof.tic("solve");
246 Alina::SolverResult r = S(zero, x);
247 prof.toc("solve");
248
249 std::cout << "Itérations: " << r.nbIteration() << std::endl
250 << "Erreur: " << r.residual() << std::endl;
251
252 // Orthonormalize the new vector
253 for (const auto& z : Z) {
254 double c = Alina::backend::inner_product(x, z) / Alina::backend::inner_product(z, z);
255 Alina::backend::axpby(-c, z, 1, x);
256 }
257
258 double nx = sqrt(Alina::backend::inner_product(x, x));
259 for (auto& v : x)
260 v /= nx;
261 Z.push_back(x);
262 }
263 prof.toc("search");
264
265 // Solve the system using the near nullspace vectors:
266 std::vector<double> N(numvec * rows);
267 {
268 auto t = prof.scoped_tic("apply");
269
270 int j = 0;
271 for (const auto& z : Z) {
272 for (ptrdiff_t i = 0; i < rows; ++i) {
273 N[i * numvec + j] = z[i];
274 }
275 ++j;
276 }
277
278 prm.put("precond.coarsening.nullspace.rows", rows);
279 prm.put("precond.coarsening.nullspace.cols", numvec);
280 prm.put("precond.coarsening.nullspace.B", N.data());
281
282 prof.tic("setup");
283 Solver S(A, prm);
284 prof.toc("setup");
285
286 std::cout << std::endl
287 << "-------------------------" << std::endl
288 << "-- Résolution du système " << std::endl
289 << "-------------------------" << std::endl
290 << S << std::endl;
291
292 Alina::backend::clear(x);
293
294 prof.tic("solve");
295 Alina::SolverResult r = S(rhs, x);
296 prof.toc("solve");
297
298 std::cout << "Itérations: " << r.nbIteration() << std::endl
299 << "Erreur: " << r.residual() << std::endl;
300 }
301
302 if (vm.count("output")) {
303 auto t = prof.scoped_tic("write");
304 Alina::IO::mm_write(vm["output"].as<string>(), N.data(), rows, numvec);
305 }
306
307 std::cout << prof << std::endl;
308}
Convenience class that bundles together a preconditioner and an iterative solver.
Classe pour stocker les paramètres sous forme d'arbre hiérarchique clé/valeur.
Definition AlinaUtils.h:112
Résultat d'une solution.
Definition AlinaUtils.h:53
Constructeur d'analyseur d'arguments en ligne de commande fluide.
Décrit un ensemble d'options en ligne de commande.
Décrit les arguments positionnels (non-options).
Stocke les valeurs d'options analysées.
apfloat sqrt(apfloat v)
Racine carrée de v.
Definition MathApfloat.h:65
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --
Runtime-configurable wrappers around iterative solvers.