I've to develop an optimizer to calculate the 14 parameters of a hidden markov chain (I know its much but possible :)). I've already done the same optimizer using IMSL(which I had during an intership) and I know it's possible, but I don't have the licence for IMSL now because I'm doing a student project and I'm trying to make the same optimizer in C++.
But I got this error (I've commented in the code where it appears):
gsl: simplex.c:288: ERROR: non-finite function value encountered
Default GSL error handler invoked.
Aborted
I'm using the GSL library, more specifically the sub-library multimin.
I'm showing you my code here in after and I would be please to comment it more if you need but I can send it with the data to anyone who could help me.
Thank you very much for your time and help.
Benjamin,
The structure we need for the optimizer:
struct dataMom {
int n; /* Number of data points */
gsl_vector *Rmom; /* Response data */
gsl_vector *Rm; /* Covariate */
};
The function that calculate the values
double my_f (const gsl_vector *v, void *params) {
struct dataMom *p = (struct dataMom *) params;
int i;
double loglik = 0;
So has you can see we have 14 parameters to optimize.
double alphaC = gsl_vector_get (v, 0);
double beta0C =gsl_vector_get (v, 1);
double betaUC =gsl_vector_get (v, 2);
double sigmamomC =gsl_vector_get (v, 3);
double muC =gsl_vector_get (v, 4);
double sigmamC =gsl_vector_get (v, 5);
double probaC =gsl_vector_get (v, 6);
double alphaT= gsl_vector_get (v, 7);
double beta0T = gsl_vector_get (v, 8);
double betaUT= gsl_vector_get (v, 9);
double sigmamomT= gsl_vector_get (v, 10);
double muT =gsl_vector_get (v, 11);
double sigmamT = gsl_vector_get (v, 12);
double probaT =gsl_vector_get (v, 13);
double epsilonmomC;
double epsilonmC;
double epsilonmomT;
double epsilonmT;
double Rmomentum;
double Rmarket;
double IUT;
double Pc;
double Pt;
double PC;
double PT;
double PI = 3.14159;
double probac = (1-probaT)/(2-probaC-probaT);
double probat = 1-probac;
for (i=0;i<p->n;i++) {
Rmomentum = gsl_vector_get(p->Rmom, i)*0.01;
Rmarket = gsl_vector_get(p->Rm, i)*0.01;
if (Rmarket>0){IUT = 1;}
else {IUT = 0;}
epsilonmomC = (1/sigmamomC)*(Rmomentum - alphaC - (beta0C + IUT*betaUC)*Rmarket);
epsilonmC = (1/sigmamC)*(Rmarket-muC);
epsilonmomT = (1/sigmamomT)*(Rmomentum - alphaT - (beta0T + IUT*betaUT)*Rmarket);
epsilonmT = (1/sigmamT)*(Rmarket-muT);
Pc = ((1/(sigmamomC*sqrt(2*PI)))*exp(-(epsilonmomC*epsilonmomC)/2)) * ((1/(sigmamC*sqrt(2*PI)))*exp(-(epsilonmC*epsilonmC)/2));
Pt = ((1/(sigmamomT*sqrt(2*PI)))*exp(-(epsilonmomT*epsilonmomT)/2)) * ((1/(sigmamT*sqrt(2*PI)))*exp(-(epsilonmT*epsilonmT)/2));
PC = Pc * (probaC*probac + (1-probaC)*(probat));
PT = Pt * ((1-probaT)*(probac) + probaT*probat);
loglik -=log(PC+PT);
probac = PC / (PC+PT);
probat = PT / (PC+PT);
}
return loglik;
}
The main:
int main (void) {
/* Initialise data and model parameters */
//these are 2 vectors of return from txt files that i can give you
vector<double> Benchmark;
vector<double> Momentum;
//these are the 2 fonctions i'm using to get the return for the txt files
Benchmark = readBenchmark();
Momentum = readMomentum();
int i, n=Benchmark.size(), nparas=14;
double initial_p[14] = {0.0204,0.41,-0.52,0.0432 , 0.0098 , 0.0362 , 0.97, 0.0402 , -0.26 , -1.28 , 0.1105 , -0.0070 , 0.0904 , 0.92};
struct dataMom myStruct;
myStruct.n = n;
myStruct.Rmom = gsl_vector_alloc(myStruct.n);
myStruct.Rm = gsl_vector_alloc(myStruct.n);
vector<double>::iterator itbenchmark;
vector<double>::iterator itmomentum;
double tempmom;
double tempm;
itbenchmark = Benchmark.begin();
itmomentum = Momentum.begin();
for (i=0;i<myStruct.n;i++) {
tempmom = *itmomentum;
tempm = *itbenchmark;
gsl_vector_set (myStruct.Rmom, i, tempmom);
gsl_vector_set (myStruct.Rm, i, tempm);
itbenchmark++;
itmomentum++;
}
/* Starting point */
gsl_vector *paras;
paras = gsl_vector_alloc (nparas);
for (i=0;i<nparas;i++)
gsl_vector_set (paras, i, initial_p[i]);
/* Initialise algorithm parameters */
size_t iter = 0;
int status;
double size;
/* Set initial STEP SIZES to 1 */
gsl_vector *ss;
ss = gsl_vector_alloc (nparas);
gsl_vector_set_all (ss, 0.5);
const gsl_multimin_fminimizer_type *T = gsl_multimin_fminimizer_nmsimplex;
gsl_multimin_fminimizer *s = NULL;
gsl_multimin_function minex_func;
/* Initialize method and iterate */
minex_func.n = nparas;
minex_func.f = my_f;
minex_func.params = &myStruct;
s = gsl_multimin_fminimizer_alloc (T, nparas);
There are no problem until here but the next line generates this error:
gsl: simplex.c:288: ERROR: non-finite function value encountered
Default GSL error handler invoked.
Aborted (core dumped)
gsl_multimin_fminimizer_set (s, &minex_func, paras, ss);
do {
iter++;
status = gsl_multimin_fminimizer_iterate(s);
if (status)
break;
size = gsl_multimin_fminimizer_size (s);
status = gsl_multimin_test_size (size, 1);
if (status == GSL_SUCCESS)
printf ("converged to minimum at\n");
for (int z = 0 ; z<14 ; z++)
{
cout <<gsl_vector_get (s->x, z)<<endl;
}
}
while (status == GSL_CONTINUE && iter < 10000);
gsl_multimin_fminimizer_free (s);
gsl_vector_free(myStruct.Rmom);
gsl_vector_free(myStruct.Rm);
gsl_vector_free(paras);
gsl_vector_free(ss);
return status;
}
Related
2nd task:
For a function f : R^n → R the gradient at a point ~x ∈ R^n is to be calculated:
- Implement a function
CMyVector gradient(CMyVector x, double (*function)(CMyVector x)),
which is given in the first parameter the location ~x and in the second parameter the function f as function pointer in the second parameter, and which calculates the gradient ~g = grad f(~x) numerically
by
gi = f(x1, . . . , xi-1, xi + h, xi+1 . . . , xn) - f(x1, . . . , xn)/h
to fixed h = 10^-8.
My currently written program:
Header
#pragma once
#include <vector>
#include <math.h>
class CMyVektor
{
private:
/* data */
int Dimension = 0;
std::vector<double>Vector;
public:
CMyVektor();
~CMyVektor();
//Public Method
void set_Dimension(int Dimension /* Aktuelle Dim*/);
void set_specified_Value(int index, int Value);
double get_specified_Value(int key);
int get_Vector_Dimension();
int get_length_Vektor();
double& operator [](int index);
string umwandlung()
};
CMyVektor::CMyVektor(/* args */)
{
Vector.resize(0, 0);
}
CMyVektor::~CMyVektor()
{
for (size_t i = 0; i < Vector.size(); i++)
{
delete Vector[i];
}
}
void CMyVektor::set_Dimension(int Dimension /* Aktuelle Dim*/)
{
Vector.resize(Dimension);
};
void CMyVektor::set_specified_Value(int index, int Value)
{
if (Vector.empty())
{
Vector.push_back(Value);
}
else {
Vector[index] = Value;
}
};
double CMyVektor::get_specified_Value(int key)
{
// vom intervall anfang - ende des Vectors
for (unsigned i = 0; i < Vector.size(); i++)
{
if (Vector[i] == key) {
return Vector[i];
}
}
};
int CMyVektor::get_Vector_Dimension()
{
return Vector.size();
};
// Berechnet den Betrag "länge" eines Vectors.
int CMyVektor::get_length_Vektor()
{
int length = 0;
for (size_t i = 0; i < Vector.size(); i++)
{
length += Vector[i]^2
}
return sqrt(length);
}
// [] Operator überladen
double& CMyVektor::operator [](int index)
{
return Vector[index];
}
main.cpp
#include <iostream>
#include "ClassVektor.h"
using namespace std;
CMyVektor operator+(CMyVektor a, CMyVektor b);
CMyVektor operator*(double lambda, CMyVektor a);
CMyVektor gradient(CMyVektor x, double (*funktion)(CMyVektor x));
int main() {
CMyVektor V1;
CMyVektor V2;
CMyVektor C;
C.set_Dimension(V1.get_length_Vector());
C= V1 + V2;
std::cout << "Addition : "<< "(";;
for (int i = 0; i < C.get_length_Vector(); i++)
{
std::cout << C[i] << " ";
}
std::cout << ")" << endl;
C = lamda * C;
std::cout << "Skalarprodukt: "<< C[0]<< " ";
}
// Vector Addition
CMyVektor operator+(CMyVektor a, CMyVektor b)
{
int ai = 0, bi = 0;
int counter = 0;
CMyVektor c;
c.set_Dimension(a.get_length_Vector());
// Wenn Dimension Gleich dann addition
if (a.get_length_Vector() == b.get_length_Vector())
{
while (counter < a.get_length_Vector())
{
c[counter] = a[ai] + b[bi];
counter++;
}
return c;
}
}
//Berechnet das Skalarprodukt
CMyVektor operator*(double lambda, CMyVektor a)
{
CMyVektor c;
c.set_Dimension(1);
for (unsigned i = 0; i < a.get_length_Vector(); i++)
{
c[0] += lambda * a[i];
}
return c;
}
/*
* Differenzenquotient : (F(x0+h)+F'(x0)) / h
* Erster Parameter die Stelle X - Zweiter Parameter die Funktion
* Bestimmt numerisch den Gradienten.
*/
CMyVektor gradient(CMyVektor x, double (*funktion)(CMyVektor x))
{
}
My problem now is that I don't quite know how to deal with the
CMyVector gradient(CMyVector x, double (*function)(CMyVector x))
function and how to define a function that corresponds to it.
I hope that it is enough information. Many thanks.
The function parameter is the f in the difference formula. It takes a CMyVector parameter x and returns a double value. You need to supply a function parameter name. I'll assume func for now.
I don't see a parameter for h. Are you going to pass a single small value into the gradient function or assume a constant?
The parameter x is a vector. Will you add a constant h to each element?
This function specification is a mess.
Function returns a double. How do you plan to turn that into a vector?
No wonder you're confused. I am.
Are you trying to do something like this?
You are given a function signature
CMyVector gradient(CMyVector x, double (*function)(CMyVector x))
Without knowing the exact definition I will assume, that at least the basic numerical vector operations are defined. That means, that the following statements compile:
CMyVector x {2.,5.,7.};
CMyVector y {1.,7.,4.};
CMyVector z {0.,0.,0.};
double a = 0.;
// vector addition and assigment
z = x + y;
// vector scalar multiplication and division
z = z * a;
z = x / 0.1;
Also we need to know the dimension of the CMyVector class. I assumed and will continue to do so that it is three dimensional.
The next step is to understand the function signature. You get two parameters. The first one denotes the point, at which you are supposed to calculate the gradient. The second is a pointer to the function f in your formula. You do not know it, but can call it on a vector from within your gradient function definition. That means, inside of the definition you can do something like
double f_at_x = function(x);
and the f_at_x will hold the value f(x) after that operation.
Armed with this, we can try to implement the formula, that you mentioned in the question title:
CMyVector gradient(CMyVector x, double (*function)(CMyVector x)) {
double h = 0.001;
// calculate first element of the gradient
CMyVector e1 {1.0, 0.0, 0.0};
double result1 = ( function(x + e1*h) - function(x) )/h;
// calculate second element of the gradient
CMyVector e2 {0.0, 1.0, 0.0};
double result2 = ( function(x + e2*h) - function(x) )/h;
// calculate third element of the gradient
CMyVector e3 {0.0, 0.0, 1.0};
double result3 = ( function(x + e3*h) - function(x) )/h;
// return the result
return CMyVector {result1, result2, result3};
}
There are several thing worth to mention in this code. First and most important I have chosen h = 0.001. This may like a very arbitrary choice, but the choice of the step size will very much impact the precision of your result. You can find a whole lot of discussion about that topic here. I took the same value that according to that wikipedia page a lot of handheld calculators use internally. That might not be the best choice for the floating point precision of your processor, but should be a fair one to start with.
Secondly the code looks very ugly for an advanced programmer. We are doing almost the same thing for each of the three dimensions. Ususally you would like to do that in a for loop. The exact way of how this is done depends on how the CMyVector type is defined.
Since the CMyVektor is just rewritting the valarray container, I will directly use the valarray:
#include <iostream>
#include <valarray>
using namespace std;
using CMyVektor = valarray<double>;
CMyVektor gradient(CMyVektor x, double (*funktion)(CMyVektor x));
const double h = 0.00000001;
int main()
{
// sum(x_i^2 + x_i)--> gradient: 2*x_i + 1
auto fun = [](CMyVektor x) {return (x*x + x).sum();};
CMyVektor d = gradient(CMyVektor{1,2,3,4,5}, fun);
for (auto i: d) cout << i<<' ';
return 0;
}
CMyVektor gradient(CMyVektor x, double (*funktion)(CMyVektor x)){
CMyVektor grads(x.size());
CMyVektor pos(x.size());
for (int i = 0; i<x.size(); i++){
pos[i] = 1;
grads[i] = (funktion(x + h * pos) - funktion(x))/ h;
pos[i] = 0;
}
return grads;
}
The prints out 3 5 7 9 11 which is what is expected from the given function and the given location
I'm using CppAD with Ipopt. In some places I have to typecast the AD format to its base format that is double. I have used CppAD::Value(AD var) it gives me output in double format.
But considering line no.27 the code is fine during compile time. Its showing the following error in runtime. The error is :
cppad-20160000.1 error from a known source:
Value: argument is a variable (not a parameter)
Error detected by false result for
Parameter(x)
at line 89 in the file
/usr/include/cppad/local/value.hpp
I have attached the code I'm running for verification. Kindly help. please install Ipopt before running the code.
The type of value is still CppAD::AD . But the Value() is not working.
#include <cppad/ipopt/solve.hpp>
#include <iostream>
namespace {
using CppAD::AD;
class FG_eval {
public:
typedef CPPAD_TESTVECTOR( AD<double> ) ADvector;
void operator()(ADvector& fg, const ADvector& x)
{ assert( fg.size() == 3 );
assert( x.size() == 4 );
// Fortran style indexing
AD<double> x1 = x[0];
AD<double> x2 = x[1];
AD<double> x3 = x[2];
AD<double> x4 = x[3];
// f(x)
fg[0] = x1 * x4 * (x1 + x2 + x3) + x3;
// g_1 (x)
fg[1] = x1 * x2 * x3 * x4;
// g_2 (x)
fg[2] = x1 * x1 + x2 * x2 + x3 * x3 + x4 * x4;
// help on this line
std::cout << CppAD::Value(x1) << std::endl;
//
return;
}
};
}
bool get_started()
{ bool ok = true;
size_t i;
typedef CPPAD_TESTVECTOR( double ) Dvector;
// number of independent variables (domain dimension for f and g)
size_t nx = 4;
// number of constraints (range dimension for g)
size_t ng = 2;
// initial value of the independent variables
Dvector xi(nx);
xi[0] = 1.0;
xi[1] = 5.0;
xi[2] = 5.0;
xi[3] = 1.0;
// lower and upper limits for x
Dvector xl(nx), xu(nx);
for(i = 0; i < nx; i++)
{ xl[i] = 1.0;
xu[i] = 5.0;
}
// lower and upper limits for g
Dvector gl(ng), gu(ng);
gl[0] = 25.0; gu[0] = 1.0e19;
gl[1] = 40.0; gu[1] = 40.0;
// object that computes objective and constraints
FG_eval fg_eval;
// options
std::string options;
// turn off any printing
options += "Integer print_level 0\n";
options += "String sb yes\n";
// maximum number of iterations
options += "Integer max_iter 10\n";
// approximate accuracy in first order necessary conditions;
// see Mathematical Programming, Volume 106, Number 1,
// Pages 25-57, Equation (6)
options += "Numeric tol 1e-6\n";
// derivative testing
options += "String derivative_test second-order\n";
// maximum amount of random pertubation; e.g.,
// when evaluation finite diff
options += "Numeric point_perturbation_radius 0.\n";
// place to return solution
CppAD::ipopt::solve_result<Dvector> solution;
// solve the problem
CppAD::ipopt::solve<Dvector, FG_eval>(
options, xi, xl, xu, gl, gu, fg_eval, solution
);
//
// Check some of the solution values
//
ok &= solution.status == CppAD::ipopt::solve_result<Dvector>::success;
//
double check_x[] = { 1.000000, 4.743000, 3.82115, 1.379408 };
double check_zl[] = { 1.087871, 0., 0., 0. };
double check_zu[] = { 0., 0., 0., 0. };
double rel_tol = 1e-6; // relative tolerance
double abs_tol = 1e-6; // absolute tolerance
for(i = 0; i < nx; i++)
{ ok &= CppAD::NearEqual(
check_x[i], solution.x[i], rel_tol, abs_tol
);
ok &= CppAD::NearEqual(
check_zl[i], solution.zl[i], rel_tol, abs_tol
);
ok &= CppAD::NearEqual(
check_zu[i], solution.zu[i], rel_tol, abs_tol
);
}
return ok;
}
int main()
{
get_started();
return 0;
}
cmakelists.txt
cmake_minimum_required(VERSION 3.5)
project(jnk)
add_compile_options(-std=c++11)
add_executable(${PROJECT_NAME} testCppAD.cpp)
target_link_libraries(${PROJECT_NAME}
ipopt z uv
)
I found out the answer. We have to use an inbuilt function CppAD::Var2Par() before using CppAD::Value(). Will work.
I am trying to solve an ODE using 4th Order Runge Kutta and the 4th Order Adams-Moulton Method. I iterate over a couple of thousand timesteps and it seems to hold fine when the values are constant(first 50 or so) However, the very first iteration when a change in input value jumps(current(I) changes from 0 to 1) it won't converge.
In order to satisfy the 4th Order Adams-Moulton Method I have split each timestep in the main function into 5 smaller timesteps so the 5th inner step will equal the next time step (0.1s) in the main function.
I will be very grateful for any advice/help!!
The code is below
#include <iostream>
#include <cmath>
using namespace std;
double state_deriv(double Vc,double I, double OCV1, double C, double Rct)
{
double newVc = (OCV1 - Vc) / (C * Rct) - (I / C);
return newVc;
}
double predict(double Vc,double Vc_[],double dt,double I_[],double OCV1_[],double C_[],double Rct_[])
{
double fn[4];
fn[0] = state_deriv(Vc_[0], I_[0],OCV1_[0],C_[0],Rct_[0]);
fn[1] = state_deriv(Vc_[1], I_[1],OCV1_[1],C_[1],Rct_[1]);
fn[2] = state_deriv(Vc_[2], I_[2],OCV1_[2],C_[2],Rct_[2]);
fn[3] = state_deriv(Vc_[3], I_[3],OCV1_[3],C_[3],Rct_[3]);
// value of next y(predicted) is returned
double y1p = Vc_[3] + (dt/24)*(55*fn[3] - 59*fn[2] + 37 *fn[1] - 9 *fn[0]);
return y1p;
}
double correct(double Vc,double Vc_[],double Vc1,double dt,double I_[],double OCV1_[],double C_[],double Rct_[])
{
double e = 0.0001;
double Vc1c = Vc1;
double fn[4];
fn[1] = state_deriv(Vc_[1], I_[1],OCV1_[1],C_[1],Rct_[1]);
fn[2] = state_deriv(Vc_[2], I_[2],OCV1_[2],C_[2],Rct_[2]);
fn[3] = state_deriv(Vc_[3], I_[3],OCV1_[3],C_[3],Rct_[3]);
do {
Vc1 = Vc1c;
fn[4] = state_deriv(Vc1, I_[4],OCV1_[4],C_[4],Rct_[4]);
Vc1c = Vc_[3] + dt/24*(9*fn[4] + 19*fn[3] - 5*fn[2] + fn[1]);
} while (fabs(Vc1c - Vc1) > e);
// every iteration is correcting the value
// of state deriv using average slope
return Vc1c;
}
double predictor_corrector(double Vc, double dt, double I[], double* OCV1, double* C, double* Rct)
{
//double x = time[0];
//double xn = time[1];
double h = dt;
//4th order RKK TO predict 4 values
double I_[4],OCV1_[5],C_[5],Rct_[5];
I_[0] = I[0];
OCV1_[0] = OCV1[0];
C_[0] = *C;
Rct_[0] = *Rct;
I_[4] = I[1];
OCV1_[4] = OCV1[1];
C_[4] = *C;
Rct_[4] = *Rct;
double newdt;
for(int i = 1;i<4;i++){
newdt = i * dt/5;
I_[i] = I_[0] + (I[1]-I[0]) * (newdt/dt);
OCV1_[i] = OCV1_[0] + (OCV1[1] - OCV1[0])*(newdt/dt);
Rct_[i] = *Rct;
C_[i] = *C;
}
//now do rk4 on each step
double k1,k2,k3,k4;
double Vc_[4];
Vc_[0] = Vc;
for(int i = 1;i<4;i++) {
// 4th order runge kutta
k1 = dt/4 * state_deriv(Vc_[i-1], *I, *OCV1, *C, *Rct);
k2 = dt/4 * state_deriv(Vc_[i-1]+k1/2.0, I_[i], OCV1_[i], *C, *Rct);
k3 = dt/4 * state_deriv(Vc_[i-1]+k2/2.0, I_[i], OCV1_[i], *C, *Rct);
k4 = dt/4 * state_deriv(Vc_[i-1]+k3, I_[i], OCV1_[i], *C, *Rct);
Vc_[i] = Vc_[i-1] + (1.0 / 6.0) * (k1 + 2 * k2 + 2 * k3 + k4);
}
double y1p = predict(Vc,Vc_,dt/4,I_,OCV1_,C_,Rct_);
double y1c = correct(Vc,Vc_,y1p,dt/4,I_,OCV1_,C_,Rct_);
Vc = y1c;
cout << Vc << endl;
return Vc;
}
int main()
{
double R1 = 0.0315973;
double C = 0.00100284;
double Vc[5];
double OCV1[5];
double I[5];
Vc[0] = 4.15;
double dt = 0.1;
for(int i=0;i<3;i++){
OCV1[i] = 4.15;
I[i] = 0;
}
I[3]=I[4]=1;
OCV1[3] = 4.13;
OCV1[4] = 4.10;
double I_[2];
for(size_t i=1;i<4;i++){
Vc[i] = predictor_corrector(Vc[i-1],dt,&I[i-1],&OCV1[i-1],&C,&R1);
}
}
When using Rcpp,I create a function named rpois_rcpp and l try to call it below in genDataList function, an error occurs and said :
"no matching function for call to 'cpprbinom',
candidate function not viable: no known conversion from 'arma::vec' (aka 'Col') to 'Rcpp::NumericVector' (aka 'Vector<14>') for 3rd argument
arma::vec cpprbinom(int n, double size, NumericVector prob).
Can someone help me ,thanks!
Here is my code:
//create a random matrix X with covariance matrix sigma
// [[Rcpp::export]]
arma::mat mvrnormArma(const int n, arma::vec mu, const int p, const
double rho) {
arma::mat sigma(p, p, arma::fill::zeros);
for (int i = 0; i < sigma.n_rows; ++i) {
for (int j = 0; j < sigma.n_cols; ++j) {
sigma(i,j) = pow(rho, abs((i + 1) - (j + 1)));
}
}
int ncols = sigma.n_cols;
arma::mat Y = arma::randn(n, ncols);
return arma::repmat(mu, 1, n).t() + Y * arma::chol(sigma);
}
//create a vector sampled from poisson distribution with mean vector
//lambda
// [[Rcpp::export]]
arma::vec rpois_rcpp( NumericVector &lambda) {
int n= lambda.length();
unsigned int lambda_i = 0;
IntegerVector sim(n);
for (unsigned int i = 0; i < n; i++) {
sim[i] = R::rpois(lambda[lambda_i]);
// update lambda_i to match next realized value with correct mean
lambda_i++;
}
return as<arma::vec>(sim);
}
//create a vector sampled from binomial distribution with probability
vector prob
// [[Rcpp::export]]
arma::vec cpprbinom(int n, double size, NumericVector prob) {
NumericVector v = no_init(n);
std::transform( prob.begin(), prob.end(), v.begin(), [=](double p){
return R::rbinom(size, p); });
return as<arma::vec>(v);}
// [[Rcpp::export]]44
List genDataList(int n, arma::vec& mu, int p, double rho,
arma::vec& beta, const double SNR, const std::string &
Test_case) {
arma::mat U, V, data, normData, Projection;
arma::vec s, y, means, noise;
data = mvrnormArma(n, mu, p, rho);
normData = arma::normalise(data,2,0);
arma::svd_econ(U,s,V,normData,"right");
Projection = V * trans(V);
beta = Projection * beta;
if(Test_case == "gaussian")
{
means=normData * beta;
y = means + arma::randn(n) * sqrt(arma::var(means) / SNR);}
else if (Test_case == "poisson")
{
means=exp(normData * beta);
y = rpois_rcpp(means);}
else
{
means=exp(normData * beta)/(1 + exp(normData * beta));
y = cpprbinom(n,1,means);}
List ret;
ret["data"] = data;
ret["normData"] = normData;
ret["V"] = V;
ret["beta"] = beta;
ret["y"] = y;
return ret;
}
Thanks for adding your code. When I tried to compile, I got the same error as you, but also an error for the line calling rpois_rcpp()
invalid initialization of reference to type 'Rcpp::NumericVector&'
Pretty much everything seems to be in arma, except the R bindings and calls to the R:: namespace, which takes doubles, ints, etc. It seems the easiest thing to do (to my mind), is just take arma::vec as arguments instead:
arma::vec rpois_rcpp( arma::vec &lambda) {
int n= lambda.n_elem;
and
arma::vec cpprbinom(int n, double size, arma::vec prob) {
You never utilize the fact that lambda and prob are Rcpp::NumericVectors specifically, you just use doubles from them, so this seems the easiest route to me. After those changes, your code compiles fine on my machine. I don't have any test cases to make sure they run as you'd expect, but I imagine they will.
I have written a program to approximate the solutions to ordinary differential equations using Adam's Method.
Running the program with gdb gives me:
Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_PROTECTION_FAILURE at address: 0x00007fff5f3ffff8
0x0000000100003977 in std::vector<double, std::allocator<double> >::push_back (this=0x100005420, __x=#0x100005310) at stl_vector.h:604
604 this->_M_impl.construct(this->_M_impl._M_finish, __x);
Clearly something is wrong with my treatment of vector.push_back, but I do not know where to begin looking. I can not think of a case where modifying a vector is illegal.
Call differentiate() to begin. Mathematics is done in step(). Adaptive time advancing across an interval with advance(). Check the chosen time step with checkdt() before running step() again.
Sorry for the huge code dump. I am sure many improvements can be made purely from the standpoint of C++, without knowledge of the mathematics:
//============================================================================
// Description : An Adam's Method Ordinary Differential Equation Approximation
// Disclaimer : Posted to StackOverflow for help on a segmentation fault
//============================================================================
#include <iostream> //IO
#include <vector> //std::vector
#include <cmath> //abs, pow, sqrt
#include <numeric> //accumulate
using namespace std;
/* Terminology:
* f(t, y) = the ordinary differential equation that will be solved
* y(t) = solution of f at point t.
* told = the previous point at which f was evaluated and solved
* tnow = the current point at which f is evaluated and solved
* tnew = the new (interesting) point at which f will be evaluated and solved
*
* Yold = the corrected solution of the differential equation at told
* Ynow = the corrected solution of the differential equation at tnow
* Ynew = the corrected solution of the differential equation at tnew
*
* fold = the value of the given differential equation at told
= f(told, Yold)
* fnow = the value of the given differential equation at tnow
= f(tnow, Ynow)
* fnew = the value of the given differential equation at tnew
= f(tnew, Ynew)
*
* Pnew = prediction for the value of Ynew
* dt = abs(tnew - tnow)
* dtold = abs(tnow - told)
*/
//Information storage
struct simTime {
double told;
double tnow;
double tnew;
double dt;
double dtold;
double tol;
double agrow;
double ashrink;
double dtmin;
double dtmax;
double endTime;
double fold;
double fnow;
double fnew;
double Yold;
double Ynow;
double Ynew;
double Pnew;
int stepsSinceRejection;
int stepsRejected;
int stepsAccepted;
} test;
//Define global variables
std::vector<double> errorIndicators(0);
std::vector<double> solutions(0);
std::vector<double> differencesDDY(0);
std::vector<double> differencesDDYSquared(0);
std::vector<double> timesTNew(0);
//Function declarations
void step(double fnow, double fold, double Ynow, double tnew, double tnow,
double dtold, double dt, double(*f)(double t, double y), double told);
void advance();
void shiftvariables();
void printvector(std::vector<double>& vec);
void differentiate(double(*f)(double t, double y), double y0, double a,
double b);
double f(double t, double y);
void checkdt();
int main() {
differentiate(f, 0, 1, 5);
cout << "Time values:" << endl;
printvector(timesTNew);
cout << "Solutions:" << endl;
printvector(solutions);
cout << "Differences between Prediction and Solution:" << endl;
printvector(differencesDDY);
return 0;
}
//Shift back all the variables to make way for the new values
void shiftvariables() {
test.tnow = test.tnew;
test.dtold = test.dt;
test.Yold = test.Ynow;
test.Ynow = test.Ynew;
test.fold = test.fnow;
test.fnow = test.fnew;
advance();
}
//Ordinary differential equation to be solved
double f(double t, double y) {
return pow(t, 2);
}
//Calculate the predicted and corrected solution at a chosen tnew
void step(double fnow, double fold, double Ynow, double tnew, double tnow,
double dtold, double dt, double(*f)(double t, double y), double told) {
//The calculation for Ynew requires integration. I first thought I would need to
// use my project 1 code to calculate the integration, but now I see in class we
// solved it analytically such that integration is not required:
//Linear prediction of Ynew using Ynow and fnow
double Pnew = Ynow + (dt * fnow) + (dt * dt / (2 * dtold)) * (fnow - fold);
test.Pnew = Pnew;
//Predict the value of f at tnew using Pnew
double fnew = f(tnew, Pnew);
test.fnew = fnew;
//Calculate the corrected solution at tnew
double interpolationFactor = fnew - (fnow + dt * (fnow - fold) / dtold);
double integration = (dt / 6) * (2 * dt + 3 * dtold) / (dt + dtold);
double Ynew = Pnew + interpolationFactor * integration;
test.Ynew = Ynew;
//Update the variables for the next round
shiftvariables();
}
//Check the previous solution and choose a new dt to continue evaluation
void advance() {
//The error indicator is the l2-norm of the prediction minus the correction
double err_ind = sqrt(
std::accumulate(differencesDDYSquared.begin(),
differencesDDYSquared.end(), 0));
errorIndicators.push_back(err_ind);
// Case where I reject the step and retry
if (err_ind > test.tol && test.dt > test.dtmin) {
++test.stepsRejected;
test.stepsSinceRejection = 0;
test.dt = test.dt * 0.5;
test.tnew = test.tnow + test.dt;
checkdt();
}
// Cases where I accept the step and move forward
else {
++test.stepsAccepted;
++test.stepsSinceRejection;
solutions.push_back(test.Ynew);
differencesDDY.push_back(abs(test.Pnew - test.Ynew));
differencesDDYSquared.push_back(pow((test.Pnew - test.Ynew), 2));
//Decrease dt
if (err_ind >= 0.75 * test.tol) {
test.dtold = test.dt;
test.dt = (test.dt * test.ashrink);
test.tnew = test.tnow + test.dt;
checkdt();
}
//Increase dt
else if (err_ind <= test.tol / 4) {
if ((test.stepsRejected != 0) && (test.stepsSinceRejection >= 2)) {
test.dt = (test.dt * test.agrow);
test.tnew = test.tnow + test.dt;
checkdt();
} else if (test.stepsRejected == 0) {
test.dt = (test.dt * test.agrow);
test.tnew = test.tnow + test.dt;
checkdt();
}
}
}
}
//Check that the dt chosen by advance is acceptable
void checkdt() {
if ((test.tnew < test.endTime) && (test.endTime - test.tnew < test.dtmin)) {
cout << "Reached endTime." << endl;
} else if (test.dt < test.dtmin) {
test.dt = test.dtmin;
test.tnew = test.tnow + test.dt;
timesTNew.push_back(test.tnew);
step(test.fnow, test.fold, test.Ynow, test.tnew, test.tnow, test.dtold,
test.dt, f, test.told);
} else if (test.dt > test.dtmax) {
test.dt = test.dtmax;
test.tnew = test.tnow + test.dt;
timesTNew.push_back(test.tnew);
step(test.fnow, test.fold, test.Ynow, test.tnew, test.tnow, test.dtold,
test.dt, f, test.told);
} else if ((test.tnew + test.dt) > test.endTime) {
test.dt = test.endTime - test.tnew;
test.tnew = test.tnow + test.dt;
checkdt();
} else if (((test.tnew + test.dt) < test.endTime)
&& ((test.tnew + 2 * test.dt) > test.endTime)) {
test.dt = (test.endTime - test.tnew) / 2;
test.tnew = test.tnow + test.dt;
checkdt();
}
//If none of the above are satisfied, then the chosen dt
// is ok and proceed with it
else {
timesTNew.push_back(test.tnew);
step(test.fnow, test.fold, test.Ynow, test.tnew, test.tnow, test.dtold,
test.dt, f, test.told);
}
}
//meta function to solve a differential equation, called only once
void differentiate(double(*f)(double t, double y), double y0, double a,
double b) {
//Set the starting conditions for the solving of the differential equation
test.fnow = f(a, y0);
test.endTime = b;
test.Ynow = y0;
//solutions.push_back(y0);
timesTNew.push_back(a);
//Set the constants
test.ashrink = 0.8;
test.agrow = 1.25;
test.dtmin = 0.05;
test.dtmax = 0.5;
test.tol = 0.1;
//Set fold = fnow for the first step
test.fold = test.fnow;
test.tnow = a;
test.told = a - test.dtmin;
test.dtold = abs(test.tnow - test.told);
//Create the first prediction, which will then lead to correcting it with step
advance();
}
// Takes a vector as its only parameters and prints it to stdout
void printvector(std::vector<double>& vec) {
for (vector<double>::iterator it = vec.begin(); it != vec.end(); ++it) {
cout << *it << ", ";
}
cout << "\n";
}
Thank you.
Since you're using recursion, could it be possible that you are running out of stack memory, thus causing the segfault? This could happen if either your app recurses too many times or if some bug causes it to recurse infinitely.
Note, as sth suggests in a comment, a debugger may help you decide whether or not this is the case.