// ====================================================================== // // Copyright (c) 2000 The CGAL Consortium // // This software and related documentation is part of an INTERNAL release // of the Computational Geometry Algorithms Library (CGAL). It is not // intended for general use. // // ---------------------------------------------------------------------- // // release : // release_date : // // file : include/CGAL/Cartesian/Linear_algebra_d.C // revision : $Revision$ // revision_date : $Date$ // author(s) : Herve.Bronnimann@sophia.inria.fr // coordinator : INRIA Sophia-Antipolis (Mariette.Yvinec@sophia.inria.fr) // // ====================================================================== #ifndef CGAL_CARTESIAN_LINEAR_ALGEBRA_D_C #define CGAL_CARTESIAN_LINEAR_ALGEBRA_D_C #include #include #include #include #include CGAL_BEGIN_NAMESPACE template < class FT > std::pair Linear_algebraCd:: transpose(std::pair p) const { std::swap(p.first,p.second); return p; } template < class FT > Linear_algebraCd::Matrix Linear_algebraCd:: transpose(const Linear_algebraCd::Matrix &M) const { Matrix P(transpose(M.dimension())); int i, j; for (i=0; i inline // in order to facilitate the optimization with unused variables void Linear_algebraCd:: Gaussian_elimination(const Linear_algebraCd::Matrix &M, // return parameters Linear_algebraCd::Matrix &L, Linear_algebraCd::Matrix &U, std::vector &row_permutation, std::vector &column_permutation, Linear_algebraCd::FT &det, int &rank, Linear_algebraCd::Vector &c) const { // Method: we use Gaussian elimination with division at each step // We do not use the variant by Bareiss (because we are on a field) // We obtain L, U, q, such that LM' = U, and U is upper diagonal, // where M' is M whose rows and columns are permuted // Picked up on the way: // det, rank, non-trivial solution c if system is degenerate (c^t M = 0) // Preconditions: CGAL_kernel_precondition( M.row_dimension() <= M.column_dimension() ); CGAL_kernel_precondition( U.dimension() == M.dimension() ); CGAL_kernel_precondition( L.row_dimension() == U.row_dimension() ); CGAL_kernel_precondition( L.column_dimension() == U.row_dimension() ); CGAL_kernel_precondition( M.row_dimension() == c.dimension() ); // Temporaries int i, j, k; int dim = M.row_dimension(), cdim = M.column_dimension(); // All the parameters are already initialized (as in C++) int sign = 1; // First create a copy of M into U, and set L and permutations to identity std::copy(M.begin(), M.end(), U.begin()); std::fill(L.begin(), L.end(), FT(0)); // should be unnecessary for (i=0; i=0; --i) { x[i] = c[i]; for (j=i+1; j inline // in order to facilitate the optimization with unused variables void Linear_algebraCd:: Triangular_left_inverse(const Linear_algebraCd::Matrix &U, // return parameters Linear_algebraCd::Matrix &Uinv) const { int i, j, k; CGAL_kernel_precondition( U.dimension() == transpose(Uinv.dimension()) ); //DEBUG: std::cerr << "system : " << U << std::endl; // std::fill(Uinv.begin(), Uinv.end(), FT(0)); for (i=U.row_dimension()-1; i>=0; --i) { Uinv[i][i] = FT(1)/U[i][i]; for (j=i+1; j bool Linear_algebraCd:: inverse(const Linear_algebraCd::Matrix &M, Linear_algebraCd::Matrix &I, FT &D, Linear_algebraCd::Vector &c) const { Matrix L(M.dimension()); Matrix U(M.dimension()); Matrix Uinv(M.column_dimension(),M.row_dimension()); int rank; std::vector rq, cq; Gaussian_elimination(M, L, U, rq, cq, D, rank, c); if (D == FT(0)) return false; // c holds the witness // Otherwise, compute the inverse of U Triangular_left_inverse(U,Uinv); Uinv = Uinv * L; // Don't forget to permute the rows of M back //DEBUG: std::cerr << "inverse before permutation : " << I << std::endl; for (rank=0; rank inline Linear_algebraCd::Matrix Linear_algebraCd:: inverse(const Linear_algebraCd::Matrix &M, Linear_algebraCd::FT &D) const { CGAL_kernel_precondition( M.row_dimension() == M.column_dimension() ); Matrix I(M.column_dimension(),M.row_dimension()); Vector c(M.row_dimension()); bool result = inverse(M,I,D,c); CGAL_kernel_precondition( result ); return I; } template < class FT > Linear_algebraCd::FT Linear_algebraCd:: determinant(const Linear_algebraCd::Matrix &M, Linear_algebraCd::Matrix &L, Linear_algebraCd::Matrix &U, std::vector &q, Linear_algebraCd::Vector &c) const { FT det; int rank; std::vector cq; Gaussian_elimination(M, L, U, q, cq, det, rank, c); return det; } template < class FT > inline Linear_algebraCd::FT Linear_algebraCd:: determinant(const Linear_algebraCd::Matrix &M) const { Matrix L(M.dimension()); Matrix U(M.dimension()); std::vector q; Vector c(M.column_dimension()); return determinant(M,L,U,q,c); } template < class FT > inline Sign Linear_algebraCd:: sign_of_determinant(const Linear_algebraCd::Matrix &M) const { return CGAL::sign(determinant(M)); } template < class FT > bool Linear_algebraCd:: verify_determinant(const Linear_algebraCd::Matrix & /*M*/, const Linear_algebraCd::Matrix & /*L*/, const Linear_algebraCd::Matrix & /*U*/, const FT & /*D*/, const std::vector & /*q*/, const Linear_algebraCd::Vector & /*c*/) const { // TODO: verify_determinant CGAL_kernel_assertion( false ); return false; } template < class FT > bool Linear_algebraCd:: linear_solver(const Linear_algebraCd::Matrix &/*M*/, const Linear_algebraCd::Vector &/*b*/, Linear_algebraCd::Vector &/*x*/, FT &/*D*/, Linear_algebraCd::Matrix &/*spanning_vectors*/, Linear_algebraCd::Vector &/*c*/) const { // TODO: full linear_solver() with spanning vectors CGAL_kernel_assertion( false ); return false; } template < class FT > inline bool Linear_algebraCd:: linear_solver(const Linear_algebraCd::Matrix &M, const Linear_algebraCd::Vector &b, Linear_algebraCd::Vector &x, FT &D, Linear_algebraCd::Vector &c) const { CGAL_kernel_precondition( M.row_dimension() <= M.column_dimension() ); CGAL_kernel_precondition( b.dimension() == M.row_dimension() ); CGAL_kernel_precondition( x.dimension() == M.column_dimension() ); CGAL_kernel_precondition( c.dimension() == M.column_dimension() ); Matrix L(M.dimension()); Matrix U(M.dimension()); FT det; int rank; std::vector rq, cq; //DEBUG: std::cerr << "system : " << M << std::endl << b << std::endl; Gaussian_elimination(M, L, U, rq, cq, D, rank, c); //DEBUG: std::cerr << "transformed : " << L << std::endl << U << std::endl; if (rank != U.row_dimension()) return false; // Compute a solution by solving triangular system // Since LM=U, and x is a solution of Mx=b, then Ux=Lb // Temporary store the solution in c Triangular_system_solver(U, L*b, c, D); // Don't forget to permute the rows of M back //DEBUG: std::cerr << "solution before permutation : " << c << std::endl; for (rank=0; rank inline bool Linear_algebraCd:: linear_solver(const Linear_algebraCd::Matrix &M, const Linear_algebraCd::Vector &b, Linear_algebraCd::Vector &x, FT &D) const { Vector c(M.column_dimension()); return linear_solver(M, b, x, D, c); } template < class FT > inline bool Linear_algebraCd:: is_solvable(const Linear_algebraCd::Matrix &M, const Linear_algebraCd::Vector &b) const { Vector x(M.column_dimension()); FT D; return linear_solver(M, b, x, D); } template < class FT > bool Linear_algebraCd:: homogeneous_linear_solver(const Linear_algebraCd::Matrix &M, Linear_algebraCd::Vector &x) const { // TODO: homogeneous_linear_solver } template < class FT > int Linear_algebraCd:: homogeneous_linear_solver(const Linear_algebraCd::Matrix &M, Linear_algebraCd::Matrix &spanning_vectors) const { // TODO: full homogeneous_linear_solver() with spanning vectors } template < class FT > int Linear_algebraCd:: rank(const Linear_algebraCd::Matrix &M, std::vector &q) const { int rank; std::vector cq; Gaussian_elimination(M, Matrix(M.dimension()), Matrix(M.dimension()), q, cq, FT(0), rank, Vector(M.row_dimension())); return rank; } template < class FT > inline int Linear_algebraCd:: rank(const Linear_algebraCd::Matrix &M) { std::vector q; return rank(M,q); } CGAL_END_NAMESPACE #endif // CGAL_CARTESIAN_LINEAR_ALGEBRA_D_C