Program Listing for File rosenbrock.hpp#
↰ Return to documentation for file (source/pele/rosenbrock.hpp)
#ifndef _PELE_TEST_FUNCS_H
#define _PELE_TEST_FUNCS_H
#include <cassert>
#include <cmath>
#include <cstddef>
#include <iostream>
#include <memory>
#include <numbers>
#include <numeric>
#include <vector>
#include "array.hpp"
#include "base_potential.hpp"
namespace pele {
class RosenBrock : public BasePotential {
private:
double m_a;
double m_b;
public:
RosenBrock(double a = 1, double b = 100) : m_a(a), m_b(b){};
virtual ~RosenBrock(){};
inline double get_energy(Array<double> const &x) {
return (m_a - x[0]) * (m_a - x[0]) +
m_b * (x[1] - x[0] * x[0]) * (x[1] - x[0] * x[0]);
}
inline double get_energy_gradient(Array<double> const &x,
Array<double> &grad) {
grad.assign(0);
grad[0] = 4 * m_b * x[0] * x[0] * x[0] - 4 * m_b * x[0] * x[1] +
2 * m_a * x[0] - 2 * m_a;
grad[1] = 2 * m_b * (x[1] - x[0] * x[0]);
return (m_a - x[0]) * (m_a - x[0]) +
m_b * (x[1] - x[0] * x[0]) * (x[1] - x[0] * x[0]);
};
};
class Saddle : public BasePotential {
private:
double m_a2;
double m_b2;
double m_a4;
double m_b4;
public:
Saddle(double a2 = 2, double b2 = 2, double a4 = 1, double b4 = 1)
: m_a2(a2), m_b2(b2), m_a4(a4), m_b4(b4){};
virtual ~Saddle(){};
inline double get_energy(Array<double> const &x) {
return m_a2 * x[0] * x[0] - m_b2 * x[1] * x[1] +
m_a4 * x[0] * x[0] * x[0] * x[0] + m_a4 * x[1] * x[1] * x[1] * x[1];
}
inline double get_energy_gradient(Array<double> const &x,
Array<double> &grad) {
grad.assign(0);
grad[0] = 2 * m_a2 * x[0] + 4 * m_b4 * x[0] * x[0] * x[0];
grad[1] = -2 * m_b2 * x[1] + 4 * m_b4 * x[1] * x[1] * x[1];
return m_a2 * x[0] * x[0] - m_b2 * x[1] * x[1] +
m_a4 * x[0] * x[0] * x[0] * x[0] + m_a4 * x[1] * x[1] * x[1] * x[1];
};
};
class XCube : public BasePotential {
public:
XCube(){};
virtual ~XCube(){};
inline double get_energy(Array<double> const &x) {
return x[0] * x[0] * x[0];
}
inline double get_energy_gradient(Array<double> const &x,
Array<double> &grad) {
grad.assign(0);
grad[0] = 3 * x[0] * x[0];
std::cout << grad[0] << " graaadient \n";
return x[0] * x[0] * x[0];
};
};
class FlatHarmonic : public BasePotential {
private:
double m_a;
public:
FlatHarmonic(double a = 1) : m_a(a){};
virtual ~FlatHarmonic(){};
inline double get_energy(Array<double> const &x) { return m_a * x[0] * x[0]; }
inline double get_energy_gradient(Array<double> const &x,
Array<double> &grad) {
grad.assign(0);
grad[0] = 2 * m_a * (x[0] - x[1]);
grad[1] = -grad[0];
return m_a * x[0] * x[0];
};
inline double get_energy_gradient_hessian(Array<double> const &x,
Array<double> &grad,
Array<double> &hess) {
grad.assign(0);
hess.assign(0);
grad[0] = 2 * m_a * (x[0] - x[1]);
grad[1] = -grad[0];
hess[0] = 2 * m_a;
hess[1] = -hess[0];
hess[2] = -hess[0];
hess[3] = hess[0];
return m_a * x[0] * x[0];
};
};
class PoweredCosineSum : public BasePotential {
private:
double _period_factor;
// precompute cos and sin values
Array<double> _cos_values;
Array<double> _sin_values;
double _power;
double _offset;
void _precompute_cos_sin(Array<double> const &x) {
for (size_t i = 0; i < x.size(); ++i) {
_cos_values[i] = std::cos(_period_factor * x[i]);
_sin_values[i] = std::sin(_period_factor * x[i]);
}
}
public:
PoweredCosineSum(size_t dim, double period = 1, double pow = 0.5,
double offset = 1.0)
: _period_factor(2 * std::numbers::pi / period),
_cos_values(dim, 0.0),
_sin_values(dim, 0.0),
_power(pow),
_offset(offset){};
virtual ~PoweredCosineSum(){};
inline double get_energy(Array<double> const &x) {
if (_cos_values.size() != x.size()) {
throw std::runtime_error(
"dim passed to cosine sume not the same size as input");
}
_precompute_cos_sin(x);
double f_x = x.size() + _offset;
f_x -= std::accumulate(_cos_values.begin(), _cos_values.end(), 0.0);
return std::pow(f_x, _power);
}
double add_energy_gradient(const Array<double> &x, Array<double> &grad) {
if (_cos_values.size() != x.size()) {
throw std::runtime_error(
"dim passed to cosine sume not the same size as input");
}
_precompute_cos_sin(x);
double f_x = x.size() + _offset;
f_x -= std::accumulate(_cos_values.begin(), _cos_values.end(), 0.0);
// m for minus
double power_m_1_term = std::pow(f_x, _power - 1);
for (size_t i = 0; i < x.size(); ++i) {
grad[i] += _power * power_m_1_term * _period_factor * _sin_values[i];
}
return power_m_1_term * f_x;
}
double get_energy_gradient(const Array<double> &x, Array<double> &grad) {
grad.assign(0);
return add_energy_gradient(x, grad);
}
void add_hessian(const Array<double> &x, Array<double> &hess) {
if (_cos_values.size() != x.size()) {
throw std::runtime_error(
"dim passed to cosine sume not the same size as input");
}
_precompute_cos_sin(x);
double f_x = x.size() + _offset;
f_x -= std::accumulate(_cos_values.begin(), _cos_values.end(), 0.0);
// m for minus
double power_m_2 = std::pow(f_x, _power - 2);
for (size_t i = 0; i < x.size(); ++i) {
for (size_t j = 0; j < x.size(); ++j) {
double common_term = _power * (_power - 1) * power_m_2 *
_period_factor * _period_factor * _sin_values[i] *
_sin_values[j];
if (i == j) {
hess[i * x.size() + j] +=
common_term + _power * power_m_2 * f_x * _period_factor *
_period_factor * _cos_values[i];
} else {
hess[i * x.size() + j] += common_term;
}
}
}
}
inline double add_energy_gradient_hessian(Array<double> const &x,
Array<double> &grad,
Array<double> &hess) {
if (_cos_values.size() != x.size()) {
throw std::runtime_error(
"dim passed to cosine sume not the same size as input");
}
_precompute_cos_sin(x);
double f_x = x.size() + _offset;
f_x -= std::accumulate(_cos_values.begin(), _cos_values.end(), 0.0);
// m for minus
double power_m_2 = std::pow(f_x, _power - 2);
for (size_t i = 0; i < x.size(); ++i) {
grad[i] += _power * power_m_2 * f_x * _period_factor * _sin_values[i];
}
for (size_t i = 0; i < x.size(); ++i) {
for (size_t j = 0; j < x.size(); ++j) {
double common_term = _power * (_power - 1) * power_m_2 *
_period_factor * _period_factor * _sin_values[i] *
_sin_values[j];
if (i == j) {
hess[i * x.size() + j] +=
common_term + _power * power_m_2 * f_x * _period_factor *
_period_factor * _cos_values[i];
} else {
hess[i * x.size() + j] += common_term;
}
}
}
return power_m_2 * f_x * f_x;
}
double get_energy_gradient_hessian(Array<double> const &x,
Array<double> &grad, Array<double> &hess) {
grad.assign(0);
hess.assign(0);
return add_energy_gradient_hessian(x, grad, hess);
}
};
} // namespace pele
#endif