ezp
lightweight C++ wrapper for selected distributed solvers for linear systems
Loading...
Searching...
No Matches
mumps.hpp
Go to the documentation of this file.
1/*******************************************************************************
2 * Copyright (C) 2025-2026 Theodore Chang
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 ******************************************************************************/
45#ifndef MUMPS_HPP
46#define MUMPS_HPP
47
48#include "../external/mumps/cmumps_c.h"
49#include "../external/mumps/dmumps_c.h"
50#include "../external/mumps/smumps_c.h"
51#include "../external/mumps/zmumps_c.h"
52#include "abstract/sparse_solver.hpp"
53
54#include <mpl/mpl.hpp>
55
56namespace ezp {
57 namespace detail {
58 template<typename> struct mumps_struc {};
59 template<> struct mumps_struc<double> {
60 using struct_type = DMUMPS_STRUC_C;
61 using entry_type = double;
62 static auto mumps_c(DMUMPS_STRUC_C* ptr) { return dmumps_c(ptr); }
63 };
64 template<> struct mumps_struc<float> {
65 using struct_type = SMUMPS_STRUC_C;
66 using entry_type = float;
67 static auto mumps_c(SMUMPS_STRUC_C* ptr) { return smumps_c(ptr); }
68 };
69 template<> struct mumps_struc<complex16> {
70 using struct_type = ZMUMPS_STRUC_C;
71 using entry_type = mumps_double_complex;
72 static auto mumps_c(ZMUMPS_STRUC_C* ptr) { return zmumps_c(ptr); }
73 };
74 template<> struct mumps_struc<complex8> {
75 using struct_type = CMUMPS_STRUC_C;
76 using entry_type = mumps_complex;
77 static auto mumps_c(CMUMPS_STRUC_C* ptr) { return cmumps_c(ptr); }
78 };
79 } // namespace detail
80
81 enum symmetric_pattern : std::int8_t {
82 unsymmetric = 0,
83 symmetric_positive_definite = 1,
84 symmetric_indefinite = 2
85 };
86
87 enum parallel_mode : std::int8_t {
88 no_host = 0,
89 host_involved = 1
90 };
91
92 template<data_t DT, index_t IT> class mumps final {
93 using struct_t = typename detail::mumps_struc<DT>::struct_type;
94 using entry_t = typename detail::mumps_struc<DT>::entry_type;
95
96 struct_t id{};
97
98 const mpl::communicator& comm_world{mpl::environment::comm_world()};
99
100 auto sync_error() {
101 IT error = id.infog[0] < 0 ? -1 : 0;
102 comm_world.allreduce(mpl::min<IT>(), error);
103 return error;
104 }
105
106 auto perform_job(const IT job) {
107 id.job = job;
109 }
110
111 public:
112 explicit mumps(const symmetric_pattern sym = unsymmetric, const parallel_mode par = no_host) {
113 id.comm_fortran = MPI_Comm_c2f(comm_world.native_handle());
114 id.sym = sym;
115 // force par=1 if there is only one process
116 id.par = comm_world.size() == 1 ? 1 : par;
117 perform_job(-1);
118 }
119
120 mumps(const mumps& other)
121 : mumps(symmetric_pattern{static_cast<std::int8_t>(other.id.sym)}, parallel_mode{static_cast<std::int8_t>(other.id.par)}) {}
122 mumps(mumps&&) = delete;
123 mumps& operator=(const mumps&) = delete;
124 mumps& operator=(mumps&&) = delete;
125
126 ~mumps() { perform_job(-2); }
127
134 auto& operator()(const IT index) { return id.icntl[index]; }
135
136 auto& icntl_output_error_message(const auto config) {
137 id.icntl[0] = config;
138 return *this;
139 }
140 auto& icntl_output_diagnostic_statistics_warning(const auto config) {
141 id.icntl[1] = config;
142 return *this;
143 }
144 auto& icntl_output_global_information(const auto config) {
145 id.icntl[2] = config;
146 return *this;
147 }
148 auto& icntl_printing_level(const auto config) {
149 id.icntl[3] = config;
150 return *this;
151 }
152 // auto& icntl_matrix_input_format(const auto config) {
153 // id.icntl[4] = config;
154 // return *this;
155 // }
156 auto& icntl_permutation_and_scaling(const auto config) {
157 id.icntl[5] = config;
158 return *this;
159 }
160 auto& icntl_symmetric_permutation(const auto config) {
161 id.icntl[6] = config;
162 return *this;
163 }
164 auto& icntl_scaling_strategy(const auto config) {
165 id.icntl[7] = config;
166 return *this;
167 }
168 auto& icntl_transpose_matrix(const auto config) {
169 id.icntl[8] = config;
170 return *this;
171 }
172 auto& icntl_iterative_refinement(const auto config) {
173 id.icntl[9] = config;
174 return *this;
175 }
176 auto& icntl_error_analysis(const auto config) {
177 id.icntl[10] = config;
178 return *this;
179 }
180 auto& icntl_ordering_strategy(const auto config) {
181 id.icntl[11] = config;
182 return *this;
183 }
184 auto& icntl_root_parallelism(const auto config) {
185 id.icntl[12] = config;
186 return *this;
187 }
188 auto& icntl_working_space_percentage_increase(const auto config) {
189 id.icntl[13] = config;
190 return *this;
191 }
192 auto& icntl_compression_block_format(const auto config) {
193 id.icntl[14] = config;
194 return *this;
195 }
196 auto& icntl_openmp_threads(const auto config) {
197 id.icntl[15] = config;
198 return *this;
199 }
200 auto& icntl_distribution_strategy_input(const auto config) {
201 id.icntl[17] = config;
202 return *this;
203 }
204 auto& icntl_schur_complement(const auto config) {
205 id.icntl[18] = config;
206 return *this;
207 }
208 // auto& icntl_rhs_format(const auto config) {
209 // id.icntl[19] = config;
210 // return *this;
211 // }
212 auto& icntl_distribution_strategy_solution(const auto config) {
213 id.icntl[20] = config;
214 return *this;
215 }
216 auto& icntl_out_of_core(const auto config) {
217 id.icntl[21] = config;
218 return *this;
219 }
220 auto& icntl_maximum_working_memory(const auto config) {
221 id.icntl[22] = config;
222 return *this;
223 }
224 auto& icntl_null_pivot_row_detection(const auto config) {
225 id.icntl[23] = config;
226 return *this;
227 }
228 auto& icntl_deficient_and_null_space_basis(const auto config) {
229 id.icntl[24] = config;
230 return *this;
231 }
232 auto& icntl_schur_complement_solution(const auto config) {
233 id.icntl[25] = config;
234 return *this;
235 }
236 auto& icntl_rhs_block_size(const auto config) {
237 id.icntl[26] = config;
238 return *this;
239 }
240 auto& icntl_ordering_computation(const auto config) {
241 id.icntl[27] = config;
242 return *this;
243 }
244 // auto& icntl_parallel_ordering_tool(const auto config) {
245 // id.icntl[28] = config;
246 // return *this;
247 // }
248 auto& icntl_inverse_computation(const auto config) {
249 id.icntl[29] = config;
250 return *this;
251 }
252 // auto& icntl_discard_factorization(const auto config) {
253 // id.icntl[30] = config;
254 // return *this;
255 // }
256 auto& icntl_forward_elimination(const auto config) {
257 id.icntl[31] = config;
258 return *this;
259 }
260 auto& icntl_determinant_computation(const auto config) {
261 id.icntl[32] = config;
262 return *this;
263 }
264 auto& icntl_out_of_core_file(const auto config) {
265 id.icntl[33] = config;
266 return *this;
267 }
268 auto& icntl_blr(const auto config) {
269 id.icntl[34] = config;
270 return *this;
271 }
272 auto& icntl_blr_variant(const auto config) {
273 id.icntl[35] = config;
274 return *this;
275 }
276 auto& icntl_blr_compression(const auto config) {
277 id.icntl[36] = config;
278 return *this;
279 }
280 auto& icntl_lu_compression_rate(const auto config) {
281 id.icntl[37] = config;
282 return *this;
283 }
284 auto& icntl_block_compression_rate(const auto config) {
285 id.icntl[38] = config;
286 return *this;
287 }
288 auto& icntl_tree_parallelism(const auto config) {
289 id.icntl[47] = config;
290 return *this;
291 }
292 auto& icntl_compact_working_space(const auto config) {
293 id.icntl[48] = config;
294 return *this;
295 }
296 auto& icntl_rank_revealing_factorization(const auto config) {
297 id.icntl[55] = config;
298 return *this;
299 }
300 auto& icntl_symbolic_factorization(const auto config) {
301 id.icntl[57] = config;
302 return *this;
303 }
304
305 auto& info() { return id.info; }
306 auto& rinfo() { return id.rinfo; }
307 auto& infog() { return id.infog; }
308 auto& rinfog() { return id.rinfog; }
309
310 IT solve(sparse_coo_mat<DT, IT>&& A, full_mat<DT, IT>&& B) {
311 if(A.n != B.n_rows) return IT{-1};
312
313 // ReSharper disable CppCStyleCast
314 id.n = A.n;
315 id.nnz = A.nnz;
316 id.irn = A.row;
317 id.jcn = A.col;
318 id.a = (entry_t*)A.data;
319
320 id.lrhs = B.n_rows;
321 id.nrhs = B.n_cols;
322 id.rhs = (entry_t*)B.data;
323 // ReSharper restore CppCStyleCast
324
325 perform_job(6);
326
327 return sync_error();
328 }
329
330 IT solve(full_mat<DT, IT>&& B) {
331 if(id.n != B.n_rows) return IT{-1};
332
333 // ReSharper disable CppCStyleCast
334 id.lrhs = B.n_rows;
335 id.nrhs = B.n_cols;
336 id.rhs = (entry_t*)B.data;
337 // ReSharper restore CppCStyleCast
338
339 perform_job(3);
340
341 return sync_error();
342 }
343
363 auto det() const {
364 using WT = work_t<DT>;
365
366 const auto a = id.rinfog[11];
367 const auto b = floating_t<DT> ? DT{0} : id.rinfog[12];
368 const auto c = std::pow(WT{2}, id.infog[33]);
369
370 return std::complex<WT>{a, b} * c;
371 }
372
373 auto sign_det() const
374 requires floating_t<DT>
375 { return id.rinfog[11] > work_t<DT>{0} ? 1 : -1; }
376 };
377} // namespace ezp
378
379#endif
380
Definition mumps.hpp:92
auto & operator()(const IT index)
Overloaded function call operator to access elements of the icntl array.
Definition mumps.hpp:134
auto det() const
Computes the determinant of a matrix using MUMPS library data.
Definition mumps.hpp:363
Definition traits.hpp:32
Definition mumps.hpp:58