LCOV - code coverage report
Current view: top level - dimred - SketchMapBase.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 96 101 95.0 %
Date: 2026-03-30 13:16:06 Functions: 5 6 83.3 %

          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 "SketchMapBase.h"
      23             : 
      24             : namespace PLMD {
      25             : namespace dimred {
      26             : 
      27          22 : void SketchMapBase::registerKeywords( Keywords& keys ) {
      28          22 :   DimensionalityReductionBase::registerKeywords( keys );
      29          22 :   keys.remove("NLOW_DIM");
      30          44 :   keys.add("compulsory","HIGH_DIM_FUNCTION","as in input action","the parameters of the switching function in the high dimensional space");
      31          44 :   keys.add("compulsory","LOW_DIM_FUNCTION","as in input action","the parameters of the switching function in the low dimensional space");
      32          44 :   keys.add("compulsory","MIXPARAM","0.0","the amount of the pure distances to mix into the stress function");
      33          22 : }
      34             : 
      35           6 : SketchMapBase::SketchMapBase( const ActionOptions& ao ):
      36             :   Action(ao),
      37             :   DimensionalityReductionBase(ao),
      38           6 :   smapbase(NULL),
      39           6 :   normw(0.0) {
      40             :   // Check if we have data from a input sketch-map object - we can reuse switching functions wahoo!!
      41           6 :   if( dimredbase ) {
      42           5 :     smapbase = dynamic_cast<SketchMapBase*>( dimredbase );
      43             :   }
      44             : 
      45             :   // Read in the switching functions
      46             :   std::string linput,hinput, errors;
      47          12 :   parse("HIGH_DIM_FUNCTION",hinput);
      48           6 :   if( hinput=="as in input action" ) {
      49           1 :     if( !smapbase ) {
      50           0 :       error("high dimensional switching function has not been set - use HIGH_DIM_FUNCTION");
      51             :     }
      52           1 :     reuse_hd=true;
      53           1 :     log.printf("  reusing high dimensional filter function defined in previous sketch-map action\n");
      54             :   } else {
      55           5 :     reuse_hd=false;
      56           5 :     highdf.set(hinput,errors);
      57           5 :     if(errors.length()>0) {
      58           0 :       error(errors);
      59             :     }
      60          10 :     log.printf("  filter function for dissimilarities in high dimensional space has cutoff %s \n",highdf.description().c_str() );
      61             :   }
      62             : 
      63          12 :   parse("LOW_DIM_FUNCTION",linput);
      64           6 :   if( linput=="as in input action" ) {
      65           1 :     if( !smapbase ) {
      66           0 :       error("low dimensional switching function has not been set - use LOW_DIM_FUNCTION");
      67             :     }
      68           1 :     reuse_ld=true;
      69           1 :     log.printf("  reusing low dimensional filter function defined in previous sketch-map action\n");
      70             :   } else {
      71           5 :     reuse_ld=false;
      72           5 :     lowdf.set(linput,errors);
      73           5 :     if(errors.length()>0) {
      74           0 :       error(errors);
      75             :     }
      76          10 :     log.printf("  filter function for distances in low dimensionality space has cutoff %s \n",lowdf.description().c_str() );
      77             :   }
      78             : 
      79             :   // Read the mixing parameter
      80           6 :   parse("MIXPARAM",mixparam);
      81           6 :   if( mixparam<0 || mixparam>1 ) {
      82           0 :     error("mixing parameter must be between 0 and 1");
      83             :   }
      84           6 :   log.printf("  mixing %f of pure distances with %f of filtered distances \n",mixparam,1.-mixparam);
      85           6 : }
      86             : 
      87           7 : void SketchMapBase::calculateProjections( const Matrix<double>& targets, Matrix<double>& projections ) {
      88           7 :   if( dtargets.size()!=targets.nrows() ) {
      89             :     // These hold data so that we can do stress calculations
      90           6 :     dtargets.resize( targets.nrows() );
      91           6 :     ftargets.resize( targets.nrows() );
      92           6 :     pweights.resize( targets.nrows() );
      93             :     // Matrices for storing input data
      94             :     transformed.resize( targets.nrows(), targets.ncols() );
      95             :     distances.resize( targets.nrows(), targets.ncols() );
      96             :   }
      97             : 
      98             :   // Stores the weights in an array for faster access, as well as the normalization
      99           7 :   normw=0;
     100        1141 :   for(unsigned i=0; i<targets.nrows() ; ++i) {
     101        1134 :     pweights[i] = getWeight(i);
     102        1134 :     normw+=pweights[i];
     103             :   }
     104           7 :   normw*=normw;
     105             : 
     106             :   // Transform the high dimensional distances
     107             :   double df;
     108             :   distances=0.;
     109             :   transformed=0.;
     110        1127 :   for(unsigned i=1; i<distances.ncols(); ++i) {
     111      172838 :     for(unsigned j=0; j<i; ++j) {
     112      171711 :       distances(i,j)=distances(j,i)=std::sqrt( targets(i,j) );
     113      171711 :       transformed(i,j)=transformed(j,i)=transformHighDimensionalDistance( distances(i,j), df );
     114             :     }
     115             :   }
     116             :   // And minimse
     117           7 :   minimise( projections );
     118           7 : }
     119             : 
     120       41344 : double SketchMapBase::calculateStress( const std::vector<double>& p, std::vector<double>& d ) {
     121             :   // Zero derivative and stress accumulators
     122      124032 :   for(unsigned i=0; i<p.size(); ++i) {
     123       82688 :     d[i]=0.0;
     124             :   }
     125             :   double stress=0;
     126       41344 :   std::vector<double> dtmp( p.size() );
     127             :   // Now accumulate total stress on system
     128     6687344 :   for(unsigned i=0; i<ftargets.size(); ++i) {
     129     6646000 :     if( dtargets[i]<epsilon ) {
     130       30215 :       continue ;
     131             :     }
     132             : 
     133             :     // Calculate distance in low dimensional space
     134     6615785 :     double dd=0;
     135    19847355 :     for(unsigned j=0; j<p.size(); ++j) {
     136    13231570 :       dtmp[j]=p[j]-projections(i,j);
     137    13231570 :       dd+=dtmp[j]*dtmp[j];
     138             :     }
     139     6615785 :     dd = std::sqrt(dd);
     140             : 
     141             :     // Now do transformations and calculate differences
     142     6615785 :     double df, fd = transformLowDimensionalDistance( dd, df );
     143     6615785 :     double ddiff = dd - dtargets[i];
     144     6615785 :     double fdiff = fd - ftargets[i];
     145             : 
     146             :     // Calculate derivatives
     147     6615785 :     double pref = 2.*getWeight(i) / dd ;
     148    19847355 :     for(unsigned j=0; j<p.size(); ++j) {
     149    13231570 :       d[j] += pref*( (1-mixparam)*fdiff*df + mixparam*ddiff )*dtmp[j];
     150             :     }
     151             : 
     152             :     // Accumulate the total stress
     153     6615785 :     stress += getWeight(i)*( (1-mixparam)*fdiff*fdiff + mixparam*ddiff*ddiff );
     154             :   }
     155       41344 :   return stress;
     156             : }
     157             : 
     158        1913 : double SketchMapBase::calculateFullStress( const std::vector<double>& p, std::vector<double>& d ) {
     159             :   // Zero derivative and stress accumulators
     160      393213 :   for(unsigned i=0; i<p.size(); ++i) {
     161      391300 :     d[i]=0.0;
     162             :   }
     163             :   double stress=0;
     164        1913 :   std::vector<double> dtmp( nlow );
     165             : 
     166      195650 :   for(unsigned i=1; i<distances.nrows(); ++i) {
     167      193737 :     double iweight = pweights[i];
     168    14802162 :     for(unsigned j=0; j<i; ++j) {
     169    14608425 :       double jweight =  pweights[j];
     170             :       // Calculate distance in low dimensional space
     171    14608425 :       double dd=0;
     172    43825275 :       for(unsigned k=0; k<nlow; ++k) {
     173    29216850 :         dtmp[k]=p[nlow*i+k] - p[nlow*j+k];
     174    29216850 :         dd+=dtmp[k]*dtmp[k];
     175             :       }
     176    14608425 :       dd = std::sqrt(dd);
     177             : 
     178             :       // Now do transformations and calculate differences
     179    14608425 :       double df, fd = transformLowDimensionalDistance( dd, df );
     180    14608425 :       double ddiff = dd - distances(i,j);
     181    14608425 :       double fdiff = fd - transformed(i,j);;
     182             : 
     183             :       // Calculate derivatives
     184    14608425 :       double pref = 2.*iweight*jweight*( (1-mixparam)*fdiff*df + mixparam*ddiff ) / dd;
     185    43825275 :       for(unsigned k=0; k<nlow; ++k) {
     186    29216850 :         double dterm=pref*dtmp[k];
     187    29216850 :         d[nlow*i+k]+=dterm;
     188    29216850 :         d[nlow*j+k]-=dterm;
     189             :       }
     190             : 
     191             :       // Accumulate the total stress
     192    14608425 :       stress += iweight*jweight*( (1-mixparam)*fdiff*fdiff + mixparam*ddiff*ddiff );
     193             :     }
     194             :   }
     195        1913 :   stress /= normw;
     196      393213 :   for (unsigned k=0; k < d.size(); ++k) {
     197      391300 :     d[k] /= normw;
     198             :   }
     199        1913 :   return stress;
     200             : }
     201             : 
     202             : }
     203             : }
     204             : 
     205             : 

Generated by: LCOV version 1.16