This commit is contained in:
Andreas Fabri 2025-12-02 19:47:51 +08:00 committed by GitHub
commit 3356483bed
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 473 additions and 3 deletions

View File

@ -51,6 +51,7 @@ and nonlinear programming problems with or without constraints.}
- `QuadraticProgramTraits` - `QuadraticProgramTraits`
\cgalCRPSection{Linear Systems} \cgalCRPSection{Linear Systems}
- `CGAL::Accelerate_solver_traits`
- `CGAL::Eigen_solver_traits` - `CGAL::Eigen_solver_traits`
- `CGAL::Eigen_diagonalize_traits` - `CGAL::Eigen_diagonalize_traits`
- `CGAL::Eigen_vector` - `CGAL::Eigen_vector`

View File

@ -6,6 +6,8 @@ project(Solver_interface_Examples)
find_package(CGAL REQUIRED) find_package(CGAL REQUIRED)
create_single_source_cgal_program("accelerate.cpp")
# Use Eigen # Use Eigen
find_package(Eigen3 QUIET) find_package(Eigen3 QUIET)
include(CGAL_Eigen3_support) include(CGAL_Eigen3_support)

View File

@ -0,0 +1,47 @@
#include <CGAL/Accelerate_sparse_matrix.h>
#include <CGAL/Accelerate_vector.h>
#include <CGAL/Accelerate_solver_traits.h>
int main()
{
{
CGAL::Accelerate_sparse_matrix<double> A(3);
A.set_coef(0,0,1);
A.set_coef(0,1,2);
A.set_coef(0,2,3);
A.set_coef(1,1,5);
A.set_coef(2,2,9);
A.assemble_matrix();
assert(A.get_coef(1,0) == 0);
CGAL::Accelerate_vector<double> B(3), X(3);
B[0] = 1.0;
B[1] = 2.0;
B[2] = 3.0;
CGAL::Accelerate_solver_traits<double> ast;
double D;
ast.linear_solver(A, B, X, D);
assert(D == 1.0);
}
std::cout << std::endl;
{
CGAL::Accelerate_sparse_matrix<double> A(3, true);// symmetric only set lower left
A.set_coef(0,0,1);
A.set_coef(1,0,2);
A.set_coef(2,0,3);
A.set_coef(1,1,5);
A.set_coef(2,2,9);
A.assemble_matrix();
assert(A.get_coef(1,0) == A.get_coef(0, 1));
}
return 0;
}

View File

@ -0,0 +1,57 @@
// Copyright (c) 2024 GeometryFactory SARL (France), All rights reserved.
//
// This file is part of CGAL (www.cgal.org)
//
// $URL$
// $Id$
// SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial
//
// Author(s) : Andreas Fabri
#ifndef CGAL_ACCELERATE_SOLVER_TRAIS_H
#define CGAL_ACCELERATE_SOLVER_TRAIS_H
#include <CGAL/Accelerate_vector.h>
#include <CGAL/Accelerate_sparse_matrix.h>
namespace CGAL {
/*!
\ingroup PkgSolverInterfaceLS
The class `Accelerate_solver_traits` provides an interface to the sparse solvers of
*/
template<class T>
class Accelerate_solver_traits
{
public:
using NT = T;
using Matrix = Accelerate_sparse_matrix<T>;
using Vector = Accelerate_vector<T>;
Accelerate_solver_traits()
{}
/// Solve the sparse linear system \f$ A \times X = B \f$.
/// Return `true` on success. The solution is then \f$ (1/D) \times X \f$.
///
/// \pre A.row_dimension() == B.dimension().
/// \pre A.column_dimension() == X.dimension().
bool linear_solver(const Matrix& A, const Vector& B, Vector& X, NT& D)
{
A.assemble_matrix();
std::cout << " A.solve()" << std::endl;
A.solve(B, X);
X.copy_back();
D = 1; // Accelerate does not support homogeneous coordinates
return true;
}
};
} // namespace CGAL
#endif // ACCELERATE_SOLVER_TRAITS

View File

