Edit
I am now using odeint. It is fairly simple to use and less memory hungry than my brute force algorithm implementation.
Check my questions here-->http://stackoverflow.com/questions/12060111/using-odeint-function-definition
and here-->http://stackoverflow.com/questions/12150160/odeint-streaming-observer-and-related-questions
I am trying to implement a numerical method (Explicit Euler) to solve a set of three coupled differential equations. I have worked with C before, but that was a very long time ago (effectively forgotten everything). I have a pretty good idea on what I want my program to do and also have a rough algorithm.
I am interested in using C++ for this task (picked up Stroustroup's Programming: Principles and Practice using C++). My question is, should I go with arrays or vectors? Vectors seem easier to handle, but I was unable to find how you can make a function return a vector? Is it possible for a function to return more than one vector? At this point, I am familiarizing myself with the C++ syntax.
I basically need my function to return many arrays. I realize that it is not possible in C++, so I can also work with some nested structure such as {{arr1},{arr2},{arr3}..}. Please bear with me as I am a noob and come from programming in Mathematica.
Thanks!
If you want to use C++ for integrating ordinary differential equations and you don't want to reinvent the wheel use odeint. This lib is on its way of becoming the de facto standard for solving ODEs in C++. The code is very flexible and highly optimized and can compete with any handcrafted C-code (and Fortran anyway).
Commenting on you question on returning vectors or arrays: Functions can return vectors and arrays if the are wrapped in a class (like std::array). But this is not recommended, since you make many unnecessary copies (incl. calling the constructors and destructors every time).
I assume you want to put your function equation into a c++ function and let it return the resulting vector. For this task it's much better if you pass a reference to a vector to the function and let the function fill this vector. This is also the way how odeint has implemented this.
This link might help you, but for ordinary differential equations :
http://www.codeproject.com/KB/recipes/odeint.aspx
To make the program do what you wan you could take a look at this code, It may be get you started.
I found it very useful, and tested it against mathematica solution, and it is ok.
for more information go here
/*
A simple code for option valuation using the explicit forward Euler method
for the class Derivative Securities, fall 2010
http://www.math.nyu.edu/faculty/goodman/teaching/DerivSec10/index.html
Written for this purpose by Jonathan Goodman, instructor.
Assignment 8
*/
#include <iostream>
#include <fstream>
#include <math.h>
#define NSPOTS 100 /* The number of spot prices computed */
/* A program to compute a simple binomial tree price for a European style put option */
using namespace std;
// The pricer, main is at the bottom of the file
void FE( // Solve a pricing PDE using the forward Euler method
double T, double sigma, double r, double K, // The standard option parameters
double Smin, double Smax, // The min and max prices to return
int nPrices, // The number of prices to compute between Smin and Smax,
// Determines the accuracy and the cost of the computation
double prices[], // An array of option prices to be returned.
double intrinsic[], // The intrinsic value at the same prices
double spots[], // The corresponding spot prices, computed here for convenience.
// Both arrays must be allocated in the calling procedure
double *SEarly ) { // The early exercise boundary
// Setup for the computation, compute computational parameters and allocate the memory
double xMin = log(Smin); // Work in the log variable
double xMax = log(Smax);
double dx = ( xMax - xMin )/ ( (double( nPrices - 1 ) ) ); // The number of gaps is one less than the number of prices
double CFL = .8; // The time step ratio
double dt = CFL*dx*dx/sigma; // The forward Euler time step size, to be adjusted slightly
int nTimeSteps = (int) (T/dt); // The number of time steps, rounded down to the nearest integer
nTimeSteps++; // Now rounded up
dt = T / ( (double) nTimeSteps ); // Adjust the time step to land precisely at T in n steps.
int nx = nPrices + 2*nTimeSteps; // The number of prices at the final time, growing by 2 ...
// ... each time step
xMin = xMin - nTimeSteps*dx; // The x values now start here
double *fOld; // The values of the pricing function at the old time
fOld = new double [nx]; // Allocated using old style C++ for simplicity
double *fNew; // The values of the pricing function at the new time
fNew = new double [nx];
double *V; // The intrinsic value = the final condition
V = new double [nx];
// Get the final conditions and the early exercise values
double x; // The log variable
double S; // A stock price = exp(x)
int j;
for ( j = 0; j < nx; j++ ) {
x = xMin + j*dx;
S = exp(x);
if ( S < K ) V[j] = K-S; // A put struck at K
else V[j] = 0;
fOld[j] = V[j]; // The final condition is the intrinsic value
}
// The time stepping loop
double alpha, beta, gamma; // The coefficients in the finite difference formula
alpha = beta = gamma = .333333333333; // XXXXXXXXXXXXXXXXXXXXXXXXXXX
int jMin = 1; // The smallest and largest j ...
int jMax = nx - 1; // ... for which f is updated. Skip 1 on each end the first time.
int jEarly ; // The last index of early exercise
for ( int k = nTimeSteps; k > 0; k-- ) { // This is, after all, a backward equation
jEarly = 0; // re-initialize the early exercise pointer
for ( j = jMin; j < jMax; j++ ) { // Compute the new values
x = xMin + j*dx; // In case the coefficients depend on S
S = exp(x);
fNew[j] = alpha*fOld[j-1] + beta*fOld[j] + gamma*fOld[j+1]; // Compute the continuation value
if ( fNew[j] < V[j] ) {
fNew[j] = V[j]; // Take the max with the intrinsic value
jEarly = j; // and record the largest early exercise index
}
}
for ( j = jMin; j < jMax; j++ ) // Copy the new values back into the old array
fOld[j] = fNew[j];
jMin++; // Move the boundaries in by one
jMax--;
}
// Copy the computed solution into the desired place
jMin--; // The last decrement and increment were mistakes
jMax++;
int i = 0; // The index into the output array
for ( j = jMin; j < jMax; j++ ) { // Now the range of j should match the output array
x = xMin + j*dx;
S = exp(x);
prices[i] = fOld[j];
intrinsic[i] = V[j];
spots[i++] = S; // Increment i after all copy operations
}
double xEarly = xMin + jEarly*dx;
*SEarly = exp(xEarly); // Pass back the computed early exercise boundary
delete fNew; // Be a good citizen and free the memory when you're done.
delete fOld;
delete V;
return;
}
int main() {
cout << "Hello " << endl;
ofstream csvFile; // The file for output, will be csv format for Excel.
csvFile.open ("PutPrice.csv");
double sigma = .3;
double r = .003;
double T = .5;
double K = 100;
double Smin = 60;
double Smax = 180;
double prices[NSPOTS];
double intrinsic[NSPOTS];
double spots[ NSPOTS];
double SEarly;
FE( T, sigma, r, K, Smin, Smax, NSPOTS, prices, intrinsic, spots, &SEarly );
for ( int j = 0; j < NSPOTS; j++ ) { // Write out the spot prices for plotting
csvFile << spots[j];
if ( j < (NSPOTS - 1) ) csvFile << ", "; // Don't put a comma after the last value
}
csvFile << endl;
for ( int j = 0; j < NSPOTS; j++ ) { // Write out the intrinsic prices for plotting
csvFile << intrinsic[j];
if ( j < (NSPOTS - 1) ) csvFile << ", "; // Don't put a comma after the last value
}
csvFile << endl;
for ( int j = 0; j < NSPOTS; j++ ) { // Write out the computed option prices
csvFile << prices[j];
if ( j < (NSPOTS - 1) ) csvFile << ", ";
}
csvFile << endl;
csvFile << "Critical price," << SEarly << endl;
csvFile << "T ," << T << endl;
csvFile << "r ," << r << endl;
csvFile << "sigma ," << sigma << endl;
csvFile << "strike ," << K << endl;
return 0 ;
}
Related
I've been doing a really really simple finite difference code that solves the 1D convection equation.
It seems to work pretty fine but if I increase the size of the arrays that I'm using I get a segmentation fault error. This happens when I reduce the timestep or if I increase the time interval.
The code is
#include <math.h>
#include <iostream>
#include <fstream>
#include <stdio.h>
#include <cmath>
using namespace std;
int main(){
double xi = 0.0;
double xf = 10.0;
double ti = 0.0;
double tf = 1.0;
Time interval, if it is equal to 1 the code works fine.
double x,t;
double dt = 0.1;
double dx = 0.1;
int nstep_x = (xf - xi)/dx;
int nstep_t = (tf - ti)/dt;
double f[nstep_x][nstep_t];
double ex[nstep_x][nstep_t];
// Parameters
const double v = 0.05;
const double D = 0.0001;
const double pi = 3.141592654;
ofstream salida;
salida.open("out");
for (int i = 0 ; i <= nstep_x; i++){
x = xi + dx*i;
f[i][0] = 0.5*sin(pi*x); //Initial conditions
salida << x << " " << 0 << " " << f[i][0] << endl;
}
salida << endl;
for (int n = 0; n <= nstep_t ; n++){
t = ti + n*dt;
for (int i = 1; i <= nstep_x; i++){
x = xi + dx*i;
f[i][n+1] = f[i][n] - ((v*dt)/(2*dx))*(f[i+1][n] - f[i-1][n]); //CONV|SOC
ex[i][n] = 0.5*sin(pi*x - v*t);
salida << x << " " << t << " " << ex[i][n] << " " << f[i][n] << endl;
}
salida << endl;
salida << endl;
}
}
I think that is not a problem of going out of the array bounds in the loops because the code works for "small" arrays.
I guess that I must be doing something wrong with the array handling but I can't find the error.
You have several issues with your code. One is that you're using variable length arrays (VLA's) which are not standard C++.
double f[nstep_x][nstep_t];
double ex[nstep_x][nstep_t];
This is not valid C++, as arrays must have its size known at compile-time, not run time.
The quick solution is to use std::vector<std::vector<double>>:
#include <vector>
//...
std::vector<std::vector<double>> f(nstep_x, std::vector<double>(nstep_t));
std::vector<std::vector<double>> ex = f; // use copy constructor to easily create a copy
The above code basically does what your originally did, but has several advantages:
1) The code is now standard C++, as it uses a standard C++ container class, std::vector.
2) You won't get into stack space issues if nstep_x and/or nstep_t are large values since std::vector gets the memory to store its items from the heap.
3) You can check boundary conditions by using std::vector::at() if it is suspected that you are accessing the vector out-of-bounds. You don't have this test if you're using VLA's (or just arrays in general).
It is item 3) that becomes important in attempting to find the errors.
If we take your code, change it to using std::vector, we see that there is a problem with "small arrays", going against what you thought was not an issue. If we look at this code:
for (int i = 0 ; i <= nstep_x; i++)
{
x = xi + dx*i;
f.at(i).at(0) = 0.5*sin(pi*x); // exception is thrown here
}
We see that there is an out-of-bounds condition. This was detected by using vector::at() instead of [ ] to access the elements in the vector. A std::out_of_range exception is thrown at the line where f[i][0] is being assigned to.
Here is a live example showing this error.
How do you fix this? Simply don't go out of bounds by changing the loop:
for (int i = 0 ; i < nstep_x; i++)
You also have boundary condition issues in your other loops:
for (int n = 0; n <= nstep_t ; n++)
{
t = ti + n*dt;
for (int i = 1; i <= nstep_x; i++)
{
x = xi + dx*i;
f.at(i).at(n+1) = f[i][n] - ((v*dt)/(2*dx))*(f.at(i+1).at(n) - f[i-1][n]);
ex.at(i)(n) = 0.5*sin(pi*x - v*t);
}
}
You will see using at() that you are accessing the f and ex vectors out-of-bounds, and thus can diagnose the issue correctly (as the other answers have done).
gdb would help to see where it actually crashes but:
f[i+1][n] and i grows up to nstep_x, but f is allocated as f[nstep_x][nstep_t],
so it seems like you'd be accessing f[nstep_x+1][n], but the maximum you can is f[nstep_x-1][n].
As noted in the comments, the reason is not the array size, but the for loops
for (int i = 0 ; i <= nstep_x; i++) {
// ...
f[i][0] = 0.5*sin(pi*x);
}
This is a classic one off error, going one beyond the end of the array. The correct way is
for (int i = 0 ; i < nstep_x; i++) {
// ...
}
Note < vs <=.
for (int n = 0; n <= nstep_t ; n++) {
for (int i = 1; i <= nstep_x; i++) {
// ...
f[i][n+1] = f[i][n] - ((v*dt)/(2*dx))*(f[i+1][n] - f[i-1][n]);
}
}
Here too, you have <= instead of <. Additionally you access indexes at i + 1 and n + 1 respectively, which means, you are not one but two steps over the end of the array.
When calculating the second time-step, you're referring to f at x=xi and t=ti+dt which wasn't calculated in the first time-step, since i runs from 1. There is a similar problem at the other boundary.
You need to specify the spatial boundary conditions for x=xi and x=xf for all t as well as fixing the off-by-one errors noted in the other answers.
To clarify, the convection equation requires boundary conditions to be specified for f(x=xi,t) and f(x=xf, t). This is typically either a constant or a prescribed flow rate in the case of an 'insulated' boundary, but other types exist.
I have the following code.
Essentially it is creating N random normal variables, and running through an equation M times for a simulation.
The output should be an NxM matrix of data, however the only way I could do the calculation has the output as MxN. ie each M run should be a column, not a row.
I have attempted in vain to follow some of the other suggestions that have been posted on previous similar topics.
Code:
#include <iostream>
#include <time.h>
#include <random>
int main()
{
double T = 1; // End time period for simulation
int N = 4; // Number of time steps
int M = 2; // Number of simulations
double x0 = 1.00; // Starting x value
double mu = 0.00; // mu(x,t) value
double sig = 1.00; // sigma(x,t) value
double dt = T/N;
double sqrt_dt = sqrt(dt);
double** SDE_X = new double*[M]; // SDE Matrix setup
// Random Number generation setup
double RAND_N;
srand ((unsigned int) time(NULL)); // Generator loop reset
std::default_random_engine generator (rand());
std::normal_distribution<double> distribution (0.0,1.0); // Mean = 0.0, Variance = 1.0 ie Normal
for (int i = 0; i < M; i++)
{
SDE_X[i] = new double[N];
for (int j=0; j < N; j++)
{
RAND_N = distribution(generator);
SDE_X[i][0] = x0;
SDE_X[i][j+1] = SDE_X[i][j] + mu * dt + sig * RAND_N * sqrt_dt; // The SDE we wish to plot the path for
std::cout << SDE_X[i][j] << " ";
}
std::cout << std::endl;
}
std::cout << std::endl;
std::cout << " The simulation is complete!!" << std::endl;
std::cout << std::endl;
system("pause");
return 0;
}
Well why can't you just create the transpose of your SDE_X matrix then? Isn't that what you want to get?
Keep in mind, that presentation has nothing to do with implementation. Whether to access columns or rows is your decision. So you want an implementation of it transposed. Then quick and dirty create your matrix first, and then create your number series. Change i and j, and N and M.
I said quick and dirty, because the program at all is bad:
why don't you just keep it simple and use a better data structure for your matrix? If you know the size: compile-time array or dynamic vectors at runtime? Maybe there are some nicer implementation for 2d array.
There is a bug I think: you create N doubles and access index 0 to N inclusive.
In every iteration you set index 0 to x0 what is also needless.
I would change your code a bit make more clear:
create your matrix at first
initialize the first value of the matrix
provide an algorithm function calculating a target cell taking the matrix and the parameters.
Go through each cell and invoke your function for that cell
Thank you all for your input. I was able to implement my code and have it displayed as needed.
I added a second for loop to rearrange the matrix rows and columns.
Please feel free to let me know if you think there is anyway I can improve it.
#include <iostream>
#include <time.h>
#include <random>
#include <vector>
int main()
{
double T = 1; // End time period for simulation
int N = 3; // Number of time steps
int M = 2; // Number of simulations
int X = 100; // Max number of matrix columns
int Y = 100; // Max number of matrix rows
double x0 = 1.00; // Starting x value
double mu = 0.00; // mu(x,t) value
double sig = 1.00; // sigma(x,t) value
double dt = T/N;
double sqrt_dt = sqrt(dt);
std::vector<std::vector<double>> SDE_X((M*N), std::vector<double>((M*N))); // SDE Matrix setup
// Random Number generation setup
double RAND_N;
srand ((unsigned int) time(NULL)); // Generator loop reset
std::default_random_engine generator (rand());
std::normal_distribution<double> distribution (0.0,1.0); // Mean = 0.0, Variance = 1.0 ie Normal
for (int i = 0; i <= M; i++)
{
SDE_X[i][0] = x0;
for (int j=0; j <= N; j++)
{
RAND_N = distribution(generator);
SDE_X[i][j+1] = SDE_X[i][j] + mu * dt + sig * RAND_N * sqrt_dt; // The SDE we wish to plot the path for
}
}
for (int j = 0; j <= N; j++)
{
for (int i = 0; i <=M; i++)
{
std::cout << SDE_X[i][j] << ", ";
}
std::cout << std::endl;
}
std::cout << std::endl;
std::cout << " The simulation is complete!!" << std::endl;
std::cout << std::endl;
system("pause");
return 0;
}
I was trying to prove a point with OpenMP compared to MPICH, and I cooked up the following example to demonstrate how easy it was to do some high performance in OpenMP.
The Gauss-Seidel iteration is split into two separate runs, such that in each sweep every operation can be performed in any order, and there should be no dependency between each task. So in theory each processor should never have to wait for another process to perform any kind of synchronization.
The problem I am encountering, is that I, independent of problem size, find there is only a weak speed-up of 2 processors and with more than 2 processors it might even be slower.
Many other linear paralleled routine I can obtain very good scaling, but this one is tricky.
My fear is that I am unable to "explain" to the compiler that operation that I perform on the array, is thread-safe, such that it is unable to be really effective.
See the example below.
Anyone has any clue on how to make this more effective with OpenMP?
void redBlackSmooth(std::vector<double> const & b,
std::vector<double> & x,
double h)
{
// Setup relevant constants.
double const invh2 = 1.0/(h*h);
double const h2 = (h*h);
int const N = static_cast<int>(x.size());
double sigma = 0;
// Setup some boundary conditions.
x[0] = 0.0;
x[N-1] = 0.0;
// Red sweep.
#pragma omp parallel for shared(b, x) private(sigma)
for (int i = 1; i < N-1; i+=2)
{
sigma = -invh2*(x[i-1] + x[i+1]);
x[i] = (h2/2.0)*(b[i] - sigma);
}
// Black sweep.
#pragma omp parallel for shared(b, x) private(sigma)
for (int i = 2; i < N-1; i+=2)
{
sigma = -invh2*(x[i-1] + x[i+1]);
x[i] = (h2/2.0)*(b[i] - sigma);
}
}
Addition:
I have now also tried with a raw pointer implementation and it has the same behavior as using STL container, so it can be ruled out that it is some pseudo-critical behavior comming from STL.
First of all, make sure that the x vector is aligned to cache boundaries. I did some test, and I get something like a 100% improvement with your code on my machine (core duo) if I force the alignment of memory:
double * x;
const size_t CACHE_LINE_SIZE = 256;
posix_memalign( reinterpret_cast<void**>(&x), CACHE_LINE_SIZE, sizeof(double) * N);
Second, you can try to assign more computation to each thread (in this way you can keep cache-lines separated), but I suspect that openmp already does something like this under the hood, so it may be worthless with large N.
In my case this implementation is much faster when x is not cache-aligned.
const int workGroupSize = CACHE_LINE_SIZE / sizeof(double);
assert(N % workGroupSize == 0); //Need to tweak the code a bit to let it work with any N
const int workgroups = N / workGroupSize;
int j, base , k, i;
#pragma omp parallel for shared(b, x) private(sigma, j, base, k, i)
for ( j = 0; j < workgroups; j++ ) {
base = j * workGroupSize;
for (int k = 0; k < workGroupSize; k+=2)
{
i = base + k + (redSweep ? 1 : 0);
if ( i == 0 || i+1 == N) continue;
sigma = -invh2* ( x[i-1] + x[i+1] );
x[i] = ( h2/2.0 ) * ( b[i] - sigma );
}
}
In conclusion, you definitely have a problem of cache-fighting, but given the way openmp works (sadly I am not familiar with it) it should be enough to work with properly allocated buffers.
I think the main problem is about type of array structure you are using. Lets try comparing results with vectors and arrays. (Arrays = c-arrays using new operator).
Vector and array sizes are N = 10000000. I force the smoothing function to repeat in order to maintain runtime > 0.1secs.
Vector Time: 0.121007 Repeat: 1 MLUPS: 82.6399
Array Time: 0.164009 Repeat: 2 MLUPS: 121.945
MLUPS = ((N-2)*repeat/runtime)/1000000 (Million Lattice Points Update per second)
MFLOPS are misleading when it comes to grid calculation. A few changes in the basic equation can lead to consider high performance for the same runtime.
The modified code:
double my_redBlackSmooth(double *b, double* x, double h, int N)
{
// Setup relevant constants.
double const invh2 = 1.0/(h*h);
double const h2 = (h*h);
double sigma = 0;
// Setup some boundary conditions.
x[0] = 0.0;
x[N-1] = 0.0;
double runtime(0.0), wcs, wce;
int repeat = 1;
timing(&wcs);
for(; runtime < 0.1; repeat*=2)
{
for(int r = 0; r < repeat; ++r)
{
// Red sweep.
#pragma omp parallel for shared(b, x) private(sigma)
for (int i = 1; i < N-1; i+=2)
{
sigma = -invh2*(x[i-1] + x[i+1]);
x[i] = (h2*0.5)*(b[i] - sigma);
}
// Black sweep.
#pragma omp parallel for shared(b, x) private(sigma)
for (int i = 2; i < N-1; i+=2)
{
sigma = -invh2*(x[i-1] + x[i+1]);
x[i] = (h2*0.5)*(b[i] - sigma);
}
// cout << "In Array: " << r << endl;
}
if(x[0] != 0) dummy(x[0]);
timing(&wce);
runtime = (wce-wcs);
}
// cout << "Before division: " << repeat << endl;
repeat /= 2;
cout << "Array Time:\t" << runtime << "\t" << "Repeat:\t" << repeat
<< "\tMLUPS:\t" << ((N-2)*repeat/runtime)/1000000.0 << endl;
return runtime;
}
I didn't change anything in the code except than array type. For better cache access and blocking you should look into data alignment (_mm_malloc).
I'm fairly new to C++ and I'm attempting to learn how to use pointers. I have the following file that creates coordinates and then moves them in random directions using a random number generator.
The value sigmaf_point is inputted from a text file:
void methane_coords(double *&sigmaf_point)
double dummy_int = 1;
string dummystring;
string s;
ifstream Dfile;
std::stringstream out;
out << 1;
s = out.str() + ".TXT";
Dfile.open (s.c_str());
if (Dfile.fail())
{
return;
}
for (int i=0; i<dummy_int; i++)
{
Dfile >> sigmaf_point[i];
}
Which I then use in another function:
double initial_energy(double **coords_fluid, const double *box_size){
// Loop over all pairs of atoms and calculate the LJ energy
double total_energy = 0;
for (int i = 0; i <= n_atoms-1; i++)
{
sf1=sigmaf_point(coords_fluid[i][3]);
ef1=epsilonf_point(coords_fluid[i][3]);
// Energy fluid-fluid
for (int j = i+1; j <= n_atoms-1; j++)
{
sf2=sigmaf_point(coords_fluid[j][3]);
ef2=epsilonf_point(coords_fluid[j][3]);
double delta_x = coords_fluid[j][0] - coords_fluid[i][0];
double delta_y = coords_fluid[j][1] - coords_fluid[i][1];
double delta_z = coords_fluid[j][2] - coords_fluid[i][2];
// Apply periodic boundaries
delta_x = make_periodic(delta_x, box_size[0]);
delta_y = make_periodic(delta_y, box_size[1]);
delta_z = make_periodic(delta_z, box_size[2]);
// Calculate the LJ potential
s=(sf1+sf2)/2.0;
e=pow((ef1*ef2),0.5);
double r = pow((delta_x*delta_x) + (delta_y*delta_y) +
(delta_z*delta_z),0.5)/s;
double e_lj = 4*((1/pow(r,12.0))-(1/pow(r,6.0))/e);
total_energy = (total_energy + e_lj);
}
}
coords_fluid is created in the main file like so:
double **coords_fluid = new double*[5000];
Now the problem is with sf1=sigmaf_point(coords_fluid[i][3]);
I get the error "expression must have pointer to function type" for sigmaf_point. I'm a bit confused about this, I know it's about how I call the variable but can't seem to fix it.
Cheers
First of all: Rereference to pointers are completly useless since it a pointer is already a sort of reference.
So change double *& to double * or double &. It will be faster.
Besides I see that you're using sigmaf_point as a function and as an array.
Which one is it?
Could you give the declaration of sigmaf_point?
Assuming it's an array change
sf1 = sigmaf_point(coords_fluid[i][3]);
to
sf1 = sigmaf_point[coords_fluid[i][3]];
I am running some calculations in an external machine and at the end I get X, Y pairs. I want to apply linear regression and obtain A, B, and R2. In this machine I can not install anything (it runs Linux) and has basic stuff installed on it, python, bash (of course), etc.
I wonder what would be the best approach to use a script (python, bash, etc) or program (I can compile C and C++) that gives me the linear regression coefficients without the need to add external libraries (numpy, etc)
For a single, simple, known function (as in your case: a line) it is not hard to simply code a basic least square routine from scratch (but does require some attention to detail). It is a very common assignment in introductory numeric analysis classes.
So, look up least squares on wikipedia or mathworld or in a text book and go to town.
How about extracting the coeffs into a file, import to another machine and then use Excel/Matlab/whatever other program that does this for you?
Hi there this is my solution that I got from the Wikipedia article on best fit line.
#include <iostream>
#include <vector>
// Returns true if linear fit was calculated. False otherwise.
// Algorithm adapted from:
// https://en.wikipedia.org/wiki/Simple_linear_regression#Fitting_the_regression_line
template <typename PairIterator>
bool GetLinearFit(PairIterator begin_it,
PairIterator end_it,
double* out_slope,
double* out_yintercept) {
if (begin_it == end_it) {
return false;
}
size_t n = 0;
double x_avg = 0;
double y_avg = 0;
for (PairIterator it = begin_it; it != end_it; ++it) {
x_avg += it->first;
y_avg += it->second;
n++;
}
x_avg /= n;
y_avg /= n;
double numerator = 0;
double denominator = 0;
for (PairIterator it = begin_it; it != end_it; ++it) {
double x_variance = it->first - x_avg;
double y_variance = it->second - y_avg;
numerator += (x_variance * y_variance);
denominator += (x_variance * x_variance);
}
double slope = numerator / denominator;
double yintercept = y_avg - slope*x_avg;
*out_slope = slope;
*out_yintercept= yintercept ;
return true;
}
// Tests the output of GetLinearFit(...).
int main() {
std::vector<std::pair<int, int> > data;
for (int i = 0; i < 10; ++i) {
data.push_back(std::pair<int, int>(i+1, 2*i));
}
double slope = 0;
double y_intercept = 0;
GetLinearFit(data.begin(), data.end(), &slope, &y_intercept);
std::cout << "slope: " << slope << "\n";
std::cout << "y_intercept: " << y_intercept<< "\n";
return 0;
}