cgal/Surface_reconstruction_poin.../include/CGAL/taucs_solver.h

478 lines
12 KiB
C++

// Copyright (c) 2007-08 INRIA Sophia-Antipolis (France).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org); you may redistribute it under
// the terms of the Q Public License version 1.0.
// See the file LICENSE.QPL distributed with CGAL.
//
// Licensees holding a valid commercial license may use this file in
// accordance with the commercial license agreement provided with the software.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//
// $URL$
// $Id$
//
// Author(s) : Pierre Alliez and Mario Botsch
#ifndef CGAL_TAUCS_SOLVER_H
#define CGAL_TAUCS_SOLVER_H
#include <CGAL/Taucs_fix.h>
#include <CGAL/surface_reconstruction_points_assertions.h>
// Uncomment the next line to see libraries selected by auto-link
//#define CGAL_LIB_DIAGNOSTIC
#include <CGAL/auto_link/TAUCS.h>
#ifdef WIN32
#include <CGAL/Win32_exception.h>
#endif
#include <vector>
#include <set>
CGAL_BEGIN_NAMESPACE
// Forward declaration
template<class T> struct Taucs_traits;
/// CLASS Taucs_solver:
/// direct solver for symmetric positive definite sparse systems.
template<class T> // Tested with T = float or double
class Taucs_solver
{
// Public types
public:
typedef std::vector<T> Vector;
typedef T NT;
// Public operations
public:
Taucs_solver(unsigned int size, ///< Number of rows = number of columns
unsigned int nb_elements_per_line=0) ///< Number of non null elements per line
///< (ignored if 0).
: PAP(0),
L(0),
SL(0),
n_rows(size),
row_index(0),
perm(0),
invperm(0),
supernodal_(true),
m_io_handle(NULL)
{
// Reserve taucs_ccs_matrix's arrays to avoid memory fragmentation:
// - rowind[] = array of non null elements of the matrix, ordered by columns.
// - values[] = array of row index of each element of rowind[].
// - colptr[j] is the index of the first element of the column j (or where it
// should be if it doesn't exist) + the past-the-end index of the last column.
colptr.reserve(n_rows+1);
if (nb_elements_per_line > 0)
{
rowind.reserve(n_rows*nb_elements_per_line + 16); // 16 is slack
values.reserve(n_rows*nb_elements_per_line + 16); // 16 is slack
}
#ifdef DEBUG_TRACE
// Turn on TAUCS trace to stderr or to a log file
#if DEBUG_TRACE >= 2
std::cerr.flush();
taucs_logfile((char*)"stderr");
#else
taucs_logfile((char*)"taucs.log");
#endif
#endif
}
~Taucs_solver()
{
delete_matrices();
}
void begin_row()
{
if (colptr.empty() || colptr.back() != (int)values.size())
{
colptr.push_back((int)values.size());
row_index = (int)colptr.size()-1;
}
CGAL_surface_reconstruction_points_assertion(row_index <= n_rows);
}
void add_value(int _i, T _val)
{
// We store only the lower diagonal matrix
if(_i <= row_index)
{
// print warning if reallocating the arrays
if (values.capacity() == values.size() || rowind.capacity() == rowind.size())
std::cerr << "Taucs_solver: reallocating the matrix\n";
values.push_back(_val);
rowind.push_back(_i);
}
}
void end_row()
{
if (colptr.empty() || colptr.back() != (int)values.size())
{
colptr.push_back((int)values.size());
row_index = (int)(colptr.size()-1);
}
CGAL_surface_reconstruction_points_assertion(row_index <= n_rows + 1);
}
bool factorize(bool _use_supernodal = true)
{
#ifdef WIN32
Win32_exception_handler eh; // catch Win32 structured exceptions
#endif
supernodal_ = _use_supernodal;
// delete old matrices
delete_matrices();
CGAL_surface_reconstruction_points_assertion(perm == NULL);
CGAL_surface_reconstruction_points_assertion(invperm == NULL);
CGAL_surface_reconstruction_points_assertion(PAP == NULL);
CGAL_surface_reconstruction_points_assertion(SL == NULL);
CGAL_surface_reconstruction_points_assertion(L == NULL);
finalize_matrix();
// bandlimitation
try {
taucs_ccs_order(&A, &perm, &invperm, (char*)"metis");
}
catch (...) {}
if (perm == NULL || invperm == NULL)
{
std::cerr << "Taucs_solver: metis failed\n";
return false;
}
try {
PAP = taucs_ccs_permute_symmetrically(&A, perm, invperm);
}
catch (...) {}
if (PAP == NULL)
{
std::cerr << "Taucs_solver: permutation failed\n";
return false;
}
// Cholesky factorization
try {
if (supernodal_) SL = taucs_ccs_factor_llt_mf (PAP);
else L = taucs_ccs_factor_llt (PAP, 0, 0);
}
catch (...) {}
if (!(L || SL))
{
std::cerr << "Taucs_solver: factorization failed\n";
return false;
}
return true;
}
bool factorize_ooc()
{
#ifdef WIN32
Win32_exception_handler eh; // catch Win32 structured exceptions
#endif
// delete old matrices
delete_matrices();
CGAL_surface_reconstruction_points_assertion(perm == NULL);
CGAL_surface_reconstruction_points_assertion(invperm == NULL);
CGAL_surface_reconstruction_points_assertion(PAP == NULL);
CGAL_surface_reconstruction_points_assertion(m_io_handle == NULL);
finalize_matrix();
// bandlimitation
try {
taucs_ccs_order(&A, &perm, &invperm, (char*)"metis");
}
catch (...) {}
if (perm == NULL || invperm == NULL)
{
std::cerr << "Taucs_solver: metis failed\n";
return false;
}
try {
PAP = taucs_ccs_permute_symmetrically(&A, perm, invperm);
}
catch (...) {}
if (PAP == NULL)
{
std::cerr << "Taucs_solver: permutation failed\n";
return false;
}
// out-of-core Cholesky factorization
char* matrixfile = tempnam(NULL, "taucs.L");
CGAL_surface_reconstruction_points_assertion(matrixfile != NULL);
try {
m_io_handle = taucs_io_create_multifile(matrixfile);
}
catch (...) {}
free(matrixfile);
if(m_io_handle == NULL)
{
std::cerr << "Taucs_solver: ooc file opening failed\n";
return false;
}
int result = TAUCS_ERROR;
try {
double available_memory = taucs_available_memory_size();
result = taucs_ooc_factor_llt(PAP,m_io_handle,available_memory);
}
catch (...) {}
if(result != TAUCS_SUCCESS)
{
std::cerr << "Taucs_solver: ooc factorization failed\n";
return false;
}
return true;
}
bool solve(Vector& _b, Vector& _x)
{
const unsigned int N = A.n;
if (N != _b.size() || N != _x.size())
{
std::cerr << "Taucs_solver: matrix size doesn't match vector size\n";
return false;
}
Vector PB(N), PX(N);
// permute rhs
for (unsigned int i=0; i<N; ++i)
PB[i] = _b[perm[i]];
// solve by back-substitution
if ((supernodal_ ?
taucs_supernodal_solve_llt(SL, &PX[0], &PB[0]) :
taucs_ccs_solve_llt(L, &PX[0], &PB[0]))
!= TAUCS_SUCCESS)
{
std::cerr << "Taucs_solver: back-substitution failed\n";
return false;
}
// re-permute x
for (unsigned int i=0; i<N; ++i)
_x[i] = PX[invperm[i]];
return true;
}
bool solve_ooc(Vector& _b, Vector& _x)
{
const unsigned int N = A.n;
if (N != _b.size() || N != _x.size())
{
std::cerr << "Taucs_solver: matrix size doesn't match vector size\n";
return false;
}
Vector PB(N), PX(N);
// permute rhs
for (unsigned int i=0; i<N; ++i)
PB[i] = _b[perm[i]];
if(taucs_ooc_solve_llt(m_io_handle,&PX[0],&PB[0]) != TAUCS_SUCCESS)
{
std::cerr << "Taucs_solver: back-substitution failed\n";
return false;
}
// re-permute x
for (unsigned int i=0; i<N; ++i)
_x[i] = PX[invperm[i]];
return true;
}
bool solve_minres(Vector& _b,
Vector& _x)
{
T* x = new T[_x.size()];
T* b = new T[_b.size()];
for(unsigned int i=0;i<_b.size();i++)
{
x[i] = _x[i];
b[i] = _b[i];
}
int result = taucs_minres(&A,NULL,NULL,x,b,1000,0.01);
delete [] x;
delete [] b;
return (result == TAUCS_SUCCESS);
}
/// Solve using a TAUCS sparse linear solver for symmetric positive definite matrices.
bool solve_linear(Vector& _b,
Vector& _x)
{
T* x = new T[_x.size()];
T* b = new T[_b.size()];
for(unsigned int i=0;i<_b.size();i++)
{
x[i] = _x[i];
b[i] = _b[i];
}
// char* options[] = { "taucs.factor.LU=true", NULL };
char* options[] = {NULL};
int result = taucs_linsolve(&A,NULL,1,x,b,options,NULL);
delete [] x;
delete [] b;
return (result == TAUCS_SUCCESS);
}
bool solve_conjugate_gradient(Vector& b,
Vector& x,
const int itermax,
const T convergetol)
{
finalize_matrix();
int result = taucs_conjugate_gradients(&A,NULL,NULL,&x[0],&b[0],itermax,convergetol);
return (result == TAUCS_SUCCESS);
}
bool solve(Vector& b,
Vector& x,
const unsigned int dim)
{
const unsigned int N = A.n;
CGAL_surface_reconstruction_points_assertion(dim >= 1);
if (N != b.size()/dim || N != x.size()/dim)
{
std::cerr << "Taucs_solver: matrix size doesn't match vector size\n";
return false;
}
Vector PB(N);
Vector PX(N);
// solver component-wise
for (unsigned int c=0;c<dim;c++)
{
// permute rhs
for(unsigned int i=0; i<N; ++i)
PB[i] = b[c*N+perm[i]];
// solve by back-substitution
if((supernodal_ ?
taucs_supernodal_solve_llt(SL, &PX[0], &PB[0]) :
taucs_ccs_solve_llt(L, &PX[0], &PB[0])) != TAUCS_SUCCESS)
{
std::cerr << "Taucs_solver: back-substitution failed\n";
return false;
}
// re-permute x
for (unsigned int i=0; i<N; ++i)
x[c*N + i] = PX[invperm[i]];
}
return true;
}
// Private operations
private:
/// Copy constructor and operator =() are not implemented.
Taucs_solver(const Taucs_solver& toCopy);
Taucs_solver& operator =(const Taucs_solver& toCopy);
// Setup ccs matrix.
void finalize_matrix()
{
A.n = (int)(colptr.size()-1);
A.m = (int)(colptr.size()-1);
// Converts matrix's T type to the corresponding TAUCS constant
A.flags = (Taucs_traits<T>::TAUCS_FLAG | TAUCS_SYMMETRIC | TAUCS_LOWER);
A.colptr = &colptr[0];
A.rowind = &rowind[0];
A.values.v = &values[0];
}
void delete_matrices()
{
if (PAP) { taucs_ccs_free(PAP); PAP = 0; }
if (L) { taucs_ccs_free(L); L = 0; }
if (SL) { taucs_supernodal_factor_free(SL); SL = 0; }
if (perm) { free(perm); perm = 0; }
if (invperm) { free(invperm); invperm = 0; }
if(m_io_handle != NULL)
{
taucs_io_delete(m_io_handle);
// taucs_io_close(m_io_handle);
m_io_handle = NULL;
}
}
// Data
private:
taucs_ccs_matrix A, *PAP, *L;
void *SL;
std::vector<T> values;
std::vector<int> colptr;
std::vector<int> rowind;
int n_rows; // number of rows = number of columns
int row_index; // index of current row
int *perm, *invperm;
bool supernodal_;
taucs_io_handle *m_io_handle;
};
// Utility class:
// convert matrix's T type to the corresponding TAUCS constant (called TAUCS_FLAG).
template<class T> struct Taucs_traits {};
template<> struct Taucs_traits<double> {
enum { TAUCS_FLAG = TAUCS_DOUBLE };
};
template<> struct Taucs_traits<float> {
enum { TAUCS_FLAG = TAUCS_SINGLE };
};
template<> struct Taucs_traits<taucs_dcomplex> {
enum { TAUCS_FLAG = TAUCS_DCOMPLEX };
};
template<> struct Taucs_traits<taucs_scomplex> {
enum { TAUCS_FLAG = TAUCS_SCOMPLEX };
};
CGAL_END_NAMESPACE
#endif // CGAL_TAUCS_SOLVER_H