I'm trying to get a hold on how to work with splines in Eigen, specifically I want do find the value of the spline interpolation and its first and second derivatives in some point. Finding the interpolated value is easy, but when I try to calculate the derivative I get strange values.
I tried following the instructions for the derivatives command in the manual (http://eigen.tuxfamily.org/dox/unsupported/classEigen_1_1Spline.html#af3586ab1929959e0161bfe7da40155c6), and this is my attempt in code:
#include <iostream>
#include <Eigen/Core>
#include <unsupported/Eigen/Splines>
using namespace Eigen;
using namespace std;
double scaling(double x, double min, double max) // for scaling numbers
{
return (x - min)/(max - min);
}
VectorXd scale(VectorXd xvals) // for scaling vectors
{
const double min = xvals.minCoeff();
const double max = xvals.maxCoeff();
for (int k = 0; k < xvals.size(); k++)
xvals(k) = scaling(xvals(k),min,max);
return xvals;
}
int main()
{
typedef Spline<double,1,3> spline;
VectorXd xvals = (VectorXd(4) << 0,1,2,4).finished();
VectorXd yvals = xvals.array().square(); // x^2
spline testspline = SplineFitting<spline>::Interpolate(yvals.transpose(), 3,
scale(xvals).transpose());
cout << "derivative at x = 0: " << testspline.derivatives(0.00,2) << endl;
cout << "derivative at x = 1: " << testspline.derivatives(0.25,2) << endl;
cout << "derivative at x = 2: " << testspline.derivatives(0.50,2) << endl;
cout << "derivative at x = 3: " << testspline.derivatives(0.75,2) << endl;
cout << "derivative at x = 4: " << testspline.derivatives(1.00,2) << endl;
}
it outputs
derivative at x = 0: 0 0 32
derivative at x = 1: 1 8 32
derivative at x = 2: 4 16 32
derivative at x = 3: 9 24 32
derivative at x = 4: 16 32 32
That is, the interpolation is correct (c.f. x = 3), but the derivatives are not, and they are off in a systematic way, so I'm thinking I'm doing something wrong. Since these follow x^2, the derivatives should be 0,2,4,6,8 and the second order derivative should be 2.
Any ideas on how to solve this?
Edit 1
Changing x^2 to x^2 + 1 yields the same derivatives, so that checks out at least. But changing x^2 to x^3 is wrong, but wrong in a slightly different way, output would then be:
derivative at x = 2: 8 48 192
derivative at x = 3: 27 108 288
derivative at x = 4: 64 192 384
Which is wrong, it should be 6, 9, 12.
Also running the x^2 case, but changing he input vector to 0,1,...9 yields the same derivative as using the original input vector, but the second order derivative becomes a steady 200, which too is wrong. I fail to see why the second order derivative should depend on the number of input points.
Solved it. You were very close. All you had to do was scale the derivatives
with
1 / (x_max - x_min) (first derivative)
1 / (x_max - x_min)^2 (second derivative).
TLDR: You normalized the x values to be between 0 and 1 while fitting the spline, but you didn't scale the y values.
Instead of the spline fitting x^2, you actually fitted:
x_norm = (x - x_min) / (x_max - x_min)
y = x_norm**2
So using the chain rule the first derivative of y = x_norm**2 would be 2x / (x_max - x_min) and the second derivative would be 2 / (x_max - x_min)**2.
Full example code:
#include <iostream>
#include <Eigen/Core>
#include <unsupported/Eigen/Splines>
using namespace Eigen;
using namespace std;
VectorXd normalize(const VectorXd &x) {
VectorXd x_norm;
x_norm.resize(x.size());
const double min = x.minCoeff();
const double max = x.maxCoeff();
for (int k = 0; k < x.size(); k++) {
x_norm(k) = (x(k) - min)/(max - min);
}
return x_norm;
}
int main() {
typedef Spline<double, 1, 3> Spline1D;
typedef SplineFitting<Spline1D> Spline1DFitting;
const Vector4d x{0, 1, 2, 4};
const Vector4d y = (x.array().square()); // x^2
const auto knots = normalize(x); // Normalize x to be between 0 and 1
const double scale = 1 / (x.maxCoeff() - x.minCoeff());
const double scale_sq = scale * scale;
Spline1D spline = Spline1DFitting::Interpolate(y.transpose(), 3, knots);
cout << "1st deriv at x = 0: " << spline.derivatives(0.00, 1)(1) * scale << endl;
cout << "1st deriv at x = 1: " << spline.derivatives(0.25, 1)(1) * scale << endl;
cout << "1st deriv at x = 2: " << spline.derivatives(0.50, 1)(1) * scale << endl;
cout << "1st deriv at x = 3: " << spline.derivatives(0.75, 1)(1) * scale << endl;
cout << "1st deriv at x = 4: " << spline.derivatives(1.00, 1)(1) * scale << endl;
cout << endl;
/**
* IMPORTANT NOTE: Eigen's spline module is not documented well. Once you fit a spline
* to find the derivative of the fitted spline at any point u [0, 1] you call:
*
* spline.derivatives(u, 1)(1)
* ^ ^ ^
* | | |
* | | +------- Access the result
* | +---------- Derivative order
* +------------- Parameter u [0, 1]
*
* The last bit `(1)` is if the spline is 1D. And value of `1` for the first
* order. `2` for the second order. Do not forget to scale the result.
*
* For higher dimensions, treat the return as a matrix and grab the 1st or
* 2nd column for the first and second derivative.
*/
cout << "2nd deriv at x = 0: " << spline.derivatives(0.00, 2)(2) * scale_sq << endl;
cout << "2nd deriv at x = 1: " << spline.derivatives(0.25, 2)(2) * scale_sq << endl;
cout << "2nd deriv at x = 2: " << spline.derivatives(0.50, 2)(2) * scale_sq << endl;
cout << "2nd deriv at x = 3: " << spline.derivatives(0.75, 2)(2) * scale_sq << endl;
cout << "2nd deriv at x = 4: " << spline.derivatives(1.00, 2)(2) * scale_sq << endl;
return 0;
}
Example output:
1st deriv at x = 0: 4.52754e-16
1st deriv at x = 1: 2
1st deriv at x = 2: 4
1st deriv at x = 3: 6
1st deriv at x = 4: 8
2nd deriv at x = 0: 2
2nd deriv at x = 1: 2
2nd deriv at x = 2: 2
2nd deriv at x = 3: 2
2nd deriv at x = 4: 2
Edit: see working .h-file for calculating B-splines of any order at the bottom.
Disclaimer: this is not an answer to my question as it is actually stated in the title, but rather a work-around with some comments.
After deliberations with user #Paul H. (see comments) I realized that my limited understanding of splines might have caused some confusion on my part. After some scrutiny of the Eigen documentation it seems plausible that the derivative() command does indeed works as intended, hence making my question badly phrased. The derivative() calculates the derivative of the spline rather than the derivative of the fitted function, as I intended it to. I have not figured out a way to get Eigen to output the function derivatives from the fit, and I don't think it is designed to to this. However, the derivatives can of course be readily calculated once the fitted points is obtained using some standard algorithm for calculating derivatives.
I wrote the following .h-file for calculating splines and their derivatives in the process which I thought worthwhile sharing. It's fairly well commented for convenience.
Note that this program uses 1-indexing rather than 0-indexing of the splines, hence for an e.g. quadratic B-spline order should be set to 4. This is a small quirk that is be easily fixed by changing the calculations to match wikipedia.
bsplines.h
//
// Header-file for calculating splines using standard libraries
//
// usage:
//
// x bsplines class constructs a set of splines up to some given order,
// on some given knot sequence, the splines are stored in a vector,
// such that splines[a][b] accesses the spline of order a and index b
// x get<some_member>() is an accessor that returns a pointer to some
// data member of the spline
// x calcsplines() calculates spline values as well as first and second
// order derivatives on some predefined grid
// x calcspline() returns the spline value as well as first and second
// derivatives in some point. This alborithm is slower than the grid
// one, due to unnecessary recalculations of intermediate results
// x writesplines() writes the splines and their derivatives to a file
// x for more details se the class declaration below
// TODO:
// x change to 0-indexation
// x introduce the possibility of calculating higher order derivatives
// recursively
//
// change log:
//
// 1.0 - initial release
// 1.1 - reworked grid such that the class now expects separate
// grid and knot files.
// - added the ability to calculate spline value in a point
// rather than calculate values on a grid
// - added a feature to change knots and grid
// 1.1.1 - reworked how returning single values works
// 1.1.2 - enabled swapping grid
//
// Note:
//
// This file uses 1-indexation rathar than 0-indexation, hence a qubic spline
// would be k = 4. Someone should eventually fix this as this is non-standard.
//
// Also, while only standard libraries are used here, you might want to check out
// some linear algebra package (e.g. Armadillo or Eigen) if you're going to use the
// splines in a context where you need linear algebraic operations.
//
// Originally developed by David Andersson
//
#include <iomanip>
#include <sstream>
#include <iostream>
#include <vector>
#include <algorithm>
#include <fstream>
#include <functional>
using namespace std;
typedef unsigned int uint;
class bsplines // class for bsplines
{
// private section
uint order; // order of spline
uint gridpts; // number of grid points
uint knotpts; // number of knot points
double tolerance; // tolerance for float comparisons
vector<double> knots; // knot sequence
vector<double> grid; // grid points
class spline // a member spline in the set of splines
{
int index; // the spline index, or number
vector<double> vals; // spline values
vector<double> d1; // spline first derivatives
vector<double> d2; // spline second derivatives
double tval; // same, but in one point
double td1;
double td2;
friend bsplines; // for ease of access
public:
};
vector<vector <spline>> splines; // the set of splines
// puclic section
public:
void readknots(string); // read knots from file
void readknotsnorm(string); // read knots from file and normalize
void readgrid(string); // read grid from file
void swapgrid(string); // reads and swaps new grid from file
void writesplines(); // write spline vals and derivs to file
void buildsplines(); // build the set of splines
void calcsplines(); // calculate spline vals and derivs
void printknots(); // print knot sequence
void printgrid(); // print grid
void printgridsize(); // print gridsize
void printvals(uint,uint); // print values of a spline
vector <double> calcspline(uint,uint,double); // calculate spline in point
// accessors // returns pointer to member
vector <double>* getknots(){return &knots;}
vector <double>* getgrid(){return &grid;}
uint* getknotpts(){return &knotpts;}
uint* getgridpts(){return &gridpts;}
uint getnosplines(uint m){return splines[m].size();}
vector <spline>* getsplines(uint m){return &splines[m];}
vector <double>* getvals(uint m, uint n){return &splines[m][n].vals;}
vector <double>* getd1(uint m, uint n){return &splines[m][n].d1;}
vector <double>* getd2(uint m, uint n){return &splines[m][n].d2;}
// constructor // sets up the spline class
bsplines (string iknots, string igrid, uint iorder, double itol)
:order(iorder), tolerance(itol)
{
readknots(iknots);
readgrid(igrid);
buildsplines();
}
};
void bsplines::buildsplines()
{
{
for (uint l = 1; l <= order; l++)
{
vector <spline> splinevec;
for (uint k = 0; k < knotpts - l; k++)
{
spline tmp;
tmp.index = k;
tmp.vals.reserve(gridpts);
tmp.d1.reserve(gridpts);
tmp.d2.reserve(gridpts);
splinevec.push_back(tmp);
}
splines.push_back(splinevec);
}
}
}
vector <double> bsplines::calcspline(uint m, uint n, double x)
{
// first order splines // exceptions handles infinities
for (auto& sp : splines[0])
{
uint i = sp.index;
if (x > knots[i+1])
sp.tval = 0;
else if ((x >= knots[i] && x < knots[i+1]) || x == knots.back())
sp.tval = 1;
else
sp.tval = 0;
}
// higher order splines
for (uint o = 1; o < order; o++)
{
uint oo = o+1; // compensating for 1-indexation
for (auto& sp : splines[o])
{
uint i = sp.index;
double t1 = knots[i+oo-1] - knots[i];
double t2 = knots[i+oo] - knots[i+1];
double c = 0;
if (abs(t1) > tolerance)
c += (x - knots[i]) / t1 * splines[o-1][i].tval;
if (abs(t2) > tolerance)
c += (knots[i+oo] - x) / t2 * splines[o-1][i+1].tval;
sp.tval = c;
}
}
uint o = order - 1;
// first order derivatives
for (auto& sp : splines[o])
{
uint i = sp.index;
double t1 = knots[i+order-1] - knots[i];
double t2 = knots[i+order] - knots[i+1];
double c = 0;
if (abs(t1) > tolerance)
c += 1.0 / t1 * splines[o-1][i].tval;
if (abs(t2) > tolerance)
c -= 1.0 / t2 * splines[o-1][i+1].tval;
c *= (order-1);
sp.td1 = c;
}
// second order derivatives
for (auto& sp : splines[o])
{
uint i = sp.index;
double t1 = (knots[i+order-1] - knots[i+0]) * (knots[i+order-2] - knots[i+0]);
double t2 = (knots[i+order-1] - knots[i+0]) * (knots[i+order-1] - knots[i+1]);
double t3 = (knots[i+order-0] - knots[i+1]) * (knots[i+order-1] - knots[i+1]);
double t4 = (knots[i+order-0] - knots[i+1]) * (knots[i+order-0] - knots[i+2]);
double c = 0;
if (abs(t1) > tolerance)
c += 1.0 / t1 * splines[o-2][sp.index].tval;
if (abs(t2) > tolerance)
c -= 1.0 / t2 * splines[o-2][sp.index+1].tval;
if (abs(t3) > tolerance)
c -= 1.0 / t3 * splines[o-2][sp.index+1].tval;
if (abs(t4) > tolerance)
c += 1.0 / t4 * splines[o-2][sp.index+2].tval;
c *= (order-1)*(order-2);
sp.td2 = c;
}
vector <double> retvals = {splines[m][n].tval, splines[m][n].td1, splines[m][n].td2};
return retvals;
}
void bsplines::calcsplines()
{
// first order splines
for (auto& sp : splines[0])
{
uint i = sp.index;
for (auto& x : grid)
{
if (x > knots[i+1])
sp.vals.push_back(0);
else if ((x >= knots[i] && x < knots[i+1]) || x == knots.back())
sp.vals.push_back(1);
else
sp.vals.push_back(0);
}
}
// higher order splines
for (uint o = 1; o < order; o++)
{
uint oo = o+1; // compensating for 1-indexation
for (auto& sp : splines[o])
{
uint i = sp.index;
double t1 = knots[i+oo-1] - knots[i];
double t2 = knots[i+oo] - knots[i+1];
for (auto& x : grid)
{
uint k = &x - &grid[0];
double c = 0;
if (abs(t1) > tolerance)
c += (x - knots[i]) / t1 * splines[o-1][i].vals[k];
if (abs(t2) > tolerance)
c += (knots[i+oo] - x) / t2 * splines[o-1][i+1].vals[k];
sp.vals.push_back(c);
}
}
}
uint o = order - 1; // use this one when accessing splines;
// first order derivatives
for (auto& sp : splines[o])
{
uint i = sp.index;
double t1 = knots[i+order-1] - knots[i];
double t2 = knots[i+order] - knots[i+1];
for (auto& x : grid)
{
uint k = &x - &grid[0];
double c = 0;
if (abs(t1) > tolerance)
c += 1.0 / t1 * splines[o-1][i].vals[k];
if (abs(t2) > tolerance)
c -= 1.0 / t2 * splines[o-1][i+1].vals[k];
c *= (order-1);
sp.d1.push_back(c);
}
}
// second order derivatives
for (auto& sp : splines[o])
{
uint i = sp.index;
double t1 = (knots[i+order-1] - knots[i+0]) * (knots[i+order-2] - knots[i+0]);
double t2 = (knots[i+order-1] - knots[i+0]) * (knots[i+order-1] - knots[i+1]);
double t3 = (knots[i+order-0] - knots[i+1]) * (knots[i+order-1] - knots[i+1]);
double t4 = (knots[i+order-0] - knots[i+1]) * (knots[i+order-0] - knots[i+2]);
for (auto& x : grid)
{
uint k = &x - &grid[0];
double c = 0;
if (abs(t1) > tolerance)
c += 1.0 / t1 * splines[o-2][sp.index].vals[k];
if (abs(t2) > tolerance)
c -= 1.0 / t2 * splines[o-2][sp.index+1].vals[k];
if (abs(t3) > tolerance)
c -= 1.0 / t3 * splines[o-2][sp.index+1].vals[k];
if (abs(t4) > tolerance)
c += 1.0 / t4 * splines[o-2][sp.index+2].vals[k];
c *= (order-1)*(order-2);
sp.d2.push_back(c);
}
}
}
void bsplines::readknots(string knotfile)
{
double x;
ifstream readknots(knotfile);
while (readknots >> x)
knots.push_back(x);
for (uint k = 0; k < order - 1; k++)
{
knots.insert(knots.begin(),knots.front());
knots.insert(knots.end(),knots.back());
}
knotpts = knots.size();
}
void bsplines::readknotsnorm(string knotfile)
{
double x;
knots.reserve(knotpts + 2*(order - 1));
ifstream readknots(knotfile);
while (readknots >> x)
knots.push_back(x);
auto minmax = minmax_element(begin(knots), end(knots));
double min = *(minmax.first);
double max = *(minmax.second);
for (auto& el : knots)
el = (el - min) / (max-min);
}
void bsplines::readgrid(string gridfile)
{
double x;
ifstream readgrid(gridfile);
while (readgrid >> x)
grid.push_back(x);
gridpts = grid.size();
}
void bsplines::swapgrid(string gridfile)
{
grid = {};
double x;
ifstream readgrid(gridfile);
while (readgrid >> x)
grid.push_back(x);
gridpts = grid.size();
}
void bsplines::printknots()
{
cout << "content in knot vector: " << endl;
for (auto& el : knots)
cout << el << " ";
cout << endl;
}
void bsplines::printgrid()
{
cout << "content in grid vector: " << endl;
for (auto& el : grid)
cout << el << " ";
cout << endl;
}
void bsplines::printgridsize()
{
cout << "number of grid points: " << endl << grid.size() << endl;
}
void bsplines::printvals(uint m, uint n)
{
cout << "content in spline (B" << m << "," << n << ") vals vector: " << endl;
for (auto& el : splines[n][m].vals)
cout << el << " ";
cout << endl;
}
void bsplines::writesplines()
{
for (uint o = 0; o < order; o++)
for (auto& sp : splines[o])
{
uint i = sp.index;
ostringstream namestream;
namestream << "B(" << fixed << setprecision(1) << i << ","
<< fixed << setprecision(1) << o << ").csv";
string filename = namestream.str();
ofstream fs;
fs.open(filename);
if (o < order - 1)
{
for (uint k = 0; k < sp.vals.size(); k++)
fs << sp.vals[k] << "," << 0 << "," << 0 << endl;
fs.close();
}
else
{
for (uint k = 0; k < sp.vals.size(); k++)
fs << sp.vals[k] << "," << sp.d1[k] << "," << sp.d2[k] << endl;
fs.close();
}
cout << "write " << sp.vals.size() << " numbers to " << filename << endl;
}
}
Edit: updated .h-file.
Related
I have a problem with the following assignment. The problem is to find the integral of the function. It gives me the error "Cannot convert argument 1 from 'double' to 'char(*)(double)'". I think the problem is in the bottom, where I define the function. And I am not even sure if I should use char for p.
Does anyone know, what the problem is?
/*43. Modify program chapter6_11 to estimate the integral of the function
f (x) = 3x − 2x^2.*/
#include <iostream> //Required for cin, cout
#include <fstream>
#include <cstdlib> //Required for srand(), rand().
#include <cmath> //Required for pow().
using namespace std;
/*-----------------------------------------------------------------*/
/* Program chapter6_11 */
/* */
/* This program finds the real roots of a cubic polynomial */
/* using the Newton-Raphson method. */
double integral(char(p)(double x), double a, double b, double n);
int main(){
// Declare objects.
int iterations(0);
double a1, a2, a3, x, p, dp, tol;
cout << "Enter coefficients a1, a2, a3 (here -2, 3 and 0)\n";
cin >> a1 >> a2 >> a3;
cout << "Enter initial guess for root\n";
cin >> x;
// Evaluate p at initial guess.
p = -2* x * x + 3 * x + 0;
// Determine tolerance.
tol = fabs(p);
while (tol > 0.001 && iterations < 100)
{
// Calculate the derivative.
dp = 2 * -2 * x + 3;
// Calculate next estimated root.
x = x - p / dp;
// Evaluate p at estimated root.
p = -2 * x * x + 3 * x + 0;
tol = fabs(p);
iterations++;
}
if (tol < 0.001)
{
cout << "Root is " << x << endl;
cout << iterations << " iterations\n";
cout << "Integral is" << integral(p, -100000, 100000, 1000);
}
else
cout << "Did not converge after 100 iterations\n";
return 0;
}
double integral(char(p)(double x), double a, double b, double n) {
double step = (b - a) / n; // width of each small rectangle
double area = 0.0; // signed area
for (int i = 0; i < n; i++) {
area += p(a + (i + 0.5) * step) * step; // sum up each small rectangle
}
return area;
}
You are calling integral,
cout << "Integral is" << integral(p, -100000, 100000, 1000);
Where p is not a pointer to a function returning a char and taking a double
char func(double x);
maybe you meant to define such at function?
I am trying to calculate distances between particles in a box. If the distance calculated is greater than a preset cut-off distance, then the potential energy is 0. Otherwise, it is 1.
There are some rounding issues I think and I am not familiar with variable types and passing variables through functions to know what to do next.
The error
When I calculate d0 by hand I get d0 = 0.070 - this is not what the computer gets! The computer gets a number on the order of e-310.
All of the calculated distances (dij) are no shorter than 1/14, which is much larger than e-310. According to my if statement, if dij>d0, then U=0, so I should get a total energy of 0, but this is what I get:
d0 is 6.95322e-310
i is 0 j is 1 dij is 0.0714286 d0 is 6.95322e-310 Uij is 1
.....
Energy of the system is 24976
Please let me know if I could provide any more information. I did not include the entirety of my code, but the other portion involves no manipulation of d0.
I copied the relevant pieces of code below
Part 1: relevant box data
class Vector {
public:
double x;
double y;
Vector() {
}
Vector (double x_, double y_) {
x = x_;
y = y_;
}
double len() {
return sqrt(x*x + y*y);
}
double lenSqr() {
return x*x + y*y;
}
};
class Atom
{
public:
Vector pos;
Vector vel;
Vector force;
Atom (double x_, double y_) {
pos = Vector(x_, y_);
}
};
class BoxData
{
public:
const double Len = 1.;
const double LenHalf = 0.5 * Len;
long double d = 1. / 14; // d is the distance between each atom
in the initial trigonal lattice
int nu = 7; // auxillary parameter - will be varied
long double d0 = d * (1 - 2^(nu - 8)); // cutoff distance
double alpha = d - d0; // maximum allowed displacement
};
int main() {
// Initialize box
LoadBox();
// Institute a for loop here
SystemEnergy();
MonteCarloMove();
return 0;
}
//Putting atoms into box
void LoadBox()
{
ofstream myfile("init.dat", ios::out);
//Load atoms in box in triangular offset lattice
const double x_shift = 1. / 14;
const double y_shift = 1. / 16;
double x = 0;
double y = 0;
double x_offset = 0;
for (y = 0; y <= 1. - y_shift; y += y_shift) {
for (x = x_offset; x < 0.99; x += x_shift) {
// create atom in position (x, y)
// and store it in array of atoms
atoms.push_back(Atom(x, y));
}
// every new row flip offset 0 -> 1/28 -> 0 -> 1/28...
if (x_offset < x_shift / 4) {
x_offset = x_shift / 2;
} else {
x_offset = 0.0;
}
}
const int numAtoms = atoms.size();
//print the position of each atom in the file init.dat
for (int i = 0; i < numAtoms; i++) {
myfile << "x is " << atoms[i].pos.x << " y is " << atoms[i].pos.y << endl;
}
myfile.close();
}
Part 2 : Energy calculation
vector<Atom> atoms;
BoxData box_;
void SystemEnergy()
{
ofstream myfile("energy.dat", ios::out);
double box_Len, box_LenHalf, box_d0;
double dij; // distance between two atoms
double Uij; // energy between two particles
double UTotal = 0;
double pbcx, pbcy; // pbc -> periodic boundary condition
double dx, dy;
myfile << "d0 is " << box_d0 << endl;
// define the number of atoms as the size of the array of atoms
const int numAtoms = atoms.size();
//pick atoms
for (int i=0; i<numAtoms-1; i++) { // pick one atom -> "Atom a"
Atom &a = atoms[i];
for (int j=i+1; j<numAtoms; j++) { // pick another atom -> "Atom b"
Atom &b = atoms[j];
dx = a.pos.x - b.pos.x;
dy = a.pos.y - b.pos.y;
pbcx = 0.0;
pbcy = 0.0;
// enforce periodic boundary conditions
if(dx > box_LenHalf) pbcx =- box_Len;
if(dx < -box_LenHalf) pbcx =+ box_Len;
if(dy > box_LenHalf) pbcy =- box_Len;
if(dy < -box_LenHalf) pbcy =+ box_Len;
dx += pbcx;
dy += pbcy;
// calculate distance between atoms
dij = sqrt(dx*dx + dy*dy);
// compare dij to the cutoff distance to determine energy
if (dij > box_d0) {
Uij = 0;
} else {
Uij = 1;
}
myfile << "i is " << i << " j is " << j << " dij is " << dij << " d0 is " << box_d0 << " Uij is " << Uij << endl;
UTotal += Uij; // sum the energies
}
}
myfile << "Energy of the system is " << UTotal << endl;
myfile.close();
}
Sorry for the formatting issues - getting the hang of copy/pasting to the forum.
Given a set of 2d points (in Cartesian form), I need to find the minimum-area ellipse such that every point in the set lies either on or inside the ellipse.
I have found the solution in the form of pseudo-code on this site, but my attempt to implement the solution in C++ has been unsuccessful.
The following image illustrates graphically what the solution to my problem looks like:
In my attempt, I used the Eigen library for the various operations on matrices.
//The tolerance for error in fitting the ellipse
double tolerance = 0.2;
int n = 10; // number of points
int d = 2; // dimension
MatrixXd p = MatrixXd::Random(d,n); //Fill matrix with random points
MatrixXd q = p;
q.conservativeResize(p.rows() + 1, p.cols());
for(size_t i = 0; i < q.cols(); i++)
{
q(q.rows() - 1, i) = 1;
}
int count = 1;
double err = 1;
const double init_u = 1.0 / (double) n;
MatrixXd u = MatrixXd::Constant(n, 1, init_u);
while(err > tolerance)
{
MatrixXd Q_tr = q.transpose();
cout << "1 " << endl;
MatrixXd X = q * u.asDiagonal() * Q_tr;
cout << "1a " << endl;
MatrixXd M = (Q_tr * X.inverse() * q).asDiagonal();
cout << "1b " << endl;
int j_x, j_y;
double maximum = M.maxCoeff(&j_x, &j_y);
double step_size = (maximum - d - 1) / ((d + 1) * (maximum + 1));
MatrixXd new_u = (1 - step_size) * u;
new_u(j_x, 0) += step_size;
cout << "2 " << endl;
//Find err
MatrixXd u_diff = new_u - u;
for(size_t i = 0; i < u_diff.rows(); i++)
{
for(size_t j = 0; j < u_diff.cols(); j++)
u_diff(i, j) *= u_diff(i, j); // Square each element of the matrix
}
err = sqrt(u_diff.sum());
count++;
u = new_u;
}
cout << "3 " << endl;
MatrixXd U = u.asDiagonal();
MatrixXd A = (1.0 / (double) d) * (p * U * p.transpose() - (p * u) * (p * u).transpose()).inverse();
MatrixXd c = p * u;
The error occurs on the following line:
MatrixXd M = (Q_tr * X.inverse() * q).asDiagonal();
and it reads as follows:
run: /usr/include/eigen3/Eigen/src/Core/DenseBase.h:261: void Eigen::DenseBase<Derived>::resize(Eigen::Index, Eigen::Index) [with Derived = Eigen::Diagonal<Eigen::Matrix<double, -1, -1>, 0>; Eigen::Index = long int]: Assertion `rows == this->rows() && cols == this->cols() && "DenseBase::resize() does not actually allow to resize."' failed.
Aborted (core dumped)
Can someone please point out why this error is occurring or even better, give me some advice on how to fit an ellipse to a set of points using C++?
With Eigen, you can get the diagonal vector from a matrix with .diagonal(); you can treat a vector as a diagonal matrix with .asDiagonal(); but you cannot treat a dense matrix as a diagonal matrix. So that line should be
MatrixXd M = (Q_tr * X.inverse() * q).diagonal();
I made a simple perceptron in c++ to study AI and even following a book(pt_br) i could not make my perceptron return an expected result, i tryed to debug and find the error but i didnt succeed.
My algorithm AND gate results (A and B = Y):
0 && 0 = 0
0 && 1 = 1
1 && 0 = 1
1 && 1 = 1
Basically its working as an OR gate or random.
I Tried to jump to Peter Norving and Russel book, but he goes fast over this and dont explain on depth one perceptron training.
I really want to learn every inch of this content, so i dont want to jump to Multilayer perceptron without making the simple one work, can you help?
The following code is the minimal code for operation with some explanations:
Sharp function:
int signal(float &sin){
if(sin < 0)
return 0;
if(sin > 1)
return 1;
return round(sin);
}
Perceptron Struct (W are Weights):
struct perceptron{
float w[3];
};
Perceptron training:
perceptron startTraining(){
//- Random factory generator
long int t = static_cast<long int>(time(NULL));
std::mt19937 gen;
gen.seed(std::random_device()() + t);
std::uniform_real_distribution<float> dist(0.0, 1.0);
//--
//-- Samples (-1 | x | y)
float t0[][3] = {{-1,0,0},
{-1,0,1},
{-1,1,0},
{-1,1,1}};
//-- Expected result
short d [] = {0,0,0,1};
perceptron per;
per.w[0] = dist(gen);
per.w[1] = dist(gen);
per.w[2] = dist(gen);
//-- print random numbers
cout <<"INIT "<< "W0: " << per.w[0] <<" W1: " << per.w[1] << " W2: " << per.w[2] << endl;
const float n = 0.1; // Lerning rate N
int saida =0; // Output Y
long int epo = 0; // Simple Couter
bool erro = true; // Loop control
while(erro){
erro = false;
for (int amost = 0; amost < 4; ++amost) { // Repeat for the number of samples x0=-1, x1,x2
float u=0; // Variable for the somatory
for (int entrad = 0; entrad < 3; ++entrad) { // repeat for every sinaptic weight W0=θ , W1, W2
u = u + (per.w[entrad] * t0[amost][entrad]);// U <- Weights * Inputs
}
// u=u-per.w[0]; // some references sau to take θ and subtract from U, i tried but without success
saida = signal(u); // returns 1 or 0
cout << d[amost] << " <- esperado | encontrado -> "<< saida<< endl;
if(saida != d[amost]){ // if the output is not equal to the expected value
for (int ajust = 0; ajust < 3; ++ajust) {
per.w[ajust] = per.w[ajust] + n * (d[amost] - saida) * t0[amost][ajust]; // W <- W + ɳ * ((d - y) x) where
erro = true; // W: Weights, ɳ: Learning rate
} // d: Desired outputs, y: outputs
} // x: samples
epo++;
}
}
cout << "Epocas(Loops): " << epo << endl;
return per;
}
Main with testing part:
int main()
{
perceptron per = startTraining();
cout << "fim" << endl;
cout << "W0: " << per.w[0] <<" W1: " << per.w[1] << " W2: " << per.w[2] << endl;
while(true){
int x,y;
cin >> x >> y;
float u=0;
u = (per.w[1] * x);
u = u + (per.w[2] * y);
//u=u-per.w[0];
cout << signal(u) << endl;
}
return 0;
}
In your main(), re-enable the line you commented out. Alternatively, you could write it like this to make it more illuminating:
float u = 0.0f;
u += (per.w[0] * float (-1));
u += (per.w[1] * float (x));
u += (per.w[2] * float (y));
The thing is that you trained the perceptron with three inputs, the first being hard-wired to a "-1" (making the first weight w[0] act like a constant "bias"). Accordingly, in your training function, your u is the sum of all THREE of those weight-input product.
However, in the main() you posted, you omit w[0] completely, thus producing a wrong result.
I am writing a bit of code to animate a point using a sequence of positions. In order to have a decent result, I'd like to add some spline interpolation
to smoothen the transitions between positions. All the positions are separated by the same amount of time (let's say 500ms).
int delay = 500;
vector<Point> positions={ (0, 0) , (50, 20), (150, 100), (30, 120) };
Here is what i have done to make a linear interpolation (which seems to work properly), juste to give you an idea of what I'm looking for later on :
Point getPositionAt(int currentTime){
Point before, after, result;
int currentIndex = (currentTime / delay) % positions.size();
before = positions[currentIndex];
after = positions[(currentIndex + 1) % positions.size()];
// progress between [before] and [after]
double progress = fmod((((double)currentTime) / (double)delay), (double)positions.size()) - currentIndex;
result.x = before.x + (int)progress*(after.x - before.x);
result.y = before.y + (int)progress*(after.y - before.y);
return result;
}
So that was simple, but now what I would like to do is spline interpolation. Thanks !
I had to write a Bezier spline creation routine for an "entity" that was following a path in a game I am working on. I created a base class to handle a "SplineInterface" and the created two derived classes, one based on the classic spline technique (e.g. Sedgewick/Algorithms) an a second one based on Bezier Splines.
Here is the code. It is a single header file, with a few includes (most should be obvious):
#ifndef __SplineCommon__
#define __SplineCommon__
#include "CommonSTL.h"
#include "CommonProject.h"
#include "MathUtilities.h"
/* A Spline base class. */
class SplineBase
{
private:
vector<Vec2> _points;
bool _elimColinearPoints;
protected:
protected:
/* OVERRIDE THESE FUNCTIONS */
virtual void ResetDerived() = 0;
enum
{
NOM_SIZE = 32,
};
public:
SplineBase()
{
_points.reserve(NOM_SIZE);
_elimColinearPoints = true;
}
const vector<Vec2>& GetPoints() { return _points; }
bool GetElimColinearPoints() { return _elimColinearPoints; }
void SetElimColinearPoints(bool elim) { _elimColinearPoints = elim; }
/* OVERRIDE THESE FUNCTIONS */
virtual Vec2 Eval(int seg, double t) = 0;
virtual bool ComputeSpline() = 0;
virtual void DumpDerived() {}
/* Clear out all the data.
*/
void Reset()
{
_points.clear();
ResetDerived();
}
void AddPoint(const Vec2& pt)
{
// If this new point is colinear with the two previous points,
// pop off the last point and add this one instead.
if(_elimColinearPoints && _points.size() > 2)
{
int N = _points.size()-1;
Vec2 p0 = _points[N-1] - _points[N-2];
Vec2 p1 = _points[N] - _points[N-1];
Vec2 p2 = pt - _points[N];
// We test for colinearity by comparing the slopes
// of the two lines. If the slopes are the same,
// we assume colinearity.
float32 delta = (p2.y-p1.y)*(p1.x-p0.x)-(p1.y-p0.y)*(p2.x-p1.x);
if(MathUtilities::IsNearZero(delta))
{
_points.pop_back();
}
}
_points.push_back(pt);
}
void Dump(int segments = 5)
{
assert(segments > 1);
cout << "Original Points (" << _points.size() << ")" << endl;
cout << "-----------------------------" << endl;
for(int idx = 0; idx < _points.size(); ++idx)
{
cout << "[" << idx << "]" << " " << _points[idx] << endl;
}
cout << "-----------------------------" << endl;
DumpDerived();
cout << "-----------------------------" << endl;
cout << "Evaluating Spline at " << segments << " points." << endl;
for(int idx = 0; idx < _points.size()-1; idx++)
{
cout << "---------- " << "From " << _points[idx] << " to " << _points[idx+1] << "." << endl;
for(int tIdx = 0; tIdx < segments+1; ++tIdx)
{
double t = tIdx*1.0/segments;
cout << "[" << tIdx << "]" << " ";
cout << "[" << t*100 << "%]" << " ";
cout << " --> " << Eval(idx,t);
cout << endl;
}
}
}
};
class ClassicSpline : public SplineBase
{
private:
/* The system of linear equations found by solving
* for the 3 order spline polynomial is given by:
* A*x = b. The "x" is represented by _xCol and the
* "b" is represented by _bCol in the code.
*
* The "A" is formulated with diagonal elements (_diagElems) and
* symmetric off-diagonal elements (_offDiagElemns). The
* general structure (for six points) looks like:
*
*
* | d1 u1 0 0 0 | | p1 | | w1 |
* | u1 d2 u2 0 0 | | p2 | | w2 |
* | 0 u2 d3 u3 0 | * | p3 | = | w3 |
* | 0 0 u3 d4 u4 | | p4 | | w4 |
* | 0 0 0 u4 d5 | | p5 | | w5 |
*
*
* The general derivation for this can be found
* in Robert Sedgewick's "Algorithms in C++".
*
*/
vector<double> _xCol;
vector<double> _bCol;
vector<double> _diagElems;
vector<double> _offDiagElems;
public:
ClassicSpline()
{
_xCol.reserve(NOM_SIZE);
_bCol.reserve(NOM_SIZE);
_diagElems.reserve(NOM_SIZE);
_offDiagElems.reserve(NOM_SIZE);
}
/* Evaluate the spline for the ith segment
* for parameter. The value of parameter t must
* be between 0 and 1.
*/
inline virtual Vec2 Eval(int seg, double t)
{
const vector<Vec2>& points = GetPoints();
assert(t >= 0);
assert(t <= 1.0);
assert(seg >= 0);
assert(seg < (points.size()-1));
const double ONE_OVER_SIX = 1.0/6.0;
double oneMinust = 1.0 - t;
double t3Minust = t*t*t-t;
double oneMinust3minust = oneMinust*oneMinust*oneMinust-oneMinust;
double deltaX = points[seg+1].x - points[seg].x;
double yValue = t * points[seg + 1].y +
oneMinust*points[seg].y +
ONE_OVER_SIX*deltaX*deltaX*(t3Minust*_xCol[seg+1] - oneMinust3minust*_xCol[seg]);
double xValue = t*(points[seg+1].x-points[seg].x) + points[seg].x;
return Vec2(xValue,yValue);
}
/* Clear out all the data.
*/
virtual void ResetDerived()
{
_diagElems.clear();
_bCol.clear();
_xCol.clear();
_offDiagElems.clear();
}
virtual bool ComputeSpline()
{
const vector<Vec2>& p = GetPoints();
_bCol.resize(p.size());
_xCol.resize(p.size());
_diagElems.resize(p.size());
for(int idx = 1; idx < p.size(); ++idx)
{
_diagElems[idx] = 2*(p[idx+1].x-p[idx-1].x);
}
for(int idx = 0; idx < p.size(); ++idx)
{
_offDiagElems[idx] = p[idx+1].x - p[idx].x;
}
for(int idx = 1; idx < p.size(); ++idx)
{
_bCol[idx] = 6.0*((p[idx+1].y-p[idx].y)/_offDiagElems[idx] -
(p[idx].y-p[idx-1].y)/_offDiagElems[idx-1]);
}
_xCol[0] = 0.0;
_xCol[p.size()-1] = 0.0;
for(int idx = 1; idx < p.size()-1; ++idx)
{
_bCol[idx+1] = _bCol[idx+1] - _bCol[idx]*_offDiagElems[idx]/_diagElems[idx];
_diagElems[idx+1] = _diagElems[idx+1] - _offDiagElems[idx]*_offDiagElems[idx]/_diagElems[idx];
}
for(int idx = (int)p.size()-2; idx > 0; --idx)
{
_xCol[idx] = (_bCol[idx] - _offDiagElems[idx]*_xCol[idx+1])/_diagElems[idx];
}
return true;
}
};
/* Bezier Spline Implementation
* Based on this article:
* http://www.particleincell.com/blog/2012/bezier-splines/
*/
class BezierSpine : public SplineBase
{
private:
vector<Vec2> _p1Points;
vector<Vec2> _p2Points;
public:
BezierSpine()
{
_p1Points.reserve(NOM_SIZE);
_p2Points.reserve(NOM_SIZE);
}
/* Evaluate the spline for the ith segment
* for parameter. The value of parameter t must
* be between 0 and 1.
*/
inline virtual Vec2 Eval(int seg, double t)
{
assert(seg < _p1Points.size());
assert(seg < _p2Points.size());
double omt = 1.0 - t;
Vec2 p0 = GetPoints()[seg];
Vec2 p1 = _p1Points[seg];
Vec2 p2 = _p2Points[seg];
Vec2 p3 = GetPoints()[seg+1];
double xVal = omt*omt*omt*p0.x + 3*omt*omt*t*p1.x +3*omt*t*t*p2.x+t*t*t*p3.x;
double yVal = omt*omt*omt*p0.y + 3*omt*omt*t*p1.y +3*omt*t*t*p2.y+t*t*t*p3.y;
return Vec2(xVal,yVal);
}
/* Clear out all the data.
*/
virtual void ResetDerived()
{
_p1Points.clear();
_p2Points.clear();
}
virtual bool ComputeSpline()
{
const vector<Vec2>& p = GetPoints();
int N = (int)p.size()-1;
_p1Points.resize(N);
_p2Points.resize(N);
if(N == 0)
return false;
if(N == 1)
{ // Only 2 points...just create a straight line.
// Constraint: 3*P1 = 2*P0 + P3
_p1Points[0] = (2.0/3.0*p[0] + 1.0/3.0*p[1]);
// Constraint: P2 = 2*P1 - P0
_p2Points[0] = 2.0*_p1Points[0] - p[0];
return true;
}
/*rhs vector*/
vector<Vec2> a(N);
vector<Vec2> b(N);
vector<Vec2> c(N);
vector<Vec2> r(N);
/*left most segment*/
a[0].x = 0;
b[0].x = 2;
c[0].x = 1;
r[0].x = p[0].x+2*p[1].x;
a[0].y = 0;
b[0].y = 2;
c[0].y = 1;
r[0].y = p[0].y+2*p[1].y;
/*internal segments*/
for (int i = 1; i < N - 1; i++)
{
a[i].x=1;
b[i].x=4;
c[i].x=1;
r[i].x = 4 * p[i].x + 2 * p[i+1].x;
a[i].y=1;
b[i].y=4;
c[i].y=1;
r[i].y = 4 * p[i].y + 2 * p[i+1].y;
}
/*right segment*/
a[N-1].x = 2;
b[N-1].x = 7;
c[N-1].x = 0;
r[N-1].x = 8*p[N-1].x+p[N].x;
a[N-1].y = 2;
b[N-1].y = 7;
c[N-1].y = 0;
r[N-1].y = 8*p[N-1].y+p[N].y;
/*solves Ax=b with the Thomas algorithm (from Wikipedia)*/
for (int i = 1; i < N; i++)
{
double m;
m = a[i].x/b[i-1].x;
b[i].x = b[i].x - m * c[i - 1].x;
r[i].x = r[i].x - m * r[i-1].x;
m = a[i].y/b[i-1].y;
b[i].y = b[i].y - m * c[i - 1].y;
r[i].y = r[i].y - m * r[i-1].y;
}
_p1Points[N-1].x = r[N-1].x/b[N-1].x;
_p1Points[N-1].y = r[N-1].y/b[N-1].y;
for (int i = N - 2; i >= 0; --i)
{
_p1Points[i].x = (r[i].x - c[i].x * _p1Points[i+1].x) / b[i].x;
_p1Points[i].y = (r[i].y - c[i].y * _p1Points[i+1].y) / b[i].y;
}
/*we have p1, now compute p2*/
for (int i=0;i<N-1;i++)
{
_p2Points[i].x=2*p[i+1].x-_p1Points[i+1].x;
_p2Points[i].y=2*p[i+1].y-_p1Points[i+1].y;
}
_p2Points[N-1].x = 0.5 * (p[N].x+_p1Points[N-1].x);
_p2Points[N-1].y = 0.5 * (p[N].y+_p1Points[N-1].y);
return true;
}
virtual void DumpDerived()
{
cout << " Control Points " << endl;
for(int idx = 0; idx < _p1Points.size(); idx++)
{
cout << "[" << idx << "] ";
cout << "P1: " << _p1Points[idx];
cout << " ";
cout << "P2: " << _p2Points[idx];
cout << endl;
}
}
};
#endif /* defined(__SplineCommon__) */
Some Notes
The classic spline will crash if you give it a vertical set of
points. That is why I created the Bezier...I have lots of vertical
lines/paths to follow.
The base class has an option to remove colinear points as you add
them. This uses a simple slope comparison of two lines to figure out
if they are on the same line. You don't have to do this, but for
long paths that are straight lines, it cuts down on cycles. When you
do a lot of pathfinding on a regular-spaced graph, you tend to get a
lot of continuous segments.
Here is an example of using the Bezier Spline:
/* Smooth the points on the path so that turns look
* more natural. We'll only smooth the first few
* points. Most of the time, the full path will not
* be executed anyway...why waste cycles.
*/
void SmoothPath(vector<Vec2>& path, int32 divisions)
{
const int SMOOTH_POINTS = 6;
BezierSpine spline;
if(path.size() < 2)
return;
// Cache off the first point. If the first point is removed,
// the we occasionally run into problems if the collision detection
// says the first node is occupied but the splined point is too
// close, so the FSM "spins" trying to find a sensor cell that is
// not occupied.
// Vec2 firstPoint = path.back();
// path.pop_back();
// Grab the points.
for(int idx = 0; idx < SMOOTH_POINTS && path.size() > 0; idx++)
{
spline.AddPoint(path.back());
path.pop_back();
}
// Smooth them.
spline.ComputeSpline();
// Push them back in.
for(int idx = spline.GetPoints().size()-2; idx >= 0; --idx)
{
for(int division = divisions-1; division >= 0; --division)
{
double t = division*1.0/divisions;
path.push_back(spline.Eval(idx, t));
}
}
// Push back in the original first point.
// path.push_back(firstPoint);
}
Notes
While the whole path could be smoothed, in this application, since
the path was changing every so often, it was better to just smooth
the first points and then connect it up.
The points are loaded in "reverse" order into the path vector. This
may or may not save cycles (I've slept since then).
This code is part of a much larger code base, but you can download it all on github and see a blog entry about it here.
You can look at this in action in this video.
Was this helpful?