ezp
lightweight C++ wrapper for selected distributed solvers for linear systems
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 
56 namespace 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: mumps.hpp:58