mirror of https://github.com/CGAL/cgal
408 lines
13 KiB
C++
408 lines
13 KiB
C++
// Copyright (c) 2005 INRIA (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) : Laurent Saboret, Pierre Alliez, Bruno Levy
|
|
|
|
|
|
#ifndef CGAL_TAUCS_MATRIX
|
|
#define CGAL_TAUCS_MATRIX
|
|
|
|
// Include TAUCS main header
|
|
#ifndef CGAL_INCLUDED_TAUCS_H
|
|
#define CGAL_INCLUDED_TAUCS_H
|
|
|
|
// GCC 3.3 complains if we include <complex.h> within "extern C {}"
|
|
#if defined(__GNUC__)
|
|
#include <complex.h>
|
|
#endif
|
|
|
|
// TAUCS is a C library
|
|
extern "C" {
|
|
#include <taucs.h>
|
|
}
|
|
|
|
// Avoid error with std::min() and std::max()
|
|
#undef min
|
|
#undef max
|
|
|
|
#endif
|
|
|
|
#include <cassert>
|
|
|
|
CGAL_BEGIN_NAMESPACE
|
|
|
|
|
|
// Forward declaration
|
|
template<class T> struct Taucs_number;
|
|
|
|
|
|
/// The class Taucs_matrix
|
|
/// is a C++ wrapper around TAUCS' matrix type taucs_ccs_matrix.
|
|
///
|
|
/// This kind of matrix can be either symmetric or not. Symmetric
|
|
/// matrices store only the lower triangle.
|
|
///
|
|
/// @todo Taucs_matrix must reallocate the array of non null elements when it's full.
|
|
/// @todo Filling a Taucs_matrix by lines is very slow. We must improve this code.
|
|
///
|
|
/// Concept: Model of the SparseLinearAlgebraTraits_d::Matrix concept.
|
|
|
|
template<class T> // Tested with T = taucs_single or taucs_double
|
|
// May also work with T = taucs_dcomplex and taucs_scomplex
|
|
struct Taucs_matrix
|
|
{
|
|
// Public types
|
|
public:
|
|
|
|
typedef T NT;
|
|
|
|
// Public operations
|
|
public:
|
|
|
|
/// Create a square matrix initialized with zeros.
|
|
Taucs_matrix(int dim, ///< Matrix dimension.
|
|
bool is_symmetric = false, ///< Symmetric/hermitian?
|
|
int nb_max_elements = 0) ///< Max number of non 0 elements in the
|
|
///< matrix (automatically computed if 0).
|
|
{
|
|
init(dim, dim, is_symmetric, nb_max_elements);
|
|
}
|
|
|
|
/// Create a rectangular matrix initialized with zeros.
|
|
Taucs_matrix(int rows, ///< Matrix dimensions.
|
|
int columns,
|
|
bool is_symmetric = false, ///< Symmetric/hermitian?
|
|
int nb_max_elements = 0) ///< Max number of non 0 elements in the
|
|
///< matrix (automatically computed if 0).
|
|
{
|
|
init(rows, columns, is_symmetric, nb_max_elements);
|
|
}
|
|
|
|
/// Delete TAUCS matrix wrapped by this object.
|
|
~Taucs_matrix() {
|
|
taucs_ccs_free(m_matrix);
|
|
m_matrix = NULL;
|
|
}
|
|
|
|
/// Return the matrix' number of rows.
|
|
inline int row_dimension() const {
|
|
return m_matrix->m;
|
|
}
|
|
/// Return the matrix' number of columns.
|
|
inline int column_dimension() const {
|
|
return m_matrix->n;
|
|
}
|
|
|
|
/// Read access to a matrix coefficient.
|
|
///
|
|
/// Preconditions:
|
|
/// - 0 <= i < row_dimension().
|
|
/// - 0 <= j < column_dimension().
|
|
T get_coef (int i, int j) const
|
|
{
|
|
// For symmetric matrices, we store only the lower triangle
|
|
// => swap i and j if (i, j) belongs to the upper triangle
|
|
if (m_matrix->flags & TAUCS_SYMMETRIC)
|
|
{
|
|
assert(m_matrix->flags & TAUCS_LOWER);
|
|
if (j > i)
|
|
std::swap(i, j);
|
|
}
|
|
|
|
assert(i < row_dimension());
|
|
assert(j < column_dimension());
|
|
|
|
// Get pointer to matrix element (NULL if it doesn't exist)
|
|
const T* element = find_element(i, j);
|
|
|
|
return (element == NULL) ? 0 : (*element);
|
|
}
|
|
|
|
/// Write access to a matrix coefficient: a_ij <- val.
|
|
///
|
|
/// Optimization:
|
|
/// For symmetric matrices, Taucs_matrix stores only the lower triangle
|
|
/// set_coef() does nothing if (i, j) belongs to the upper triangle.
|
|
///
|
|
/// Preconditions:
|
|
/// - 0 <= i < row_dimension().
|
|
/// - 0 <= j < column_dimension().
|
|
void set_coef(int i, int j, T val)
|
|
{
|
|
if (m_matrix->flags & TAUCS_SYMMETRIC)
|
|
{
|
|
assert(m_matrix->flags & TAUCS_LOWER);
|
|
if (j > i)
|
|
return;
|
|
}
|
|
|
|
assert(i < row_dimension());
|
|
assert(j < column_dimension());
|
|
|
|
// Get pointer to matrix element. Create it if it doesn't exist.
|
|
T* element = find_element(i, j, true);
|
|
assert(element != NULL);
|
|
|
|
*element = val; // =
|
|
}
|
|
|
|
/// Write access to a matrix coefficient: a_ij <- a_ij + val.
|
|
///
|
|
/// Optimization:
|
|
/// For symmetric matrices, Taucs_matrix stores only the lower triangle
|
|
/// add_coef() does nothing if (i, j) belongs to the upper triangle.
|
|
///
|
|
/// Preconditions:
|
|
/// - 0 <= i < row_dimension().
|
|
/// - 0 <= j < column_dimension().
|
|
void add_coef(int i, int j, T val)
|
|
{
|
|
if (m_matrix->flags & TAUCS_SYMMETRIC)
|
|
{
|
|
assert(m_matrix->flags & TAUCS_LOWER);
|
|
if (j > i)
|
|
return;
|
|
}
|
|
|
|
assert(i < row_dimension());
|
|
assert(j < column_dimension());
|
|
|
|
// Get pointer to matrix element. Create it if it doesn't exist.
|
|
T* element = find_element(i, j, true);
|
|
assert(element != NULL);
|
|
|
|
*element += val; // +=
|
|
}
|
|
|
|
/// Get TAUCS matrix wrapped by this object.
|
|
const taucs_ccs_matrix* get_taucs_matrix() const {
|
|
return m_matrix;
|
|
}
|
|
taucs_ccs_matrix* get_taucs_matrix() {
|
|
return m_matrix;
|
|
}
|
|
|
|
// Private operations
|
|
private:
|
|
|
|
/// Create a matrix initialized with zeros.
|
|
void init(int rows, ///< Matrix dimensions
|
|
int columns,
|
|
bool is_symmetric, ///< Symmetric/hermitian?
|
|
int nb_max_elements) ///< Max number of non 0 elements in the
|
|
///< matrix (automatically computed if 0)
|
|
{
|
|
assert(rows > 0);
|
|
assert(columns > 0);
|
|
|
|
// Convert matrix's T type to the corresponding TAUCS constant
|
|
int flags = Taucs_number<T>::TAUCS_FLAG;
|
|
|
|
// We store only the lower triangle of symmetric matrices
|
|
if (is_symmetric)
|
|
{
|
|
assert(rows == columns);
|
|
flags |= TAUCS_TRIANGULAR | TAUCS_SYMMETRIC | TAUCS_LOWER;
|
|
}
|
|
|
|
// Compute default max number of non null elements
|
|
if (nb_max_elements <= 0)
|
|
{
|
|
// Pick a number larger than the average valence in a triangular mesh (6)
|
|
int average_nb_elements_per_row_or_column = 16;
|
|
// 16 is fine for Surface_mesh_parameterization package
|
|
|
|
if (!is_symmetric)
|
|
nb_max_elements = average_nb_elements_per_row_or_column * std::max(rows,columns);
|
|
else
|
|
nb_max_elements = (average_nb_elements_per_row_or_column/2+1) * std::max(rows,columns);
|
|
}
|
|
|
|
// Create TAUCS matrix wrapped by this object
|
|
m_matrix = taucs_ccs_create(rows, columns, nb_max_elements, flags);
|
|
|
|
// Init the current and max number of non null elements in m_matrix
|
|
m_nb_elements = 0;
|
|
m_nb_max_elements = nb_max_elements;
|
|
|
|
// Init m_matrix's colptr[] array
|
|
// Implementation note:
|
|
// 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
|
|
for (int col=0; col <= columns; col++)
|
|
m_matrix->colptr[col] = 0;
|
|
}
|
|
|
|
/// Read/write access to a matrix coefficient:
|
|
/// Get a pointer to a matrix element. Optionaly create it.
|
|
/// Return NULL if it doesn't exist (cannot happen if 'create' is true).
|
|
///
|
|
/// Preconditions:
|
|
/// - 0 <= i < row_dimension().
|
|
/// - 0 <= j < column_dimension().
|
|
/// - j <= i for symmetric matrices (we store only the lower triangle).
|
|
T* find_element(int i, int j, bool create)
|
|
{
|
|
T* element = NULL; // returned value
|
|
T* matrix_values = (T*)(m_matrix->values.v);// cast to actual array type
|
|
|
|
assert(i < row_dimension());
|
|
assert(j < column_dimension());
|
|
if (m_matrix->flags & TAUCS_SYMMETRIC)
|
|
{
|
|
assert(m_matrix->flags & TAUCS_LOWER);
|
|
assert(j <= i);
|
|
}
|
|
|
|
// Search for the i element of the j column's range in rowind[] and values[]
|
|
// Implementation note:
|
|
// 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
|
|
for (int idx = m_matrix->colptr[j]; idx <= m_matrix->colptr[j+1]; idx++)
|
|
{
|
|
// At the the (i, j) element's position (which may exist or not)
|
|
if ((m_matrix->rowind[idx] >= i) // on element i position of the column j
|
|
|| (idx == m_matrix->colptr[j+1])) // or on the 1st index of column j+1
|
|
{
|
|
// If the (i, j) element doesn't exist yet and 'create' is true,
|
|
// shift the next elements and insert a new null element
|
|
if (((m_matrix->rowind[idx] > i) // too far in the column j
|
|
|| (idx == m_matrix->colptr[j+1])) // or on the column j+1
|
|
&& create )
|
|
{
|
|
// @todo reallocate m_matrix if it's full
|
|
assert(m_nb_elements < m_nb_max_elements);
|
|
|
|
// The number of elements to shift is:
|
|
int nb_elements_to_shift = m_matrix->colptr[column_dimension()] - idx;
|
|
|
|
// Shift values[] and insert a 0
|
|
if (nb_elements_to_shift > 0)
|
|
memmove(&matrix_values[idx+1], &matrix_values[idx], nb_elements_to_shift*sizeof(T));
|
|
matrix_values[idx] = 0;
|
|
|
|
// Shift rowind[] and add the i index
|
|
if (nb_elements_to_shift > 0)
|
|
memmove(&m_matrix->rowind[idx+1], &m_matrix->rowind[idx], nb_elements_to_shift*sizeof(int));
|
|
m_matrix->rowind[idx] = i;
|
|
|
|
// Shift colptr[]
|
|
for (int col=j+1; col <= column_dimension(); col++)
|
|
m_matrix->colptr[col]++;
|
|
|
|
m_nb_elements++;
|
|
}
|
|
|
|
// If the (i, j) element exists (now), return its address
|
|
if ((m_matrix->rowind[idx] == i) && (idx < m_matrix->colptr[j+1]))
|
|
element = &matrix_values[idx];
|
|
|
|
// exit for() statement
|
|
break;
|
|
}
|
|
}
|
|
|
|
return element;
|
|
}
|
|
|
|
/// Read access to a matrix coefficient:
|
|
/// Get a pointer to a matrix element. Return NULL if it doesn't exist.
|
|
///
|
|
/// Preconditions:
|
|
/// - 0 <= i < row_dimension().
|
|
/// - 0 <= j < column_dimension().
|
|
/// - j <= i for symmetric matrices (we store only the lower triangle).
|
|
const T* find_element(int i, int j) const
|
|
{
|
|
return ((Taucs_matrix<T>*)this)->find_element(i, j, false);
|
|
}
|
|
|
|
/// Taucs_matrix cannot be copied (yet)
|
|
Taucs_matrix(const Taucs_matrix& rhs);
|
|
Taucs_matrix& operator=(const Taucs_matrix& rhs);
|
|
|
|
// Fields
|
|
private:
|
|
|
|
/// The actual TAUCS matrix wrapped by this object.
|
|
taucs_ccs_matrix* m_matrix;
|
|
|
|
/// Current and max number of non null elements in m_matrix.
|
|
int m_nb_elements;
|
|
int m_nb_max_elements;
|
|
};
|
|
|
|
|
|
/// The class Taucs_symmetric_matrix is a C++ wrapper
|
|
/// around a TAUCS *symmetric* matrix (type taucs_ccs_matrix).
|
|
///
|
|
/// Symmetric matrices store only the lower triangle.
|
|
///
|
|
/// Concept: Model of the SparseLinearAlgebraTraits_d::Matrix concept.
|
|
|
|
template<class T> // Tested with T = taucs_single or taucs_double
|
|
// May also work with T = taucs_dcomplex and taucs_scomplex
|
|
struct Taucs_symmetric_matrix
|
|
: public Taucs_matrix<T>
|
|
{
|
|
// Public types
|
|
public:
|
|
|
|
typedef T NT;
|
|
|
|
// Public operations
|
|
public:
|
|
|
|
/// Create a square SYMMETRIC matrix initialized with zeros.
|
|
/// The max number of non 0 elements in the matrix is automatically computed.
|
|
Taucs_symmetric_matrix(int dim) ///< Matrix dimension.
|
|
: Taucs_matrix<T>(dim, true)
|
|
{
|
|
}
|
|
|
|
/// Create a square SYMMETRIC matrix initialized with zeros.
|
|
Taucs_symmetric_matrix(int rows, ///< Matrix dimensions.
|
|
int columns,
|
|
int nb_max_elements = 0) ///< Max number of non 0 elements in the
|
|
///< matrix (automatically computed if 0).
|
|
: Taucs_matrix<T>(rows, columns, true, nb_max_elements)
|
|
{
|
|
}
|
|
};
|
|
|
|
|
|
// Utility class to Taucs_matrix
|
|
// Convert matrix's T type to the corresponding TAUCS constant (called TAUCS_FLAG)
|
|
template<class T> struct Taucs_number {};
|
|
template<> struct Taucs_number<taucs_double> {
|
|
enum { TAUCS_FLAG = TAUCS_DOUBLE };
|
|
};
|
|
template<> struct Taucs_number<taucs_single> {
|
|
enum { TAUCS_FLAG = TAUCS_SINGLE };
|
|
};
|
|
template<> struct Taucs_number<taucs_dcomplex> {
|
|
enum { TAUCS_FLAG = TAUCS_DCOMPLEX };
|
|
};
|
|
template<> struct Taucs_number<taucs_scomplex> {
|
|
enum { TAUCS_FLAG = TAUCS_SCOMPLEX };
|
|
};
|
|
|
|
|
|
CGAL_END_NAMESPACE
|
|
|
|
#endif // CGAL_TAUCS_MATRIX
|