I am a beginner in c++. My focus of learning c++ is to do scientific computation. I want to use blitz++ library. I am trying to solve rk4 method but I am not getting the inner workings of the code(I know rk4 algorithm)
#include <blitz/array.h>
#include <iostream>
#include <stdlib.h>
#include <math.h>
using namespace blitz;
using namespace std;
# This will evaluate the slopes. say if dy/dx = y, rhs_eval will return y.
void rhs_eval(double x, Array<double, 1> y, Array<double, 1>& dydx)
{
dydx = y;
}
void rk4_fixed(double& x, Array<double, 1>& y, void (*rhs_eval)(double, Array<double, 1>, Array<double, 1>&), double h)
{
// Array y assumed to be of extent n, where n is no. of coupled equations
int n = y.extent(0);
// Declare local arrays
Array<double, 1> k1(n), k2(n), k3(n), k4(n), f(n), dydx(n);
// Zeroth intermediate step
(*rhs_eval) (x, y, dydx);
for (int j = 0; j < n; j++)
{
k1(j) = h * dydx(j);
f(j) = y(j) + k1(j) / 2.;
}
// First intermediate step
(*rhs_eval) (x + h / 2., f, dydx);
for (int j = 0; j < n; j++)
{
k2(j) = h * dydx(j);
f(j) = y(j) + k2(j) / 2.;
}
// Second intermediate step
(*rhs_eval) (x + h / 2., f, dydx);
for (int j = 0; j < n; j++)
{
k3(j) = h * dydx(j);
f(j) = y(j) + k3(j);
}
// Third intermediate step
(*rhs_eval) (x + h, f, dydx);
for (int j = 0; j < n; j++)
{
k4(j) = h * dydx(j);
}
// Actual step
for (int j = 0; j < n; j++)
{
y(j) += k1(j) / 6. + k2(j) / 3. + k3(j) / 3. + k4(j) / 6.;
}
x += h;
return; # goes back to function. evaluate y at x+h without returning anything
}
int main()
{
cout << y <<endl; # this will not work. The scope of y is limited to rk4_fixed
}
Here are my questions?
In rhs_eval x,y are just values. But dydx is pointer. So rhs_eval's output value will be assigned to y. No need to return anything. Am i correct?
What does int n = y.extent(0) do? In comment n is saying it's the number of coupled equation. What is the meaning of extent(0). what does extent do? what is that '0'? Is it the size of first element?
How do I print the value of 'y'? what is the format? I want to get the value of y from rk4 by calling it from main. then print it.
I compiled blitz++ using MSVS 2019 with cmake using these instruction--
Instruction
I got the code from here- only the function is given
Yes, change also y to be passed by reference. Pointer is with * or a pointer template, reference is with &.
Your vector has 1 dimension or extend. In general Array<T,n> is a tensor of order n, for n=2 a matrix. .extend(0) is the size of the first dimension, with a zero-based index.
This is complicated and not well documented. I mean the facilities provided by the Blitz library. You can just manually print the components. For some reason my version produces a memory error if the first print command is commented out.
#include <blitz/array.h>
#include <iostream>
#include <cstdlib>
//#include <cmath>
using namespace blitz;
using namespace std;
/* This will evaluate the slopes. say if dy/dx = y, rhs_eval will return y. */
const double sig = 10; const double rho = 28; const double bet = 8.0/3;
void lorenz(double x, Array<double, 1> & y, Array<double, 1> & dydx)
{
/* y vector = x,y,z in components */
/*
dydx[0] = sig * (y[1] - y[0]);
dydx[1] = rho * y[0] - y[1] - y[0] * y[2];
dydx[2] = y[0] * y[1] - bet * y[2];
*/
/* use the comma operator */
dydx = sig * (y[1] - y[0]), rho * y[0] - y[1] - y[0] * y[2], y[0] * y[1] - bet * y[2];
}
void rk4_fixed(double& x, Array<double, 1> & y, void (*rhs_eval)(double, Array<double, 1>&, Array<double, 1>&), double h)
{
// Array y assumed to be of extent n, where n is no. of coupled equations
int n = y.extent(0);
// Declare local arrays
Array<double, 1> k1(n), k2(n), k3(n), k4(n), f(n), dydx(n);
// Zeroth intermediate step
rhs_eval (x, y, dydx);
k1 = h * dydx; f=y+0.5*k1;
// First intermediate step
rhs_eval(x + 0.5*h, f, dydx);
k2 = h * dydx; f = y+0.5*k2;
// Second intermediate step
rhs_eval (x + 0.5*h, f, dydx);
k3 = h * dydx; f=y+k3;
// Third intermediate step
rhs_eval (x + h, f, dydx);
k4 = h * dydx;
// Actual step
y += k1 / 6. + k2 / 3. + k3 / 3. + k4 / 6.;
x += h;
return; //# goes back to function. evaluate y at x+h without returning anything
}
int main()
{
Array<double, 1> y(3);
y = 1,1,1;
cout << y << endl;
double x=0, h = 0.05;
while(x<20) {
rk4_fixed(x,y,lorenz,h);
cout << x;
for(int k =0; k<3; k++) {
cout << ", "<< y(k);
}
cout << endl;
}
return 0;
}
#include <blitz/array.h>
#include <iostream>
#include <cstdlib>
using namespace blitz;
using namespace std;
/* This will evaluate the slopes. say if dy/dx = y, rhs_eval will return y. */
const double sig = 10; const double rho = 28; const double bet = 8.0 / 3;
void lorenz(double x, Array<double, 1> y, Array<double, 1> &dydx)
{
/* y vector = x,y,z in components */
dydx(0) = sig * (y(1) - y(0));
dydx(1) = rho * y(0) - y(1) - y(0) * y(2);
dydx(2) = y(0) * y(1) - bet * y(2);
}
void rk4_fixed(double& x, Array<double, 1>& y, void (*rhs_eval)(double, Array<double, 1>, Array<double, 1> &), double h)
{
int n = y.extent(0);
Array<double, 1> k1(n), k2(n), k3(n), k4(n), f(n), dydx(n);
(*rhs_eval) (x, y, dydx);
for (int j = 0; j < n; j++)
{
k1(j) = h * dydx(j);
f(j) = y(j) + k1(j) / 2.0;
}
(*rhs_eval) (x + h / 2., f, dydx);
for (int j = 0; j < n; j++)
{
k2(j) = h * dydx(j);
f(j) = y(j) + k2(j) / 2.;
}
(*rhs_eval) (x + h / 2., f, dydx);
for (int j = 0; j < n; j++)
{
k3(j) = h * dydx(j);
f(j) = y(j) + k3(j);
}
(*rhs_eval) (x + h, f, dydx);
for (int j = 0; j < n; j++)
{
k4(j) = h * dydx(j);
}
for (int j = 0; j < n; j++)
{
y(j) += k1(j) / 6. + k2(j) / 3. + k3(j) / 3. + k4(j) / 6.;
}
x += h;
}
int main()
{
Array<double, 1> y(3);
y = 1, 1, 1;
double x = 0, h = 0.05;
Array<double, 1> dydx(3);
dydx = 0, 0, 0;
for (int i = 0; i < 10; i++)
{
rk4_fixed(x, y, &lorenz, h);
cout << x << " ,";
for (int j = 0; j < 3; j++)
{
cout << y(j)<<" ";
}
cout << endl;
}
return 0;
}
Another great thing is, it is possible to use blitz++ without any compilation. In Visual Studio 2019, expand {project name} than right click "references" and "Manage NuGet Packages" search for blitz++. download it. No added extra linking or others have to be done.
Related
I found the following code in this page to compute a double integral. Whenever I run it with all variables being declared as float, it gives the right result for the example integral, which is 3.91905. However, if I just change all float variables to double, the program gives a completely wrong result (2.461486) for this integral.
Could you help me undestanding why this happens? I expected to have a better result using double precision, but that's evidently not the case here.
Below is the code pasted from the aforementioned website.
// C++ program to calculate
// double integral value
#include <bits/stdc++.h>
using namespace std;
// Change the function according to your need
float givenFunction(float x, float y)
{
return pow(pow(x, 4) + pow(y, 5), 0.5);
}
// Function to find the double integral value
float doubleIntegral(float h, float k,
float lx, float ux,
float ly, float uy)
{
int nx, ny;
// z stores the table
// ax[] stores the integral wrt y
// for all x points considered
float z[50][50], ax[50], answer;
// Calculating the number of points
// in x and y integral
nx = (ux - lx) / h + 1;
ny = (uy - ly) / k + 1;
// Calculating the values of the table
for (int i = 0; i < nx; ++i) {
for (int j = 0; j < ny; ++j) {
z[i][j] = givenFunction(lx + i * h,
ly + j * k);
}
}
// Calculating the integral value
// wrt y at each point for x
for (int i = 0; i < nx; ++i) {
ax[i] = 0;
for (int j = 0; j < ny; ++j) {
if (j == 0 || j == ny - 1)
ax[i] += z[i][j];
else if (j % 2 == 0)
ax[i] += 2 * z[i][j];
else
ax[i] += 4 * z[i][j];
}
ax[i] *= (k / 3);
}
answer = 0;
// Calculating the final integral value
// using the integral obtained in the above step
for (int i = 0; i < nx; ++i) {
if (i == 0 || i == nx - 1)
answer += ax[i];
else if (i % 2 == 0)
answer += 2 * ax[i];
else
answer += 4 * ax[i];
}
answer *= (h / 3);
return answer;
}
// Driver Code
int main()
{
// lx and ux are upper and lower limit of x integral
// ly and uy are upper and lower limit of y integral
// h is the step size for integration wrt x
// k is the step size for integration wrt y
float h, k, lx, ux, ly, uy;
lx = 2.3, ux = 2.5, ly = 3.7,
uy = 4.3, h = 0.1, k = 0.15;
printf("%f", doubleIntegral(h, k, lx, ux, ly, uy));
return 0;
}
Thanks in advance for your help!
Due to numeric imprecisions, this line:
ny = (uy - ly) / k + 1; // 'ny' is an int.
Evaluates to 5 when the types of uy, ly and k are float. When the type is double, it yields 4.
You may use std::round((uy - ly) / k) or a different formula (I haven't checked the mathematical correctness of the whole program).
how do I replace the pow() function in two cases in my code ?
I think this can be done with a for loop
#include <iostream>
#include <cmath>
using namespace std;
int main(){
double a, b, h, PI = 3.141592;
int n;
cin >> a >> b >> h >> n;
for (double x = a; x <= b; x += h) {
double ans = 1, y;
for (int k = 0; k <= n; k++) {
ans *= cos(k * PI / 4) * pow(x, k);
for (int i = 2; i <= k; i++) {
ans /= i;
}
}
y = pow(exp(cos(x * sin(PI / 4))), x * cos(PI / 4));
cout << ans << " " << y << " " << fabs(y-ans) << endl;
}
return 0;
}
Do not write everything in main.
Define double S(double x, int n) and double U(double x).
each element of sum can be calculated based on previous element.
cos(k * M_PI / 4) has repeating values so it can be stored in table.
double S(double x, int n)
{
double a = 1;
double s = a;
constexpr double q = std::cos(M_PI / 4);
constexpr double cos_val[]{ 1, q, 0, -q, -1, -q, 0, q };
for (int k = 1; k <= n; ++k) {
a *= x / k;
s += cos_val[k & 7] * a
}
return s;
}
For the inner loop, you need not calculate the power in each iteration if you consider that on the previous iteration you already calculated pow(x,k-1) and that pow(x,k) == pow(x,k-1)*x:
double pow_x = 1; // on first iteration pow(x,0) == 1
for (int k = 0; k <= n; k++) {
ans *= cos(k * PI / 4) * pow_x;
// ...
pow_x *= x; // pow(x,k) -> pow(x,k+1)
}
The second use of pow in your code cannot be easily replaced, because of the floating point exponent. You would have to rewrite pow to get the same result. However, your code does not match the formula in the image. The image says (pseudo maths notation):
e ^ ( x * C1 ) * C2
your code is calculating
y = pow(exp(cos(x * sin(PI / 4))), x * cos(PI / 4));
( e^(C2) ) ^ (x * C1)
change it to
y = exp(x * cos(PI / 4)) * cos(x * sin(PI / 4))
I have a general question with a specific example. I wrote a function to calculate columnwise variance of a matrix in C (using .Call interface) and C++ (using Rcpp interface). Looking at the following benchmarks I wonder:
> microbenchmark(times = 1000,
+ colVar(AB), # .Call Interface
+ colV(AB, ncol(AB), nrow(AB)), #Rcpp
+ apply(AB, 2, var)) #R
Unit: milliseconds
expr min lq mean median uq max neval
colVar(AB) 3.245000 3.350793 3.474891 3.433126 3.543796 5.110652 1000
colV(AB, ncol(AB), nrow(AB)) 4.064942 4.408336 10.215952 5.934169 6.383477 99.651530 1000
apply(AB, 2, var) 28.260730 30.740058 46.674155 31.464449 33.586160 129.343892 1000
>
In distribution and mean the C and the C++ function perform pretty similar, however when it comes to a maximum value there is a huge difference. Can anybody explain to me why? This is especially interesting since I am trying to learn C/C++ but also because I want to write more complicated functions in C/C++, where this could actually matter.
AB is a matrix with dimension 1000 x 1000, created with 1 000 000 rnorm() values.
Below you find the Codes for my C and Rcpp functions:
C (R-Level):
colVar <- function(x){
.Call("colV", x, ncol(x), nrow(x))
}
C (C-Level):
#include <R.h>
#include <Rinternals.h>
#include <math.h>
SEXP colV(SEXP y, SEXP n, SEXP r){
int *nc = INTEGER(n);
double *x = REAL(y);
int d = length(y);
int *nr = INTEGER(r);
int i, j, z;
//int d = nr * nc;
double xSq[(d)];
SEXP result;
PROTECT(result = allocVector(REALSXP, (*nc)));
memset(REAL(result), 0, (*nc) * sizeof(double));
double *colVar = REAL(result);
int fr = ((*nr) - 1);
for(z = 0; z < (d); z++){
xSq[z] = pow(x[z], 2);
}
for(i = 0; i < (*nc); i++){
double colMean = 0;
double xSm = 0;
double colMsq = 0;
for(j = 0; j < (*nr); j++){
colMean += ((x[(j + ((*nr) * i)) ]) / (*nr));
xSm += (xSq[(j + (*nr * i))]);
}
colMsq = (*nr) * (pow(colMean, 2));
colVar[i] = ((xSm - colMsq) / fr);
}
UNPROTECT(1);
return(result);
}
And the Rcpp-Function:
cppFunction(plugins = "unwindProtect",'NumericVector colV(NumericVector y, int n, int r){
int nc = n;
NumericVector x = y;
int nr = r;
int d = n * r;
int i, j, z;
// NumericVector colMean (nc);
NumericVector xSq (d);
// NumericVector colMsq (nc);
// NumericVector xSm (nc);
NumericVector colVar (nc);
int fr = ((nr) - 1);
for(z = 0; z < (d); z++){
xSq[z] = x[z] * x[z];
}
for(i = 0; i < (nc); i++){
double colMean = 0;
double xSm = 0;
double colMsq = 0;
for(j = 0; j < (nr); j++){
colMean += ((x[(j + ((nr) * i)) ]) / (nr));
xSm += (xSq[(j + (nr * i))]);
}
colMsq = (nr) * (colMean * colMean);
colVar[i] = ((xSm - colMsq) / fr);
}
return colVar;
}')
I have commented out stuff in the C++ function to make it as similar as possible to the C function.
If anybody of you can help me with my question I would be very thankful.
i'm trying to make my runge-kutta 4th order code modular. I don't want to have to write and declare the code everytime I use it, but declare it in a .hpp and a .cpp file to use it separetely. But i'm having some problems. Generally I want to solve a n-dimension system of equations. For that I use two functions: one for the system of equations and another for the runge-kutta method as follows:
double F(double t, double x[], int eq)
{
// System equations
if (eq == 0) { return (x[1]); }
else if (eq == 1) { return (gama * sin(OMEGA*t) - zeta * x[1] - alpha * x[0] - beta * pow(x[0], 3) - chi * x[2]); }
else if (eq == 2) { return (-kappa * x[1] - phi * x[2]); }
else { return 0; }
}
void rk4(double &t, double x[], double step)
{
double x_temp1[sistvar], x_temp2[sistvar], x_temp3[sistvar];
double k1[sistvar], k2[sistvar], k3[sistvar], k4[sistvar];
int j;
for (j = 0; j < sistvar; j++)
{
x_temp1[j] = x[j] + 0.5*(k1[j] = step * F(t, x, j));
}
for (j = 0; j < sistvar; j++)
{
x_temp2[j] = x[j] + 0.5*(k2[j] = step * F(t + 0.5 * step, x_temp1, j));
}
for (j = 0; j < sistvar; j++)
{
x_temp3[j] = x[j] + (k3[j] = step * F(t + 0.5 * step, x_temp2, j));
}
for (j = 0; j < sistvar; j++)
{
k4[j] = step * F(t + step, x_temp3, j);
}
for (j = 0; j < sistvar; j++)
{
x[j] += (k1[j] + 2 * k2[j] + 2 * k3[j] + k4[j]) / 6.0;
}
t += step;
}
The above code works and it is validated. However it has some dependencies as it uses some global variables to work:
gama, OMEGA, zeta, alpha, beta, chi, kappa and phi are global variables that I want to read from a .txt file. I already manage to do that, however only in a single .cpp file with all code included.
Also, sistvar is the system dimension and also a global variable. I'm trying to enter it as an argument in F. But the way it is written seems to give errors as sistvar is a const and can't be changed as a variable and I can't put variables inside an array's size.
In addition, the two functions has an interdependency as when a call F inside rk4, eq number is needeed.
Could you give me tips in how to do that? I already searched and read books about this and could not find an answer for it. It is probably an easy task but i'm relatively new in c/c++ programming languages.
Thanks in advance!
* EDITED (Tried to implement using std::vector)*
double F(double t, std::vector<double> x, int eq)
{
// System Equations
if (eq == 0) { return (x[1]); }
else if (eq == 1) { return (gama * sin(OMEGA*t) - zeta * x[1] - alpha * x[0] - beta * pow(x[0], 3) - chi * x[2]); }
else if (eq == 2) { return (-kappa * x[1] - phi * x[2]); }
else { return 0; }
}
double rk4(double &t, std::vector<double> &x, double step, const int dim)
{
std::vector<double> x_temp1(dim), x_temp2(dim), x_temp3(dim);
std::vector<double> k1(dim), k2(dim), k3(dim), k4(dim);
int j;
for (j = 0; j < dim; j++) {
x_temp1[j] = x[j] + 0.5*(k1[j] = step * F(t, x, j));
}
for (j = 0; j < dim; j++) {
x_temp2[j] = x[j] + 0.5*(k2[j] = step * F(t + 0.5 * step, x_temp1, j));
}
for (j = 0; j < dim; j++) {
x_temp3[j] = x[j] + (k3[j] = step * F(t + 0.5 * step, x_temp2, j));
}
for (j = 0; j < dim; j++) {
k4[j] = step * F(t + step, x_temp3, j);
}
for (j = 0; j < dim; j++) {
x[j] += (k1[j] + 2 * k2[j] + 2 * k3[j] + k4[j]) / 6.0;
}
t += step;
for (j = 0; j < dim; j++) {
return x[j];
}
}
vector array
2.434 s | | 0.859 s
2.443 s | | 0.845 s
2.314 s | | 0.883 s
2.418 s | | 0.884 s
2.505 s | | 0.852 s
2.428 s | | 0.923 s
2.097 s | | 0.814 s
2.266 s | | 0.922 s
2.133 s | | 0.954 s
2.266 s | | 0.868 s
_______ _______
average = 2.330 s average = 0.880 s
Using vector function where the vector arithmetic is taken from Eigen3
#include <eigen3/Eigen/Dense>
using namespace Eigen;
of the same parts as discussed in the question could look like (inspired by function pointer with Eigen)
VectorXd Func(const double t, const VectorXd& x)
{ // equations for solving simple harmonic oscillator
Vector3d dxdt;
dxdt[0] = x[1];
dxdt[1] = gama * sin(OMEGA*t) - zeta * x[1] - alpha * x[0] - beta * pow(x[0], 3) - chi * x[2];
dxdt[2] = -kappa * x[1] - phi * x[2];
return dxdt;
}
MatrixXd RK4(VectorXd Func(double t, const VectorXd& y), const Ref<const VectorXd>& y0, double t, double h, int step_num)
{
MatrixXd y(y0.rows(), step_num );
VectorXd k1, k2, k3, k4;
y.col(0) = y0;
for (int i=1; i<step_num; i++){
k1 = Func(t, y.col(i-1));
k2 = Func(t+0.5*h, y.col(i-1)+0.5*h*k1);
k3 = Func(t+0.5*h, y.col(i-1)+0.5*h*k2);
k4 = Func(t+h, y.col(i-1)+h*k3);
y.col(i) = y.col(i-1) + (k1 + 2*k2 + 2*k3 + k4)*h/6;
t = t+h;
}
return y.transpose();
}
Passing a vector to a function to be filled apparently requires some higher template contemplations in Eigen.
This code should output 0 0.25 0.5 0.75 1, instead it outputs zeros. Why is that?
Define a function u(x)=x;
void pde_advect_IC(double* x, double* u)
{
int N = sizeof(x) / sizeof(x[0]); //size of vector u
for (int i = 0; i <= N; i++)
u[i] = x[i];
}
Here is the implementation:
int main()
{
double a = 0.0;
double b = 1.0;
int nx = 4;
double dx = (b - a) / double(nx);
double xx[nx + 1]; //array xx with intervals
// allocate memory for vectors of solutions u0
double* u0 = new double [nx + 1];
//fill in array x
for (int i = 0; i <= nx; i++)
xx[i] = a + double(i) * dx;
pde_advect_IC(xx, u0); // u0 = x (initial conditions)
for (int i = 0; i <= nx; i++)
cout<<u0[i]<<endl;
// de-allocate memory of u0
delete [] u0;
delete [] u1;
return 0;
}
You can't use sizeof(x) because that will return the size of the pointer, not the array you thought you passed to it. You have to specify the size with a third parameter or use something more convenient like an std::vector and use size().
This works.
#include <iostream>
#include <cstdlib>
using namespace std;
void pde_advect_IC(double* x, double* u, const int& N)
{
for (int i = 0; i < N; i++)
u[i] = x[i];
}
int main()
{
double a = 0.0;
double b = 1.0;
int nx = 4;
double dx = (b - a) / double(nx);
double xx[nx + 1]; //array xx with intervals
// allocate memory for vectors of solutions u0
double* u0 = new double [nx + 1];
//fill in array x
for (int i = 0; i <= nx; i++)
xx[i] = a + double(i) * dx;
pde_advect_IC(xx, u0, nx + 1); // u0 = x (initial conditions)
for (int i = 0; i <= nx; i++)
cout << u0[i] << endl;
// de-allocate memory of u0
delete [] u0;
return 0;
}
Note that I added const int& N to pde_advect_IC() in order to pass it the size of the array, by const reference, to be sure it does not get modified by mistake.
Note that your trick with sizeof() does not work with pointers.