cgal/Kernel_d/include/CGAL/Kernel_d/Linear_algebraHd_impl.h

1015 lines
28 KiB
C++

// Copyright (c) 1997-2000
// Utrecht University (The Netherlands),
// ETH Zurich (Switzerland),
// INRIA Sophia-Antipolis (France),
// Max-Planck-Institute Saarbruecken (Germany),
// and Tel-Aviv University (Israel). 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) : Michael Seel <seel@mpi-sb.mpg.de>
//---------------------------------------------------------------------
// file generated by notangle from Linear_algebra.lw
// please debug or modify noweb file
// based on LEDA architecture by S. Naeher, C. Uhrig
// coding: K. Mehlhorn, M. Seel
// debugging and templatization: M. Seel
//---------------------------------------------------------------------
#ifndef CGAL_LINEAR_ALGEBRAHD_C
#define CGAL_LINEAR_ALGEBRAHD_C
namespace CGAL {
template <class RT_, class AL_>
bool Linear_algebraHd<RT_,AL_>::
linear_solver(const Matrix& A, const Vector& b,
Vector& x, RT& D,
Matrix& spanning_vectors, Vector& c)
{
bool solvable = true;
int i,j,k; // indices to step through the matrix
int rows = A.row_dimension();
int cols = A.column_dimension();
/* at this point one might want to check whether the computation can
be carried out with doubles, see section \ref{ optimization }. */
CGAL_assertion_msg(b.dimension() == rows,
"linear_solver: b has wrong dimension");
Matrix C(rows,cols + 1);
// the matrix in which we will calculate ($C = (A \vert b)$)
/* copy |A| and |b| into |C| and L becomes the identity matrix */
Matrix L(rows); // zero initialized
for(i=0; i<rows; i++) {
for(j=0; j<cols; j++)
C(i,j)=A(i,j);
C(i,cols)=b[i];
L(i,i) = 1; // diagonal elements are 1
}
std::vector<int> var(cols);
// column $j$ of |C| represents the |var[j]| - th variable
// the array is indexed between |0| and |cols - 1|
for(j=0; j<cols; j++)
var[j]= j; // at the beginning, variable $x_j$ stands in column $j$
RT_ denom = 1; // the determinant of an empty matrix is 1
int sign = 1; // no interchanges yet
int rank = 0; // we have not seen any non-zero row yet
/* here comes the main loop */
for(k=0; k<rows; k++) {
bool non_zero_found = false;
for(i = k; i < rows; i++) { // step through rows $k$ to |rows - 1|
for (j = k ; j < cols && C(i,j) == 0; j++) {}
// step through columns |k| to |cols - 1|
if (j < cols) {
non_zero_found = true;
break;
}
}
if ( non_zero_found ) {
rank++; //increase the rank
if (i != k) {
sign = -sign;
/* we interchange rows |k| and |i| of |L| and |C| */
L.swap_rows(i,k); C.swap_rows(i,k);
}
if (j != k) {
/* We interchange columns |k| and |j|, and
store the exchange of variables in |var| */
sign = - sign;
C.swap_columns(j,k);
std::swap(var[k],var[j]);
}
for(i = k + 1; i < rows; i++)
for (j = 0; j < rows; j++) //and all columns of |L|
L(i,j) = (L(i,j)*C(k,k) - C(i,k)*L(k,j))/denom;
for(i = k + 1; i < rows; i++) {
/* the following iteration uses and changes |C(i,k)| */
RT temp = C(i,k);
for (j = k; j <= cols; j++)
C(i,j) = (C(i,j)*C(k,k) - temp*C(k,j))/denom;
}
denom = C(k,k);
#ifdef CGAL_LA_SELFTEST
for(i = 0; i < rows; i++) {
for (j = 0; j < cols; j++) {
RT Sum = 0;
for (int l = 0; l < rows; l++)
Sum += L(i,l)*A(l, var[j]);
CGAL_assertion_msg( Sum == C(i,j),
"linear_solver: L*A*P different from C");
}
RT Sum = 0;
for (int l = 0; l < rows; l++)
Sum += L(i,l)*b[l];
CGAL_assertion_msg( Sum == C(i,cols),
"linear_solver: L*A*P different from C");
}
#endif
}
else
break;
}
for(i = rank; i < rows && C(i,cols) == 0; ++i) {}
if (i < rows)
{ solvable = false; c = L.row(i); }
if (solvable) {
x = Vector(cols);
D = denom;
for(i = rank - 1; i >= 0; i--) {
RT_ h = C(i,cols) * D;
for (j = i + 1; j < rank; j++) {
h -= C(i,j)*x[var[j]];
}
x[var[i]]= h / C(i,i);
}
#ifdef CGAL_LA_SELFTEST
CGAL_assertion( (M*x).is_zero() );
#endif
int defect = cols - rank; // dimension of kernel
spanning_vectors = Matrix(cols,defect);
if (defect > 0) {
for(int l=0; l < defect; l++) {
spanning_vectors(var[rank + l],l)=D;
for(i = rank - 1; i >= 0 ; i--) {
RT_ h = - C(i,rank + l)*D;
for ( j= i + 1; j<rank; j++)
h -= C(i,j)*spanning_vectors(var[j],l);
spanning_vectors(var[i],l)= h / C(i,i);
}
#ifdef CGAL_LA_SELFTEST
/* we check whether the $l$ - th spanning vector is a solution
of the homogeneous system */
CGAL_assertion( (M*spanning_vectors.column(l)).is_zero() );
#endif
}
}
}
return solvable;
}
template <class RT_, class AL_>
RT_ Linear_algebraHd<RT_,AL_>::
determinant(const Matrix& A)
{
if (A.row_dimension() != A.column_dimension())
CGAL_error_msg( "determinant(): only square matrices are legal inputs.");
Vector b(A.row_dimension()); // zero - vector
int i,j,k; // indices to step through the matrix
int rows = A.row_dimension();
int cols = A.column_dimension();
/* at this point one might want to check whether the computation can
be carried out with doubles, see section \ref{ optimization }. */
CGAL_assertion_msg(b.dimension() == rows,
"linear_solver: b has wrong dimension");
Matrix C(rows,cols + 1);
// the matrix in which we will calculate ($C = (A \vert b)$)
/* copy |A| and |b| into |C| and L becomes the identity matrix */
Matrix L(rows); // zero initialized
for(i=0; i<rows; i++) {
for(j=0; j<cols; j++)
C(i,j)=A(i,j);
C(i,cols)=b[i];
L(i,i) = 1; // diagonal elements are 1
}
std::vector<int> var(cols);
// column $j$ of |C| represents the |var[j]| - th variable
// the array is indexed between |0| and |cols - 1|
for(j=0; j<cols; j++)
var[j]= j; // at the beginning, variable $x_j$ stands in column $j$
RT_ denom = 1; // the determinant of an empty matrix is 1
int sign = 1; // no interchanges yet
int rank = 0; // we have not seen any non-zero row yet
/* here comes the main loop */
for(k=0; k<rows; k++) {
bool non_zero_found = false;
for(i = k; i < rows; i++) { // step through rows $k$ to |rows - 1|
for (j = k ; j < cols && C(i,j) == 0; j++) {}
// step through columns |k| to |cols - 1|
if (j < cols) {
non_zero_found = true;
break;
}
}
if ( non_zero_found ) {
rank++; //increase the rank
if (i != k) {
sign = -sign;
/* we interchange rows |k| and |i| of |L| and |C| */
L.swap_rows(i,k); C.swap_rows(i,k);
}
if (j != k) {
/* We interchange columns |k| and |j|, and
store the exchange of variables in |var| */
sign = - sign;
C.swap_columns(j,k);
std::swap(var[k],var[j]);
}
for(i = k + 1; i < rows; i++)
for (j = 0; j < rows; j++) //and all columns of |L|
L(i,j) = (L(i,j)*C(k,k) - C(i,k)*L(k,j))/denom;
for(i = k + 1; i < rows; i++) {
/* the following iteration uses and changes |C(i,k)| */
RT temp = C(i,k);
for (j = k; j <= cols; j++)
C(i,j) = (C(i,j)*C(k,k) - temp*C(k,j))/denom;
}
denom = C(k,k);
#ifdef CGAL_LA_SELFTEST
for(i = 0; i < rows; i++) {
for (j = 0; j < cols; j++) {
RT Sum = 0;
for (int l = 0; l < rows; l++)
Sum += L(i,l)*A(l, var[j]);
CGAL_assertion_msg( Sum == C(i,j),
"linear_solver: L*A*P different from C");
}
RT Sum = 0;
for (int l = 0; l < rows; l++)
Sum += L(i,l)*b[l];
CGAL_assertion_msg( Sum == C(i,cols),
"linear_solver: L*A*P different from C");
}
#endif
}
else
break;
}
if (rank < rows)
return 0;
else
return RT(sign) * denom;
}
template <class RT_, class AL_>
RT_ Linear_algebraHd<RT_,AL_>::
determinant(const Matrix& A,
Matrix& Ld, Matrix& Ud,
std::vector<int>& q, Vector& c)
{
if (A.row_dimension() != A.column_dimension())
CGAL_error_msg( "determinant(): only square matrices are legal inputs.");
Vector b(A.row_dimension()); // zero - vector
int i,j,k; // indices to step through the matrix
int rows = A.row_dimension();
int cols = A.column_dimension();
/* at this point one might want to check whether the computation can
be carried out with doubles, see section \ref{ optimization }. */
CGAL_assertion_msg(b.dimension() == rows,
"linear_solver: b has wrong dimension");
Matrix C(rows,cols + 1);
// the matrix in which we will calculate ($C = (A \vert b)$)
/* copy |A| and |b| into |C| and L becomes the identity matrix */
Matrix L(rows); // zero initialized
for(i=0; i<rows; i++) {
for(j=0; j<cols; j++)
C(i,j)=A(i,j);
C(i,cols)=b[i];
L(i,i) = 1; // diagonal elements are 1
}
std::vector<int> var(cols);
// column $j$ of |C| represents the |var[j]| - th variable
// the array is indexed between |0| and |cols - 1|
for(j=0; j<cols; j++)
var[j]= j; // at the beginning, variable $x_j$ stands in column $j$
RT_ denom = 1; // the determinant of an empty matrix is 1
int sign = 1; // no interchanges yet
int rank = 0; // we have not seen any non-zero row yet
/* here comes the main loop */
for(k=0; k<rows; k++) {
bool non_zero_found = false;
for(i = k; i < rows; i++) { // step through rows $k$ to |rows - 1|
for (j = k ; j < cols && C(i,j) == 0; j++) {}
// step through columns |k| to |cols - 1|
if (j < cols) {
non_zero_found = true;
break;
}
}
if ( non_zero_found ) {
rank++; //increase the rank
if (i != k) {
sign = -sign;
/* we interchange rows |k| and |i| of |L| and |C| */
L.swap_rows(i,k); C.swap_rows(i,k);
}
if (j != k) {
/* We interchange columns |k| and |j|, and
store the exchange of variables in |var| */
sign = - sign;
C.swap_columns(j,k);
std::swap(var[k],var[j]);
}
for(i = k + 1; i < rows; i++)
for (j = 0; j < rows; j++) //and all columns of |L|
L(i,j) = (L(i,j)*C(k,k) - C(i,k)*L(k,j))/denom;
for(i = k + 1; i < rows; i++) {
/* the following iteration uses and changes |C(i,k)| */
RT temp = C(i,k);
for (j = k; j <= cols; j++)
C(i,j) = (C(i,j)*C(k,k) - temp*C(k,j))/denom;
}
denom = C(k,k);
#ifdef CGAL_LA_SELFTEST
for(i = 0; i < rows; i++) {
for (j = 0; j < cols; j++) {
RT Sum = 0;
for (int l = 0; l < rows; l++)
Sum += L(i,l)*A(l, var[j]);
CGAL_assertion_msg( Sum == C(i,j),
"linear_solver: L*A*P different from C");
}
RT Sum = 0;
for (int l = 0; l < rows; l++)
Sum += L(i,l)*b[l];
CGAL_assertion_msg( Sum == C(i,cols),
"linear_solver: L*A*P different from C");
}
#endif
}
else
break;
}
if (rank < rows) {
c = L.row(rows - 1);
return 0;
} else {
Ld = L;
Ud = Matrix(rows); // square
for (i = 0; i < rows; i++)
for(j = 0; j <rows; j++)
Ud(i,j) = C(i,j);
q = var;
return RT(sign) * denom;
}
}
template <class RT_, class AL_>
int Linear_algebraHd<RT_,AL_>::
sign_of_determinant(const Matrix& M)
{ return CGAL_NTS sign(determinant(M)); }
template <class RT_, class AL_>
bool Linear_algebraHd<RT_,AL_>::
verify_determinant(const Matrix& A, RT_ D,
Matrix& L, Matrix& U,
const std::vector<int>& q, Vector& c)
{
if ((int)q.size() != A.column_dimension())
CGAL_error_msg( "verify_determinant: q should be a permutation array \
with index range [0,A.column_dimension() - 1].");
int n = A.row_dimension();
int i,j;
if (D == 0) { /* we have $c^T \cdot A = 0$ */
Vector zero(n);
return (transpose(A) * c == zero);
} else {
/* we check the conditions on |L| and |U| */
if (L(0,0) != 1) return false;
for (i = 0; i<n; i++) {
for (j = 0; j < i; j++)
if (U(i,j) != 0)
return false;
if (i > 0 && L(i,i) != U(i - 1,i - 1))
return false;
for (j = i + 1; j < n; j++)
if (L(i,j) != 0)
return false;
}
/* check whether $L \cdot A \cdot Q = U$ */
Matrix LA = L * A;
for (j = 0; j < n; j++)
if (LA.column(q[j]) != U.column(j))
return false;
/* compute sign |s| of |Q| */
int sign = 1;
/* we chase the cycles of |q|. An even length cycle contributes - 1
and vice versa */
std::vector<bool> already_considered(n);
for (i = 0; i < n; i++)
already_considered[i] = false;
for (i = 0; i < n; i++)
already_considered[q[i]] = true;
for (i = 0; i < n; i++)
if (! already_considered[i])
CGAL_error_msg("verify_determinant:q is not a permutation.");
else
already_considered[i] = false;
for (i = 0; i < n; i++) {
if (already_considered[i]) continue;
/* we have found a new cycle with minimal element $i$. */
int k = q[i];
already_considered[i] =true;
while (k != i) {
sign = - sign;
already_considered[k]= true;
k = q[k];
}
}
return (D == RT(sign) * U(n - 1,n - 1));
}
}
template <class RT_, class AL_>
int Linear_algebraHd<RT_,AL_>::
independent_columns(const Matrix& A,
std::vector<int>& columns)
{
Vector b(A.row_dimension()); // zero - vector
int i,j,k; // indices to step through the matrix
int rows = A.row_dimension();
int cols = A.column_dimension();
/* at this point one might want to check whether the computation can
be carried out with doubles, see section \ref{ optimization }. */
CGAL_assertion_msg(b.dimension() == rows,
"linear_solver: b has wrong dimension");
Matrix C(rows,cols + 1);
// the matrix in which we will calculate ($C = (A \vert b)$)
/* copy |A| and |b| into |C| and L becomes the identity matrix */
Matrix L(rows); // zero initialized
for(i=0; i<rows; i++) {
for(j=0; j<cols; j++)
C(i,j)=A(i,j);
C(i,cols)=b[i];
L(i,i) = 1; // diagonal elements are 1
}
std::vector<int> var(cols);
// column $j$ of |C| represents the |var[j]| - th variable
// the array is indexed between |0| and |cols - 1|
for(j=0; j<cols; j++)
var[j]= j; // at the beginning, variable $x_j$ stands in column $j$
RT_ denom = 1; // the determinant of an empty matrix is 1
int sign = 1; // no interchanges yet
int rank = 0; // we have not seen any non-zero row yet
/* here comes the main loop */
for(k=0; k<rows; k++) {
bool non_zero_found = false;
for(i = k; i < rows; i++) { // step through rows $k$ to |rows - 1|
for (j = k ; j < cols && C(i,j) == 0; j++) {}
// step through columns |k| to |cols - 1|
if (j < cols) {
non_zero_found = true;
break;
}
}
if ( non_zero_found ) {
rank++; //increase the rank
if (i != k) {
sign = -sign;
/* we interchange rows |k| and |i| of |L| and |C| */
L.swap_rows(i,k); C.swap_rows(i,k);
}
if (j != k) {
/* We interchange columns |k| and |j|, and
store the exchange of variables in |var| */
sign = - sign;
C.swap_columns(j,k);
std::swap(var[k],var[j]);
}
for(i = k + 1; i < rows; i++)
for (j = 0; j < rows; j++) //and all columns of |L|
L(i,j) = (L(i,j)*C(k,k) - C(i,k)*L(k,j))/denom;
for(i = k + 1; i < rows; i++) {
/* the following iteration uses and changes |C(i,k)| */
RT temp = C(i,k);
for (j = k; j <= cols; j++)
C(i,j) = (C(i,j)*C(k,k) - temp*C(k,j))/denom;
}
denom = C(k,k);
#ifdef CGAL_LA_SELFTEST
for(i = 0; i < rows; i++) {
for (j = 0; j < cols; j++) {
RT Sum = 0;
for (int l = 0; l < rows; l++)
Sum += L(i,l)*A(l, var[j]);
CGAL_assertion_msg( Sum == C(i,j),
"linear_solver: L*A*P different from C");
}
RT Sum = 0;
for (int l = 0; l < rows; l++)
Sum += L(i,l)*b[l];
CGAL_assertion_msg( Sum == C(i,cols),
"linear_solver: L*A*P different from C");
}
#endif
}
else
break;
}
/* at this point we have:
|C| has an $rank \times rank$ upper triangular matrix
in its left upper corner;
|var| tells us the columns of |A| corresponding to the
dependent variables; */
columns = std::vector<int>(rank);
for(i = 0; i < rank; i++)
columns[i] = var[i];
return rank;
}
template <class RT_, class AL_>
int Linear_algebraHd<RT_,AL_>::
rank(const Matrix& A)
{
Vector b(A.row_dimension()); // zero - vector
int i,j,k; // indices to step through the matrix
int rows = A.row_dimension();
int cols = A.column_dimension();
/* at this point one might want to check whether the computation can
be carried out with doubles, see section \ref{ optimization }. */
CGAL_assertion_msg(b.dimension() == rows,
"linear_solver: b has wrong dimension");
Matrix C(rows,cols + 1);
// the matrix in which we will calculate ($C = (A \vert b)$)
/* copy |A| and |b| into |C| and L becomes the identity matrix */
Matrix L(rows); // zero initialized
for(i=0; i<rows; i++) {
for(j=0; j<cols; j++)
C(i,j)=A(i,j);
C(i,cols)=b[i];
L(i,i) = 1; // diagonal elements are 1
}
std::vector<int> var(cols);
// column $j$ of |C| represents the |var[j]| - th variable
// the array is indexed between |0| and |cols - 1|
for(j=0; j<cols; j++)
var[j]= j; // at the beginning, variable $x_j$ stands in column $j$
RT_ denom = 1; // the determinant of an empty matrix is 1
int sign = 1; // no interchanges yet
int rank = 0; // we have not seen any non-zero row yet
/* here comes the main loop */
for(k=0; k<rows; k++) {
bool non_zero_found = false;
for(i = k; i < rows; i++) { // step through rows $k$ to |rows - 1|
for (j = k ; j < cols && C(i,j) == 0; j++) {}
// step through columns |k| to |cols - 1|
if (j < cols) {
non_zero_found = true;
break;
}
}
if ( non_zero_found ) {
rank++; //increase the rank
if (i != k) {
sign = -sign;
/* we interchange rows |k| and |i| of |L| and |C| */
L.swap_rows(i,k); C.swap_rows(i,k);
}
if (j != k) {
/* We interchange columns |k| and |j|, and
store the exchange of variables in |var| */
sign = - sign;
C.swap_columns(j,k);
std::swap(var[k],var[j]);
}
for(i = k + 1; i < rows; i++)
for (j = 0; j < rows; j++) //and all columns of |L|
L(i,j) = (L(i,j)*C(k,k) - C(i,k)*L(k,j))/denom;
for(i = k + 1; i < rows; i++) {
/* the following iteration uses and changes |C(i,k)| */
RT temp = C(i,k);
for (j = k; j <= cols; j++)
C(i,j) = (C(i,j)*C(k,k) - temp*C(k,j))/denom;
}
denom = C(k,k);
#ifdef CGAL_LA_SELFTEST
for(i = 0; i < rows; i++) {
for (j = 0; j < cols; j++) {
RT Sum = 0;
for (int l = 0; l < rows; l++)
Sum += L(i,l)*A(l, var[j]);
CGAL_assertion_msg( Sum == C(i,j),
"linear_solver: L*A*P different from C");
}
RT Sum = 0;
for (int l = 0; l < rows; l++)
Sum += L(i,l)*b[l];
CGAL_assertion_msg( Sum == C(i,cols),
"linear_solver: L*A*P different from C");
}
#endif
}
else
break;
}
return rank;
}
template <class RT_, class AL_>
bool Linear_algebraHd<RT_,AL_>::
inverse(const Matrix& A, Matrix& inverse,
RT_& D, Vector& c)
{
if (A.row_dimension() != A.column_dimension())
CGAL_error_msg("inverse: only square matrices are legal inputs.");
Vector b(A.row_dimension()); // zero - vector
int i,j,k; // indices to step through the matrix
int rows = A.row_dimension();
int cols = A.column_dimension();
/* at this point one might want to check whether the computation can
be carried out with doubles, see section \ref{ optimization }. */
CGAL_assertion_msg(b.dimension() == rows,
"linear_solver: b has wrong dimension");
Matrix C(rows,cols + 1);
// the matrix in which we will calculate ($C = (A \vert b)$)
/* copy |A| and |b| into |C| and L becomes the identity matrix */
Matrix L(rows); // zero initialized
for(i=0; i<rows; i++) {
for(j=0; j<cols; j++)
C(i,j)=A(i,j);
C(i,cols)=b[i];
L(i,i) = 1; // diagonal elements are 1
}
std::vector<int> var(cols);
// column $j$ of |C| represents the |var[j]| - th variable
// the array is indexed between |0| and |cols - 1|
for(j=0; j<cols; j++)
var[j]= j; // at the beginning, variable $x_j$ stands in column $j$
RT_ denom = 1; // the determinant of an empty matrix is 1
int sign = 1; // no interchanges yet
int rank = 0; // we have not seen any non-zero row yet
/* here comes the main loop */
for(k=0; k<rows; k++) {
bool non_zero_found = false;
for(i = k; i < rows; i++) { // step through rows $k$ to |rows - 1|
for (j = k ; j < cols && C(i,j) == 0; j++) {}
// step through columns |k| to |cols - 1|
if (j < cols) {
non_zero_found = true;
break;
}
}
if ( non_zero_found ) {
rank++; //increase the rank
if (i != k) {
sign = -sign;
/* we interchange rows |k| and |i| of |L| and |C| */
L.swap_rows(i,k); C.swap_rows(i,k);
}
if (j != k) {
/* We interchange columns |k| and |j|, and
store the exchange of variables in |var| */
sign = - sign;
C.swap_columns(j,k);
std::swap(var[k],var[j]);
}
for(i = k + 1; i < rows; i++)
for (j = 0; j < rows; j++) //and all columns of |L|
L(i,j) = (L(i,j)*C(k,k) - C(i,k)*L(k,j))/denom;
for(i = k + 1; i < rows; i++) {
/* the following iteration uses and changes |C(i,k)| */
RT temp = C(i,k);
for (j = k; j <= cols; j++)
C(i,j) = (C(i,j)*C(k,k) - temp*C(k,j))/denom;
}
denom = C(k,k);
#ifdef CGAL_LA_SELFTEST
for(i = 0; i < rows; i++) {
for (j = 0; j < cols; j++) {
RT Sum = 0;
for (int l = 0; l < rows; l++)
Sum += L(i,l)*A(l, var[j]);
CGAL_assertion_msg( Sum == C(i,j),
"linear_solver: L*A*P different from C");
}
RT Sum = 0;
for (int l = 0; l < rows; l++)
Sum += L(i,l)*b[l];
CGAL_assertion_msg( Sum == C(i,cols),
"linear_solver: L*A*P different from C");
}
#endif
}
else
break;
}
if (rank < rows) {
// matrix is singular; return a vector $c$ with $c^T \cdot A = 0$.*/
c = L.row(rows-1);
return false;
}
D = denom;
inverse = Matrix(rows); //square
RT_ h;
for(i = 0; i <rows; i++)
{ // $i$-th column of inverse
for (j = rows - 1; j >= 0; j--) {
h = L (j,i) * D;
for (int l = j + 1; l<rows; l++)
h -= C(j,l)*inverse(var[l],i);
inverse(var[j],i) = h / C(j,j);
}
}
#ifdef CGAL_LA_SELFTEST
if (A*inverse != Matrix(rows,Matrix::RT_val(1))*D)
CGAL_error_msg("inverse(): matrix inverse computed incorrectly.");
#endif
return true;
}
template <class RT_, class AL_>
int Linear_algebraHd<RT_,AL_>::
homogeneous_linear_solver(const Matrix &A,
Matrix& spanning_vectors)
/* returns the dimension of the solution space of the homogeneous system
$Ax = 0$. The columns of spanning\_vectors span the solution space. */
{
Vector b(A.row_dimension()); // zero - vector
RT_ D;
int i,j,k; // indices to step through the matrix
int rows = A.row_dimension();
int cols = A.column_dimension();
/* at this point one might want to check whether the computation can
be carried out with doubles, see section \ref{ optimization }. */
CGAL_assertion_msg(b.dimension() == rows,
"linear_solver: b has wrong dimension");
Matrix C(rows,cols + 1);
// the matrix in which we will calculate ($C = (A \vert b)$)
/* copy |A| and |b| into |C| and L becomes the identity matrix */
Matrix L(rows); // zero initialized
for(i=0; i<rows; i++) {
for(j=0; j<cols; j++)
C(i,j)=A(i,j);
C(i,cols)=b[i];
L(i,i) = 1; // diagonal elements are 1
}
std::vector<int> var(cols);
// column $j$ of |C| represents the |var[j]| - th variable
// the array is indexed between |0| and |cols - 1|
for(j=0; j<cols; j++)
var[j]= j; // at the beginning, variable $x_j$ stands in column $j$
RT_ denom = 1; // the determinant of an empty matrix is 1
int sign = 1; // no interchanges yet
int rank = 0; // we have not seen any non-zero row yet
/* here comes the main loop */
for(k=0; k<rows; k++) {
bool non_zero_found = false;
for(i = k; i < rows; i++) { // step through rows $k$ to |rows - 1|
for (j = k ; j < cols && C(i,j) == 0; j++) {}
// step through columns |k| to |cols - 1|
if (j < cols) {
non_zero_found = true;
break;
}
}
if ( non_zero_found ) {
rank++; //increase the rank
if (i != k) {
sign = -sign;
/* we interchange rows |k| and |i| of |L| and |C| */
L.swap_rows(i,k); C.swap_rows(i,k);
}
if (j != k) {
/* We interchange columns |k| and |j|, and
store the exchange of variables in |var| */
sign = - sign;
C.swap_columns(j,k);
std::swap(var[k],var[j]);
}
for(i = k + 1; i < rows; i++)
for (j = 0; j < rows; j++) //and all columns of |L|
L(i,j) = (L(i,j)*C(k,k) - C(i,k)*L(k,j))/denom;
for(i = k + 1; i < rows; i++) {
/* the following iteration uses and changes |C(i,k)| */
RT temp = C(i,k);
for (j = k; j <= cols; j++)
C(i,j) = (C(i,j)*C(k,k) - temp*C(k,j))/denom;
}
denom = C(k,k);
#ifdef CGAL_LA_SELFTEST
for(i = 0; i < rows; i++) {
for (j = 0; j < cols; j++) {
RT Sum = 0;
for (int l = 0; l < rows; l++)
Sum += L(i,l)*A(l, var[j]);
CGAL_assertion_msg( Sum == C(i,j),
"linear_solver: L*A*P different from C");
}
RT Sum = 0;
for (int l = 0; l < rows; l++)
Sum += L(i,l)*b[l];
CGAL_assertion_msg( Sum == C(i,cols),
"linear_solver: L*A*P different from C");
}
#endif
}
else
break;
}
Vector x;
x = Vector(cols);
D = denom;
for(i = rank - 1; i >= 0; i--) {
RT_ h = C(i,cols) * D;
for (j = i + 1; j < rank; j++) {
h -= C(i,j)*x[var[j]];
}
x[var[i]]= h / C(i,i);
}
#ifdef CGAL_LA_SELFTEST
CGAL_assertion( (M*x).is_zero() );
#endif
int defect = cols - rank; // dimension of kernel
spanning_vectors = Matrix(cols,defect);
if (defect > 0) {
for(int l=0; l < defect; l++) {
spanning_vectors(var[rank + l],l)=D;
for(i = rank - 1; i >= 0 ; i--) {
RT_ h = - C(i,rank + l)*D;
for ( j= i + 1; j<rank; j++)
h -= C(i,j)*spanning_vectors(var[j],l);
spanning_vectors(var[i],l)= h / C(i,i);
}
#ifdef CGAL_LA_SELFTEST
/* we check whether the $l$ - th spanning vector is a solution
of the homogeneous system */
CGAL_assertion( (M*spanning_vectors.column(l)).is_zero() );
#endif
}
}
;
return defect;
}
template <class RT_, class AL_>
bool Linear_algebraHd<RT_,AL_>::
homogeneous_linear_solver(const Matrix& A, Vector& x)
/* returns true if the homogeneous system $Ax = 0$ has a non - trivial
solution and false otherwise. */
{
x = Vector(A.row_dimension());
Matrix spanning_vectors;
int dimension = homogeneous_linear_solver(A,spanning_vectors);
if (dimension == 0) return false;
/* return first column of |spanning_vectors| */
for (int i = 0; i < spanning_vectors.row_dimension(); i++)
x[i] = spanning_vectors(i,0);
return true;
}
template <class RT_, class AL_>
typename Linear_algebraHd<RT_,AL_>::Matrix
Linear_algebraHd<RT_,AL_>::transpose(const Matrix& M)
{
int d1 = M.row_dimension();
int d2 = M.column_dimension();
Matrix result(d2,d1);
for(int i = 0; i < d2; i++)
for(int j = 0; j < d1; j++)
result(i,j) = M(j,i);
return result;
}
} //namespace CGAL
#endif //CGAL_LINEAR_ALGEBRAHD_C