From a28b315c40785a6dcc1693c97f37cc0d2f391e1a Mon Sep 17 00:00:00 2001
From: Simon Praetorius <simon.praetorius@tu-dresden.de>
Date: Wed, 17 Jun 2015 08:39:54 +0000
Subject: [PATCH] UMFPACK solver updated

---
 AMDiS/src/solver/UmfPackSolver.h        |  10 +-
 AMDiS/src/solver/itl/umfpack2_solve.hpp | 567 ++++++++++++++++++++++++
 2 files changed, 572 insertions(+), 5 deletions(-)
 create mode 100644 AMDiS/src/solver/itl/umfpack2_solve.hpp

diff --git a/AMDiS/src/solver/UmfPackSolver.h b/AMDiS/src/solver/UmfPackSolver.h
index 8c51c8eb..76159128 100644
--- a/AMDiS/src/solver/UmfPackSolver.h
+++ b/AMDiS/src/solver/UmfPackSolver.h
@@ -28,7 +28,7 @@
 
 #include <iostream>
 #include <boost/numeric/mtl/operation/two_norm.hpp>
-#include <boost/numeric/mtl/interface/umfpack_solve.hpp>
+#include "solver/itl/umfpack2_solve.hpp"
 #include "solver/LinearSolver.h"
 
 namespace AMDiS {
@@ -60,8 +60,8 @@ namespace AMDiS {
       }
 
       try {
-	solver = new mtl::matrix::umfpack::solver<MatrixType>(fullMatrix, symmetric_strategy, alloc_init);
-      } catch (mtl::matrix::umfpack::error& e) {
+	solver = new mtl::matrix::umfpack2::solver<MatrixType>(fullMatrix, symmetric_strategy, alloc_init);
+      } catch (mtl::matrix::umfpack2::error& e) {
 	ERROR_EXIT("UMFPACK_ERROR(factorize, %d) = %s\n", e.code, e.what());
       }
     }