@ -0,0 +1,244 @@
// Copyright (c) 2024 GeometryFactory SARL (France), All rights reserved.
//
// This file is part of CGAL (www.cgal.org)
//
// $URL$
// $Id$
// SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial
//
// Author(s) : Andreas Fabri
#ifndef CGAL_SOLVER_INTERFACE_ACCELERATE_SPARSE_MATRIX_H
#define CGAL_SOLVER_INTERFACE_ACCELERATE_SPARSE_MATRIX_H
#include <CGAL/basic.h> // include basic.h before testing #defines
#include <CGAL/Accelerate_vector.h>
#include "accelerate/accelerate-swift.h"
#include <map>
namespace CGAL {
/*!
\ingroup PkgSolverInterfaceLS
The class `Accelerate_sparse_matrix` is a wrapper around the `SparseMatrix_Double` matrix type
<a href=https://developer.apple.com/documentation/accelerate/sparsematrix_double">`Accelerate::SparseMatrix`_Double</a>
that represents general matrices, be they symmetric or not.
\cgalModels{SparseLinearAlgebraTraits_d::Matrix}
\tparam T Number type.
\sa `CGAL::Accelerate_vector<T>`
\sa `CGAL::Accelerate_matrix<T>`
\sa `CGAL::Accelerate_sparse_symmetric_matrix<T>`
*/
template<class T>
class Accelerate_sparse_matrix
{
// Public types
public:
/// \name Types
/// @{
/// The internal matrix type from \ref thirdpartyAccelerate "Accelerate".
typedef SwiftAccelerate::Matrix Matrix;
typedef T NT;
/// @}
#if 0
Accelerate_sparse_matrix(const AccelerateType& et)
: m_is_already_built(true), m_has_been_changed(false), m_matrix(et), m_is_symmetric(false)
{}
#endif
// Public operations
public:
Accelerate_sparse_matrix()
: m_matrix(Matrix::init()), m_is_already_built(false), m_has_been_changed(false)
{ }
/// Create a square matrix initialized with zeros.
Accelerate_sparse_matrix(int dim, ///< Matrix dimension.
bool is_symmetric = false) ///< Symmetric/hermitian?
: m_matrix(Matrix::init()), m_rows(dim), m_columns(dim), m_is_already_built(false), m_has_been_changed(false), m_is_symmetric(is_symmetric)
{
CGAL_precondition(dim > 0);
}
/// Create a rectangular matrix initialized with zeros.
///
/// \pre rows == columns if `is_symmetric` is true.
Accelerate_sparse_matrix(int rows, ///< Number of rows.
int columns, ///< Number of columns.
bool is_symmetric = false) ///< Symmetric/hermitian?
: m_matrix(Matrix::init()), m_rows(rows), m_columns(columns), m_is_already_built(false), m_has_been_changed(false), m_is_symmetric(is_symmetric)
{
CGAL_precondition(rows > 0);
CGAL_precondition(columns > 0);
if(m_is_symmetric)
{
CGAL_precondition(rows == columns);
}
// reserve memory for a regular 3D grid
}
void swap(Accelerate_sparse_matrix& other)
{
std::swap(m_rows, other.m_rows);
std::swap(m_columns, other.m_columns);
std::swap(m_is_already_built, other.m_is_already_built);
std::swap(m_has_been_changed, other.m_has_been_changed);
std::swap(m_is_symmetric, other.m_is_symmetric);
//m_matrix.swap(other.m_matrix);
m_triplets.swap(other.m_triplets);
}
/// Delete this object and the wrapped matrix.
~Accelerate_sparse_matrix() = default;
/// Return the matrix number of rows
int row_dimension() const { return m_rows; }
/// Return the matrix number of columns
int column_dimension() const { return m_columns; }
/// Write access to a matrix coefficient: a_ij <- val.
///
/// Users can optimize calls to this function by setting 'new_coef' to `true`
/// if the coefficient does not already exist in the matrix.
///
/// \warning For symmetric matrices, `Accelerate_sparse_matrix` only stores the lower triangle
/// and `set_coef()` does nothing if (i, j) belongs to the upper triangle.
///
/// \pre 0 <= i < row_dimension().
/// \pre 0 <= j < column_dimension().
void set_coef(std::size_t i_, std::size_t j_, T val, bool new_coef = false)
{
int i = static_cast<int>(i_);
int j = static_cast<int>(j_);
CGAL_precondition(i < row_dimension());
CGAL_precondition(j < column_dimension());
if (m_is_symmetric && (j > i))
return;
m_triplets[std::make_pair(i,j)] = val;
if(m_is_already_built){
m_has_been_changed = true;
}
}
/// Write access to a matrix coefficient: a_ij <- a_ij + val.
///
/// \warning For symmetric matrices, Accelerate_sparse_matrix only stores the lower triangle
/// `add_coef()` does nothing if (i, j) belongs to the upper triangle.
///
/// \pre 0 <= i < row_dimension().
/// \pre 0 <= j < column_dimension().
void add_coef(std::size_t i_, std::size_t j_, T val)
{
int i = static_cast<int>(i_);
int j = static_cast<int>(j_);
if(m_is_symmetric && (j > i))
return;
m_triplets[std::make_pair(i,j)] += val;
if(m_is_already_built){
m_has_been_changed = true;
}
}
/// Read access to a matrix coefficient.
///
/// \pre 0 <= i < row_dimension().
/// \pre 0 <= j < column_dimension().
NT get_coef (std::size_t i_, std::size_t j_) const
{
int i = static_cast<int>(i_);
int j = static_cast<int>(j_);
CGAL_precondition(i < row_dimension());
CGAL_precondition(j < column_dimension());
if(m_is_symmetric && j > i){
std::swap(i, j);
}
auto it = m_triplets.find(std::make_pair(i,j));
if(it != m_triplets.end()){
return it->second;
}
return 0;
}
/// \cond SKIP_IN_MANUAL
void assemble_matrix() const
{
SwiftAccelerate::Indices rows = SwiftAccelerate::Indices::init();
SwiftAccelerate::Indices columns = SwiftAccelerate::Indices::init();
SwiftAccelerate::Values values = SwiftAccelerate::Values::init();
for(const auto& triplet : m_triplets){
int i = triplet.first.first;
int j = triplet.first.second;
const NT& val = triplet.second;
rows.push_back(i);
columns.push_back(j);
values.push_back(val);
if(m_is_symmetric && (i != j)){
rows.push_back(j);
columns.push_back(i);
values.push_back(val);
}
}
m_matrix.initialize(m_rows, rows, columns, values);
m_is_already_built = true;
m_has_been_changed = false;
}
/// \endcond
public:
void solve(const Accelerate_vector<T>& B, Accelerate_vector<T>& X) const
{
Accelerate_vector<T>& ncB = const_cast<Accelerate_vector<T>&>(B);
Accelerate_vector<T>& ncX = const_cast<Accelerate_vector<T>&>(X);
m_matrix.solve(ncB.data(), ncX.data());
}
/// \cond SKIP_IN_MANUAL
friend Accelerate_sparse_matrix
operator*(const T& c, const Accelerate_sparse_matrix& M)
{
std::cout << "todo: implement operator*(scalar, matrix)" << std::endl;
assert(false);
return M;
}
friend Accelerate_sparse_matrix
operator+(const Accelerate_sparse_matrix& M0, const Accelerate_sparse_matrix& M1)
{
std::cout << "todo: implement operator+( matrix, matrix)" << std::endl;
assert(false);
return M0;
}
/// \endcond
// Fields
private:
mutable bool m_is_already_built;
mutable bool m_has_been_changed;
bool m_is_symmetric;
int m_rows, m_columns;
mutable std::map<std::pair<int,int>,NT> m_triplets;
mutable Matrix m_matrix;
}; // Accelerate_sparse_matrix
} //namespace CGAL
#endif // CGAL_SOLVER_INTERFACE_ACCELERATE_SPARSE_MATRIX_H

