Program Listing for File gaussianpot.hpp#

↰ Return to documentation for file (source/pele/gaussianpot.hpp)

#ifndef _PELE_GAUSSIANPOT_H
#define _PELE_GAUSSIANPOT_H

#include <algorithm>

#include "pele/base_potential.hpp"

namespace pele {

class GaussianPot : public BasePotential {
 private:
  const Array<double> m_mean;
  const Array<double> m_cov_diag;
  const double m_gauss_prefactor;
  const size_t m_bdim;
  std::vector<double> m_diag_icov;

 public:
  GaussianPot(Array<double> mean, Array<double> cov_diag)
      : m_mean(mean.copy()),
        m_cov_diag(cov_diag.copy()),
        m_gauss_prefactor(-1),
        m_bdim(mean.size()) {
    assert(m_mean.size() == m_bdim);
    assert(m_cov_diag.size() == m_bdim);
    for (size_t i = 0; i < m_bdim; ++i) {
      m_diag_icov.push_back(1. / m_cov_diag[i]);
    }
    m_diag_icov.shrink_to_fit();
  }
  virtual double get_energy(Array<double> const &x) {
    double xTAx = 0;
    for (size_t i = 0; i < m_bdim; ++i) {
      const double tmp = x[i] - m_mean[i];
      xTAx += tmp * m_diag_icov[i] * tmp;
    }
    return m_gauss_prefactor * std::exp(-0.5 * xTAx);
  }
  virtual double get_energy_gradient(Array<double> const &x,
                                     Array<double> &grad) {
    double xTAx = 0;
    for (size_t i = 0; i < m_bdim; ++i) {
      const double tmp = x[i] - m_mean[i];
      xTAx += tmp * m_diag_icov[i] * tmp;
      grad[i] = 2 * m_diag_icov[i] * tmp;
    }
    const double energy = m_gauss_prefactor * std::exp(-0.5 * xTAx);
    grad *= -0.5 * energy;
    return energy;
  }
  virtual double get_energy_gradient_hessian(Array<double> const &x,
                                             Array<double> &grad,
                                             Array<double> &hess) {
    double xTAx = 0;
    for (size_t i = 0; i < m_bdim; ++i) {
      const double tmp = x[i] - m_mean[i];
      xTAx += tmp * m_diag_icov[i] * tmp;
      grad[i] = 2 * m_diag_icov[i] * tmp;
    }
    const double energy = m_gauss_prefactor * std::exp(-0.5 * xTAx);
    grad *= -0.5 * energy;
    for (size_t i = 0; i < m_bdim; ++i) {
      for (size_t j = 0; j < m_bdim; ++j) {
        const double xi = x[i] - m_mean[i];
        const double xj = x[j] - m_mean[j];
        hess[i * m_bdim + j] =
            (xi * xj * m_diag_icov[j] - (i == j)) * m_diag_icov[i] * energy;
      }
    }
    return energy;
  }
  virtual double add_energy_gradient(Array<double> const &x,
                                     Array<double> &grad) {
    Array<double> grad_term(grad.size());
    const double energy = get_energy_gradient(x, grad_term);
    grad += grad_term;
    return energy;
  }
  virtual double add_energy_gradient_hessian(Array<double> const &x,
                                             Array<double> &grad,
                                             Array<double> &hess) {
    Array<double> grad_term(grad.size());
    Array<double> hess_term(hess.size());
    const double energy = get_energy_gradient_hessian(x, grad_term, hess_term);
    grad += grad_term;
    hess += hess_term;
    return energy;
  }
};

}  // namespace pele

#endif  // #ifndef _PELE_GAUSSIANPOT_H