Arcane  4.2.3.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 Alina::AlinaContext context;
51 po::options_description desc("Options");
52
53 desc.add_options()("help,h", "Affiche cette aide.");
54 desc.add_options()("prm-file,P",
55 po::value<string>(),
56 "Fichier de paramètres au format json. ");
57 desc.add_options()("prm,p",
58 po::value<vector<string>>()->multitoken(),
59 "Paramètres spécifiés sous forme de paires nom=valeur. "
60 "Peut être fourni plusieurs fois. Exemples:\n"
61 " -p solver.tol=1e-3\n"
62 " -p precond.coarse_enough=300");
63 desc.add_options()("matrix,A",
64 po::value<string>()->required(),
65 "Matrice du système au format MatrixMarket.");
66 desc.add_options()("rhs,f",
67 po::value<string>(),
68 "Le vecteur du membre de droite (RHS) au format MatrixMarket. "
69 "Lorsqu'il est omis, un vecteur de uns est utilisé par défaut. "
70 "Ne doit être fourni qu'avec une matrice de système. ");
71 desc.add_options()("scale,s",
72 po::bool_switch()->default_value(false),
73 "Mettre à l'échelle la matrice de sorte que la diagonale soit unitaire. ");
74 desc.add_options()("null,N",
75 po::value<string>(),
76 "Vecteurs nuls de départ au format MatrixMarket. ");
77 desc.add_options()("numvec,n",
78 po::value<int>()->default_value(3),
79 "Le nombre de vecteurs proches de l'espace nul à rechercher. ");
80 desc.add_options()("binary,B",
81 po::bool_switch()->default_value(false),
82 "Lorsqu'il est spécifié, traiter les fichiers d'entrée comme binaires au lieu de MatrixMarket. "
83 "Il est supposé que les fichiers ont été convertis au format binaire avec l'utilitaire mm2bin. ");
84 desc.add_options()("output,o",
85 po::value<string>(),
86 "Sortir l'espace nul calculé dans le fichier MatrixMarket.");
87
89 p.add("prm", -1);
90
92 po::store(po::command_line_parser(argc, argv).options(desc).positional(p).run(), vm);
93 po::notify(vm);
94
95 if (vm.count("help")) {
96 std::cout << desc << std::endl;
97 return 0;
98 }
99
100 for (int i = 0; i < argc; ++i) {
101 if (i)
102 std::cout << " ";
103 std::cout << argv[i];
104 }
105 std::cout << std::endl;
106
108 if (vm.count("prm-file")) {
109 prm.read_json(vm["prm-file"].as<string>());
110 }
111
112 if (vm.count("prm")) {
113 for (const string& v : vm["prm"].as<vector<string>>()) {
114 prm.putKeyValue(v);
115 }
116 }
117
118 ptrdiff_t rows, nv = 0, numvec = vm["numvec"].as<int>();
119 vector<ptrdiff_t> ptr, col;
120 vector<double> val, rhs;
121 std::list<std::vector<double>> Z;
122
123 {
124 auto t = prof.scoped_tic("read");
125
126 string Afile = vm["matrix"].as<string>();
127 bool binary = vm["binary"].as<bool>();
128
129 if (binary) {
130 io::read_crs(Afile, rows, ptr, col, val);
131 }
132 else {
133 ptrdiff_t cols;
134 std::tie(rows, cols) = io::mm_reader(Afile)(ptr, col, val);
135 precondition(rows == cols, "Matrice de système non carrée");
136 }
137
138 if (vm.count("rhs")) {
139 string bfile = vm["rhs"].as<string>();
140
141 ptrdiff_t n, m;
142
143 if (binary) {
144 io::read_dense(bfile, n, m, rhs);
145 }
146 else {
147 std::tie(n, m) = io::mm_reader(bfile)(rhs);
148 }
149
150 precondition(n == rows && m == 1, "Le vecteur RHS a la mauvaise taille");
151 }
152 else {
153 rhs.resize(rows, 1.0);
154 }
155
156 if (vm.count("null")) {
157 string nfile = vm["null"].as<string>();
158
159 std::vector<double> null;
160 ptrdiff_t m;
161
162 if (binary) {
163 io::read_dense(nfile, m, nv, null);
164 }
165 else {
166 std::tie(m, nv) = io::mm_reader(nfile)(null);
167 }
168
169 precondition(m == rows, "Les vecteurs proches de l'espace nul ont la mauvaise taille");
170
171 for (ptrdiff_t i = 0; i < nv; ++i) {
172 Z.emplace_back(rows);
173 for (ptrdiff_t j = 0; j < rows; ++j) {
174 Z.back()[j] = null[j * nv + i];
175 }
176 }
177 }
178 }
179
180 if (vm["scale"].as<bool>()) {
181 auto t = prof.scoped_tic("scaling");
182 std::vector<double> dia(rows, 1.0);
183
184 for (ptrdiff_t i = 0; i < static_cast<ptrdiff_t>(rows); ++i) {
185 double d = 1.0;
186 for (ptrdiff_t j = ptr[i], e = ptr[i + 1]; j < e; ++j) {
187 if (col[j] == i) {
188 d = 1 / sqrt(val[j]);
189 }
190 }
191 if (!std::isnan(d))
192 dia[i] = d;
193 }
194
195 for (ptrdiff_t i = 0; i < static_cast<ptrdiff_t>(rows); ++i) {
196 rhs[i] *= dia[i];
197 for (ptrdiff_t j = ptr[i], e = ptr[i + 1]; j < e; ++j) {
198 val[j] *= dia[i] * dia[col[j]];
199 }
200 }
201 }
202
203 using Backend = Alina::BuiltinBackend<double>;
206
207 std::mt19937 rng;
208 std::uniform_real_distribution<double> rnd(-1, 1);
209 std::vector<double> x(rows), zero(rows, 0.0);
210
211 auto A = std::tie(rows, ptr, col, val);
212
213 prm.put("solver.ns_search", true);
214
215 prof.tic("search");
216 for (int k = nv; k < numvec; ++k) {
217 auto t = prof.scoped_tic(std::string("vector ") + std::to_string(k));
218 std::vector<double> N;
219
220 if (k) {
221 N.resize(k * rows);
222 int j = 0;
223 for (const auto& z : Z) {
224 for (ptrdiff_t i = 0; i < rows; ++i) {
225 N[i * k + j] = z[i];
226 }
227 ++j;
228 }
229
230 prm.put("precond.coarsening.nullspace.rows", rows);
231 prm.put("precond.coarsening.nullspace.cols", k);
232 prm.put("precond.coarsening.nullspace.B", N.data());
233 }
234
235 prof.tic("setup");
236 Solver S(context, A, prm);
237 prof.toc("setup");
238
239 std::cout << std::endl
240 << "-------------------------" << std::endl
241 << "-- Recherche du vecteur " << k << std::endl
242 << "-------------------------" << std::endl
243 << S << std::endl;
244
245 for (auto& v : x)
246 v = rnd(rng);
247
248 prof.tic("solve");
249 Alina::SolverResult r = S(zero, x);
250 prof.toc("solve");
251
252 std::cout << "Itérations: " << r.nbIteration() << std::endl
253 << "Erreur: " << r.residual() << std::endl;
254
255 // Orthonormalize the new vector
256 for (const auto& z : Z) {
257 double c = Alina::backend::inner_product(x, z) / Alina::backend::inner_product(z, z);
258 Alina::backend::axpby(-c, z, 1, x);
259 }
260
261 double nx = sqrt(Alina::backend::inner_product(x, x));
262 for (auto& v : x)
263 v /= nx;
264 Z.push_back(x);
265 }
266 prof.toc("search");
267
268 // Solve the system using the near nullspace vectors:
269 std::vector<double> N(numvec * rows);
270 {
271 auto t = prof.scoped_tic("apply");
272
273 int j = 0;
274 for (const auto& z : Z) {
275 for (ptrdiff_t i = 0; i < rows; ++i) {
276 N[i * numvec + j] = z[i];
277 }
278 ++j;
279 }
280
281 prm.put("precond.coarsening.nullspace.rows", rows);
282 prm.put("precond.coarsening.nullspace.cols", numvec);
283 prm.put("precond.coarsening.nullspace.B", N.data());
284
285 prof.tic("setup");
286 Solver S(context, A, prm);
287 prof.toc("setup");
288
289 std::cout << std::endl
290 << "-------------------------" << std::endl
291 << "-- Résolution du système " << std::endl
292 << "-------------------------" << std::endl
293 << S << std::endl;
294
295 Alina::backend::clear(x);
296
297 prof.tic("solve");
298 Alina::SolverResult r = S(rhs, x);
299 prof.toc("solve");
300
301 std::cout << "Itérations: " << r.nbIteration() << std::endl
302 << "Erreur: " << r.residual() << std::endl;
303 }
304
305 if (vm.count("output")) {
306 auto t = prof.scoped_tic("write");
307 Alina::IO::mm_write(vm["output"].as<string>(), N.data(), rows, numvec);
308 }
309
310 std::cout << prof << std::endl;
311}
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:113
Résultat d'une solution.
Definition AlinaUtils.h:56
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.