/******************************************************************************* siMath.cpp - Shape-it Copyright 2012 by Silicos-it, a division of Imacosi BVBA This file is part of Shape-it. Shape-it is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Shape-it 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with Shape-it. If not, see . Shape-it is linked against OpenBabel version 2. OpenBabel 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 version 2 of the License. ***********************************************************************/ #include using namespace SiMath; Vector::Vector(const unsigned int n, const double * v) : _n(n), _pVector(n) { for ( unsigned int i=0; i<_n; ++i) _pVector[i] = v[i]; } Vector::Vector(const std::vector & v) : _n(v.size()), _pVector(_n) { for ( unsigned int i=0; i<_n; ++i) _pVector[i] = v[i]; } Vector::Vector(const Vector & v) : _n(v._n), _pVector(_n) { for ( unsigned int i=0; i<_n; ++i) _pVector[i] = v._pVector[i]; } Vector::~Vector() { _pVector.clear(); } void Vector::clear() { _pVector.clear(); _n = 0; } void Vector::reset(unsigned int n) { if ( _n != n ) // only reset the vector itself if the new size is larger _pVector.resize(n); _n = n; for ( unsigned int i=0; i<_n; ++i ) _pVector[i] = 0; } void Vector::resize(unsigned int n) { if ( _n != n ) _pVector.resize(n); _n = n; } double Vector::getValueAt(const unsigned int i) { return _pVector[i]; } double Vector::getValueAt(const unsigned int i) const { return _pVector[i]; } double Vector::max() const { double d = _pVector[0]; for ( unsigned int i=1; i<_n; ++i) { if ( _pVector[i] > d ) { d = _pVector[i]; } } return d; } double Vector::max(unsigned int & index) const { double d = _pVector[0]; for ( unsigned int i=1; i<_n; ++i) { if ( _pVector[i] > d ) { d = _pVector[i]; index = i; } } return d; } double Vector::min() const { double d = _pVector[0]; for ( unsigned int i=1; i<_n; ++i) { if ( _pVector[i] < d ) { d = _pVector[i]; } } return d; } double Vector::min(unsigned int & index) const { double d = _pVector[0]; for ( unsigned int i=1; i<_n; ++i) { if ( _pVector[i] > d ) { d = _pVector[i]; index = i; } } return d; } double Vector::sum() const { double m(0.0); for ( unsigned int i=0; i<_n; ++i) m += _pVector[i]; return m; } double Vector::mean() const { double m(0.0); for ( unsigned int i=0; i<_n; ++i) m += _pVector[i]; return m/_n; } double Vector::stDev() const { double m(0.0); for ( unsigned int i=0; i<_n; ++i) m += _pVector[i]; double s(0.0); for ( unsigned int i=0; i<_n; ++i) s += (m-_pVector[i])*(m-_pVector[i]); return sqrt(s/(_n-1)); } double Vector::stDev(double m) const { double s(0.0); for ( unsigned int i=0; i<_n; ++i) s += (m-_pVector[i])*(m-_pVector[i]); return sqrt(s/(_n-1)); } Vector & Vector::operator=(const Vector & src) { if ( _n != src._n ) { _n = src._n; _pVector.resize(_n); } for ( unsigned int i=0; i<_n; ++i) _pVector[i] = src._pVector[i]; return *this; } Vector & Vector::operator= (const double & v) { for ( unsigned int i=0; i<_n; ++i) _pVector[i] = v; return *this; } Vector & Vector::operator+= (const double & v) { for ( unsigned int i=0; i<_n; ++i) _pVector[i] += v; return *this; } Vector & Vector::operator+= (const Vector & V) { for ( unsigned int i=0; i<_n; ++i) _pVector[i] += V._pVector[i]; return *this; } Vector & Vector::operator-= (const double & v) { for ( unsigned int i=0; i<_n; ++i) _pVector[i] -= v; return *this; } Vector & Vector::operator-= (const Vector & V) { for ( unsigned int i=0; i<_n; ++i) _pVector[i] -= V._pVector[i]; return *this; } Vector & Vector::operator*= (const double & v) { for ( unsigned int i=0; i<_n; ++i) _pVector[i] *= v; return *this; } Vector & Vector::operator*= (const Vector & V) { for ( unsigned int i=0; i<_n; ++i) _pVector[i] *= V._pVector[i]; return *this; } Vector & Vector::operator/= (const double & v) { for ( unsigned int i=0; i<_n; ++i) _pVector[i] /= v; return *this; } Vector & Vector::operator/= (const Vector & V) { for ( unsigned int i=0; i<_n; ++i) _pVector[i] /= V._pVector[i]; return *this; } Vector & Vector::operator- () { for ( unsigned int i=0; i<_n; ++i) _pVector[i] = -_pVector[i]; return *this; } Vector Vector::operator+ (const Vector & V) const { Vector r(_n); for ( unsigned int i=0; i<_n; ++i) r[i] = _pVector[i] + V._pVector[i]; return r; } Vector Vector::operator- (const Vector & V) const { Vector r(_n); for ( unsigned int i=0; i<_n; ++i) r[i] = _pVector[i] - V._pVector[i]; return r; } Vector Vector::operator* (const Vector & V) const { Vector r(_n); for ( unsigned int i=0; i<_n; ++i) r[i] = _pVector[i] * V._pVector[i]; return r; } Vector Vector::operator/ (const Vector & V) const { Vector r(_n); for ( unsigned int i=0; i<_n; ++i) r[i] = _pVector[i] / V._pVector[i]; return r; } bool Vector::operator== (const Vector & V) const { for ( unsigned int i=0; i<_n; ++i) { if ( _pVector[i] != V._pVector[i] ) return false; } return true; } bool Vector::operator!= (const Vector & V) const { for ( unsigned int i=0; i<_n; ++i) { if ( _pVector[i] != V._pVector[i] ) return true; } return false; } double Vector::dotProd(const Vector & v){ double d(0.0); for (unsigned int i=0; i<_n; ++i ) { d += _pVector[i] * v[i]; } return d; } void Vector::swap(const unsigned int i, const unsigned int j) { double dummy = _pVector[i]; _pVector[i] = _pVector[j]; _pVector[j] = dummy; return; } Matrix::Matrix(const unsigned int n, const unsigned int m) : _nRows(n), _nCols(m), _pMatrix(0) { if ( n && m ) { double* dummy = new double[n*m]; // data _pMatrix = new double*[n]; // row pointers for ( unsigned int i=0; i= 0; k--) { if (_S[k] != 0.0) { for (j = k+1; j < nu; j++) { double t = 0; for (i = k; i < _m; i++) { t += _U[i][k]*_U[i][j]; } t = -t/_U[k][k]; for (i = k; i < _m; i++) { _U[i][j] += t*_U[i][k]; } } for (i = k; i < _m; i++ ) { _U[i][k] = -_U[i][k]; } _U[k][k] = 1.0 + _U[k][k]; for (i = 0; i < k-1; i++) { _U[i][k] = 0.0; } } else { for (i = 0; i < _m; i++) { _U[i][k] = 0.0; } _U[k][k] = 1.0; } } } // If required, generate _V. if ( _computeV ) { for (k = _n-1; k >= 0; k--) { if ((k < nrt) & (e[k] != 0.0)) { for (j = k+1; j < nu; j++) { double t = 0; for (i = k+1; i < _n; i++) { t += _V[i][k]*_V[i][j]; } t = -t/_V[k+1][k]; for (i = k+1; i < _n; i++) { _V[i][j] += t*_V[i][k]; } } } for (i = 0; i < _n; i++) { _V[i][k] = 0.0; } _V[k][k] = 1.0; } } // Main iteration loop for the singular values. int pp = p-1; int iter = 0; double eps = pow(2.0,-52.0); while (p > 0) { k=0; unsigned int mode=0; // Here is where a test for too many iterations would go. // This section of the program inspects for negligible elements in the s and e arrays. // On completion the variables mode and k are set as follows. // mode = 1 if s(p) and e[k-1] are negligible and k