View File

@ -0,0 +1,110 @@
// Copyright (c) 2024 GeometryFactory SARL (France), All rights reserved.
//
// This file is part of CGAL (www.cgal.org)
//
// $URL$
// $Id$
// SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial
//
// Author(s) : Andreas Fabri
#ifndef CGAL_ACCELERATE_VECTOR_H
#define CGAL_ACCELERATE_VECTOR_H
#include <vector>
#include "accelerate/accelerate-swift.h"
namespace CGAL {
/*!
\ingroup PkgSolverInterfaceLS
The class `Accelerate_vector` is a vector of numbers.
\cgalModels{SvdTraits::Vector,SparseLinearAlgebraTraits_d::Vector}
\tparam T Number type. Must be `double` or `float`
\sa `CGAL::Accelerate_solver_traits<T>`
\sa `CGAL::Accelerate_sparse_matrix<T>`
*/
template<class T>
class Accelerate_vector
{
// Public types
public:
/// \name Types
/// @{
typedef T NT;
typedef SwiftAccelerate::Values Vec;
/// @}
// Public operations
public:
/// Constructs a null vector.
Accelerate_vector()
: m_vec(dimension), m_svec(Vec::init())
{}
/// Create a vector initialized with zeros.
Accelerate_vector(std::size_t dimension)
: m_vec(dimension), m_svec(Vec::init(dimension, dimension))
{}
void set(int i, NT v)
{
m_vec[i] = v;
}
/// Return the vector's number of coefficients.
int dimension() const { return static_cast<int>(m_vec.size()); }
NT& operator[](int row)
{
return m_vec[row];
}
void copy_back()
{
for(int i = 0; i < m_vec.size(); i++){
m_vec[i] = m_svec.get(i);
}
}
const NT& operator[](int row) const
{
return m_vec[row];
}
/*
NT& operator[](int row)
{
return m_vec[row];
}
*/
/// Return a pointer to the data array of this vector.
const Vec& data() const {
for(int i = 0; i < m_vec.size(); i++){
m_svec.set(i,m_vec[i]);
}
return m_svec;
}
Vec& data() {
for(int i = 0; i < m_vec.size(); i++){
m_svec.set(i,m_vec[i]);
}
return m_svec;
}
private:
std::vector<T> m_vec;
mutable Vec m_svec;
};
} // namespace CGAL
#endif // CGAL_ACCELERATE_VECTOR_H

