Commit 7dbb1f1f authored by MIJIEUX Thomas's avatar MIJIEUX Thomas

Factorize, rename, and comment

parent b90b54ac
......@@ -8,6 +8,7 @@
#include "../src/Arnoldi_Ortho.hpp"
#include "../src/Arnoldi_IB.hpp"
#include "../src/BGMRes.hpp"
#include "../src/BGMResDR.hpp"
#include "fabulous.h"
#include "MatrixApi.hpp"
......@@ -15,169 +16,165 @@
namespace fabulous {
/**
* @brief This class is used to dereference the handle given by the
* user without knowing in which arithmetic we are.
* \brief This interface is used to operate on the handle given by the user
* without knowing which arithmetic is used.
*/
struct ApiEngineI
{
virtual ~ApiEngineI(){}
virtual void set_rightprecond(
fabulous_rightprecond_t user_rpc, void *user_rpc_data) = 0;
virtual void set_usergemm(fabulous_mvp_t user_mvp) = 0;
virtual void set_mvp(fabulous_mvp_t user_mvp) = 0;
virtual void set_rightprecond(fabulous_rightprecond_t user_rpc) = 0;
virtual void set_dot_product(fabulous_dot_t user_dot) = 0;
virtual void set_parameters(
int max_mvp, int max_krylov_space_size, void *tolerance, int nb_tol) = 0;
virtual void set_dotProduct(fabulous_dot_t user_dot) = 0;
virtual void set_ortho_process(fabulous_orthoproc orthoproc) = 0;
virtual int solve(int dim, void *RHS, void *X0) = 0;
virtual int solve_IB(int dim, void *RHS, void *X0) = 0;
virtual int solve_QR(int dim, void *RHS, void *X0) = 0;
virtual void *get_results() = 0;
virtual int solve(int nrhs, void *B, int ldb, void *X, int ldx) = 0;
virtual int solve_QR(int nrhs, void *B, int ldb, void *X, int ldx) = 0;
virtual int solve_IB(int nrhs, void *B, int ldb, void *X, int ldx) = 0;
virtual int solve_DR(int nrhs, void *B, int ldb, void *X, int ldx,
int nb_eigen_pair, void *target) = 0;
virtual const double *get_logs(int *size) = 0;
};
/**
* @brief Main Engine of the Library. Each method of the API except for
* \brief Main Engine of the Library. Each method of the API except for
* the init function is a member function of both this class and its
* parent's one.
*/
template< class U > class ApiEngine : public ApiEngineI
template< class S > class ApiEngine : public ApiEngineI
{
public:
typedef typename Arithmetik<U>::value_type value_type;
typedef typename Arithmetik<U>::primary_type primary_type;
using value_type = typename Arithmetik<S>::value_type;
using primary_type = typename Arithmetik<S>::primary_type;
using P = primary_type;
private:
MatrixApi<U> matrix;
// Solve parameters
int max_mvp;
std::vector<primary_type> tolerance;
int max_krylov_space_size;
OrthoScheme ortho;
Block<U> sol; // Solution storage
Logger<primary_type> log;
int _dim;
MatrixApi<S> _matrix;
int _maxMVP;
std::vector<P> _tolerance;
int _max_krylov_space_size;
OrthoScheme _ortho_scheme;
public:
ApiEngine(void *user_mvp_data, int dim, void *user_env):
matrix{user_env, user_mvp_data, dim},
max_mvp(0),
tolerance(0),
max_krylov_space_size(0),
ortho(OrthoScheme::MGS)
ApiEngine(int dim, void *user_env):
_dim{dim},
_matrix{dim, user_env},
_maxMVP{0},
_tolerance{},
_max_krylov_space_size{0},
_ortho_scheme(OrthoScheme::MGS)
{
}
/**
* @brief This function set the user Dot product
* \brief This function set the user Dot product
*/
void set_dotProduct(fabulous_dot_t user_dot) override
void set_dot_product(fabulous_dot_t user_dot) override
{
matrix.setDotProduct(user_dot);
_matrix.set_dot_product(user_dot);
}
/**
* @brief This function allow to set a right pre conditionner
* \brief This function allow to set a right pre conditionner
*
*/
void set_rightprecond(fabulous_rightprecond_t user_rpc, void *user_rpc_data) override
void set_rightprecond(fabulous_rightprecond_t user_rpc) override
{
matrix.setRightPreCond(user_rpc, user_rpc_data);
_matrix.set_rpc(user_rpc);
}
void set_usergemm(fabulous_mvp_t user_mvp) override
void set_mvp(fabulous_mvp_t user_mvp) override
{
matrix.setMatBlockVect(user_mvp);
_matrix.set_mvp(user_mvp);
}
void set_parameters(int inMaxIte, int inMax_Krylov_Space_Size, void *in_tolerance, int nb_tol) override
void set_parameters(int maxMVP, int max_krylov_space_size,
void *tolerance, int nb_tolerance) override
{
primary_type *p_tol = reinterpret_cast<primary_type*>(in_tolerance);
tolerance.clear();
tolerance.reserve(nb_tol);
tolerance.assign(p_tol, p_tol+nb_tol);
P *pTolerance = reinterpret_cast<P*>(tolerance);
_tolerance.clear();
_tolerance.reserve(nb_tolerance);
_tolerance.assign(pTolerance, pTolerance+nb_tolerance);
max_mvp = inMaxIte;
max_krylov_space_size = inMax_Krylov_Space_Size;
_maxMVP = maxMVP;
_max_krylov_space_size = max_krylov_space_size;
}
void set_ortho_process(fabulous_orthoproc orthoproc) override
{
switch (orthoproc) {
case FABULOUS_MGS: ortho = OrthoScheme::MGS; break;
case FABULOUS_CGS: ortho = OrthoScheme::CGS; break;
case FABULOUS_IMGS: ortho = OrthoScheme::IMGS; break;
case FABULOUS_ICGS: ortho = OrthoScheme::ICGS; break;
case FABULOUS_MGS: _ortho_scheme = OrthoScheme::MGS; break;
case FABULOUS_CGS: _ortho_scheme = OrthoScheme::CGS; break;
case FABULOUS_IMGS: _ortho_scheme = OrthoScheme::IMGS; break;
case FABULOUS_ICGS: _ortho_scheme = OrthoScheme::ICGS; break;
default:
::fabulous::warning("Value for Ortho is not part of {0,1,2,3}\n"
"Ortho process used will be MGS\n");
ortho = OrthoScheme::MGS;
_ortho_scheme = OrthoScheme::MGS;
break;
}
}
template< class BLOCK >
void ConvertStructures(void *RHS, void *X0, BLOCK &B, BLOCK &X_init)
template< template<class> class ARNOLDI >
int call_solve(int nrhs, S *B, int ldb, S *X, int ldx)
{
X_init.InitBlock(reinterpret_cast<U*>(X0));
B.InitBlock(reinterpret_cast<U*>(RHS));
BGMRes<S> bgmres;
return bgmres.template solve<ARNOLDI>(
_matrix, _dim, nrhs, B, ldb, X, ldx,
_maxMVP, _max_krylov_space_size, _tolerance,
_ortho_scheme, OrthoType::RUHE
);
}
template<class ARNOLDI, class BLOCK,
class P = typename BLOCK::primary_type >
int call_solve(BLOCK &B, BLOCK &X0, BLOCK &sol, Logger<P> &log)
int solve(int nrhs, void *B, int ldb, void *X, int ldx) override
{
return BGMRes<ARNOLDI>(matrix, B, X0,
max_mvp, max_krylov_space_size,
sol, log, tolerance,
ortho, OrthoType::RUHE );
S *B_ = reinterpret_cast<S*>(B);
S *X_ = reinterpret_cast<S*>(X);
return call_solve<Arnoldi>(nrhs, B_, ldb, X_, ldx);
}
// Solve method : RHS and X0 have the same size
int solve(int nbRHS, void *RHS, void *X0) override
int solve_QR(int nrhs, void *B, int ldb, void *X, int ldx) override
{
// Convert raw data to Block
Block<U> X_init{nbRHS, matrix.size()};
Block<U> B{nbRHS, matrix.size()};
ConvertStructures(RHS, X0, B, X_init);
// Init an empty block to store solution
sol.initData(nbRHS, matrix.size());
return call_solve<Arnoldi>(B, X_init, sol, log);
S *B_ = reinterpret_cast<S*>(B);
S *X_ = reinterpret_cast<S*>(X);
return call_solve<Arnoldi_QRInc>(nrhs, B_, ldb, X_, ldx);
}
// Solve method : RHS and X0 have the same size
int solve_QR(int nbRHS, void *RHS, void *X0) override
int solve_IB(int nrhs, void *B, int ldb, void *X, int ldx) override
{
// Convert raw data to Block
Block<U> X_init{nbRHS, matrix.size()};
Block<U> B{nbRHS, matrix.size()};
ConvertStructures(RHS, X0, B, X_init);
// Init an empty block to store solution
sol.initData(nbRHS, matrix.size());
return call_solve<Arnoldi_QRInc>(B, X_init, sol, log);
}
int solve_IB(int nbRHS, void *RHS, void *X0) override
{
Block<U> X_init{nbRHS, matrix.size()}; // Convert raw data to Block
Block<U> B{nbRHS, matrix.size()};
ConvertStructures(RHS, X0, B, X_init);
// Init an empty block to store solution
sol.initData(nbRHS, matrix.size());
return call_solve<Arnoldi_IB>(B, X_init, sol, log);
S *B_ = reinterpret_cast<S*>(B);
S *X_ = reinterpret_cast<S*>(X);
return call_solve<Arnoldi_IB>(nrhs, B_, ldb, X_, ldx);
}
void *get_results() override
int solve_DR(int nrhs, void *B, int ldb, void *X, int ldx,
int nb_eigen_pair, void *target) override
{
return sol.getPtr();
S *B_ = reinterpret_cast<S*>(B);
S *X_ = reinterpret_cast<S*>(X);
P Target;
if (target != nullptr)
Target = *reinterpret_cast<P*>(target);
else
Target = P{0.0};
BGMResDR<S> bgmres;
return bgmres.template solve<Arnoldi>(
_matrix, _dim, nrhs, B_, ldb, X_, ldx,
_maxMVP, _max_krylov_space_size, _tolerance,
nb_eigen_pair, Target,
_ortho_scheme, OrthoType::RUHE
);
}
const double *get_logs(int *size) override
{
*size = log.getNbIteLogged();
return log.writeDownArray();
Logger<P> _logger;
*size = _logger.get_nb_iterations();
return _logger.write_down_array();
}
};
......
......@@ -4,125 +4,112 @@
#include <cassert>
#include "fabulous.h"
#include "Block.hpp"
#include "../../src/Block.hpp"
#include "../../src/Algorithm.hpp"
namespace fabulous {
/**
* @brief This class is a object wrapper over the callback from user.
* The MatrixVectorProduct will be set here
* \brief Object Oriented wrapper over the user's callbacks.
*
* Note: the matrix must be square
* The MatBlockVect, DotProduct, and PrecondBlockVect will be set here
*
* \note the matrix must be square
*/
template< class U > class MatrixApi
template< class S > class MatrixApi
{
public:
typedef typename Arithmetik<U>::value_type value_type;
typedef typename Arithmetik<U>::primary_type primary_type;
typedef typename Arithmetik<S>::value_type value_type;
typedef typename Arithmetik<S>::primary_type primary_type;
int _dim;
void *_user_env;
fabulous_mvp_t _user_mvp;
fabulous_rightprecond_t _user_rpc;
fabulous_dot_t _user_dot;
int _dim;
void *_user_mvp_data;
void *_user_rpc_data;
void *_user_env;
bool _use_rightprecond;
public:
MatrixApi():
MatrixApi(int dim, void *user_env):
_dim(dim),
_user_env(user_env),
_user_mvp(nullptr),
_user_rpc(nullptr),
_user_dot(nullptr),
_dim(0),
_user_mvp_data(nullptr),
_user_rpc_data(nullptr),
_user_env(nullptr),
_use_rightprecond(false)
_user_dot(nullptr)
{
}
int size() const { return _dim; } // Return dimension of matrix (square matrix)
MatrixApi(void *user_env, void *user_mvp_data, int dim):
_user_mvp(nullptr),
_user_rpc(nullptr),
_user_dot(nullptr),
_dim(dim),
_user_mvp_data(user_mvp_data),
_user_rpc_data(nullptr),
_user_env(user_env),
_use_rightprecond(false)
{
}
U at(int, int) { FABULOUS_FATAL_ERROR("should not be reached"); return U{0.0}; }
S at(int, int) { FABULOUS_FATAL_ERROR("should not be reached"); return S{0.0}; }
void MatBlockVect(Block<U> &input, Block<U> &output, int idxToWrite=0)
void MatBlockVect(const Block<S> &input, Block<S> &output,
S alpha = S{1.0}, S beta = S{0.0}) const
{
void* toWrite = output.getPtr(idxToWrite);
std::cout<<"MatBlockVect : Input is "<<input.getSizeBlock()<<" x "
<<input.getLeadingDim()<<"\n";
std::cout<<" : Output is "<<output.getSizeBlock()<<" x "
<<output.getLeadingDim()<<"\n";
assert( _user_mvp != nullptr );
_user_mvp(_user_mvp_data,
input.getSizeBlock(), input.getPtr(), &toWrite,
_user_env );
if ( _user_mvp == nullptr ) {
FABULOUS_NOTE("User matrix vector product is not set!");
FABULOUS_NOTE("Have you called fabulous_set_mvp() ?!");
FABULOUS_FATAL_ERROR("missing user matrix product; cannot recover");
}
void MatBaseProduct(U *ptrToRead, int nbRHS, void *ptrToWrite)
{
assert( _user_mvp != nullptr );
_user_mvp(_user_mvp_data, nbRHS, ptrToRead, &ptrToWrite, _user_env);
_user_mvp(
_user_env, input.get_nb_col(),
input.get_ptr(), input.get_leading_dim(),
output.get_ptr(), output.get_leading_dim(),
&alpha, &beta
);
}
void setMatBlockVect(fabulous_mvp_t user_mvp)
void set_mvp(fabulous_mvp_t user_mvp)
{
_user_mvp = user_mvp;
}
void setRightPreCond(fabulous_rightprecond_t user_rpc, void *user_rpc_data)
void set_rpc(fabulous_rightprecond_t user_rpc)
{
_user_rpc = user_rpc;
_user_rpc_data = user_rpc_data;
_use_rightprecond = true;
}
void setDotProduct(fabulous_dot_t user_dot)
void set_dot_product(fabulous_dot_t user_dot)
{
_user_dot = user_dot;
}
bool useRightPreCond() const { return _use_rightprecond; }
bool useRightPrecond() const { return _user_rpc != nullptr; }
template< class BLOCK >
void preCondBlockVect(BLOCK &input, BLOCK &output)
void PrecondBlockVect(const BLOCK &input, BLOCK &output) const
{
void *toWrite = output.getPtr();
assert( _user_rpc != nullptr );
_user_rpc(_user_rpc_data,
input.getSizeBlock(), input.getPtr(), &toWrite,
_user_env );
assert ( _user_rpc != nullptr );
_user_rpc(
_user_env, input.get_nb_col(),
input.get_ptr(), input.get_leading_dim(),
output.get_ptr(), output.get_leading_dim()
);
}
template< class BLOCK >
void preCondBaseProduct(U *ptrToRead, BLOCK &output)
void DotProduct(int M, int N,
const S *A, int lda,
const S *B, int ldb,
S *C, int ldc) const
{
if ( _user_dot == nullptr) {
FABULOUS_NOTE("User dot product is not set!");
FABULOUS_NOTE("Have you called fabulous_set_dot_product() ?!");
FABULOUS_FATAL_ERROR("missing user dot product; cannot recover");
}
_user_dot( _user_env, M, N, A, lda, B, ldb, C, ldc );
}
void DotProduct(const Block<S> &A, const Block<S> &B, Block<S> &C) const
{
void *toWrite = output.getPtr();
assert( _user_rpc != nullptr );
_user_rpc(_user_rpc_data,
output.getSizeBlock(), ptrToRead, &toWrite,
_user_env );
DotProduct( A.get_nb_col(), B.get_nb_col(),
A.get_ptr(), A.get_leading_dim(),
B.get_ptr(), B.get_leading_dim(),
C.get_tpr(), C.get_leading_dim() );
}
void DotProduct(int size, int nbVect, U *vectA, U *vectB, U *res)
void QRFacto(Block<S> &Q, Block<S> &R) const
{
assert( _user_dot != nullptr );
_user_dot(size, nbVect, vectA, vectB, res, _user_env);
Algorithm::InPlaceQRFactoMGS_User(Q, R, *this);
}
};
......
......@@ -10,26 +10,22 @@ FABULOUS_BEGIN_C_DECL
#define FABULOUS_HANDLE(engine_) \
reinterpret_cast<fabulous_handle>(engine_)
/**
* Implement Init function by creating an instance of the Engine
* class. The ptr to the instance is the Handle.
*/
fabulous_handle fabulous_init(
fabulous_arithmetic ari, void *mvp_data, int dim, void *userEnv)
fabulous_handle fabulous_create(
fabulous_arithmetic ari, int dim, void *user_env)
{
ApiEngineI *engine = nullptr;
switch (ari) {
case FABULOUS_FLOAT:
engine = new ApiEngine<float>(mvp_data, dim, userEnv);
case FABULOUS_REAL_FLOAT:
engine = new ApiEngine<float>(dim, user_env);
break;
case FABULOUS_DOUBLE:
engine = new ApiEngine<double>(mvp_data, dim, userEnv);
case FABULOUS_REAL_DOUBLE:
engine = new ApiEngine<double>(dim, user_env);
break;
case FABULOUS_COMPLEX_FLOAT:
engine = new ApiEngine<std::complex<float>>(mvp_data, dim, userEnv);
engine = new ApiEngine<std::complex<float>>(dim, user_env);
break;
case FABULOUS_COMPLEX_DOUBLE:
engine = new ApiEngine<std::complex<double>>(mvp_data, dim, userEnv);
engine = new ApiEngine<std::complex<double>>(dim, user_env);
break;
default:
FABULOUS_FATAL_ERROR(
......@@ -41,24 +37,23 @@ fabulous_handle fabulous_init(
return FABULOUS_HANDLE(engine);
}
void fabulous_set_usergemm(fabulous_mvp_t user_mvp, fabulous_handle handle)
void fabulous_set_mvp(fabulous_mvp_t user_mvp, fabulous_handle handle)
{
ApiEngineI *disp = FABULOUS_API_ENGINE(handle);
disp->set_usergemm(user_mvp);
disp->set_mvp(user_mvp);
}
void fabulous_set_rightprecond(fabulous_rightprecond_t user_rpc,
void *user_rpc_data,
fabulous_handle handle)
{
ApiEngineI *disp = FABULOUS_API_ENGINE(handle);
disp->set_rightprecond(user_rpc, user_rpc_data);
disp->set_rightprecond(user_rpc);
}
void fabulous_set_dot_product(fabulous_dot_t user_dot, fabulous_handle handle)
{
ApiEngineI *disp = FABULOUS_API_ENGINE(handle);
disp->set_dotProduct(user_dot);
disp->set_dot_product(user_dot);
}
void fabulous_set_parameters(int max_mvp, int max_space_size,
......@@ -76,40 +71,44 @@ void fabulous_set_ortho_process(fabulous_orthoproc orthoproc,
disp->set_ortho_process(orthoproc);
}
int fabulous_solve(int nbRHS, void *RHS, void *X0, fabulous_handle handle)
int fabulous_solve(int nrhs, void *B, int ldb, void *X, int ldx, fabulous_handle handle)
{
ApiEngineI *disp = FABULOUS_API_ENGINE(handle);
return disp->solve(nbRHS, RHS, X0);
return disp->solve(nrhs, B, ldb, X, ldx);
}
int fabulous_solve_QR(int nbRHS, void *RHS, void *X0, fabulous_handle handle)
int fabulous_solve_QR(int nrhs, void *B, int ldb, void *X, int ldx,
fabulous_handle handle)
{
ApiEngineI *disp = FABULOUS_API_ENGINE(handle);
return disp->solve_QR(nbRHS, RHS, X0);
return disp->solve_QR(nrhs, B, ldb, X, ldx);
}
int fabulous_solve_IB(int nbRHS, void *RHS, void *X0, fabulous_handle handle)
int fabulous_solve_IB(int nrhs, void *B, int ldb, void *X, int ldx,
fabulous_handle handle)
{
ApiEngineI *disp = FABULOUS_API_ENGINE(handle);
return disp->solve_IB(nbRHS, RHS, X0);
return disp->solve_IB(nrhs, B, ldb, X, ldx);
}
void fabulous_dealloc(fabulous_handle handle)
int fabulous_solve_DR(int nrhs, void *B, int ldb, void *X, int ldx,
int nb_eigen_pair, void *target,
fabulous_handle handle)
{
ApiEngineI *disp = FABULOUS_API_ENGINE(handle);
delete disp;
return disp->solve_DR(nrhs, B, ldb, X, ldx, nb_eigen_pair, target);
}
void *fabulous_get_results(fabulous_handle handle)
const double *fabulous_get_logs(int *size, fabulous_handle handle)
{
ApiEngineI *disp = FABULOUS_API_ENGINE(handle);
return disp->get_results();
return disp->get_logs(size);
}
const double *fabulous_get_logs(int *size, fabulous_handle handle)
void fabulous_destroy(fabulous_handle handle)
{
ApiEngineI *disp = FABULOUS_API_ENGINE(handle);
return disp->get_logs(size);
delete disp;
}
FABULOUS_END_C_DECL
// Author cpiacibello : cyrille.piacibello@inria.fr,
// lgiraud : luc.giraud@inria.fr
/* authors:
* Cyrille Piacibello: cyrille.piacibello@inria.fr
* Luc Giraud: luc.giraud@inria.fr
* Thomas Mijieux: thomas.mijieux@inria.fr
*/
#ifndef FABULOUS_H
#define FABULOUS_H
/**
* @file fabulous.h Header for using the Ib-GMRes-Dr library from C.
* \file fabulous.h Header for using the fabulous library.
*
* \brief Block Krylov iterative solver API.
*
* This Library is implementing Block Krylov General Minimum Residual iterative solver
* (denoted as BGMRES) which means that this library can solve linear equations
* with multiple right hand sides.
*
* This library also implements several algorithm variants that may improve the
* performance of the library (Incremental QR factorization, IB-BGMRES, BGMRES-DR,
* and IB-BGMRES-DR (not implemented yet)
*
* IB-BGMRES: M. Robbé and M. Sadkane. <br/>
* Exact and inexact breakdowns in the block GMRES method. <br/>
* Linear Algebra and its Applications, 419:265–285, 2006
*
* BGMRES-DR: R. B. Morgan. <br/>
* Restarted block GMRES with deflation of eigenvalues. <br/>
* Applied Numerical Mathematics, 54(2):222–236, 2005.
*
* IB-BGMRES-DR: E. Agullo, L. Giraud, Y.-F. Jing <br/>
* Block GMRES method with inexact breakdowns and deflated restarting <br/>
* SIAM Journal on Matrix Analysis and Applications
* 35, 4, November 2014, p. 1625–1651
*
* @brief This Library is Matrix free, meaning that the user must
* provide a method to compute a Matrix x Block of Vector
* product. Then, he can provide a Right PreConditionner x block of
* Vector product too.
*
* The Matrix x Vector product is not handled by the library and must be implemented
* as a callback by the user. <br/>
* This allow the user to implement a algorithm adapted to his/her problem. <br/>
* (whether the matrix is sparse/dense or have a specific structure)
*
* The user must also implements a DotProduct callback. This allow the user to
* use the library in a distributed fashion. <br/>
* (The input solution and right hand sides may be distributed with block lines style)
* If the user intend to distribute its vector over several nodes, <br/>
* the the callbacks must be adapted to perform the necessary
* communications and/or reductions.
*
*/
......@@ -26,223 +60,317 @@
FABULOUS_BEGIN_C_DECL
/**
* \brief opaque handle for the fabulous library
*/
typedef void *fabulous_handle;
/**
* @brief Enum over different arithmetic available
* \brief The different arithmetics available
*/
enum fabulous_arithmetic {
FABULOUS_REAL_FLOAT = 0, /*!< correspond to 'float' type */
FABULOUS_REAL_DOUBLE = 1, /*!< correspond to 'double' type */
FABULOUS_COMPLEX_FLOAT = 2, /*!< correspond to 'float complex' type */
FABULOUS_COMPLEX_DOUBLE = 3, /*!< correspond to 'double complex' type */
};
/**
* \brief The different orthogonalization schemas available
*/
typedef enum fabulous_arithmetic {
FABULOUS_FLOAT = 0,
FABULOUS_DOUBLE = 1,
FABULOUS_COMPLEX_FLOAT = 2,
FABULOUS_COMPLEX_DOUBLE = 3,
} fabulous_arithmetic;
enum fabulous_orthoproc {
FABULOUS_MGS = 0, /*!< Modified Gram-Schmidt */
FABULOUS_CGS = 1, /*!< Classical Gram-Schmidt */
FABULOUS_IMGS = 2, /*!< Iterated Modified Gram-Schmidt */
FABULOUS_ICGS = 3, /*!< Iteratied Classical Gram-Schmidt */
};
typedef enum fabulous_orthoproc {
FABULOUS_MGS = 0,
FABULOUS_CGS = 1,
FABULOUS_IMGS = 2,
FABULOUS_ICGS = 3,
} fabulous_orthoproc;
typedef enum fabulous_arithmetic fabulous_arithmetic;
typedef enum fabulous_orthoproc fabulous_orthoproc;
/**
* @brief User defined function to compute product between Matrix and
* a block of vector
* \brief User defined function to compute
* product between user's Matrix (A) and Matrix given in argument (X)
*