00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #ifndef MTL_MATRIX_UMFPACK_SOLVE_INCLUDE
00013 #define MTL_MATRIX_UMFPACK_SOLVE_INCLUDE
00014
00015 #ifdef MTL_HAS_UMFPACK
00016
00017 #include <iostream>
00018
00019
00020 #include <cassert>
00021 #include <algorithm>
00022 #include <boost/type_traits.hpp>
00023 #include <boost/mpl/bool.hpp>
00024 #include <boost/numeric/mtl/matrix/compressed2D.hpp>
00025 #include <boost/numeric/mtl/matrix/parameter.hpp>
00026 #include <boost/numeric/mtl/concept/collection.hpp>
00027 #include <boost/numeric/mtl/utility/exception.hpp>
00028 #include <boost/numeric/mtl/utility/make_copy_or_reference.hpp>
00029 #include <boost/numeric/mtl/operation/merge_complex_vector.hpp>
00030 #include <boost/numeric/mtl/operation/split_complex_vector.hpp>
00031
00032 extern "C" {
00033 # include <umfpack.h>
00034 }
00035
00036 namespace mtl { namespace matrix {
00037
00038 namespace umfpack {
00039
00040
00041 template <typename Value> struct value {};
00042 template<> struct value<double> { typedef double type; };
00043 template<> struct value<float> { typedef double type; };
00044 template<> struct value<std::complex<double> > { typedef std::complex<double> type; };
00045 template<> struct value<std::complex<float> > { typedef std::complex<double> type; };
00046
00047 template <typename Value> struct use_long { static const bool value= sizeof(Value) > sizeof(int); };
00048
00049 template <bool Larger> struct index_aux { typedef int type; };
00050 template<> struct index_aux<true> { typedef UF_long type; };
00051
00052 template <typename Value> struct index
00053 : index_aux<use_long<Value>::value> {};
00054
00055 template <typename Matrix, typename Value, typename Orientation>
00056 struct matrix_copy {};
00057
00058
00059 template <typename Value, typename Parameters, typename Orientation>
00060 struct matrix_copy<compressed2D<Value, Parameters>, Value, Orientation>
00061 {
00062 typedef typename value<Value>::type value_type;
00063 typedef compressed2D<value_type, parameters<col_major> > matrix_type;
00064 typedef compressed2D<Value, Parameters> in_matrix_type;
00065
00066 matrix_copy(const in_matrix_type& A) : matrix(A) {}
00067 matrix_type matrix;
00068 };
00069
00070 struct error : public domain_error
00071 {
00072 error(const char *s, int code) : domain_error(s), code(code) {}
00073 int code;
00074 };
00075
00076 inline void check(int res, const char *s)
00077 {
00078 MTL_THROW_IF(res != UMFPACK_OK, error(s, res));
00079 }
00080
00082
00084 template <typename T> class solver {};
00085
00086 template <typename Parameters>
00087 class solver<compressed2D<double, Parameters> >
00088 {
00089 typedef double value_type;
00090 typedef compressed2D<value_type, Parameters> matrix_type;
00091 typedef typename matrix_type::size_type size_type;
00092 typedef typename index<size_type>::type index_type;
00093
00094 static const bool copy_indices= sizeof(index_type) != sizeof(size_type),
00095 long_indices= use_long<size_type>::value;
00096 typedef boost::mpl::bool_<long_indices> blong;
00097 typedef boost::mpl::true_ true_;
00098 typedef boost::mpl::false_ false_;
00099
00100
00101
00102 void assign_pointers()
00103 {
00104 if (copy_indices) {
00105 if (Apc == 0) Apc= new index_type[n + 1];
00106 if (my_nnz != A.nnz() && Aic) { delete[] Aic; Aic= 0; }
00107 if (Aic == 0) Aic= new index_type[A.nnz()];
00108 std::copy(A.address_major(), A.address_major() + n + 1, Apc);
00109 std::copy(A.address_minor(), A.address_minor() + A.nnz(), Aic);
00110 Ap= Apc;
00111 Ai= Aic;
00112 } else {
00113 Ap= reinterpret_cast<const index_type*>(A.address_major());
00114 Ai= reinterpret_cast<const index_type*>(A.address_minor());
00115 }
00116 Ax= A.address_data();
00117 }
00118
00119 void init_aux(true_)
00120 {
00121 check(umfpack_dl_symbolic(n, n, Ap, Ai, Ax, &Symbolic, Control, Info), "Error in dl_symbolic");
00122 check(umfpack_dl_numeric(Ap, Ai, Ax, Symbolic, &Numeric, Control, Info), "Error in dl_numeric");
00123 }
00124
00125 void init_aux(false_)
00126 {
00127 check(umfpack_di_symbolic(n, n, Ap, Ai, Ax, &Symbolic, Control, Info), "Error in di_symbolic");
00128 check(umfpack_di_numeric(Ap, Ai, Ax, Symbolic, &Numeric, Control, Info), "Error in di_numeric");
00129 }
00130
00131 void init()
00132 {
00133 MTL_THROW_IF(num_rows(A) != num_cols(A), matrix_not_square());
00134 n= num_rows(A);
00135 assign_pointers();
00136 init_aux(blong());
00137 }
00138
00139
00140
00141 public:
00142 explicit solver(const matrix_type& A)
00143 : A(A), Apc(0), Aic(0), my_nnz(0), Symbolic(0), Numeric(0)
00144 {
00145
00146 if (long_indices)
00147 umfpack_dl_defaults(Control);
00148 else
00149 umfpack_di_defaults(Control);
00150 init();
00151 }
00152
00153 ~solver()
00154 {
00155 if (long_indices) {
00156 umfpack_dl_free_numeric(&Numeric);
00157 umfpack_dl_free_symbolic(&Symbolic);
00158 } else {
00159 umfpack_di_free_numeric(&Numeric);
00160 umfpack_di_free_symbolic(&Symbolic);
00161 }
00162 if (Apc) delete[] Apc;
00163 if (Aic) delete[] Aic;
00164 }
00165
00166 void update_numeric_aux(true_)
00167 {
00168 umfpack_dl_free_numeric(&Numeric);
00169 check(umfpack_dl_numeric(Ap, Ai, Ax, Symbolic, &Numeric, Control, Info), "Error in dl_numeric");
00170 }
00171
00172 void update_numeric_aux(false_)
00173 {
00174 umfpack_di_free_numeric(&Numeric);
00175 check(umfpack_di_numeric(Ap, Ai, Ax, Symbolic, &Numeric, Control, Info), "Error in di_numeric");
00176 }
00177
00179 void update_numeric()
00180 {
00181 assign_pointers();
00182 update_numeric_aux(blong());
00183 }
00184
00186 void update()
00187 {
00188 if (long_indices) {
00189 umfpack_dl_free_numeric(&Numeric);
00190 umfpack_dl_free_symbolic(&Symbolic);
00191 } else {
00192 umfpack_di_free_numeric(&Numeric);
00193 umfpack_di_free_symbolic(&Symbolic);
00194 }
00195 init();
00196 }
00197
00198 template <typename VectorX, typename VectorB>
00199 void solve_aux(int sys, VectorX& xx, const VectorB& bb, true_)
00200 {
00201 check(umfpack_dl_solve(sys, Ap, Ai, Ax, &xx.value[0], &bb.value[0], Numeric, Control, Info), "Error in dl_numeric");
00202 }
00203
00204 template <typename VectorX, typename VectorB>
00205 void solve_aux(int sys, VectorX& xx, const VectorB& bb, false_)
00206 {
00207 check(umfpack_di_solve(sys, Ap, Ai, Ax, &xx.value[0], &bb.value[0], Numeric, Control, Info), "Error in di_numeric");
00208 }
00209
00211 template <typename VectorX, typename VectorB>
00212 int operator()(VectorX& x, const VectorB& b)
00213 {
00214 MTL_THROW_IF(num_rows(A) != size(x) || num_rows(A) != size(b), incompatible_size());
00215 make_in_out_copy_or_reference<dense_vector<value_type>, VectorX> xx(x);
00216 make_in_copy_or_reference<dense_vector<value_type>, VectorB> bb(b);
00217 int sys= mtl::traits::is_row_major<Parameters>::value ? UMFPACK_At : UMFPACK_A;
00218 solve_aux(sys, xx, bb, blong());
00219 return UMFPACK_OK;
00220 }
00221
00222 private:
00223 const matrix_type& A;
00224 int n;
00225 const index_type *Ap, *Ai;
00226 index_type *Apc, *Aic;
00227 size_type my_nnz;
00228 const double *Ax;
00229 double Control[UMFPACK_CONTROL], Info[UMFPACK_INFO];
00230 void *Symbolic, *Numeric;
00231 };
00232
00233 template <typename Parameters>
00234 class solver<compressed2D<std::complex<double>, Parameters> >
00235 {
00236 typedef std::complex<double> value_type;
00237 typedef compressed2D<value_type, Parameters> matrix_type;
00238 typedef typename matrix_type::size_type size_type;
00239 typedef typename index<size_type>::type index_type;
00240
00241 static const bool copy_indices= sizeof(index_type) != sizeof(size_type),
00242 long_indices= use_long<size_type>::value;
00243
00244 typedef boost::mpl::bool_<long_indices> blong;
00245 typedef boost::mpl::true_ true_;
00246 typedef boost::mpl::false_ false_;
00247
00248
00249 void assign_pointers()
00250 {
00251 if (copy_indices) {
00252 if (Apc == 0) Apc= new index_type[n + 1];
00253 if (Aic == 0) Aic= new index_type[A.nnz()];
00254 std::copy(A.address_major(), A.address_major() + n + 1, Apc);
00255 std::copy(A.address_minor(), A.address_minor() + A.nnz(), Aic);
00256 Ap= Apc;
00257 Ai= Aic;
00258 } else {
00259 Ap= reinterpret_cast<const index_type*>(A.address_major());
00260 Ai= reinterpret_cast<const index_type*>(A.address_minor());
00261 }
00262 split_complex_vector(A.data, Ax, Az);
00263 }
00264
00265 void init_aux(true_)
00266 {
00267 check(umfpack_zl_symbolic(n, n, Ap, Ai, &Ax[0], &Az[0], &Symbolic, Control, Info), "Error in dl_symbolic");
00268 check(umfpack_zl_numeric(Ap, Ai, &Ax[0], &Az[0], Symbolic, &Numeric, Control, Info), "Error in dl_numeric");
00269 }
00270
00271 void init_aux(false_)
00272 {
00273 check(umfpack_zi_symbolic(n, n, Ap, Ai, &Ax[0], &Az[0], &Symbolic, Control, Info), "Error in di_symbolic");
00274 check(umfpack_zi_numeric(Ap, Ai, &Ax[0], &Az[0], Symbolic, &Numeric, Control, Info), "Error in di_numeric");
00275 }
00276
00277 void initialize()
00278 {
00279 MTL_THROW_IF(num_rows(A) != num_cols(A), matrix_not_square());
00280 n= num_rows(A);
00281 assign_pointers();
00282 init_aux(blong());
00283 }
00284 public:
00285 explicit solver(const compressed2D<value_type, Parameters>& A) : A(A), Apc(0), Aic(0)
00286 {
00287
00288 if (long_indices)
00289 umfpack_zl_defaults(Control);
00290 else
00291 umfpack_zi_defaults(Control);
00292
00293 initialize();
00294 }
00295
00296 ~solver()
00297 {
00298 if (long_indices) {
00299 umfpack_zl_free_numeric(&Numeric);
00300 umfpack_zl_free_symbolic(&Symbolic);
00301 } else {
00302 umfpack_zi_free_numeric(&Numeric);
00303 umfpack_zi_free_symbolic(&Symbolic);
00304 }
00305 if (Apc) delete[] Apc;
00306 if (Aic) delete[] Aic;
00307 }
00308
00309 void update_numeric_aux(true_)
00310 {
00311 umfpack_zl_free_numeric(&Numeric);
00312 check(umfpack_zl_numeric(Ap, Ai, &Ax[0], &Az[0], Symbolic, &Numeric, Control, Info), "Error in dl_numeric");
00313 }
00314
00315 void update_numeric_aux(false_)
00316 {
00317 umfpack_zi_free_numeric(&Numeric);
00318 check(umfpack_zi_numeric(Ap, Ai, &Ax[0], &Az[0], Symbolic, &Numeric, Control, Info), "Error in di_numeric");
00319 }
00320
00322 void update_numeric()
00323 {
00324 assign_pointers();
00325 update_numeric_aux(blong());
00326 }
00327
00329 void update()
00330 {
00331 Ax.change_dim(0); Az.change_dim(0);
00332 if (long_indices) {
00333 umfpack_zl_free_numeric(&Numeric);
00334 umfpack_zl_free_symbolic(&Symbolic);
00335 } else {
00336 umfpack_zi_free_numeric(&Numeric);
00337 umfpack_zi_free_symbolic(&Symbolic);
00338 }
00339 initialize();
00340 }
00341
00342 template <typename VectorX, typename VectorB>
00343 void solve_aux(int sys, VectorX& Xx, VectorX& Xz, const VectorB& Bx, const VectorB& Bz, true_)
00344 {
00345 check(umfpack_zl_solve(sys, Ap, Ai, &Ax[0], &Az[0], &Xx[0], &Xz[0], &Bx[0], &Bz[0], Numeric, Control, Info),
00346 "Error in zi_solve");
00347 }
00348
00349 template <typename VectorX, typename VectorB>
00350 void solve_aux(int sys, VectorX& Xx, VectorX& Xz, const VectorB& Bx, const VectorB& Bz, false_)
00351 {
00352 check(umfpack_zi_solve(sys, Ap, Ai, &Ax[0], &Az[0], &Xx[0], &Xz[0], &Bx[0], &Bz[0], Numeric, Control, Info),
00353 "Error in zi_solve");
00354 }
00355
00357 template <typename VectorX, typename VectorB>
00358 int operator()(VectorX& x, const VectorB& b)
00359 {
00360 MTL_THROW_IF(num_rows(A) != size(x) || num_rows(A) != size(b), incompatible_size());
00361 dense_vector<double> Xx(size(x)), Xz(size(x)), Bx, Bz;
00362 split_complex_vector(b, Bx, Bz);
00363 int sys= mtl::traits::is_row_major<Parameters>::value ? UMFPACK_Aat : UMFPACK_A;
00364 solve_aux(sys, Xx, Xz, Bx, Bz, blong());
00365 merge_complex_vector(Xx, Xz, x);
00366 return UMFPACK_OK;
00367 }
00368
00369 private:
00370 const matrix_type& A;
00371 int n;
00372 const index_type *Ap, *Ai;
00373 index_type *Apc, *Aic;
00374 dense_vector<double> Ax, Az;
00375 double Control[UMFPACK_CONTROL], Info[UMFPACK_INFO];
00376 void *Symbolic, *Numeric;
00377 };
00378
00379 template <typename Value, typename Parameters>
00380 class solver<compressed2D<Value, Parameters> >
00381 : matrix_copy<compressed2D<Value, Parameters>, Value, typename Parameters::orientation>,
00382 public solver<typename matrix_copy<compressed2D<Value, Parameters>, Value, typename Parameters::orientation>::matrix_type >
00383 {
00384 typedef matrix_copy<compressed2D<Value, Parameters>, Value, typename Parameters::orientation> copy_type;
00385 typedef solver<typename matrix_copy<compressed2D<Value, Parameters>, Value, typename Parameters::orientation>::matrix_type > solver_type;
00386 public:
00387 explicit solver(const compressed2D<Value, Parameters>& A)
00388 : copy_type(A), solver_type(copy_type::matrix), A(A)
00389 {}
00390
00391 void update()
00392 {
00393 copy_type::matrix= A;
00394 solver_type::update();
00395 }
00396
00397 void update_numeric()
00398 {
00399 copy_type::matrix= A;
00400 solver_type::update_numeric();
00401 }
00402 private:
00403 const compressed2D<Value, Parameters>& A;
00404 };
00405 }
00406
00407
00408 template <typename Value, typename Parameters, typename VectorX, typename VectorB>
00409 int umfpack_solve(const compressed2D<Value, Parameters>& A, VectorX& x, const VectorB& b)
00410 {
00411 umfpack::solver<compressed2D<Value, Parameters> > solver(A);
00412 return solver(x, b);
00413 }
00414
00415 }}
00416
00417 #endif
00418
00419 #endif // MTL_MATRIX_UMFPACK_SOLVE_INCLUDE