= -1; k--) { if (k == -1) { break; } if (fabs(e[k]) <= eps*(fabs(_S[k]) + fabs(_S[k+1]))) { e[k] = 0.0; break; } } if ( k == p-2 ) { mode = 4; } else { int ks(p-1); // start from ks == p-1 for ( ; ks >= k; ks--) { if (ks == k) { break; } double t = ( (ks != p) ? fabs(e[ks]) : 0.0) + ( (ks != k+1) ? fabs(e[ks-1]) : 0.0); if (fabs(_S[ks]) <= eps*t) { _S[ks] = 0.0; break; } } if (ks == k) { mode = 3; } else if (ks == p-1) { mode = 1; } else { mode = 2; k = ks; } } k++; // Perform the task indicated by the selected mode. switch ( mode ) { case 1: { // Deflate negligible _S[p] double f = e[p-2]; e[p-2] = 0.0; for (j = p-2; j >= k; j--) { double t = SiMath::triangle(_S[j],f); double cs = _S[j]/t; double sn = f/t; _S[j] = t; if (j != k) { f = -sn*e[j-1]; e[j-1] = cs*e[j-1]; } // update V if ( _computeV ) { for (i = 0; i < _n; i++) { t = cs*_V[i][j] + sn*_V[i][p-1]; _V[i][p-1] = -sn*_V[i][j] + cs*_V[i][p-1]; _V[i][j] = t; } } } } break; // end case 1 case 2: { // Split at negligible _S[k] double f = e[k-1]; e[k-1] = 0.0; for (j = k; j < p; j++) { double t = triangle(_S[j],f); double cs = _S[j]/t; double sn = f/t; _S[j] = t; f = -sn*e[j]; e[j] = cs*e[j]; if ( _computeU ) { for (i = 0; i < _m; i++) { t = cs*_U[i][j] + sn*_U[i][k-1]; _U[i][k-1] = -sn*_U[i][j] + cs*_U[i][k-1]; _U[i][j] = t; } } } } break; // end case 2 case 3: { // Perform one qr step. // Calculate the shift. double scale = max(max(max(max(fabs(_S[p-1]),fabs(_S[p-2])),fabs(e[p-2])),fabs(_S[k])),fabs(e[k])); double sp = _S[p-1]/scale; double spm1 = _S[p-2]/scale; double epm1 = e[p-2]/scale; double sk = _S[k]/scale; double ek = e[k]/scale; double b = ((spm1 + sp)*(spm1 - sp) + epm1*epm1)/2.0; double c = (sp*epm1)*(sp*epm1); double shift = 0.0; if ((b != 0.0) || (c != 0.0)) { shift = sqrt(b*b + c); if (b < 0.0) { shift = -shift; } shift = c/(b + shift); } double f = (sk + sp)*(sk - sp) + shift; double g = sk*ek; // Chase zeros. for (j = k; j < p-1; j++) { double t = SiMath::triangle(f,g); double cs = f/t; double sn = g/t; if (j != k) { e[j-1] = t; } f = cs*_S[j] + sn*e[j]; e[j] = cs*e[j] - sn*_S[j]; g = sn*_S[j+1]; _S[j+1] = cs*_S[j+1]; if ( _computeV ) { for (i = 0; i < _n; i++) { t = cs*_V[i][j] + sn*_V[i][j+1]; _V[i][j+1] = -sn*_V[i][j] + cs*_V[i][j+1]; _V[i][j] = t; } } t = SiMath::triangle(f,g); cs = f/t; sn = g/t; _S[j] = t; f = cs*e[j] + sn*_S[j+1]; _S[j+1] = -sn*e[j] + cs*_S[j+1]; g = sn*e[j+1]; e[j+1] = cs*e[j+1]; if ( _computeU && (j < _m-1) ) { for (i = 0; i < _m; i++) { t = cs*_U[i][j] + sn*_U[i][j+1]; _U[i][j+1] = -sn*_U[i][j] + cs*_U[i][j+1]; _U[i][j] = t; } } } e[p-2] = f; iter++; } break; // end case 3 // convergence step case 4: { // Make the singular values positive. if (_S[k] <= 0.0) { _S[k] = (_S[k] < 0.0 ) ? -_S[k] : 0.0; if ( _computeV ) { for (i = 0; i <= pp; i++) { _V[i][k] = -_V[i][k]; } } } // Order the singular values. while (k < pp) { if (_S[k] >= _S[k+1]) break; // swap values and columns if necessary _S.swap(k,k+1); if ( _computeV && (k < _n-1)) _V.swapColumns(k,k+1); if ( _computeU && (k < _m-1) ) _U.swapColumns(k,k+1); k++; } iter = 0; p--; } break; // end case 4 } } } Matrix SVD::getSingularMatrix() { unsigned int n = _S.size(); Matrix A(n,n,0.0); // set diagonal elements for (int i = 0; i < n; i++) { A[i][i] = _S[i]; } return A; } int SVD::rank() { double eps = pow(2.0,-52.0); double tol = max(_m,_n) * _S[0] * eps; int r = 0; for (int i = 0; i < _S.size(); i++) { if (_S[i] > tol) { r++; } } return r; } double SiMath::randD(double a, double b) { double d(a); d += (b-a) * ((double)rand()/RAND_MAX); return d; }