LCOV - code coverage report
Current view: top level - dimred - SMACOF.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 32 33 97.0 %
Date: 2024-10-11 08:09:47 Functions: 2 2 100.0 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2015-2023 The plumed team
       3             :    (see the PEOPLE file at the root of the distribution for a list of names)
       4             : 
       5             :    See http://www.plumed.org for more information.
       6             : 
       7             :    This file is part of plumed, version 2.
       8             : 
       9             :    plumed is free software: you can redistribute it and/or modify
      10             :    it under the terms of the GNU Lesser General Public License as published by
      11             :    the Free Software Foundation, either version 3 of the License, or
      12             :    (at your option) any later version.
      13             : 
      14             :    plumed is distributed in the hope that it will be useful,
      15             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      16             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17             :    GNU Lesser General Public License for more details.
      18             : 
      19             :    You should have received a copy of the GNU Lesser General Public License
      20             :    along with plumed.  If not, see <http://www.gnu.org/licenses/>.
      21             : +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
      22             : #include "SMACOF.h"
      23             : 
      24             : namespace PLMD {
      25             : namespace dimred {
      26             : 
      27           1 : void SMACOF::run( const Matrix<double>& Weights, const Matrix<double>& Distances, const double& tol, const unsigned& maxloops, Matrix<double>& InitialZ ) {
      28             :   unsigned M = Distances.nrows();
      29             : 
      30             :   // Calculate V
      31             :   Matrix<double> V(M,M); double totalWeight=0.;
      32         501 :   for(unsigned i=0; i<M; ++i) {
      33      250500 :     for(unsigned j=0; j<M; ++j) {
      34      250000 :       if(i==j) continue;
      35      249500 :       V(i,j)=-Weights(i,j);
      36      249500 :       if( j<i ) totalWeight+=Weights(i,j);
      37             :     }
      38      250500 :     for(unsigned j=0; j<M; ++j) {
      39      250000 :       if(i==j)continue;
      40      249500 :       V(i,i)-=V(i,j);
      41             :     }
      42             :   }
      43             : 
      44             :   // And pseudo invert V
      45           1 :   Matrix<double> mypseudo(M, M); pseudoInvert(V, mypseudo);
      46           1 :   Matrix<double> dists( M, M ); double myfirstsig = calculateSigma( Weights, Distances, InitialZ, dists ) / totalWeight;
      47             : 
      48             :   // initial sigma is made up of the original distances minus the distances between the projections all squared.
      49             :   Matrix<double> temp( M, M ), BZ( M, M ), newZ( M, InitialZ.ncols() );
      50          14 :   for(unsigned n=0; n<maxloops; ++n) {
      51          14 :     if(n==maxloops-1) plumed_merror("ran out of steps in SMACOF algorithm");
      52             : 
      53             :     // Recompute BZ matrix
      54        7014 :     for(unsigned i=0; i<M; ++i) {
      55     3507000 :       for(unsigned j=0; j<M; ++j) {
      56     3500000 :         if(i==j) continue;  //skips over the diagonal elements
      57             : 
      58     3493000 :         if( dists(i,j)>0 ) BZ(i,j) = -Weights(i,j)*Distances(i,j) / dists(i,j);
      59           0 :         else BZ(i,j)=0.;
      60             :       }
      61             :       //the diagonal elements are -off diagonal elements BZ(i,i)-=BZ(i,j)   (Equation 8.25)
      62        7000 :       BZ(i,i)=0; //create the space memory for the diagonal elements which are scalars
      63     3507000 :       for(unsigned j=0; j<M; ++j) {
      64     3500000 :         if(i==j) continue;
      65     3493000 :         BZ(i,i)-=BZ(i,j);
      66             :       }
      67             :     }
      68             : 
      69          14 :     mult( mypseudo, BZ, temp); mult(temp, InitialZ, newZ);
      70             :     //Compute new sigma
      71          14 :     double newsig = calculateSigma( Weights, Distances, newZ, dists ) / totalWeight;
      72             :     //Computing whether the algorithm has converged (has the mass of the potato changed
      73             :     //when we put it back in the oven!)
      74          14 :     if( std::fabs( newsig - myfirstsig )<tol ) break;
      75             :     myfirstsig=newsig;
      76             :     InitialZ = newZ;
      77             :   }
      78           1 : }
      79             : 
      80          15 : double SMACOF::calculateSigma( const Matrix<double>& Weights, const Matrix<double>& Distances, const Matrix<double>& InitialZ, Matrix<double>& dists ) {
      81             :   unsigned M = Distances.nrows(); double sigma=0;
      82        7500 :   for(unsigned i=1; i<M; ++i) {
      83     1878735 :     for(unsigned j=0; j<i; ++j) {
      84     5613750 :       double dlow=0; for(unsigned k=0; k<InitialZ.ncols(); ++k) { double tmp=InitialZ(i,k) - InitialZ(j,k); dlow+=tmp*tmp; }
      85     1871250 :       dists(i,j)=dists(j,i)=std::sqrt(dlow); double tmp3 = Distances(i,j) - dists(i,j);
      86     1871250 :       sigma += Weights(i,j)*tmp3*tmp3;
      87             :     }
      88             :   }
      89          15 :   return sigma;
      90             : }
      91             : 
      92             : }
      93             : }

Generated by: LCOV version 1.15