@@ -75,7 +75,7 @@ namespace AMDiS {
       int code = 0;
       try {
 	code = (*solver)(x, b);
-      } catch (mtl::matrix::umfpack::error& e) {
+      } catch (mtl::matrix::umfpack2::error& e) {
 	ERROR_EXIT("UMFPACK_ERROR(solve, %d) = %s\n", e.code, e.what());
       }
       
@@ -103,7 +103,7 @@ namespace AMDiS {
     LinearSolverInterface& oem;
 
   private:
-    mtl::matrix::umfpack::solver<MatrixType> *solver;
+    mtl::matrix::umfpack2::solver<MatrixType> *solver;
 
     int store_symbolic;
 
diff --git a/AMDiS/src/solver/itl/umfpack2_solve.hpp b/AMDiS/src/solver/itl/umfpack2_solve.hpp
new file mode 100644
index 00000000..76943ee2
--- /dev/null
+++ b/AMDiS/src/solver/itl/umfpack2_solve.hpp
@@ -0,0 +1,567 @@
+// Software License for MTL
+// 
+// Copyright (c) 2007 The Trustees of Indiana University. 
+//               2008 Dresden University of Technology and the Trustees of Indiana University.
+//               2010 SimuNova UG (haftungsbeschränkt), www.simunova.com. 
+// All rights reserved.
+// Authors: Peter Gottschling and Andrew Lumsdaine
+// 
+// This file is part of the Matrix Template Library
+// 
+// See also license.mtl.txt in the distribution.
+
+#ifndef MTL_MATRIX_UMFPACK2_SOLVE_INCLUDE
+#define MTL_MATRIX_UMFPACK2_SOLVE_INCLUDE
+
+#ifdef MTL_HAS_UMFPACK
+
+#include <iostream>
+
+
+#include <cassert>
+#include <algorithm>
+#include <boost/mpl/bool.hpp>
+#include <boost/numeric/mtl/matrix/compressed2D.hpp>
+#include <boost/numeric/mtl/matrix/parameter.hpp>
+#include <boost/numeric/mtl/concept/collection.hpp>
+#include <boost/numeric/mtl/utility/exception.hpp>
+#include <boost/numeric/mtl/utility/make_copy_or_reference.hpp>
+#include <boost/numeric/mtl/operation/merge_complex_vector.hpp>
+#include <boost/numeric/mtl/operation/split_complex_vector.hpp>
+#include <boost/numeric/mtl/interface/vpt.hpp>
+
+extern "C" {
+#  include <umfpack.h>
+}
+
+namespace mtl { namespace matrix {
+
+    /// Namespace for Umfpack solver
+    namespace umfpack2 {
+
+	// conversion for value_type needed if not double or complex<double> (where possible)
+	template <typename Value> struct value         	    {};
+	template<> struct value<long double>           	    { typedef double               type; };
+	template<> struct value<double>                	    { typedef double               type; };
+	template<> struct value<float>                 	    { typedef double               type; };
+	template<> struct value<std::complex<long double> > { typedef std::complex<double> type; };
+	template<> struct value<std::complex<double> > 	    { typedef std::complex<double> type; };
+	template<> struct value<std::complex<float> >  	    { typedef std::complex<double> type; };
+
+	template <typename Value> struct use_long { static const bool value= sizeof(Value) > sizeof(int); };
+
+	template <bool Larger> struct index_aux   { typedef int     type; };
+#if defined(UF_long)
+	template<> struct index_aux<true>         { typedef UF_long type; };
+#elif defined(SuiteSparse_long)
+	template<> struct index_aux<true>         { typedef SuiteSparse_long type; };
+#else
+	template<> struct index_aux<true>         { typedef long type; };
+#endif
+
+	template <typename Value> struct index 
+          : index_aux<use_long<Value>::value> {};
+
+	template <typename Matrix, typename Value, typename Orientation> 
+	struct matrix_copy {};
+
+	// If arbitrary compressed matrix -> copy
+	template <typename Value, typename Parameters, typename Orientation>
+	struct matrix_copy<compressed2D<Value, Parameters>, Value, Orientation>
+	{
+	    typedef typename value<Value>::type                      value_type;
+	    typedef compressed2D<value_type, parameters<col_major> > matrix_type;
+	    typedef compressed2D<Value, Parameters>                  in_matrix_type;
+
+	    matrix_copy(const in_matrix_type& A) : matrix(A) {}
+	    matrix_type matrix;
+	};
+
+	struct error : public domain_error
+	{
+	    error(const char *s, int code) : domain_error(s), code(code) {}
+	    int code;
+	};
+
+	inline void check(int res, const char* s)
+	{
+	    MTL_THROW_IF(res != UMFPACK_OK, error(s, res));
+	}
+
+	/// Class for repeated Umfpack solutions
+	/** Keeps symbolic and numeric preprocessing. Numeric part can be updated. 
+	    Only defined for compressed2D<double> and compressed2D<complex<double> >. **/
+	template <typename T> 
+	class solver {
+	  public:
+	    /// Constructor referring to matrix \p A (not changed) and optionally Umfpack's strategy and alloc_init (look for the specializations)
+	    // \ref solver<compressed2D<double, Parameters> > and \ref solver<compressed2D<std::complex<double>, Parameters> >)
+	    explicit solver(const T& A) {}
+
+	    /// Update numeric part, for matrices that kept the sparsity and changed the values
+	    void update_numeric() {}
+
+	    /// Update symbolic and numeric part
+	    void update() {}
+
+	    /// Solve system A*x == b with matrix passed in constructor
+	    /** Please note that the order of b and x is different than in solve() !!! **/
+	    template <typename VectorX, typename VectorB>
+	    int operator()(VectorX& x, const VectorB& b) const {return 0;}
+
+	    /// Solve system A*x == b with matrix passed in constructor
+	    /** Please note that the order of b and x is different than in operator() !!! **/
+	    template <typename VectorB, typename VectorX>
+	    int operator()(const VectorB& b, VectorX& x) const {return 0;}
+	};
+
+	/// Speciatization of solver for \ref matrix::compressed2D with double values
+	template <typename Parameters>
+	class solver<compressed2D<double, Parameters> >
+	{
+	    typedef double                                    value_type;
+	    typedef compressed2D<value_type, Parameters>      matrix_type;
+	    typedef typename matrix_type::size_type           size_type;
+	    typedef typename index<size_type>::type           index_type;
+
+	    static const bool copy_indices= sizeof(index_type) != sizeof(size_type),
+		              long_indices= use_long<size_type>::value;
+	    typedef boost::mpl::bool_<long_indices>           blong;
+	    typedef boost::mpl::true_                         true_;
+	    typedef boost::mpl::false_                        false_;
+
+	    // typedef parameters<col_major>     Parameters;
+
+	    void assign_pointers()
+	    {
+		if (copy_indices) {
+		    if (Apc == 0) Apc= new index_type[n + 1]; 
+		    if (my_nnz != A.nnz() && Aic) { delete[] Aic; Aic= 0; }
+		    if (Aic == 0) Aic= new index_type[A.nnz()];
+		    std::copy(A.address_major(), A.address_major() + n + 1, Apc);
+		    std::copy(A.address_minor(), A.address_minor() + A.nnz(), Aic);
+		    Ap= Apc;
+		    Ai= Aic;
+		} else {
+		    Ap= reinterpret_cast<const index_type*>(A.address_major());
+		    Ai= reinterpret_cast<const index_type*>(A.address_minor());
+		}
+		Ax= A.address_data();
+	    }
+
+	    void init_aux(true_)
+	    {
+	      check(umfpack_dl_symbolic(n, n, Ap, Ai, Ax, &Symbolic, Control, Info), "Error in dl_symbolic");
+	      check(umfpack_dl_numeric(Ap, Ai, Ax, Symbolic, &Numeric, Control, Info), "Error in dl_numeric");
+	    }
+	    
+	    void init_aux(false_)
+	    {
+		check(umfpack_di_symbolic(n, n, Ap, Ai, Ax, &Symbolic, Control, Info), "Error in di_symbolic");
+#if 0
+		std::cout << "=== INFO of umfpack_*_symbolic ===\n";
+		std::cout << "    UMFPACK_STATUS: " << (Info[UMFPACK_STATUS] == UMFPACK_OK ? "OK" : "ERROR") << "\n";
+		std::cout << "    UMFPACK_NROW: " << Info[UMFPACK_NROW] << "\n";
+		std::cout << "    UMFPACK_NCOL: " << Info[UMFPACK_NCOL] << "\n";
+		std::cout << "    UMFPACK_NZ: " << Info[UMFPACK_NZ] << "\n";
+		std::cout << "    UMFPACK_SIZE_OF_UNIT: " << Info[UMFPACK_SIZE_OF_UNIT] << "\n";
+		std::cout << "    UMFPACK_NDENSE_ROW: " << Info[UMFPACK_NDENSE_ROW] << "\n";
+		std::cout << "    UMFPACK_NEMPTY_ROW: " << Info[UMFPACK_NEMPTY_ROW] << "\n";
+		std::cout << "    UMFPACK_NDENSE_COL: " << Info[UMFPACK_NDENSE_COL] << "\n";
+		std::cout << "    UMFPACK_NEMPTY_COL: " << Info[UMFPACK_NEMPTY_COL] << "\n";
+		std::cout << "    UMFPACK_SYMBOLIC_DEFRAG: " << Info[UMFPACK_SYMBOLIC_DEFRAG] << "\n";
+		std::cout << "    UMFPACK_SYMBOLIC_PEAK_MEMORY: " << Info[UMFPACK_SYMBOLIC_PEAK_MEMORY] << "\n";
+		std::cout << "    UMFPACK_SYMBOLIC_SIZE: " << Info[UMFPACK_SYMBOLIC_SIZE] << "\n";
+		std::cout << "    UMFPACK_VARIABLE_PEAK_ESTIMATE: " << Info[UMFPACK_VARIABLE_PEAK_ESTIMATE]  << "\n";
+		std::cout << "    UMFPACK_NUMERIC_SIZE_ESTIMATE: " << Info[UMFPACK_NUMERIC_SIZE_ESTIMATE] << "\n";
+		std::cout << "    UMFPACK_PEAK_MEMORY_ESTIMATE: " << Info[UMFPACK_PEAK_MEMORY_ESTIMATE] << "\n";
+		std::cout << "    UMFPACK_FLOPS_ESTIMATE: " << Info[UMFPACK_FLOPS_ESTIMATE] << "\n";
+		std::cout << "    UMFPACK_LNZ_ESTIMATE: " << Info[UMFPACK_LNZ_ESTIMATE] << "\n";
+		std::cout << "    UMFPACK_UNZ_ESTIMATE: " << Info[UMFPACK_UNZ_ESTIMATE] << "\n";
+		std::cout << "    UMFPACK_MAX_FRONT_SIZE_ESTIMATE: " << Info[UMFPACK_MAX_FRONT_SIZE_ESTIMATE] << "\n";
+		std::cout << "    UMFPACK_SYMBOLIC_TIME: " << Info[UMFPACK_SYMBOLIC_TIME] << "\n";
+		std::cout << "    UMFPACK_SYMBOLIC_WALLTIME: " << Info[UMFPACK_SYMBOLIC_WALLTIME] << "\n";
+		
+		if (Info[UMFPACK_STRATEGY_USED] == UMFPACK_STRATEGY_SYMMETRIC)
+		  std::cout << "    UMFPACK_STRATEGY_USED: SYMMETRIC\n";
+		else {
+		  if(Info[UMFPACK_STRATEGY_USED] == UMFPACK_STRATEGY_UNSYMMETRIC)
+		    std::cout << "    UMFPACK_STRATEGY_USED: UNSYMMETRIC\n";
+		  else {
+		    if (Info[UMFPACK_STRATEGY_USED] == UMFPACK_STRATEGY_2BY2)
+		      std::cout << "    UMFPACK_STRATEGY_USED: 2BY2\n";
+		    else
+		      std::cout << "    UMFPACK_STRATEGY_USED: UNKOWN STRATEGY " << Info[UMFPACK_STRATEGY_USED] << "\n";
+		  }
+		}
+		  
+		std::cout << "    UMFPACK_ORDERING_USED: " << Info[UMFPACK_ORDERING_USED] << "\n";
+		std::cout << "    UMFPACK_QFIXED: " << Info[UMFPACK_QFIXED] << "\n";
+		std::cout << "    UMFPACK_DIAG_PREFERRED: " << Info[UMFPACK_DIAG_PREFERRED] << "\n";
+		std::cout << "    UMFPACK_ROW_SINGLETONS: " << Info[UMFPACK_ROW_SINGLETONS] << "\n";
+		std::cout << "    UMFPACK_COL_SINGLETONS: " << Info[UMFPACK_COL_SINGLETONS] << "\n";
+		std::cout << "    UMFPACK_PATTERN_SYMMETRY: " << Info[UMFPACK_PATTERN_SYMMETRY] << "\n";
+		std::cout << "    UMFPACK_NZ_A_PLUS_AT: " << Info[UMFPACK_NZ_A_PLUS_AT] << "\n";
+		std::cout << "    UMFPACK_NZDIAG: " << Info[UMFPACK_NZDIAG] << "\n";
+		std::cout << "    UMFPACK_N2: " << Info[UMFPACK_N2] << "\n";
+		std::cout << "    UMFPACK_S_SYMMETRIC: " << Info[UMFPACK_S_SYMMETRIC] << "\n";
+		std::cout << "    UMFPACK_MAX_FRONT_NROWS_ESTIMATE: " << Info[UMFPACK_MAX_FRONT_NROWS_ESTIMATE] << "\n";
+		std::cout << "    UMFPACK_MAX_FRONT_NCOLS_ESTIMATE: " << Info[UMFPACK_MAX_FRONT_NCOLS_ESTIMATE] << "\n";
+		std::cout << "    UMFPACK_SYMMETRIC_LUNZ: " << Info[UMFPACK_SYMMETRIC_LUNZ] << "\n";
+		std::cout << "    UMFPACK_SYMMETRIC_FLOPS: " << Info[UMFPACK_SYMMETRIC_FLOPS] << "\n";
+		std::cout << "    UMFPACK_SYMMETRIC_NDENSE: " << Info[UMFPACK_SYMMETRIC_NDENSE] << "\n";
+		std::cout << "    UMFPACK_SYMMETRIC_DMAX: " << Info[UMFPACK_SYMMETRIC_DMAX] << "\n";
+#endif
+
+		check(umfpack_di_numeric(Ap, Ai, Ax, Symbolic, &Numeric, Control, Info), "Error in di_numeric");
+
+#if 0
+		std::cout << "=== INFO of umfpack_*_numeric ===\n";
+		std::cout << "    UMFPACK_STATUS: " << (Info[UMFPACK_STATUS] == UMFPACK_OK ? "OK" : "ERROR") << "\n";
+		std::cout << "    UMFPACK_VARIABLE_PEAK: " << Info[UMFPACK_VARIABLE_PEAK]  << "\n";
+		std::cout << "    UMFPACK_PEAK_MEMORY: " << Info[UMFPACK_PEAK_MEMORY] << "\n";
+		std::cout << "    UMFPACK_FLOPS: " << Info[UMFPACK_FLOPS] << "\n";
+		std::cout << "    UMFPACK_LNZ: " << Info[UMFPACK_LNZ] << "\n";
+		std::cout << "    UMFPACK_UNZ: " << Info[UMFPACK_UNZ] << "\n";
+		std::cout << "    UMFPACK_NUMERIC_DEFRAG: " << Info[UMFPACK_NUMERIC_DEFRAG] << "\n";
+		std::cout << "    UMFPACK_NUMERIC_REALLOC: " << Info[UMFPACK_NUMERIC_REALLOC] << "\n";
+		std::cout << "    UMFPACK_NUMERIC_COSTLY_REALLOC: " << Info[UMFPACK_NUMERIC_COSTLY_REALLOC] << "\n";
+		std::cout << "    UMFPACK_COMPRESSED_PATTERN: " << Info[UMFPACK_COMPRESSED_PATTERN] << "\n";
+		std::cout << "    UMFPACK_LU_ENTRIES: " << Info[UMFPACK_LU_ENTRIES] << "\n";
+		std::cout << "    UMFPACK_NUMERIC_TIME: " << Info[UMFPACK_NUMERIC_TIME] << "\n";
+		std::cout << "    UMFPACK_RCOND: " << Info[UMFPACK_RCOND] << "\n";
+		std::cout << "    UMFPACK_UDIAG_NZ: " << Info[UMFPACK_UDIAG_NZ] << "\n";
+		std::cout << "    UMFPACK_UMIN: " << Info[UMFPACK_UMIN] << "\n";
+		std::cout << "    UMFPACK_UMAX: " << Info[UMFPACK_UMAX] << "\n";
+		std::cout << "    UMFPACK_MAX_FRONT_NROWS: " << Info[UMFPACK_MAX_FRONT_NROWS] << "\n";
+		std::cout << "    UMFPACK_MAX_FRONT_NCOLS: " << Info[UMFPACK_MAX_FRONT_NCOLS] << "\n";
+		std::cout << "    UMFPACK_ALL_LNZ: " << Info[UMFPACK_ALL_LNZ] << "\n";
+		std::cout << "    UMFPACK_ALL_UNZ: " << Info[UMFPACK_ALL_UNZ] << "\n";
+#endif
+	    }
+
+	    void init()
+	    {
+		MTL_THROW_IF(num_rows(A) != num_cols(A), matrix_not_square());
+		n= num_rows(A);
+		assign_pointers();
+		init_aux(blong());
+	    }
+
+
+
+	  public:
+	    /// Constructor referring to matrix \p A (not changed) and optionally Umfpack's strategy and alloc_init
+	    solver(const matrix_type& A, int strategy = UMFPACK_STRATEGY_AUTO, double alloc_init = 0.7) 
+	      : A(A), Apc(0), Aic(0), my_nnz(0), Symbolic(0), Numeric(0) 
+	    {
+		vampir_trace<5060> trace;
+		// Use default setings.
+		if (long_indices)
+		    umfpack_dl_defaults(Control);
+		else
+		    umfpack_di_defaults(Control);
+
+		Control[UMFPACK_STRATEGY] = strategy;
+		Control[UMFPACK_ALLOC_INIT] = alloc_init;
+		init(); 
+	    }
+
+	    ~solver()
+	    {
+		vampir_trace<5061> trace;
+		if (long_indices) {
+		    umfpack_dl_free_numeric(&Numeric);
+		    umfpack_dl_free_symbolic(&Symbolic);
+		} else {
+		    umfpack_di_free_numeric(&Numeric);
+		    umfpack_di_free_symbolic(&Symbolic);
+		}
+		if (Apc) delete[] Apc; 
+		if (Aic) delete[] Aic;
+	    }
+
+	    void update_numeric_aux(true_)
+	    {
+		umfpack_dl_free_numeric(&Numeric);
+		check(umfpack_dl_numeric(Ap, Ai, Ax, Symbolic, &Numeric, Control, Info), "Error in dl_numeric");
+	    }
+	    
+	    void update_numeric_aux(false_)
+	    {
+		umfpack_di_free_numeric(&Numeric);
+		check(umfpack_di_numeric(Ap, Ai, Ax, Symbolic, &Numeric, Control, Info), "Error in di_numeric");
+	    }
+
+	    /// Update numeric part, for matrices that kept the sparsity and changed the values
+	    void update_numeric()
+	    {
+		assign_pointers();
+		update_numeric_aux(blong());
+	    }
+
+	    /// Update symbolic and numeric part
+	    void update()
+	    {
+		if (long_indices) {
+		    umfpack_dl_free_numeric(&Numeric);
+		    umfpack_dl_free_symbolic(&Symbolic);
+		} else {
+		    umfpack_di_free_numeric(&Numeric);
+		    umfpack_di_free_symbolic(&Symbolic);
+		}
+		init();
+	    }
+
+	    template <typename VectorX, typename VectorB>
+	    void solve_aux(int sys, VectorX& xx, const VectorB& bb, true_)
+	    {
+	      check(umfpack_dl_solve(sys, Ap, Ai, Ax, &xx.value[0], &bb.value[0], Numeric, Control, Info), "Error in dl_solve");
+	    }
+
+	    template <typename VectorX, typename VectorB>
+	    void solve_aux(int sys, VectorX& xx, const VectorB& bb, false_)
+	    {
+		check(umfpack_di_solve(sys, Ap, Ai, Ax, &xx.value[0], &bb.value[0], Numeric, Control, Info), "Error in di_solve");
+	    }
+
+	    /// Solve double system
+	    template <typename VectorX, typename VectorB>
+	    int operator()(VectorX& x, const VectorB& b)
+	    {
+		vampir_trace<5062> trace;
+		MTL_THROW_IF(num_rows(A) != size(x) || num_rows(A) != size(b), incompatible_size());
+		make_in_out_copy_or_reference<dense_vector<value_type>, VectorX> xx(x);
+		make_in_copy_or_reference<dense_vector<value_type>, VectorB>     bb(b);
+		int sys= mtl::traits::is_row_major<Parameters>::value ? UMFPACK_At : UMFPACK_A;
+		solve_aux(sys, xx, bb, blong());
+		return UMFPACK_OK;
+	    }
+
+	    /// Solve double system
+	    template <typename VectorB, typename VectorX>
+	    int solve(const VectorB& b, VectorX& x) const
+	    {
+		// return (*this)(x, b);
+		return const_cast<solver&>(*this)(x, b); // evil hack because Umfpack has no const
+	    }
+
+	  private:
+	    const matrix_type&  A;
+	    int                 n;
+	    const index_type    *Ap, *Ai;
+	    index_type          *Apc, *Aic;
+	    size_type           my_nnz;
+	    const double        *Ax;
+	    double              Control[UMFPACK_CONTROL], Info[UMFPACK_INFO];
+	    void                *Symbolic, *Numeric;
+	};
+
+	/// Speciatization of solver for \ref matrix::compressed2D with double values
+	template <typename Parameters>
+	class solver<compressed2D<std::complex<double>, Parameters> >
+	{
+	    typedef std::complex<double>                      value_type;
+	    typedef compressed2D<value_type, Parameters>      matrix_type;
+	    typedef typename matrix_type::size_type           size_type;
+	    typedef typename index<size_type>::type           index_type;
+
+	    static const bool copy_indices= sizeof(index_type) != sizeof(size_type),
+		              long_indices= use_long<size_type>::value;
+
+	    typedef boost::mpl::bool_<long_indices>           blong;
+	    typedef boost::mpl::true_                         true_;
+	    typedef boost::mpl::false_                        false_;
+	    
+
+	    void assign_pointers()
+	    {
+		if (copy_indices) {
+		    if (Apc == 0) Apc= new index_type[n + 1]; 
+		    if (Aic == 0) Aic= new index_type[A.nnz()];
+		    std::copy(A.address_major(), A.address_major() + n + 1, Apc);
+		    std::copy(A.address_minor(), A.address_minor() + A.nnz(), Aic);
+		    Ap= Apc;
+		    Ai= Aic;
+		} else {
+		    Ap= reinterpret_cast<const index_type*>(A.address_major());
+		    Ai= reinterpret_cast<const index_type*>(A.address_minor());
+		}
+		split_complex_vector(A.data, Ax, Az);
+	    }
+
+	    void init_aux(true_)
+	    {
+		check(umfpack_zl_symbolic(n, n, Ap, Ai, &Ax[0], &Az[0], &Symbolic, Control, Info), "Error in zl_symbolic");
+		check(umfpack_zl_numeric(Ap, Ai, &Ax[0], &Az[0], Symbolic, &Numeric, Control, Info), "Error in zl_numeric");
+	    }
+	    
+	    void init_aux(false_)
+	    {
+		check(umfpack_zi_symbolic(n, n, Ap, Ai, &Ax[0], &Az[0], &Symbolic, Control, Info), "Error in zi_symbolic");
+		check(umfpack_zi_numeric(Ap, Ai, &Ax[0], &Az[0], Symbolic, &Numeric, Control, Info), "Error in zi_numeric");
+	    }
+
+	    void initialize()
+	    {
+		MTL_THROW_IF(num_rows(A) != num_cols(A), matrix_not_square());
+		n= num_rows(A);
+		assign_pointers();
+		init_aux(blong());
+	    }
+	public:
+	    /// Constructor referring to matrix \p A (not changed) and optionally Umfpack's strategy and alloc_init (look for the specializations)
+	    explicit solver(const compressed2D<value_type, Parameters>& A, int strategy = UMFPACK_STRATEGY_AUTO, double alloc_init = 0.7) 
+	      : A(A), Apc(0), Aic(0)
+	    {
+		vampir_trace<5060> trace;
+		// Use default setings.
+		if (long_indices)
+		    umfpack_zl_defaults(Control);
+		else
+		    umfpack_zi_defaults(Control);
+		// umfpack_zi_defaults(Control);
+
+		Control[UMFPACK_STRATEGY] = strategy;
+		Control[UMFPACK_ALLOC_INIT] = alloc_init;
+		initialize();
+	    }
+
+	    ~solver()
+	    {
+		vampir_trace<5061> trace;
+		if (long_indices) {
+		    umfpack_zl_free_numeric(&Numeric);
+		    umfpack_zl_free_symbolic(&Symbolic);
+		} else {
+		    umfpack_zi_free_numeric(&Numeric);
+		    umfpack_zi_free_symbolic(&Symbolic);
+		}
+		if (Apc) delete[] Apc; 
+		if (Aic) delete[] Aic;
+	    }
+
+	    void update_numeric_aux(true_)
+	    {
+		umfpack_zl_free_numeric(&Numeric);
+		check(umfpack_zl_numeric(Ap, Ai, &Ax[0], &Az[0], Symbolic, &Numeric, Control, Info), "Error in dl_numeric D");
+	    }
+	    
+	    void update_numeric_aux(false_)
+	    {
+		umfpack_zi_free_numeric(&Numeric);
+		check(umfpack_zi_numeric(Ap, Ai, &Ax[0], &Az[0], Symbolic, &Numeric, Control, Info), "Error in di_numeric");
+	    }
+
+	    /// Update numeric part, for matrices that kept the sparsity and changed the values
+	    void update_numeric()
+	    {
+		assign_pointers();
+		update_numeric_aux(blong());
+	    }
+
+	    /// Update symbolic and numeric part
+	    void update()
+	    {
+		Ax.change_dim(0); Az.change_dim(0);
+		if (long_indices) {
+		    umfpack_zl_free_numeric(&Numeric);
+		    umfpack_zl_free_symbolic(&Symbolic);
+		} else {
+		    umfpack_zi_free_numeric(&Numeric);
+		    umfpack_zi_free_symbolic(&Symbolic);
+		}
+		initialize();
+	    }
+
+	    template <typename VectorX, typename VectorB>
+	    void solve_aux(int sys, VectorX& Xx, VectorX& Xz, const VectorB& Bx, const VectorB& Bz, true_)
+	    {
+		check(umfpack_zl_solve(sys, Ap, Ai, &Ax[0], &Az[0], &Xx[0], &Xz[0], &Bx[0], &Bz[0], Numeric, Control, Info), 
+		      "Error in zi_solve");
+	    }
+
+	    template <typename VectorX, typename VectorB>
+	    void solve_aux(int sys, VectorX& Xx, VectorX& Xz, const VectorB& Bx, const VectorB& Bz, false_)
+	    {
+		check(umfpack_zi_solve(sys, Ap, Ai, &Ax[0], &Az[0], &Xx[0], &Xz[0], &Bx[0], &Bz[0], Numeric, Control, Info), 
+		      "Error in zi_solve");
+	    }
+
+	    /// Solve complex system
+	    template <typename VectorX, typename VectorB>
+	    int operator()(VectorX& x, const VectorB& b)
+	    {
+		vampir_trace<5062> trace;
+		MTL_THROW_IF(num_rows(A) != size(x) || num_rows(A) != size(b), incompatible_size());
+		dense_vector<double> Xx(size(x)), Xz(size(x)), Bx, Bz;
+		split_complex_vector(b, Bx, Bz);
+		int sys= mtl::traits::is_row_major<Parameters>::value ? UMFPACK_Aat : UMFPACK_A;
+		solve_aux(sys, Xx, Xz, Bx, Bz, blong());
+		merge_complex_vector(Xx, Xz, x);
+		return UMFPACK_OK;
+	    }
+
+	    /// Solve complex system
+	    template <typename VectorB, typename VectorX>
+	    int solve(const VectorB& b, VectorX& x)
+	    {
+		return (*this)(x, b);
+	    }
+
+	private:
+	    const matrix_type&   A;
+	    int                  n; 
+	    const index_type     *Ap, *Ai;
+	    index_type          *Apc, *Aic;
+	    dense_vector<double> Ax, Az;
+	    double               Control[UMFPACK_CONTROL], Info[UMFPACK_INFO];
+	    void                 *Symbolic, *Numeric;
+	};
+
+	template <typename Value, typename Parameters>
+	class solver<compressed2D<Value, Parameters> >
+	  : matrix_copy<compressed2D<Value, Parameters>, Value, typename Parameters::orientation>,
+	    public solver<typename matrix_copy<compressed2D<Value, Parameters>, Value, typename Parameters::orientation>::matrix_type >
+	{
+	    typedef matrix_copy<compressed2D<Value, Parameters>, Value, typename Parameters::orientation> copy_type;
+	    typedef solver<typename matrix_copy<compressed2D<Value, Parameters>, Value, typename Parameters::orientation>::matrix_type > solver_type;
+	public:
+	    explicit solver(const compressed2D<Value, Parameters>& A) 
+		: copy_type(A), solver_type(copy_type::matrix), A(A)
+	    {}
+
+	    void update()
+	    {
+		copy_type::matrix= A;
+		solver_type::update();
+	    }
+
+	    void update_numeric()
+	    {
+		copy_type::matrix= A;
+		solver_type::update_numeric();
+	    }
+	private:
+	    const compressed2D<Value, Parameters>& A;
+	};
+    } // umfpack
+
+/// Solve A*x == b with umfpack
+/** Only available when compiled with enabled macro MTL_HAS_UMFPACK.
+    Uses classes umfpack::solver internally.
+    If you want more control on single operations or to keep umfpack's
+    internal factorization, use this class.
+ **/
+template <typename Value, typename Parameters, typename VectorX, typename VectorB>
+int umfpack2_solve(const compressed2D<Value, Parameters>& A, VectorX& x, const VectorB& b)
+{
+    umfpack2::solver<compressed2D<Value, Parameters> > solver(A);
+    return solver(x, b);
+}
+
+}} // namespace mtl::matrix
+
+#endif
+
+#endif // MTL_MATRIX_UMFPACK_SOLVE_INCLUDE
-- 
GitLab