// Copyright (c) 2015 GeometryFactory (France), All rights reserved. // // This file is part of CGAL (www.cgal.org) // // $URL: https://github.com/CGAL/cgal/blob/v5.1/Solver_interface/include/CGAL/Diagonalize_traits.h $ // $Id: Diagonalize_traits.h 0779373 2020-03-26T13:31:46+01:00 Sébastien Loriot // SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial // // Author(s) : Simon Giraudot #ifndef CGAL_DIAGONALIZE_TRAITS_H #define CGAL_DIAGONALIZE_TRAITS_H #include #include #include #include #include #ifndef CGAL_I_WANT_TO_USE_DIAGONALIZE_TRAITS #define CGAL_WARNING_DIAGONALIZE_TRAITS \ CGAL_DEPRECATED_MSG("CGAL::Diagonalize_traits is a deprecated class that can \ lead to precision issues, please use CGAL::Eigen_diagonalize_traits") #else #define CGAL_WARNING_DIAGONALIZE_TRAITS #endif /// \cond SKIP_IN_MANUAL namespace CGAL { /// \ingroup PkgSolverInterfaceRef /// /// The class `Diagonalize_traits` provides an internal /// implementation for the diagonalization of Variance-Covariance /// Matrices. /// /// \warning This class is outdated: it can lead to precision issues /// and should only be used if \ref thirdpartyEigen "Eigen" is not /// available. Otherwise, `Eigen_diagonalize_traits` should be used. /// /// \tparam FT Number type /// \tparam dim Dimension of the matrices and vectors /// /// \cgalModels `DiagonalizeTraits` template class Diagonalize_traits { public: typedef std::array Vector; typedef std::array Matrix; typedef std::array Covariance_matrix; /// Fill `eigenvalues` with the eigenvalues of the covariance matrix represented by `cov`. /// Eigenvalues are sorted by increasing order. /// \return `true` if the operation was successful and `false` otherwise. CGAL_WARNING_DIAGONALIZE_TRAITS static bool diagonalize_selfadjoint_covariance_matrix(const Covariance_matrix& cov, Vector& eigenvalues) { Matrix eigenvectors; return diagonalize_selfadjoint_covariance_matrix(cov, eigenvalues, eigenvectors); } /// Extract the eigenvector associated to the largest eigenvalue /// of the covariance matrix represented by `cov`. /// \return `true` if the operation was successful and `false` otherwise. CGAL_WARNING_DIAGONALIZE_TRAITS static bool extract_largest_eigenvector_of_covariance_matrix(const Covariance_matrix& cov, Vector& normal) { Vector eigenvalues; Matrix eigenvectors; diagonalize_selfadjoint_covariance_matrix(cov, eigenvalues, eigenvectors); for(std::size_t i = 0; i < dim; ++ i) normal[i] = static_cast(eigenvectors[(dim*(dim-1))+i]); return true; } /// Fill `eigenvalues` with the eigenvalues and `eigenvectors` with /// the eigenvectors of the covariance matrix represented by `cov`. /// Eigenvalues are sorted by increasing order. /// \return `true` if the operation was successful and `false` otherwise. CGAL_WARNING_DIAGONALIZE_TRAITS static bool diagonalize_selfadjoint_covariance_matrix(const Covariance_matrix& mat, Vector& eigen_values, Matrix& eigen_vectors) { const int n = dim; const int max_iter = 100; static const FT epsilon = (FT)0.00001; // number of entries in mat int nn = (n * (n+1)) / 2; // copy matrix FT *a = new FT[nn]; int ij; // This function requires lower triangular, so we switch for(int i=0; i a_normEPS && nb_iter < max_iter) { nb_iter++; FT thr_nn = thr / nn; for(int l=1; l< n; l++) { for(int m=l+1; m<=n; m++) { // compute sinx and cosx int lq = (l*l-l)/2; int mq = (m*m-m)/2; int lm = l + mq; FT a_lm = a[lm]; FT a_lm_2 = a_lm * a_lm; if(a_lm_2 < thr_nn) continue; int ll = l + lq; int mm = m + mq; FT a_ll = a[ll]; FT a_mm = a[mm]; FT delta = a_ll - a_mm; FT x; if(delta == 0.0) x = (FT) - CGAL_PI / 4; else x = (FT)(- std::atan( (a_lm+a_lm) / delta ) / 2.0); FT sinx = std::sin(x); FT cosx = std::cos(x); FT sinx_2 = sinx * sinx; FT cosx_2 = cosx * cosx; FT sincos = sinx * cosx; // rotate L and M columns int ilv = n*(l-1); int imv = n*(m-1); int i; for(i=1; i<=n; i++) { if((i!=l) && (i!=m)) { int iq = (i*i-i)/2; int im; if( i eigen_values[j]) { k = j; x = eigen_values[j]; } } eigen_values[k] = eigen_values[i]; eigen_values[i] = x; int jj = index[k]; index[k] = index[i]; index[i] = jj; } // save eigen vectors v++; // back to C++ ij = 0; for(int k=0; k