Ignore:
Timestamp:
Apr 10, 2018, 6:43:30 AM (7 years ago)
Author:
Frederik Heber <frederik.heber@…>
Branches:
AutomationFragmentation_failures, Candidate_v1.6.1, ChemicalSpaceEvaluator, Exclude_Hydrogens_annealWithBondGraph, ForceAnnealing_with_BondGraph, ForceAnnealing_with_BondGraph_contraction-expansion, Gui_displays_atomic_force_velocity, PythonUI_with_named_parameters, StoppableMakroAction, TremoloParser_IncreasedPrecision
Children:
07d4b1
Parents:
7b4e67
git-author:
Frederik Heber <frederik.heber@…> (07/18/17 22:24:12)
git-committer:
Frederik Heber <frederik.heber@…> (04/10/18 06:43:30)
Message:

We now obtain weights via levmar minimization.

  • this should yield the best possible weights within the interval of [1/n,1.].
  • note that we cannot always get an exact solution because of this constraint.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/Dynamics/BondVectors.cpp

    r7b4e67 rf433ec  
    4545#include "CodePatterns/Assert.hpp"
    4646#include "CodePatterns/Log.hpp"
     47
     48#include <levmar.h>
    4749
    4850#include "Atom/atom.hpp"
     
    111113}
    112114
     115struct WeightsMinimization {
     116
     117  static void evaluate(double *p, double *x, int m, int n, void *data)
     118  {
     119    // current weights in p, output to x
     120    double *matrix = static_cast<double*>(data);
     121    for(size_t i=0;i<(size_t)n;++i) {
     122      x[i] = 0.;
     123      for(size_t j=0;j<(size_t)n;++j)
     124        x[i] += p[j]*matrix[i*n+j];
     125//      x[i] = .5*x[i]*x[i];
     126    }
     127  }
     128
     129  static void evaluate_derivative(double *p, double *jac, int m, int n, void *data)
     130  {
     131    // current weights in p, output to x
     132    double *matrix = static_cast<double*>(data);
     133//    // tmp = (Bx - 1)
     134//    double *tmp = new double[n];
     135//    for(size_t i=0;i<(size_t)n;++i) {
     136//      tmp[i] = -1.;
     137//      for(size_t j=0;j<(size_t)n;++j)
     138//        tmp[i] += p[j]*matrix[i*n+j];
     139//    }
     140//    // tmp(i) * B_(ij)
     141//    for(size_t i=0;i<(size_t)n;++i)
     142//      for(size_t j=0;j<(size_t)n;++j)
     143//        jac[i*n+j] = tmp[i]*matrix[i*n+j];
     144//    delete[] tmp ;
     145    for(size_t i=0;i<(size_t)n;++i)
     146      for(size_t j=0;j<(size_t)n;++j)
     147        jac[i*n+j] = matrix[i*n+j];
     148  }
     149
     150  static double* getMatrixFromBondVectors(
     151      const std::vector<Vector> &_bondvectors
     152      )
     153  {
     154    const size_t n = _bondvectors.size();
     155    double *matrix = new double[n*n];
     156    size_t i=0;
     157    for (std::vector<Vector>::const_iterator iter = _bondvectors.begin();
     158        iter != _bondvectors.end(); ++iter, ++i) {
     159      size_t j=0;
     160      for (std::vector<Vector>::const_iterator otheriter = _bondvectors.begin();
     161          otheriter != _bondvectors.end(); ++otheriter, ++j) {
     162        // only magnitude is important not the sign
     163        matrix[i*n+j] = fabs((*iter).ScalarProduct(*otheriter));
     164      }
     165    }
     166
     167    return matrix;
     168  }
     169};
     170
     171
     172BondVectors::weights_t BondVectors::getWeightsForAtomAtStep(
     173    const atom &_walker,
     174    const std::vector<Vector> &_bondvectors,
     175    const size_t &_step) const
     176{
     177  // let levmar optimize
     178  register int i, j;
     179  int ret;
     180  double *p;
     181  double *x;
     182  int n=_bondvectors.size();
     183  double opts[LM_OPTS_SZ], info[LM_INFO_SZ];
     184
     185  double *matrix = WeightsMinimization::getMatrixFromBondVectors(_bondvectors);
     186
     187  weights_t weights(n, 0.);
     188
     189  // minim. options [\tau, \epsilon1, \epsilon2, \epsilon3]. Respectively the scale factor for initial \mu,
     190  // * stopping thresholds for ||J^T e||_inf, ||Dp||_2 and ||e||_2.
     191  opts[0]=LM_INIT_MU; opts[1]=1E-15; opts[2]=1E-15; opts[3]=1E-20;
     192  opts[4]= LM_DIFF_DELTA; // relevant only if the Jacobian is approximated using finite differences; specifies forward differencing
     193  //opts[4]=-LM_DIFF_DELTA; // specifies central differencing to approximate Jacobian; more accurate but more expensive to compute!
     194
     195  // prepare initial values for weights
     196  p = new double[n];
     197  for (i=0;i<n;++i)
     198    p[i] = 1.;
     199  // prepare output value, i.e. the row sums
     200  x = new double[n];
     201  for (i=0;i<n;++i)
     202    x[i] = 1.;
     203
     204  {
     205    double *work, *covar;
     206    work=(double *)malloc((LM_DIF_WORKSZ(n, n)+n*n)*sizeof(double));
     207    if(!work){
     208      ELOG(0, "BondVectors::getWeightsForAtomAtStep() - memory allocation request failed.");
     209      return weights;
     210    }
     211    covar=work+LM_DIF_WORKSZ(n, n);
     212
     213    // give this pointer as additional data to construct function pointer in
     214    // LevMarCallback and call
     215    double *lb = new double[n];
     216    double *ub = new double[n];
     217    for (i=0;i<n;++i) {
     218      lb[i] = 1./(double)n;
     219      ub[i] = 1.;
     220    }
     221    ret=dlevmar_bc_der(
     222        &WeightsMinimization::evaluate,
     223        &WeightsMinimization::evaluate_derivative,
     224        p, x, n, n, lb, ub, NULL, 1000, opts, info, work, covar, matrix); // no Jacobian, caller allocates work memory, covariance estimated
     225    delete[] lb;
     226    delete[] ub;
     227
     228    if (0)
     229    {
     230      std::stringstream covar_msg;
     231      covar_msg << "Covariance of the fit:\n";
     232      for(i=0; i<n; ++i){
     233        for(j=0; j<n; ++j)
     234          covar_msg << covar[i*n+j] << " ";
     235        covar_msg << std::endl;
     236      }
     237      covar_msg << std::endl;
     238      LOG(1, "INFO: " << covar_msg.str());
     239    }
     240
     241    free(work);
     242  }
     243
     244  if (DoLog(4)) {
     245   std::stringstream result_msg;
     246   result_msg << "Levenberg-Marquardt returned " << ret << " in " << info[5] << " iter, reason " << info[6] << "\nSolution: ";
     247   for(i=0; i<n; ++i)
     248     result_msg << p[i] << " ";
     249   result_msg << "\n\nMinimization info:\n";
     250   std::vector<std::string> infonames(LM_INFO_SZ);
     251   infonames[0] = std::string("||e||_2 at initial p");
     252   infonames[1] = std::string("||e||_2");
     253   infonames[2] = std::string("||J^T e||_inf");
     254   infonames[3] = std::string("||Dp||_2");
     255   infonames[4] = std::string("mu/max[J^T J]_ii");
     256   infonames[5] = std::string("# iterations");
     257   infonames[6] = std::string("reason for termination");
     258   infonames[7] = std::string(" # function evaluations");
     259   infonames[8] = std::string(" # Jacobian evaluations");
     260   infonames[9] = std::string(" # linear systems solved");
     261   for(i=0; i<LM_INFO_SZ; ++i)
     262      result_msg << infonames[i] << ": " << info[i] << " ";
     263    result_msg << std::endl;
     264    LOG(4, "DEBUG: " << result_msg.str());
     265  }
     266
     267  std::copy(p, p+n, weights.begin());
     268  LOG(4, "DEBUG: Weights for atom #" << _walker.getId() << ": " << weights);
     269
     270  delete[] p;
     271  delete[] x;
     272  delete[] matrix;
     273
     274  return weights;
     275}
     276
    113277BondVectors::weights_t BondVectors::getWeightsForAtomAtStep(
    114278    const atom &_walker,
     
    118282      getAtomsBondVectorsAtStep(_walker, _step);
    119283
    120   weights_t weights;
    121   for (std::vector<Vector>::const_iterator iter = BondVectors.begin();
    122       iter != BondVectors.end(); ++iter) {
     284  return getWeightsForAtomAtStep(_walker, BondVectors, _step);
     285}
     286
     287Vector BondVectors::getRemnantGradientForAtomAtStep(
     288    const atom &_walker,
     289    const std::vector<Vector> _BondVectors,
     290    const BondVectors::weights_t &_weights,
     291    const size_t &_step,
     292    forcestore_t _forcestore) const
     293{
     294  const Vector &walkerGradient = _walker.getAtomicForceAtStep(_step);
     295  BondVectors::weights_t::const_iterator weightiter = _weights.begin();
     296  std::vector<Vector>::const_iterator vectoriter = _BondVectors.begin();
     297  const BondList& ListOfBonds = _walker.getListOfBonds();
     298
     299  Vector forcesum;
     300  for(BondList::const_iterator bonditer = ListOfBonds.begin();
     301      bonditer != ListOfBonds.end(); ++bonditer, ++weightiter, ++vectoriter) {
     302    const bond::ptr &current_bond = *bonditer;
     303    const Vector &BondVector = *vectoriter;
     304
     305    const double temp = (*weightiter)*walkerGradient.ScalarProduct(BondVector);
     306    _forcestore(_walker, current_bond, _step, temp);
     307    LOG(4, "DEBUG: BondVector " << BondVector << " receives projected force of "
     308        << temp);
     309    forcesum += temp * BondVector;
     310  }
     311  ASSERT( weightiter == _weights.end(),
     312      "BondVectors::getRemnantGradientForAtomAtStep() - weightiter is not at end when it should be.");
     313  ASSERT( vectoriter == _BondVectors.end(),
     314      "BondVectors::getRemnantGradientForAtomAtStep() - vectoriter is not at end when it should be.");
     315
     316  return walkerGradient-forcesum;
     317}
     318
     319bool BondVectors::getCheckWeightSumForAtomAtStep(
     320    const atom &_walker,
     321    const std::vector<Vector> _BondVectors,
     322    const BondVectors::weights_t &_weights,
     323    const size_t &_step) const
     324{
     325  bool status = true;
     326  for (std::vector<Vector>::const_iterator iter = _BondVectors.begin();
     327      iter != _BondVectors.end(); ++iter) {
    123328    std::vector<double> scps;
    124     scps.reserve(BondVectors.size());
     329    scps.reserve(_BondVectors.size());
    125330    std::transform(
    126         BondVectors.begin(), BondVectors.end(),
    127         std::back_inserter(scps),
    128         boost::bind(static_cast< double (*)(double) >(&fabs),
    129             boost::bind(&Vector::ScalarProduct, boost::cref(*iter), _1))
    130         );
    131     const double scp_sum = std::accumulate(scps.begin(), scps.end(), 0.);
    132     ASSERT( (scp_sum-1.) > -MYEPSILON,
    133         "ForceAnnealing() - sum of weights must be equal or larger one but is "
    134         +toString(scp_sum));
    135     weights.push_back( 1./scp_sum );
    136   }
    137   LOG(4, "DEBUG: Weights for atom #" << _walker.getId() << ": " << weights);
    138 
    139   // for testing we check whether all weighted scalar products now come out as 1.
    140 #ifndef NDEBUG
    141   for (std::vector<Vector>::const_iterator iter = BondVectors.begin();
    142       iter != BondVectors.end(); ++iter) {
    143     std::vector<double> scps;
    144     scps.reserve(BondVectors.size());
    145     std::transform(
    146         BondVectors.begin(), BondVectors.end(),
    147         weights.begin(),
     331        _BondVectors.begin(), _BondVectors.end(),
     332        _weights.begin(),
    148333        std::back_inserter(scps),
    149334        boost::bind(static_cast< double (*)(double) >(&fabs),
     
    153338        );
    154339    const double scp_sum = std::accumulate(scps.begin(), scps.end(), 0.);
    155     ASSERT( fabs(scp_sum - 1.) < MYEPSILON,
    156         "ForceAnnealing::operator() - for BondVector "+toString(*iter)
    157         +" we have weighted scalar product of "+toString(scp_sum)+" != 1.");
    158   }
    159 #endif
    160   return weights;
    161 }
     340    if (fabs(scp_sum -1.) > MYEPSILON)
     341      status = false;
     342  }
     343
     344  return status;
     345}
Note: See TracChangeset for help on using the changeset viewer.