My objective is to parallelise a one-dimensional integral. I have looked around, and I would say that I could do that in two ways: i) implementing OpenMP with ODEINT, boost library integrate_adapative function (see https://www.boost.org/doc/libs/1_56_0/libs/numeric/odeint/doc/html/boost_numeric_odeint/tutorial/parallel_computation_with_openmp_and_mpi.html).; ii) implementing OpenMP with GSL monte carlo integration (as in here: Internal compiler error with nested functions in OpenMP parallel regions).
My problem is that I cannot really understand what they did in both links I provided.
I was wondering whether someone has experience with that, and may point out how I could implement both approaches on my case. Is it OpenMP with boost faster or GSL and OpenMP implementation?
PDFfunction represents the probability density function that is used within the integrand function. PDFfunction is equivalent to , and in LateX is expressed as:
And this is how I code it:
double PDFfunction(double invL, int t, double invtau, double x0, double x, int n) {
const double c = M_PI * (M_PI/4) * ((2 * t) * invtau);
double res = 0;
for(int i = 1; i <= n; ++n){
res += exp(-1 * (i * i) * c) * cos((i * M_PI * x) * invL) * cos((i * M_PI * x0) * invL);
}
return invL + ((2 * invL) * res);
}
Composite_at_t is a function that makes use of the PDFfunction to compute pbA and pbB. Composite_at_t is equivalent to , where ) and ).
double Composite_at_t(double t, double B, double x0, double xt_pos, double y0, double yt_pos, double invLtot, double invtau, int n_lim) {
double pbA = PDFfunction(invLtot, t, invtau, x0, xt_pos, n_lim);
double pbB = PDFfunction(invLtot, t, invtau, y0, yt_pos, n_lim);
double b1 = 2 * (2 * t) * exp(-2 * t * B);
return pbA * pbB * b1;
}
Composite_at_tCLASS is a Func class which computes a first integral over variable t.
class Composite_at_tCLASS: public Func{
private:
double B;
double x0;
double xt_pos;
double y0;
double yt_pos;
double invLtot;
double invtau;
int n_lim;
public:
Composite_at_tCLASS(double B_, double x0_, double xt_pos_, double y0_, double yt_pos_, double invLtot_, double invtau_, int n_lim_) : B(B_), x0(x0_), xt_pos(xt_pos_), y0(y0_), yt_pos(yt_pos_), invLtot(invLtot_), invtau(invtau_), n_lim(n_lim_) {}
double operator()(const double& t) const{
return Composite_at_t(t, B, x0, xt_pos, y0, yt_pos, invLtot, invtau, n_lim);
}
};
integrate_CompositeCLASS is the actual function that uses the class Composite_at_tCLASS and perform the integral over t, between 0 and time_lim.
double integrate_CompositeCLASS(double B, double x0, double xt_pos, double y0, double yt_pos, double invLtot, double invtau, int n_lim, double time_lim){
Composite_at_tCLASS f(B, x0, xt_pos, y0, yt_pos, invLtot, invtau, n_lim);
double err_est;
int err_code;
double res = integrate(f, 0, time_lim, err_est, err_code);
return res;
}
For the numerical integration using the GSL library I would use the following code:
struct my_f_params { double B; double x0; double xt_pos; double y0; double yt_pos; double invtau; int n_lim; double invLtot;};
double g(double *k, size_t dim, void *p){
struct my_f_params * fp = (struct my_f_params *)p;
return Composite_at_t(k[0],fp->B, fp->x0, fp->xt_pos, fp->y0, fp->yt_pos, fp->invLtot, fp->invtau, fp->n_lim);
}
And this is the actual object that perform the GSL integral:
double integrate_integral(const double& invtau, const int& n_lim, const double& invLtot,
const double& x0, const double& xt_pos, const double& y0, const double& yt_pos, const double& time_lim){
double res, err;
double xl[1] = {0};
double xu[1] = {time_lim};
const gsl_rng_type *T;
gsl_rng *r;
gsl_monte_function G;
struct my_f_params params = { B, x0, xt_pos, y0, yt_pos, invtau, n_lim, invLtot};
G.f = &g;
G.dim = 1;
G.params = ¶ms;
size_t calls = 10000;
gsl_rng_env_setup ();
T = gsl_rng_default;
r = gsl_rng_alloc (T);
gsl_monte_vegas_state *s = gsl_monte_vegas_alloc (1);
gsl_monte_vegas_integrate (&G, xl, xu, 1, 10000, r, s,
&res, &err);
do
{
gsl_monte_vegas_integrate (&G, xl, xu, 1, calls/5, r, s,
&res, &err);
}
while (fabs (gsl_monte_vegas_chisq (s) - 1.0) > 0.5);
gsl_monte_vegas_free (s);
gsl_rng_free (r);
return res;
}
Related
My aim is to use GSL monte carlo integration for an integrand in which an arbitrary multiprecision library (Boost) is used. I decided to use an arbitrary multiprecision library because the integral had difficulties to reach convergence.
This is the actual mathematical formula describing what I am trying to code. My guess is that I do not reach convergence and therefore NaN because and can get very small values, near zeros.
This is my code:
mp::float128 PDFfunction(double invL, int t, double invtau, double x0, double x, int n_lim) {
const double c = M_PI * (M_PI/4) * ((2 * t) * invtau);
mp::float128 res = 0;
for(int n = 1; n <= n_lim; ++n){
res += exp(-1 * (n * n) * c) * cos((n * M_PI * x) * invL) * cos((n * M_PI * x0) * invL);
}
mp::float128 res_tot = invL + ((2 * invL) * res);
return res_tot;
}
The following lines define the integral that I carry out using GSL:
struct my_f_params {double x0; double xt_pos; double y0; double yt_pos; double invLx; double invLy;
double invtau_x; double invtau_y; int n_lim; double tax_rate;};
double g(double *k, size_t dim, void *p){
struct my_f_params * fp = (struct my_f_params *)p;
mp::float128 temp_pbx = prob1Dbox(fp->invLx, k[0], fp->invtau_x, fp->x0, fp->xt_pos, fp->n_lim);
mp::float128 temp_pby = prob1Dbox(fp->invLy, k[0], fp->invtau_y, fp->y0, fp->yt_pos, fp->n_lim);
mp::float128 AFac = (-2 * k[0] * fp->tax_rate);
mp::float128 res = exp(log(temp_pbx) + log(temp_pby) + AFac);
return res.convert_to<double>();
}
double integrate_integral(const double& x0, const double& xt_pos, const double& y0,
const double& yt_pos, const double& invLx, const double& invLy, const double& invtau_x,
const double& invtau_y, const int& n_lim, const double& tax_rate){
double res, err;
double xl[1] = {0};
double xu[1] = {10000000};
const gsl_rng_type *T;
gsl_rng *r;
gsl_monte_function G;
struct my_f_params params = {x0, xt_pos, y0, yt_pos, invLx, invLy, invtau_x, invtau_y, n_lim, tax_rate};
G.f = &g;
G.dim = 1;
G.params = ¶ms;
size_t calls = 10000;
gsl_rng_env_setup ();
T = gsl_rng_default;
r = gsl_rng_alloc (T);
gsl_monte_vegas_state *s = gsl_monte_vegas_alloc (1);
gsl_monte_vegas_integrate (&G, xl, xu, 1, 10000, r, s,
&res, &err);
do
{
gsl_monte_vegas_integrate (&G, xl, xu, 1, calls/5, r, s,
&res, &err);
}
while (fabs (gsl_monte_vegas_chisq (s) - 1.0) > 0.5);
gsl_monte_vegas_free (s);
gsl_rng_free (r);
return res;
}
When I try to run integral_integrate with x0 = 0; xt_pos = 0; y0 = 0; yt_pos = 10; invLx = invLy = 0.09090909; invtau_x = invtau_y = 0.000661157; n_lim = 1000; tax_rate = 7e-8; I get NaN. Why is this the case? I was not expecting this result since I used Log-Sum-Exp to get rid of possible underflow.
I have issues with memory leaks on a C++ function that I have sourced into R through Rcpp. This result in a sudden abortion of my R session, without returning any specific error message.
What is weird to me is that if in function_test I move double lower =1; and double upper = value2; inside the for loop and edited them by also adding 'i': double lower =1 + i; and double upper = value2 + i; the function works without aborting my R session.
The code below is sourced in R using the function sourceCpp from Rcpp R package. I run the function with the following values:
R function:
function_test(value1=4000, value2=4000, alpha = 5e-04)
C++ code sourced in R:
// [[Rcpp::depends(RcppEigen)]]
// [[Rcpp::depends(RcppNumerical)]]
#define EIGEN_PERMANENTLY_DISABLE_STUPID_WARNINGS
#include <Eigen/Eigen>
#include <RcppNumerical.h>
#include <Rcpp.h>
using namespace Rcpp;
using namespace Numer;
// [[Rcpp::export]]
double func1(double t, double alpha, double beta){
double term1 = (( 2.0 * log(t - 0.5)) + 1) / 25.0;
int N;
if (t == 1 || t == 2) {
N = 2;
}else{
if (t <= 44) {
N = t;
}else{
N = 44;
}
}
NumericVector term_up(N);
term_up[0] = 0;
term_up[1] = term1;
double res = std::accumulate(term_up.begin(), term_up.end(), 0.0);
double int_final = (1/(25.0*t)) * (1 - (0.96)*res);
return int_final;
}
class Func1PDF: public Func
{
private:
double alpha;
double beta;
public:
Func1PDF(double alpha_, double beta_) : alpha(alpha_), beta(beta_) {}
double operator()(const double& t) const{
return func1(t, alpha, beta);
}
};
// [[Rcpp::export]]
double integrate_func(double lower, double upper, double alpha, double beta)
{
Func1PDF f(alpha, beta);
double err_est;
int err_code;
const double res = integrate(f, lower, upper, err_est, err_code);
return res;
}
// [[Rcpp::export]]
NumericVector function_test(double value1, double value2, double alpha) {
NumericVector res(value1);
double lower = 1;
double upper = value2;
for(int i=1;i<=value1;i++){
double beta = i;
res[i-1] = integrate_func(lower, upper, alpha, beta);
}
return res;
}
In order to integrate a two dimensional function of the form
$$\int_{1}^\infty \int_{-\sqrt{x^2-1}}^{\sqrt{x^2-1}} e^{-x} \rm{d}y \rm{d}x,$$
I have been attempting to use the following code (written in C++) taken mostly from the Numerical Recipes book which calls a gaussian quadrature routine for the integration:
static float xsav;
static float (*nrfunc)(float,float);
float quad2d(float (*func)(float, float), float x1, float x2)
{
float qgaus(float (*func)(float), float a, float b);
float f1(float x);
nrfunc=func;
return qgaus(f1,x1,x2);
}
float f1(float x)
{
float qgaus(float (*func)(float), float a, float b);
float f2(float y);
float yy1(float),yy2(float);
xsav=x;
return qgaus(f2,yy1(x),yy2(x));
}
float f2(float y)
{
return (*nrfunc)(xsav,y);
}
This code works fine for two dimensional integrals with finite limits, but fails as the outer limit is taken to infinity. To account for this, I have attempted to use a change of variables:
#define FUNC(x) ((*funk)(-log(x))/(x))
float qgaus(float (*funk)(float), float aa, float bb)
{
int j;
float xr,xm,dx,s,a,b;
b=exp(-aa);
a=0.0;
static float x[]={0.0,0.1488743389,0.4333953941,
0.6794095682,0.8650633666,0.9739065285};
static float w[]={0.0,0.2955242247,0.2692667193,
0.2190863625,0.1494513491,0.0666713443};
xm=0.5*(b+a);
xr=0.5*(b-a);
s=0;
for (j=1;j<=5;j++)
{
dx=xr*x[j];
s += w[j]*(FUNC(xm+dx)+FUNC(xm-dx));
}
return s *= xr;
}
float f(float x, float y)
{
float a = exp(-x);
return a;
}
float yy1(float x)
{
float y = -sqrt(x*x-1);
return y;
}
float yy2(float x)
{
float y = sqrt(x*x-1);
return y;
}
static float xsav;
static float (*nrfunc)(float, float);
float quad2d(float (*func)(float, float), float x1, float x2)
{
float qgaus(float (*func)(float), float aa, float bb);
float f1(float x);
nrfunc=func;
float t = qgaus(f1,x1,x2);
return t;
}
float f1(float x)
{
float qgaus(float (*func)(float), float aa, float bb);
float f2(float y);
float yy1(float);
float yy2(float);
xsav=x;
float r = qgaus(f2,yy1(x),yy2(x));
return r;
}
float f2(float y)
{
float k = (*nrfunc)(xsav,y);
return k;
}
int main ()
{
float z;
z = quad2d(f, 1.0, 20.0);
cout << z << endl;
}
but this still doesn't give the right answer. It should be
$2 \times \rm{BesselK}[1,1] \approx 1.20381$
but instead gives
2.15501
Any suggestions on how I could modify this code to account for the infinite limit would be greatly appreciated!
So I've read this formula generates a uniform random point inside of a triangle, from this article... http://www.cs.princeton.edu/~funk/tog02.pdf
P = (1 - sqrt(R1)) * A + (sqrt(R1) * (1 - R2)) * B + (sqrt(R1) * R2) * C
Where...
R1 & R2 are random floats in between 0 and 1.
A, B, & C are the points that create our triangle.
I've implemented this formula in my code with MANY test conditions, expecting each condition to have a point generated in the triangle... However, there always seems to be a few cases of it outside the triangle.
Here is my code (in C++)...
#include "stdafx.h"
#include <random>
#include <time.h>
class Location
{
public:
Location(
int x,
int y)
{
m_x = x;
m_y = y;
}
int m_x;
int m_y;
private:
};
double RandomValueBetweenZeroAndOne()
{
return ((double)rand() / (RAND_MAX));
}
float GetArea(
float x1, float y1,
float x2, float y2,
float x3, float y3)
{
return abs((x1*(y2 - y3) + x2*(y3 - y1) + x3*(y1 - y2)) / 2.0f);
}
bool InsideTriangle(
float Ax, float Ay,
float Bx, float By,
float Cx, float Cy,
float Px, float Py)
{
/* Calculate area of triangle ABC */
float A = GetArea(Ax, Ay, Bx, By, Cx, Cy);
/* Calculate area of triangle PBC */
float A1 = GetArea(Px, Py, Bx, By, Cx, Cy);
/* Calculate area of triangle PAC */
float A2 = GetArea(Ax, Ay, Px, Py, Cx, Cy);
/* Calculate area of triangle PAB */
float A3 = GetArea(Ax, Ay, Bx, By, Px, Py);
/* Check if sum of A1, A2 and A3 is same as A */
if ((A == (A1 + A2 + A3)))
{
return true;
}
return false;
};
int main()
{
srand(time(0));
Location* A = new Location(-54900, 933200);
Location* B = new Location(-62800, 934300);
Location* C = new Location(-70000, 932100);
bool in_triangle = true;
int i = 0;
do
{
float R1 = static_cast<float>(RandomValueBetweenZeroAndOne());
float R2 = static_cast<float>(RandomValueBetweenZeroAndOne());
float random_x = (1.0f - sqrt(R1)) * static_cast<float>(A->m_x) + (sqrt(R1) * (1.0f - R2)) * static_cast<float>(B->m_x) + (sqrt(R1) * R2) * static_cast<float>(C->m_x);
float random_y = (1.0f - sqrt(R1)) * static_cast<float>(A->m_y) + (sqrt(R1) * (1.0f - R2)) * static_cast<float>(B->m_y) + (sqrt(R1) * R2) * static_cast<float>(C->m_y);
in_triangle = InsideTriangle(
static_cast<float>(A->m_x), static_cast<float>(A->m_y),
static_cast<float>(B->m_x), static_cast<float>(B->m_y),
static_cast<float>(C->m_x), static_cast<float>(C->m_y),
random_x, random_y);
if (!in_triangle)
{
printf("Point located outside of Triangle on %i iteration", i);
}
i++;
} while (in_triangle);
system("pause");
}
In one example... The equation assigned the random coordinates as follows:
random_x = -66886;
random_y = 932326;
I even made a C# program to verify if the point was truley outside of the triangle (visually). Here's the results, everything above the line that is visible is INSIDE of the triangle... Everything Below the line that is visible is OUTSIDE of the triangle...
https://puu.sh/rJtSJ/7a7a88c346.png
For reference, I know that I can just wrap the number generating in a do while loop until a value inside the triangle is generated... I just wanted to know why it's generating outside when it's not supposed to be, and where the bug is...
Floating point arithmetic isn't perfect.That means when you do an artihmetic operation with floating points it may not give exact expected result.In that cases generally you should correct your code with wisely using a small number.
In that case part that should be corrected should be
float random_x = (1.0f - sqrt(R1)) * static_cast<float>(A->m_x) + (sqrt(R1) * (1.0f - R2)) * static_cast<float>(B->m_x) + (sqrt(R1) * R2) * static_cast<float>(C->m_x);
float random_y = (1.0f - sqrt(R1)) * static_cast<float>(A->m_y) + (sqrt(R1) * (1.0f - R2)) * static_cast<float>(B->m_y) + (sqrt(R1) * R2) * static_cast<float>(C->m_y);
Since I didn't understand the formula I can't fix it.But if you were use that formula:
if(R1+R2>1)
{
R1=1-R1;
R2=1-R2;
}
float random_x = A->m_x+(B->m_x-A->m_x)*R1+(C->m_x-A->m_x)*R2;
float random_y = A->m_y+(B->m_y-A->m_y)*R1+(C->m_y-A->m_y)*R2;
You could correct it as:
if(R1+R2>1)
{
R1=1-R1;
R2=1-R2;
}
float error=0.01;
float D=1-error;
float random_x = D*A->m_x+D*(B->m_x-A->m_x)*R1+D*(C->m_x-A->m_x)*R2+error*(A->m_x+B->m_x+C->m_x)/3;
float random_y = D*A->m_y+D*(B->m_y-A->m_y)*R1+D*(C->m_y-A->m_y)*R2+error*(A->m_x+B->m_x+C->m_x)/3;
That will ensure points will be inside the triangle.
You have a rounding problem, this needs to round down to smaller precision. Also using double instead of float will give better result.
Instead of comparing two double (or float) values to see if they are the same, take their difference and see if it is within a margin of error. The function below has arbitrary margin of 0.00001
bool InsideTriangle(double Ax, double Ay, double Bx, double By,
double Cx, double Cy, double Px, double Py)
{
double A = GetArea(Ax, Ay, Bx, By, Cx, Cy);
double A1 = GetArea(Px, Py, Bx, By, Cx, Cy);
double A2 = GetArea(Ax, Ay, Px, Py, Cx, Cy);
double A3 = GetArea(Ax, Ay, Bx, By, Px, Py);
double diff = A1 + A2 + A3 - A;
if (abs(diff) < 0.00001) return true;
std::cout << diff << "\n";
return false;
};
To compare the values directly, use the example below:
double getround(double f)
{
return floor(f * 1000.0f + 0.5f) / 1000.0f;
}
bool InsideTriangle(double Ax, double Ay, double Bx, double By,
double Cx, double Cy, double Px, double Py)
{
double A = GetArea(Ax, Ay, Bx, By, Cx, Cy);
double A1 = GetArea(Px, Py, Bx, By, Cx, Cy);
double A2 = GetArea(Ax, Ay, Px, Py, Cx, Cy);
double A3 = GetArea(Ax, Ay, Bx, By, Px, Py);
if ((A == (A1 + A2 + A3)))
{
return true;
}
double t1 = getround(A1 + A2 + A3);
double t2 = getround(A);
if (t1 == t2)
return true;
std::cout << t1 << ", " << t2 << "\n";
return false;
};
Note that you should not use cast unless the compiler complains. For example the following cast is not needed
float foo(){return 0.1f;}
...
float R1 = static_cast<float>(foo());
Because foo is already float. If you automatically put cast everywhere then it can hide potential problems.
Avoid using memory allocation when it's not need. For example, use Location A(-54900, 933200); instead of new operator. If you use new then be sure to free the memory with delete when it is no longer needed.
I have to compute the distance from a point to a line (check if it is line or a line segment). I am not sure that the bool function IsSegment is working properly. Can i have some suggestions? Thank you.
double Distance_From_Line_to_Point(int *a, int *b, int *c, bool IsSegment) {
double distance;
int dot1;
int dot2;
distance = Cross_Product(a, b, c) / Distance(a, b);
if (IsSegment(a,b,c) == true) {
dot1 = Dot_Product(a, b, c);
if (dot1 > 0) {
return Distance(b, c);
}
dot2 = Dot_Product(b, a, c);
if (dot2 > 0) {
return Distance(a, c);
}
}
return fabs(distance);
}
bool IsSegment(int *a, int *b, int *c) {
double angle1;
double angle2;
angle1 = atan(double(b[1] - a[1]) / (b[0] - a[0]));
angle2 = atan(double(c[1] - b[1]) / (c[0] - b[0]));
if ((angle2 - angle1) * (180 / PI) > 90) {
return false;
}
return true;
}
Can't you just use the formula to get the distance?
So to find the line:
void getLine(double x1, double y1, double x2, double y2, double &a, double &b, double &c)
{
// (x- p1X) / (p2X - p1X) = (y - p1Y) / (p2Y - p1Y)
a = y1 - y2; // Note: this was incorrectly "y2 - y1" in the original answer
b = x2 - x1;
c = x1 * y2 - x2 * y1;
}
http://formule-matematica.tripod.com/distanta-de-dreapta.htm
double dist(double pct1X, double pct1Y, double pct2X, double pct2Y, double pct3X, double pct3Y)
{
double a, b, c;
getLine(pct2X, pct2Y, pct3X, pct3Y, a, b, c);
return abs(a * pct1X + b * pct1Y + c) / sqrt(a * a + b * b);
}
Example on how to use the code:
#include <CMATH>
void getLine(double x1, double y1, double x2, double y2, double &a, double &b, double &c)
{
// (x- p1X) / (p2X - p1X) = (y - p1Y) / (p2Y - p1Y)
a = y1 - y2; // Note: this was incorrectly "y2 - y1" in the original answer
b = x2 - x1;
c = x1 * y2 - x2 * y1;
}
double dist(double pct1X, double pct1Y, double pct2X, double pct2Y, double pct3X, double pct3Y)
{
double a, b, c;
getLine(pct2X, pct2Y, pct3X, pct3Y, a, b, c);
return abs(a * pct1X + b * pct1Y + c) / sqrt(a * a + b * b);
}
int main(int argc, char* argv[])
{
double d = dist(1,2,3,4,5,6);
return 0;
}
Distance from a point to a line
You need 2 formulas:
Line formula: source this answer.
private Vector2 m_point1;
private Vector2 m_point1;
private float m_A;
private float m_B;
private float m_C;
public void CalculateLine()
{
m_A = m_point1.y - m_point2.y;
m_B = m_point2.x - m_point1.x;
m_C = m_point1.x * m_point2.y - m_point2.x * m_point1.y;
if(m_A == 0 && m_B == 0)
{
Debug.LogError("Line error: A & B = 0");
}
}
Distance from point to line: source Wikipedia
public float Distance2DPointToLine(Vector2 point)
{
return Mathf.Abs(m_A * point.x + m_B * point.y + m_C) /
Mathf.Sqrt(m_A * m_A + m_B * m_B);
}
Distance from a point to a line segment
It depends what you define "Distance from a point to a line segment"
Maybe distance from a point to a line segment is the distance from a point to the segment's middle point:
Maybe the distance is available if the point can be projected on the line segment
Maybe you didn't imagine what's result when you ask about segment, so I can't answer the segment part for you.