635 lines
17 KiB
C++
635 lines
17 KiB
C++
/****************************************************************************
|
|
* VCGLib o o *
|
|
* Visual and Computer Graphics Library o o *
|
|
* _ O _ *
|
|
* Copyright(C) 2004-2016 \/)\/ *
|
|
* Visual Computing Lab /\/| *
|
|
* ISTI - Italian National Research Council | *
|
|
* \ *
|
|
* All rights reserved. *
|
|
* *
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
* (at your option) any later version. *
|
|
* *
|
|
* This program is distributed in the hope that it will be useful, *
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
|
|
* for more details. *
|
|
* *
|
|
****************************************************************************/
|
|
#ifndef __VCGLIB_LINALGEBRA_H
|
|
#define __VCGLIB_LINALGEBRA_H
|
|
|
|
#include <vcg/math/base.h>
|
|
#include <vcg/math/matrix44.h>
|
|
#include <algorithm>
|
|
#ifndef _YES_I_WANT_TO_USE_DANGEROUS_STUFF
|
|
#error "Please do not never user this file. Use EIGEN!!!!"
|
|
#endif
|
|
namespace vcg
|
|
{
|
|
/** \addtogroup math */
|
|
/* @{ */
|
|
|
|
/*!
|
|
*
|
|
*/
|
|
template< typename MATRIX_TYPE >
|
|
static void JacobiRotate(MATRIX_TYPE &A, typename MATRIX_TYPE::ScalarType s, typename MATRIX_TYPE::ScalarType tau, int i,int j,int k,int l)
|
|
{
|
|
typename MATRIX_TYPE::ScalarType g=A[i][j];
|
|
typename MATRIX_TYPE::ScalarType h=A[k][l];
|
|
A[i][j]=g-s*(h+g*tau);
|
|
A[k][l]=h+s*(g-h*tau);
|
|
};
|
|
|
|
/*!
|
|
* Computes all eigenvalues and eigenvectors of a real symmetric matrix .
|
|
* On output, elements of the input matrix above the diagonal are destroyed.
|
|
* \param d returns the eigenvalues of a.
|
|
* \param v is a matrix whose columns contain, the normalized eigenvectors
|
|
* \param nrot returns the number of Jacobi rotations that were required.
|
|
*/
|
|
template <typename MATRIX_TYPE, typename POINT_TYPE>
|
|
static void Jacobi(MATRIX_TYPE &w, POINT_TYPE &d, MATRIX_TYPE &v, int &nrot)
|
|
{
|
|
typedef typename MATRIX_TYPE::ScalarType ScalarType;
|
|
assert(w.RowsNumber()==w.ColumnsNumber());
|
|
int dimension = w.RowsNumber();
|
|
|
|
int j,iq,ip,i;
|
|
//assert(w.IsSymmetric());
|
|
typename MATRIX_TYPE::ScalarType tresh, theta, tau, t, sm, s, h, g, c;
|
|
POINT_TYPE b, z;
|
|
|
|
v.SetIdentity();
|
|
|
|
for (ip=0;ip<dimension;++ip) //Initialize b and d to the diagonal of a.
|
|
{
|
|
b[ip]=d[ip]=w[ip][ip];
|
|
z[ip]=ScalarType(0.0); //This vector will accumulate terms of the form tapq as in equation (11.1.14).
|
|
}
|
|
nrot=0;
|
|
for (i=0;i<50;i++)
|
|
{
|
|
sm=ScalarType(0.0);
|
|
for (ip=0;ip<dimension-1;++ip) // Sum off diagonal elements
|
|
{
|
|
for (iq=ip+1;iq<dimension;++iq)
|
|
sm += math::Abs(w[ip][iq]);
|
|
}
|
|
if (sm == ScalarType(0.0)) //The normal return, which relies on quadratic convergence to machine underflow.
|
|
{
|
|
return;
|
|
}
|
|
if (i < 4)
|
|
tresh=ScalarType(0.2)*sm/(dimension*dimension); //...on the first three sweeps.
|
|
else
|
|
tresh=ScalarType(0.0); //...thereafter.
|
|
for (ip=0;ip<dimension-1;++ip)
|
|
{
|
|
for (iq=ip+1;iq<dimension;iq++)
|
|
{
|
|
g=ScalarType(100.0)*fabs(w[ip][iq]);
|
|
//After four sweeps, skip the rotation if the off-diagonal element is small.
|
|
if(i>4 && (float)(fabs(d[ip])+g) == (float)fabs(d[ip]) && (float)(fabs(d[iq])+g) == (float)fabs(d[iq]))
|
|
w[ip][iq]=ScalarType(0.0);
|
|
else if (fabs(w[ip][iq]) > tresh)
|
|
{
|
|
h=d[iq]-d[ip];
|
|
if ((float)(fabs(h)+g) == (float)fabs(h))
|
|
t=(w[ip][iq])/h; //t =1/(2#)
|
|
else
|
|
{
|
|
theta=ScalarType(0.5)*h/(w[ip][iq]); //Equation (11.1.10).
|
|
t=ScalarType(1.0)/(fabs(theta)+sqrt(ScalarType(1.0)+theta*theta));
|
|
if (theta < ScalarType(0.0)) t = -t;
|
|
}
|
|
c=ScalarType(1.0)/sqrt(ScalarType(1.0)+t*t);
|
|
s=t*c;
|
|
tau=s/(ScalarType(1.0)+c);
|
|
h=t*w[ip][iq];
|
|
z[ip] -= h;
|
|
z[iq] += h;
|
|
d[ip] -= h;
|
|
d[iq] += h;
|
|
w[ip][iq]=ScalarType(0.0);
|
|
for (j=0;j<=ip-1;j++) { //Case of rotations 1 <= j < p.
|
|
JacobiRotate<MATRIX_TYPE>(w,s,tau,j,ip,j,iq) ;
|
|
}
|
|
for (j=ip+1;j<=iq-1;j++) { //Case of rotations p < j < q.
|
|
JacobiRotate<MATRIX_TYPE>(w,s,tau,ip,j,j,iq);
|
|
}
|
|
for (j=iq+1;j<dimension;j++) { //Case of rotations q< j <= n.
|
|
JacobiRotate<MATRIX_TYPE>(w,s,tau,ip,j,iq,j);
|
|
}
|
|
for (j=0;j<dimension;j++) {
|
|
JacobiRotate<MATRIX_TYPE>(v,s,tau,j,ip,j,iq);
|
|
}
|
|
++nrot;
|
|
}
|
|
}
|
|
}
|
|
for (ip=0;ip<dimension;ip++)
|
|
{
|
|
b[ip] += z[ip];
|
|
d[ip]=b[ip]; //Update d with the sum of ta_pq ,
|
|
z[ip]=0.0; //and reinitialize z.
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
/*!
|
|
* Given the eigenvectors and the eigenvalues as output from JacobiRotate, sorts the eigenvalues
|
|
* into descending order, and rearranges the columns of v correspondinlgy.
|
|
* \param eigenvalues
|
|
* \param eigenvector (in columns)
|
|
* \param absComparison sort according to the absolute values of the eigenvalues.
|
|
*/
|
|
template < typename MATRIX_TYPE, typename POINT_TYPE >
|
|
void SortEigenvaluesAndEigenvectors(POINT_TYPE &eigenvalues, MATRIX_TYPE &eigenvectors, bool absComparison = false)
|
|
{
|
|
assert(eigenvectors.ColumnsNumber()==eigenvectors.RowsNumber());
|
|
int dimension = eigenvectors.ColumnsNumber();
|
|
int i, j, k;
|
|
float p,q;
|
|
for (i=0; i<dimension-1; i++)
|
|
{
|
|
if (absComparison)
|
|
{
|
|
p = fabs(eigenvalues[k=i]);
|
|
for (j=i+1; j<dimension; j++)
|
|
if ((q=fabs(eigenvalues[j])) >= p)
|
|
{
|
|
p = q;
|
|
k = j;
|
|
}
|
|
p = eigenvalues[k];
|
|
}
|
|
else
|
|
{
|
|
p = eigenvalues[ k=i ];
|
|
for (j=i+1; j<dimension; j++)
|
|
if (eigenvalues[j] >= p)
|
|
p = eigenvalues[ k=j ];
|
|
}
|
|
|
|
if (k != i)
|
|
{
|
|
eigenvalues[k] = eigenvalues[i]; // i.e.
|
|
eigenvalues[i] = p; // swaps the value of the elements i-th and k-th
|
|
|
|
for (j=0; j<dimension; j++)
|
|
{
|
|
p = eigenvectors[j][i]; // i.e.
|
|
eigenvectors[j][i] = eigenvectors[j][k]; // swaps the eigenvectors stored in the
|
|
eigenvectors[j][k] = p; // i-th and the k-th column
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
template <typename TYPE>
|
|
inline static TYPE sqr(TYPE a)
|
|
{
|
|
TYPE sqr_arg = a;
|
|
return (sqr_arg == 0 ? 0 : sqr_arg*sqr_arg);
|
|
}
|
|
|
|
// Computes (a^2 + b^2)^(1/2) without destructive underflow or overflow.
|
|
template <typename TYPE>
|
|
inline static TYPE pythagora(TYPE a, TYPE b)
|
|
{
|
|
TYPE abs_a = fabs(a);
|
|
TYPE abs_b = fabs(b);
|
|
if (abs_a > abs_b)
|
|
return abs_a*sqrt((TYPE)1.0+sqr(abs_b/abs_a));
|
|
else
|
|
return (abs_b == (TYPE)0.0 ? (TYPE)0.0 : abs_b*sqrt((TYPE)1.0+sqr(abs_a/abs_b)));
|
|
}
|
|
|
|
template <typename TYPE>
|
|
inline static TYPE sign(TYPE a, TYPE b)
|
|
{
|
|
return (b >= 0.0 ? fabs(a) : -fabs(a));
|
|
}
|
|
|
|
/*!
|
|
*
|
|
*/
|
|
enum SortingStrategy {LeaveUnsorted=0, SortAscending=1, SortDescending=2};
|
|
template< typename MATRIX_TYPE >
|
|
void Sort(MATRIX_TYPE &U, typename MATRIX_TYPE::ScalarType W[], MATRIX_TYPE &V, const SortingStrategy sorting) ;
|
|
|
|
|
|
/*!
|
|
* Given a matrix <I>A<SUB>mxn</SUB></I>, this routine computes its singular value decomposition,
|
|
* i.e. <I>A=UxWxV<SUP>T</SUP></I>. The matrix <I>A</I> will be destroyed!
|
|
* (This is the implementation described in <I>Numerical Recipies</I>).
|
|
* \param A the matrix to be decomposed
|
|
* \param W the diagonal matrix of singular values <I>W</I>, stored as a vector <I>W[1...N]</I>
|
|
* \param V the matrix <I>V</I> (not the transpose <I>V<SUP>T</SUP></I>)
|
|
* \param max_iters max iteration number (default = 30).
|
|
* \return
|
|
*/
|
|
template <typename MATRIX_TYPE>
|
|
static bool SingularValueDecomposition(MATRIX_TYPE &A, typename MATRIX_TYPE::ScalarType *W, MATRIX_TYPE &V, const SortingStrategy sorting=LeaveUnsorted, const int max_iters=30)
|
|
{
|
|
typedef typename MATRIX_TYPE::ScalarType ScalarType;
|
|
int m = (int) A.RowsNumber();
|
|
int n = (int) A.ColumnsNumber();
|
|
int flag,i,its,j,jj,k,l,nm;
|
|
ScalarType anorm, c, f, g, h, s, scale, x, y, z, *rv1;
|
|
bool convergence = true;
|
|
|
|
rv1 = new ScalarType[n];
|
|
g = scale = anorm = 0;
|
|
// Householder reduction to bidiagonal form.
|
|
for (i=0; i<n; i++)
|
|
{
|
|
l = i+1;
|
|
rv1[i] = scale*g;
|
|
g = s = scale = 0.0;
|
|
if (i < m)
|
|
{
|
|
for (k = i; k<m; k++)
|
|
scale += fabs(A[k][i]);
|
|
if (scale)
|
|
{
|
|
for (k=i; k<m; k++)
|
|
{
|
|
A[k][i] /= scale;
|
|
s += A[k][i]*A[k][i];
|
|
}
|
|
f=A[i][i];
|
|
g = -sign<ScalarType>( sqrt(s), f );
|
|
h = f*g - s;
|
|
A[i][i]=f-g;
|
|
for (j=l; j<n; j++)
|
|
{
|
|
for (s=0.0, k=i; k<m; k++)
|
|
s += A[k][i]*A[k][j];
|
|
f = s/h;
|
|
for (k=i; k<m; k++)
|
|
A[k][j] += f*A[k][i];
|
|
}
|
|
for (k=i; k<m; k++)
|
|
A[k][i] *= scale;
|
|
}
|
|
}
|
|
W[i] = scale *g;
|
|
g = s = scale = 0.0;
|
|
if (i < m && i != (n-1))
|
|
{
|
|
for (k=l; k<n; k++)
|
|
scale += fabs(A[i][k]);
|
|
if (scale)
|
|
{
|
|
for (k=l; k<n; k++)
|
|
{
|
|
A[i][k] /= scale;
|
|
s += A[i][k]*A[i][k];
|
|
}
|
|
f = A[i][l];
|
|
g = -sign<ScalarType>(sqrt(s),f);
|
|
h = f*g - s;
|
|
A[i][l] = f-g;
|
|
for (k=l; k<n; k++)
|
|
rv1[k] = A[i][k]/h;
|
|
for (j=l; j<m; j++)
|
|
{
|
|
for (s=0.0, k=l; k<n; k++)
|
|
s += A[j][k]*A[i][k];
|
|
for (k=l; k<n; k++)
|
|
A[j][k] += s*rv1[k];
|
|
}
|
|
for (k=l; k<n; k++)
|
|
A[i][k] *= scale;
|
|
}
|
|
}
|
|
anorm=std::max( anorm, (math::Abs(W[i])+math::Abs(rv1[i])) );
|
|
}
|
|
// Accumulation of right-hand transformations.
|
|
for (i=(n-1); i>=0; i--)
|
|
{
|
|
//Accumulation of right-hand transformations.
|
|
if (i < (n-1))
|
|
{
|
|
if (g)
|
|
{
|
|
for (j=l; j<n;j++) //Double division to avoid possible underflow.
|
|
V[j][i]=(A[i][j]/A[i][l])/g;
|
|
for (j=l; j<n; j++)
|
|
{
|
|
for (s=0.0, k=l; k<n; k++)
|
|
s += A[i][k] * V[k][j];
|
|
for (k=l; k<n; k++)
|
|
V[k][j] += s*V[k][i];
|
|
}
|
|
}
|
|
for (j=l; j<n; j++)
|
|
V[i][j] = V[j][i] = 0.0;
|
|
}
|
|
V[i][i] = 1.0;
|
|
g = rv1[i];
|
|
l = i;
|
|
}
|
|
// Accumulation of left-hand transformations.
|
|
for (i=std::min(m,n)-1; i>=0; i--)
|
|
{
|
|
l = i+1;
|
|
g = W[i];
|
|
for (j=l; j<n; j++)
|
|
A[i][j]=0.0;
|
|
if (g)
|
|
{
|
|
g = (ScalarType)1.0/g;
|
|
for (j=l; j<n; j++)
|
|
{
|
|
for (s=0.0, k=l; k<m; k++)
|
|
s += A[k][i]*A[k][j];
|
|
f = (s/A[i][i])*g;
|
|
for (k=i; k<m; k++)
|
|
A[k][j] += f*A[k][i];
|
|
}
|
|
for (j=i; j<m; j++)
|
|
A[j][i] *= g;
|
|
}
|
|
else
|
|
for (j=i; j<m; j++)
|
|
A[j][i] = 0.0;
|
|
++A[i][i];
|
|
}
|
|
// Diagonalization of the bidiagonal form: Loop over
|
|
// singular values, and over allowed iterations.
|
|
for (k=(n-1); k>=0; k--)
|
|
{
|
|
for (its=1; its<=max_iters; its++)
|
|
{
|
|
flag=1;
|
|
for (l=k; l>=0; l--)
|
|
{
|
|
// Test for splitting.
|
|
nm=l-1;
|
|
// Note that rv1[1] is always zero.
|
|
if ((double)(fabs(rv1[l])+anorm) == anorm)
|
|
{
|
|
flag=0;
|
|
break;
|
|
}
|
|
if ((double)(fabs(W[nm])+anorm) == anorm)
|
|
break;
|
|
}
|
|
if (flag)
|
|
{
|
|
c=0.0; //Cancellation of rv1[l], if l > 1.
|
|
s=1.0;
|
|
for (i=l ;i<=k; i++)
|
|
{
|
|
f = s*rv1[i];
|
|
rv1[i] = c*rv1[i];
|
|
if ((double)(fabs(f)+anorm) == anorm)
|
|
break;
|
|
g = W[i];
|
|
h = pythagora<ScalarType>(f,g);
|
|
W[i] = h;
|
|
h = (ScalarType)1.0/h;
|
|
c = g*h;
|
|
s = -f*h;
|
|
for (j=0; j<m; j++)
|
|
{
|
|
y = A[j][nm];
|
|
z = A[j][i];
|
|
A[j][nm] = y*c + z*s;
|
|
A[j][i] = z*c - y*s;
|
|
}
|
|
}
|
|
}
|
|
z = W[k];
|
|
if (l == k) //Convergence.
|
|
{
|
|
if (z < 0.0) { // Singular value is made nonnegative.
|
|
W[k] = -z;
|
|
for (j=0; j<n; j++)
|
|
V[j][k] = -V[j][k];
|
|
}
|
|
break;
|
|
}
|
|
if (its == max_iters)
|
|
{
|
|
convergence = false;
|
|
}
|
|
x = W[l]; // Shift from bottom 2-by-2 minor.
|
|
nm = k-1;
|
|
y = W[nm];
|
|
g = rv1[nm];
|
|
h = rv1[k];
|
|
f = ((y-z)*(y+z) + (g-h)*(g+h))/((ScalarType)2.0*h*y);
|
|
g = pythagora<ScalarType>(f,1.0);
|
|
f=((x-z)*(x+z) + h*((y/(f+sign(g,f)))-h))/x;
|
|
c=s=1.0;
|
|
//Next QR transformation:
|
|
for (j=l; j<= nm;j++)
|
|
{
|
|
i = j+1;
|
|
g = rv1[i];
|
|
y = W[i];
|
|
h = s*g;
|
|
g = c*g;
|
|
z = pythagora<ScalarType>(f,h);
|
|
rv1[j] = z;
|
|
c = f/z;
|
|
s = h/z;
|
|
f = x*c + g*s;
|
|
g = g*c - x*s;
|
|
h = y*s;
|
|
y *= c;
|
|
for (jj=0; jj<n; jj++)
|
|
{
|
|
x = V[jj][j];
|
|
z = V[jj][i];
|
|
V[jj][j] = x*c + z*s;
|
|
V[jj][i] = z*c - x*s;
|
|
}
|
|
z = pythagora<ScalarType>(f,h);
|
|
W[j] = z;
|
|
// Rotation can be arbitrary if z = 0.
|
|
if (z)
|
|
{
|
|
z = (ScalarType)1.0/z;
|
|
c = f*z;
|
|
s = h*z;
|
|
}
|
|
f = c*g + s*y;
|
|
x = c*y - s*g;
|
|
for (jj=0; jj<m; jj++)
|
|
{
|
|
y = A[jj][j];
|
|
z = A[jj][i];
|
|
A[jj][j] = y*c + z*s;
|
|
A[jj][i] = z*c - y*s;
|
|
}
|
|
}
|
|
rv1[l] = 0.0;
|
|
rv1[k] = f;
|
|
W[k] = x;
|
|
}
|
|
}
|
|
delete []rv1;
|
|
|
|
if (sorting!=LeaveUnsorted)
|
|
Sort<MATRIX_TYPE>(A, W, V, sorting);
|
|
|
|
return convergence;
|
|
};
|
|
|
|
|
|
/*!
|
|
* Sort the singular values computed by the <CODE>SingularValueDecomposition</CODE> procedure and
|
|
* modify the matrices <I>U</I> and <I>V</I> accordingly.
|
|
*/
|
|
// TODO modify the last parameter type
|
|
template< typename MATRIX_TYPE >
|
|
void Sort(MATRIX_TYPE &U, typename MATRIX_TYPE::ScalarType W[], MATRIX_TYPE &V, const SortingStrategy sorting)
|
|
{
|
|
typedef typename MATRIX_TYPE::ScalarType ScalarType;
|
|
|
|
assert(U.ColumnsNumber()==V.ColumnsNumber());
|
|
|
|
int mu = U.RowsNumber();
|
|
int mv = V.RowsNumber();
|
|
int n = U.ColumnsNumber();
|
|
|
|
//ScalarType* u = &U[0][0];
|
|
//ScalarType* v = &V[0][0];
|
|
|
|
for (int i=0; i<n; i++)
|
|
{
|
|
int k = i;
|
|
ScalarType p = W[i];
|
|
switch (sorting)
|
|
{
|
|
case SortAscending:
|
|
{
|
|
for (int j=i+1; j<n; j++)
|
|
{
|
|
if (W[j] < p)
|
|
{
|
|
k = j;
|
|
p = W[j];
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case SortDescending:
|
|
{
|
|
for (int j=i+1; j<n; j++)
|
|
{
|
|
if (W[j] > p)
|
|
{
|
|
k = j;
|
|
p = W[j];
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case LeaveUnsorted: break; // nothing to do.
|
|
}
|
|
if (k != i)
|
|
{
|
|
W[k] = W[i]; // i.e.
|
|
W[i] = p; // swaps the i-th and the k-th elements
|
|
|
|
int j = mu;
|
|
//ScalarType* uji = u + i; // uji = &U[0][i]
|
|
//ScalarType* ujk = u + k; // ujk = &U[0][k]
|
|
//ScalarType* vji = v + i; // vji = &V[0][i]
|
|
//ScalarType* vjk = v + k; // vjk = &V[0][k]
|
|
//if (j)
|
|
//{
|
|
// for(;;) for( ; j!=0; --j, uji+=n, ujk+=n)
|
|
// { {
|
|
// p = *uji; p = *uji; // i.e.
|
|
// *uji = *ujk; *uji = *ujk; // swap( U[s][i], U[s][k] )
|
|
// *ujk = p; *ujk = p; //
|
|
// if (!(--j)) }
|
|
// break;
|
|
// uji += n;
|
|
// ujk += n;
|
|
// }
|
|
//}
|
|
for(int s=0; j!=0; ++s, --j)
|
|
std::swap(U[s][i], U[s][k]);
|
|
|
|
j = mv;
|
|
//if (j!=0)
|
|
//{
|
|
// for(;;) for ( ; j!=0; --j, vji+=n, ujk+=n)
|
|
// { {
|
|
// p = *vji; p = *vji; // i.e.
|
|
// *vji = *vjk; *vji = *vjk; // swap( V[s][i], V[s][k] )
|
|
// *vjk = p; *vjk = p; //
|
|
// if (!(--j)) }
|
|
// break;
|
|
// vji += n;
|
|
// vjk += n;
|
|
// }
|
|
//}
|
|
for (int s=0; j!=0; ++s, --j)
|
|
std::swap(V[s][i], V[s][k]);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*!
|
|
* Solves AxX = B for a vector X, where A is specified by the matrices <I>U<SUB>mxn</SUB></I>,
|
|
* <I>W<SUB>nx1</SUB></I> and <I>V<SUB>nxn</SUB></I> as returned by <CODE>SingularValueDecomposition</CODE>.
|
|
* No input quantities are destroyed, so the routine may be called sequentially with different bxs.
|
|
* \param x is the output solution vector (<I>x<SUB>nx1</SUB></I>)
|
|
* \param b is the input right-hand side (<I>b<SUB>nx1</SUB></I>)
|
|
*/
|
|
template <typename MATRIX_TYPE>
|
|
static void SingularValueBacksubstitution(const MATRIX_TYPE &U,
|
|
const typename MATRIX_TYPE::ScalarType *W,
|
|
const MATRIX_TYPE &V,
|
|
typename MATRIX_TYPE::ScalarType *x,
|
|
const typename MATRIX_TYPE::ScalarType *b)
|
|
{
|
|
typedef typename MATRIX_TYPE::ScalarType ScalarType;
|
|
unsigned int jj, j, i;
|
|
unsigned int columns_number = U.ColumnsNumber();
|
|
unsigned int rows_number = U.RowsNumber();
|
|
ScalarType s;
|
|
ScalarType *tmp = new ScalarType[columns_number];
|
|
for (j=0; j<columns_number; j++) //Calculate U^T * B.
|
|
{
|
|
s = 0;
|
|
if (W[j]!=0) //Nonzero result only if wj is nonzero.
|
|
{
|
|
for (i=0; i<rows_number; i++)
|
|
s += U[i][j]*b[i];
|
|
s /= W[j]; //This is the divide by wj .
|
|
}
|
|
tmp[j]=s;
|
|
}
|
|
for (j=0;j<columns_number;j++) //Matrix multiply by V to get answer.
|
|
{
|
|
s = 0;
|
|
for (jj=0; jj<columns_number; jj++)
|
|
s += V[j][jj]*tmp[jj];
|
|
x[j]=s;
|
|
}
|
|
delete []tmp;
|
|
};
|
|
|
|
/*! @} */
|
|
}; // end of namespace
|
|
|
|
#endif
|