View File

@ -91,7 +91,7 @@ public:
{ {
CGAL_precondition(rows > 0); CGAL_precondition(rows > 0);
CGAL_precondition(columns > 0); CGAL_precondition(columns > 0);
if(m_is_symmetric) if(is_symmetric)
{ {
CGAL_precondition(rows == columns); CGAL_precondition(rows == columns);
} }

View File

@ -1,5 +1,7 @@
#include <CGAL/Simple_cartesian.h> #include <CGAL/Simple_cartesian.h>
#include <CGAL/Timer.h>
#include <CGAL/Surface_mesh.h> #include <CGAL/Surface_mesh.h>
#include <CGAL/Surface_mesh_parameterization/IO/File_off.h> #include <CGAL/Surface_mesh_parameterization/IO/File_off.h>
@ -19,6 +21,7 @@ typedef CGAL::Simple_cartesian<double> Kernel;
typedef Kernel::Point_2 Point_2; typedef Kernel::Point_2 Point_2;
typedef Kernel::Point_3 Point_3; typedef Kernel::Point_3 Point_3;
typedef CGAL::Surface_mesh<Kernel::Point_3> SurfaceMesh; typedef CGAL::Surface_mesh<Kernel::Point_3> SurfaceMesh;
typedef CGAL::Timer Timer;
typedef boost::graph_traits<SurfaceMesh>::halfedge_descriptor halfedge_descriptor; typedef boost::graph_traits<SurfaceMesh>::halfedge_descriptor halfedge_descriptor;
typedef boost::graph_traits<SurfaceMesh>::vertex_descriptor vertex_descriptor; typedef boost::graph_traits<SurfaceMesh>::vertex_descriptor vertex_descriptor;
@ -47,7 +50,11 @@ int main(int argc, char** argv)
typedef SMP::Circular_border_arc_length_parameterizer_3<SurfaceMesh> Border_parameterizer; typedef SMP::Circular_border_arc_length_parameterizer_3<SurfaceMesh> Border_parameterizer;
typedef SMP::Discrete_authalic_parameterizer_3<SurfaceMesh, Border_parameterizer> Parameterizer; typedef SMP::Discrete_authalic_parameterizer_3<SurfaceMesh, Border_parameterizer> Parameterizer;
Timer t;
t.start();
SMP::Error_code err = SMP::parameterize(sm, Parameterizer(), bhd, uv_map); SMP::Error_code err = SMP::parameterize(sm, Parameterizer(), bhd, uv_map);
std::cout << t.time() << " sec." << std::endl;
if(err != SMP::OK) { if(err != SMP::OK) {
std::cerr << "Error: " << SMP::get_error_message(err) << std::endl; std::cerr << "Error: " << SMP::get_error_message(err) << std::endl;

View File

@ -23,6 +23,7 @@
#include <CGAL/Default.h> #include <CGAL/Default.h>
#if defined(CGAL_EIGEN3_ENABLED) #if defined(CGAL_EIGEN3_ENABLED)
#include <CGAL/Eigen_solver_traits.h> #include <CGAL/Eigen_solver_traits.h>
#endif #endif

View File

@ -276,7 +276,8 @@ public:
if(status != OK) if(status != OK)
return status; return status;
std::cout << "Xu: " << Xu[120] << std::endl;
std::cout << "Xv: " << Xv[120] << std::endl;
// WARNING: this package does not support homogeneous coordinates! // WARNING: this package does not support homogeneous coordinates!
CGAL_assertion(Du == 1.0); CGAL_assertion(Du == 1.0);
CGAL_assertion(Dv == 1.0); CGAL_assertion(Dv == 1.0);