AlgLib_ver3.19/diffequations.mqh
super.admin 9e263d779c convert
2025-05-30 14:39:48 +02:00

849 lines
32 KiB
MQL5

//+------------------------------------------------------------------+
//| diffequations.mqh |
//| Copyright 2003-2022 Sergey Bochkanov (ALGLIB project) |
//| Copyright 2012-2023, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
//| Implementation of ALGLIB library in MetaQuotes Language 5 |
//| |
//| The features of the library include: |
//| - Linear algebra (direct algorithms, EVD, SVD) |
//| - Solving systems of linear and non-linear equations |
//| - Interpolation |
//| - Optimization |
//| - FFT (Fast Fourier Transform) |
//| - Numerical integration |
//| - Linear and nonlinear least-squares fitting |
//| - Ordinary differential equations |
//| - Computation of special functions |
//| - Descriptive statistics and hypothesis testing |
//| - Data analysis - classification, regression |
//| - Implementing linear algebra algorithms, interpolation, etc. |
//| in high-precision arithmetic (using MPFR) |
//| |
//| This file is free software; you can redistribute it and/or |
//| modify it under the terms of the GNU General Public License as |
//| published by the Free Software Foundation (www.fsf.org); either |
//| version 2 of the License, or (at your option) any later version. |
//| |
//| This program is distributed in the hope that it will be useful, |
//| but WITHOUT ANY WARRANTY; without even the implied warranty of |
//| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
//| GNU General Public License for more details. |
//+------------------------------------------------------------------+
#include "matrix.mqh"
#include "alglibinternal.mqh"
//+------------------------------------------------------------------+
//| Auxiliary class for CODESolver |
//+------------------------------------------------------------------+
class CODESolverState
{
public:
int m_n;
int m_m;
double m_xscale;
double m_h;
double m_eps;
bool m_fraceps;
int m_repterminationtype;
int m_repnfev;
int m_solvertype;
bool m_needdy;
double m_x;
RCommState m_rstate;
//--- arrays
double m_yc[];
double m_escale[];
double m_xg[];
double m_y[];
double m_dy[];
double m_yn[];
double m_yns[];
double m_rka[];
double m_rkc[];
double m_rkcs[];
//--- matrices
CMatrixDouble m_ytbl;
CMatrixDouble m_rkb;
CMatrixDouble m_rkk;
public:
CODESolverState(void);
~CODESolverState(void) {}
void Copy(CODESolverState &obj);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CODESolverState::CODESolverState(void)
{
m_n=0;
m_m=0;
m_xscale=0;
m_h=0;
m_eps=0;
m_fraceps=false;
m_repterminationtype=0;
m_repnfev=0;
m_solvertype=0;
m_needdy=false;
m_x=0;
}
//+------------------------------------------------------------------+
//| Copy |
//+------------------------------------------------------------------+
void CODESolverState::Copy(CODESolverState &obj)
{
//--- copy variables
m_n=obj.m_n;
m_m=obj.m_m;
m_xscale=obj.m_xscale;
m_h=obj.m_h;
m_eps=obj.m_eps;
m_fraceps=obj.m_fraceps;
m_repterminationtype=obj.m_repterminationtype;
m_repnfev=obj.m_repnfev;
m_solvertype=obj.m_solvertype;
m_needdy=obj.m_needdy;
m_x=obj.m_x;
m_rstate.Copy(obj.m_rstate);
//--- copy arrays
ArrayCopy(m_yc,obj.m_yc);
ArrayCopy(m_escale,obj.m_escale);
ArrayCopy(m_xg,obj.m_xg);
ArrayCopy(m_y,obj.m_y);
ArrayCopy(m_dy,obj.m_dy);
ArrayCopy(m_yn,obj.m_yn);
ArrayCopy(m_yns,obj.m_yns);
ArrayCopy(m_rka,obj.m_rka);
ArrayCopy(m_rkc,obj.m_rkc);
ArrayCopy(m_rkcs,obj.m_rkcs);
//--- copy matrices
m_ytbl=obj.m_ytbl;
m_rkb=obj.m_rkb;
m_rkk=obj.m_rkk;
}
//+------------------------------------------------------------------+
//| This class is a shell for class CODESolverState |
//+------------------------------------------------------------------+
class CODESolverStateShell
{
private:
CODESolverState m_innerobj;
public:
//--- constructors, destructor
CODESolverStateShell(void) {}
CODESolverStateShell(CODESolverState &obj) { m_innerobj.Copy(obj); }
~CODESolverStateShell(void) {}
//--- methods
bool GetNeedDY(void);
void SetNeedDY(const bool b);
double GetX(void);
void SetX(const double d);
CODESolverState *GetInnerObj(void);
};
//+------------------------------------------------------------------+
//| Returns the value of the variable needdy |
//+------------------------------------------------------------------+
bool CODESolverStateShell::GetNeedDY(void)
{
return(m_innerobj.m_needdy);
}
//+------------------------------------------------------------------+
//| Changing the value of the variable needdy |
//+------------------------------------------------------------------+
void CODESolverStateShell::SetNeedDY(const bool b)
{
m_innerobj.m_needdy=b;
}
//+------------------------------------------------------------------+
//| Returns the value of the variable x |
//+------------------------------------------------------------------+
double CODESolverStateShell::GetX(void)
{
return(m_innerobj.m_x);
}
//+------------------------------------------------------------------+
//| Changing the value of the variable x |
//+------------------------------------------------------------------+
void CODESolverStateShell::SetX(const double d)
{
m_innerobj.m_x=d;
}
//+------------------------------------------------------------------+
//| Return object of class |
//+------------------------------------------------------------------+
CODESolverState *CODESolverStateShell::GetInnerObj(void)
{
return(GetPointer(m_innerobj));
}
//+------------------------------------------------------------------+
//| Auxiliary class for CODESolver |
//+------------------------------------------------------------------+
class CODESolverReport
{
public:
//--- class variables
int m_nfev;
int m_terminationtype;
//--- constructor, destructor
CODESolverReport(void) { ZeroMemory(this); }
~CODESolverReport(void) {}
//--- copy
void Copy(CODESolverReport &obj);
};
//+------------------------------------------------------------------+
//| Copy |
//+------------------------------------------------------------------+
void CODESolverReport::Copy(CODESolverReport &obj)
{
//--- copy variables
m_nfev=obj.m_nfev;
m_terminationtype=obj.m_terminationtype;
}
//+------------------------------------------------------------------+
//| This class is a shell for class CODESolverReport |
//+------------------------------------------------------------------+
class CODESolverReportShell
{
private:
CODESolverReport m_innerobj;
public:
//--- constructor, destructor
CODESolverReportShell(void) {}
CODESolverReportShell(CODESolverReport &obj) { m_innerobj.Copy(obj); }
~CODESolverReportShell(void) {}
//--- methods
int GetNFev(void);
void SetNFev(const int i);
int GetTerminationType(void);
void SetTerminationType(const int i);
CODESolverReport *GetInnerObj(void);
};
//+------------------------------------------------------------------+
//| Returns the value of the variable nfev |
//+------------------------------------------------------------------+
int CODESolverReportShell::GetNFev(void)
{
return(m_innerobj.m_nfev);
}
//+------------------------------------------------------------------+
//| Changing the value of the variable nfev |
//+------------------------------------------------------------------+
void CODESolverReportShell::SetNFev(const int i)
{
m_innerobj.m_nfev=i;
}
//+------------------------------------------------------------------+
//| Returns the value of the variable terminationtype |
//+------------------------------------------------------------------+
int CODESolverReportShell::GetTerminationType(void)
{
return(m_innerobj.m_terminationtype);
}
//+------------------------------------------------------------------+
//| Changing the value of the variable terminationtype |
//+------------------------------------------------------------------+
void CODESolverReportShell::SetTerminationType(const int i)
{
m_innerobj.m_terminationtype=i;
}
//+------------------------------------------------------------------+
//| Return object of class |
//+------------------------------------------------------------------+
CODESolverReport *CODESolverReportShell::GetInnerObj(void)
{
return(GetPointer(m_innerobj));
}
//+------------------------------------------------------------------+
//| Solution of ordinary differential equations |
//+------------------------------------------------------------------+
class CODESolver
{
public:
//--- class constants
static const double m_odesolvermaxgrow;
static const double m_odesolvermaxshrink;
//--- public methods
static void ODESolverRKCK(double &y[],const int n,double &x[],const int m,const double eps,const double h,CODESolverState &state);
static void ODESolverResults(CODESolverState &state,int &m,double &xtbl[],CMatrixDouble &ytbl,CODESolverReport &rep);
static bool ODESolverIteration(CODESolverState &state);
private:
//--- private method
static void ODESolverInit(int solvertype,double &y[],const int n,double &x[],const int m,const double eps,double h,CODESolverState &state);
//--- auxiliary functions for ODESolverIteration
static void Func_lbl_rcomm(CODESolverState &state,int n,int m,int i,int j,int k,int klimit,bool gridpoint,double xc,double v,double h,double h2,double err,double maxgrowpow);
static bool Func_lbl_6(CODESolverState &state,int &n,int &m,int &i,int &j,int &k,int &klimit,bool &gridpoint,double &xc,double &v,double &h,double &h2,double &err,double &maxgrowpow);
static bool Func_lbl_8(CODESolverState &state,int &n,int &m,int &i,int &j,int &k,int &klimit,bool &gridpoint,double &xc,double &v,double &h,double &h2,double &err,double &maxgrowpow);
static bool Func_lbl_10(CODESolverState &state,int &n,int &m,int &i,int &j,int &k,int &klimit,bool &gridpoint,double &xc,double &v,double &h,double &h2,double &err,double &maxgrowpow);
};
//+------------------------------------------------------------------+
//| Initialize constants |
//+------------------------------------------------------------------+
const double CODESolver::m_odesolvermaxgrow=3.0;
const double CODESolver::m_odesolvermaxshrink=10.0;
//+------------------------------------------------------------------+
//| Cash-Karp adaptive ODE solver. |
//| This subroutine solves ODE Y'=f(Y,x) with initial conditions |
//| Y(xs)=Ys (here Y may be single variable or vector of N variables)|
//| INPUT PARAMETERS: |
//| Y - initial conditions, array[0..N-1]. |
//| contains values of Y[] at X[0] |
//| N - system size |
//| X - points at which Y should be tabulated, |
//| array[0..M-1] integrations starts at X[0], ends |
//| at X[M-1], intermediate values at X[i] are |
//| returned too. |
//| SHOULD BE ORDERED BY ASCENDING OR BY DESCENDING!!|
//| M - number of intermediate points + first point + |
//| last point: |
//| * M>2 means that you need both Y(X[M-1]) and M-2 |
//| values at intermediate points |
//| * M=2 means that you want just to integrate from |
//| X[0] to X[1] and don't interested in |
//| intermediate values. |
//| * M=1 means that you don't want to integrate :) |
//| it is degenerate case, but it will be handled |
//| correctly. |
//| * M<1 means error |
//| Eps - tolerance (absolute/relative error on each step |
//| will be less than Eps). When passing: |
//| * Eps>0, it means desired ABSOLUTE error |
//| * Eps<0, it means desired RELATIVE error. |
//| Relative errors are calculated with respect to |
//| maximum values of Y seen so far. Be careful to |
//| use this criterion when starting from Y[] that |
//| are close to zero. |
//| H - initial step lenth, it will be adjusted |
//| automatically after the first step. If H=0, step |
//| will be selected automatically (usualy it will |
//| be equal to 0.001 of min(x[i]-x[j])). |
//| OUTPUT PARAMETERS |
//| State - structure which stores algorithm state between |
//| subsequent calls of OdeSolverIteration. Used |
//| for reverse communication. This structure should |
//| be passed to the OdeSolverIteration subroutine. |
//| SEE ALSO |
//| AutoGKSmoothW, AutoGKSingular, AutoGKIteration, AutoGKResults|
//+------------------------------------------------------------------+
void CODESolver::ODESolverRKCK(double &y[],const int n,double &x[],
const int m,const double eps,
const double h,CODESolverState &state)
{
//--- check
if(!CAp::Assert(n>=1,"ODESolverRKCK: N<1!"))
return;
//--- check
if(!CAp::Assert(m>=1,"ODESolverRKCK: M<1!"))
return;
//--- check
if(!CAp::Assert(CAp::Len(y)>=n,"ODESolverRKCK: Length(Y)<N!"))
return;
//--- check
if(!CAp::Assert(CAp::Len(x)>=m,"ODESolverRKCK: Length(X)<M!"))
return;
//--- check
if(!CAp::Assert(CApServ::IsFiniteVector(y,n),"ODESolverRKCK: Y contains infinite or NaN values!"))
return;
//--- check
if(!CAp::Assert(CApServ::IsFiniteVector(x,m),"ODESolverRKCK: Y contains infinite or NaN values!"))
return;
//--- check
if(!CAp::Assert(CMath::IsFinite(eps),"ODESolverRKCK: Eps is not finite!"))
return;
//--- check
if(!CAp::Assert(eps!=0.0,"ODESolverRKCK: Eps is zero!"))
return;
//--- check
if(!CAp::Assert(CMath::IsFinite(h),"ODESolverRKCK: H is not finite!"))
return;
//--- function call
ODESolverInit(0,y,n,x,m,eps,h,state);
}
//+------------------------------------------------------------------+
//| ODE solver results |
//| Called after OdeSolverIteration returned False. |
//| INPUT PARAMETERS: |
//| State - algorithm state (used by OdeSolverIteration). |
//| OUTPUT PARAMETERS: |
//| M - number of tabulated values, M>=1 |
//| XTbl - array[0..M-1], values of X |
//| YTbl - array[0..M-1,0..N-1], values of Y in X[i] |
//| Rep - solver report: |
//| * Rep.TerminationType completetion code: |
//| * -2 X is not ordered by |
//| ascending/descending or there are |
//| non-distinct X[], i.e. X[i]=X[i+1] |
//| * -1 incorrect parameters were specified |
//| * 1 task has been solved |
//| * Rep.NFEV contains number of function |
//| calculations |
//+------------------------------------------------------------------+
void CODESolver::ODESolverResults(CODESolverState &state,int &m,
double &xtbl[],CMatrixDouble &ytbl,
CODESolverReport &rep)
{
//--- create variables
double v=0;
int i=0;
int i_=0;
//--- initialization
m=0;
rep.m_terminationtype=state.m_repterminationtype;
//--- check
if(rep.m_terminationtype>0)
{
//--- change values
m=state.m_m;
rep.m_nfev=state.m_repnfev;
//--- allocation
ArrayResize(xtbl,state.m_m);
v=state.m_xscale;
//--- calculation
for(i_=0; i_<=state.m_m-1; i_++)
xtbl[i_]=v*state.m_xg[i_];
//--- allocation
ytbl.Resize(state.m_m,state.m_n);
for(i=0; i<=state.m_m-1; i++)
{
for(i_=0; i_<=state.m_n-1; i_++)
ytbl.Set(i,i_,state.m_ytbl[i][i_]);
}
}
else
rep.m_nfev=0;
}
//+------------------------------------------------------------------+
//| Internal initialization subroutine |
//+------------------------------------------------------------------+
void CODESolver::ODESolverInit(int solvertype,double &y[],const int n,
double &x[],const int m,const double eps,
double h,CODESolverState &state)
{
//--- create variables
int i=0;
double v=0;
int i_=0;
//--- Prepare RComm
state.m_rstate.ia.Resize(6);
ArrayResizeAL(state.m_rstate.ba,1);
state.m_rstate.ra.Resize(6);
state.m_rstate.stage=-1;
state.m_needdy=false;
//--- check parameters.
if((n<=0 || m<1) || eps==0.0)
{
state.m_repterminationtype=-1;
return;
}
//--- check
if(h<0.0)
h=-h;
//--- quick exit if necessary.
//--- after this block we assume that M>1
if(m==1)
{
//--- change values
state.m_repnfev=0;
state.m_repterminationtype=1;
state.m_ytbl.Resize(1,n);
for(i_=0; i_<=n-1; i_++)
state.m_ytbl.Set(0,i_,y[i_]);
//--- allocation
ArrayResize(state.m_xg,m);
for(i_=0; i_<=m-1; i_++)
state.m_xg[i_]=x[i_];
//--- exit the function
return;
}
//--- check again: correct order of X[]
if(x[1]==x[0])
{
state.m_repterminationtype=-2;
return;
}
for(i=1; i<=m-1; i++)
{
//--- check
if((x[1]>x[0] && x[i]<=x[i-1]) || (x[1]<x[0] && x[i]>=x[i-1]))
{
state.m_repterminationtype=-2;
return;
}
}
//--- auto-select H if necessary
if(h==0.0)
{
v=MathAbs(x[1]-x[0]);
for(i=2; i<=m-1; i++)
v=MathMin(v,MathAbs(x[i]-x[i-1]));
h=0.001*v;
}
//--- store parameters
state.m_n=n;
state.m_m=m;
state.m_h=h;
state.m_eps=MathAbs(eps);
state.m_fraceps=eps<0.0;
//--- allocation
ArrayResize(state.m_xg,m);
for(i_=0; i_<=m-1; i_++)
state.m_xg[i_]=x[i_];
//--- check
if(x[1]>x[0])
state.m_xscale=1;
else
{
state.m_xscale=-1;
for(i_=0; i_<=m-1; i_++)
state.m_xg[i_]=-1*state.m_xg[i_];
}
//--- allocation
ArrayResize(state.m_yc,n);
for(i_=0; i_<=n-1; i_++)
state.m_yc[i_]=y[i_];
//--- change values
state.m_solvertype=solvertype;
state.m_repterminationtype=0;
//--- Allocate arrays
ArrayResize(state.m_y,n);
ArrayResize(state.m_dy,n);
}
//+------------------------------------------------------------------+
//| Iterative method |
//+------------------------------------------------------------------+
bool CODESolver::ODESolverIteration(CODESolverState &state)
{
//--- create variables
int n=0;
int m=0;
int i=0;
int j=0;
int k=0;
double xc=0;
double v=0;
double h=0;
double h2=0;
bool gridpoint;
double err=0;
double maxgrowpow=0;
int klimit=0;
int i_=0;
//--- This code initializes locals by:
//--- * random values determined during code
//--- generation - on first subroutine call
//--- * values from previous call - on subsequent calls
if(state.m_rstate.stage>=0)
{
//--- initialization
n=state.m_rstate.ia[0];
m=state.m_rstate.ia[1];
i=state.m_rstate.ia[2];
j=state.m_rstate.ia[3];
k=state.m_rstate.ia[4];
klimit=state.m_rstate.ia[5];
gridpoint=state.m_rstate.ba[0];
xc=state.m_rstate.ra[0];
v=state.m_rstate.ra[1];
h=state.m_rstate.ra[2];
h2=state.m_rstate.ra[3];
err=state.m_rstate.ra[4];
maxgrowpow=state.m_rstate.ra[5];
}
else
{
//--- initialization
n=-983;
m=-989;
i=-834;
j=900;
k=-287;
klimit=364;
gridpoint=false;
xc=-338;
v=-686;
h=912;
h2=585;
err=497;
maxgrowpow=-271;
}
//--- check
if(state.m_rstate.stage==0)
{
//--- change values
state.m_needdy=false;
state.m_repnfev=state.m_repnfev+1;
v=h*state.m_xscale;
for(i_=0; i_<=n-1; i_++)
state.m_rkk.Set(k,i_,v*state.m_dy[i_]);
//--- update YN/YNS
v=state.m_rkc[k];
for(i_=0; i_<=n-1; i_++)
state.m_yn[i_]=state.m_yn[i_]+v*state.m_rkk[k][i_];
v=state.m_rkcs[k];
for(i_=0; i_<=n-1; i_++)
state.m_yns[i_]=state.m_yns[i_]+v*state.m_rkk[k][i_];
k=k+1;
return(Func_lbl_8(state,n,m,i,j,k,klimit,gridpoint,xc,v,h,h2,err,maxgrowpow));
}
//--- Routine body
//--- prepare
if(state.m_repterminationtype!=0)
return(false);
//--- change values
n=state.m_n;
m=state.m_m;
h=state.m_h;
maxgrowpow=MathPow(m_odesolvermaxgrow,5);
state.m_repnfev=0;
//--- some preliminary checks for internal errors
//--- after this we assume that H>0 and M>1
if(!CAp::Assert(state.m_h>0.0,"ODESolver: internal error"))
return(false);
//--- check
if(!CAp::Assert(m>1,"ODESolverIteration: internal error"))
return(false);
//--- choose solver
if(state.m_solvertype!=0)
return(false);
//--- Cask-Karp solver
//--- Prepare coefficients table.
//--- Check it for errors
ArrayResize(state.m_rka,6);
//--- calculation
state.m_rka[0]=0;
state.m_rka[1]=1.0/5.0;
state.m_rka[2]=3.0/10.0;
state.m_rka[3]=3.0/5.0;
state.m_rka[4]=1;
state.m_rka[5]=7.0/8.0;
state.m_rkb.Resize(6,5);
state.m_rkb.Set(1,0,1.0/5.0);
state.m_rkb.Set(2,0,3.0/40.0);
state.m_rkb.Set(2,1,9.0/40.0);
state.m_rkb.Set(3,0,3.0/10.0);
state.m_rkb.Set(3,1,-(9.0/10.0));
state.m_rkb.Set(3,2,6.0/5.0);
state.m_rkb.Set(4,0,-(11.0/54.0));
state.m_rkb.Set(4,1,5.0/2.0);
state.m_rkb.Set(4,2,-(70.0/27.0));
state.m_rkb.Set(4,3,35.0/27.0);
state.m_rkb.Set(5,0,1631.0/55296.0);
state.m_rkb.Set(5,1,175.0/512.0);
state.m_rkb.Set(5,2,575.0/13824.0);
state.m_rkb.Set(5,3,44275.0/110592.0);
state.m_rkb.Set(5,4,253.0/4096.0);
//--- allocation
ArrayResize(state.m_rkc,6);
//--- calculation
state.m_rkc[0]=37.0/378.0;
state.m_rkc[1]=0;
state.m_rkc[2]=250.0/621.0;
state.m_rkc[3]=125.0/594.0;
state.m_rkc[4]=0;
state.m_rkc[5]=512.0/1771.0;
//--- allocation
ArrayResize(state.m_rkcs,6);
//--- calculation
state.m_rkcs[0]=2825.0/27648.0;
state.m_rkcs[1]=0;
state.m_rkcs[2]=18575.0/48384.0;
state.m_rkcs[3]=13525.0/55296.0;
state.m_rkcs[4]=277.0/14336.0;
state.m_rkcs[5]=1.0/4.0;
state.m_rkk.Resize(6,n);
//--- Main cycle consists of two iterations:
//--- * outer where we travel from X[i-1] to X[i]
//--- * inner where we travel inside [X[i-1],X[i]]
state.m_ytbl.Resize(m,n);
ArrayResize(state.m_escale,n);
ArrayResize(state.m_yn,n);
ArrayResize(state.m_yns,n);
//--- change value
xc=state.m_xg[0];
for(i_=0; i_<=n-1; i_++)
state.m_ytbl.Set(0,i_,state.m_yc[i_]);
for(j=0; j<=n-1; j++)
state.m_escale[j]=0;
i=1;
//--- check
if(i>m-1)
{
state.m_repterminationtype=1;
//--- return result
return(false);
}
//--- begin inner iteration
return(Func_lbl_6(state,n,m,i,j,k,klimit,gridpoint,xc,v,h,h2,err,maxgrowpow));
}
//+------------------------------------------------------------------+
//| Auxiliary function for ODESolverIteration. Is a product to get |
//| rid of the operator unconditional jump goto |
//+------------------------------------------------------------------+
void CODESolver::Func_lbl_rcomm(CODESolverState &state,int n,int m,
int i,int j,int k,int klimit,
bool gridpoint,double xc,double v,
double h,double h2,double err,
double maxgrowpow)
{
//--- save
state.m_rstate.ia.Set(0,n);
state.m_rstate.ia.Set(1,m);
state.m_rstate.ia.Set(2,i);
state.m_rstate.ia.Set(3,j);
state.m_rstate.ia.Set(4,k);
state.m_rstate.ia.Set(5,klimit);
state.m_rstate.ba[0]= gridpoint;
state.m_rstate.ra.Set(0,xc);
state.m_rstate.ra.Set(1,v);
state.m_rstate.ra.Set(2,h);
state.m_rstate.ra.Set(3,h2);
state.m_rstate.ra.Set(4,err);
state.m_rstate.ra.Set(5,maxgrowpow);
}
//+------------------------------------------------------------------+
//| Auxiliary function for ODESolverIteration. Is a product to get |
//| rid of the operator unconditional jump goto |
//+------------------------------------------------------------------+
bool CODESolver::Func_lbl_6(CODESolverState &state,int &n,int &m,
int &i,int &j,int &k,int &klimit,
bool &gridpoint,double &xc,double &v,
double &h,double &h2,double &err,
double &maxgrowpow)
{
//--- truncate step if needed (beyond right boundary).
//--- determine should we store X or not
if(xc+h>=state.m_xg[i])
{
h=state.m_xg[i]-xc;
gridpoint=true;
}
else
gridpoint=false;
//--- Update error scale maximums
//--- These maximums are initialized by zeros,
//--- then updated every iterations.
for(j=0; j<=n-1; j++)
state.m_escale[j]=MathMax(state.m_escale[j],MathAbs(state.m_yc[j]));
//--- make one step:
//--- 1. calculate all info needed to do step
//--- 2. update errors scale maximums using values/derivatives
//--- obtained during (1)
//--- Take into account that we use scaling of X to reduce task
//--- to the form where x[0] < x[1] < ... < x[n-1]. So X is
//--- replaced by x=xscale*t,and dy/dx=f(y,x) is replaced
//--- by dy/dt=xscale*f(y,xscale*t).
for(int i_=0; i_<=n-1; i_++)
state.m_yn[i_]=state.m_yc[i_];
for(int i_=0; i_<=n-1; i_++)
state.m_yns[i_]=state.m_yc[i_];
k=0;
//--- function call, return result
return(Func_lbl_8(state,n,m,i,j,k,klimit,gridpoint,xc,v,h,h2,err,maxgrowpow));
}
//+------------------------------------------------------------------+
//| Auxiliary function for ODESolverIteration. Is a product to get |
//| rid of the operator unconditional jump goto |
//+------------------------------------------------------------------+
bool CODESolver::Func_lbl_8(CODESolverState &state,int &n,int &m,
int &i,int &j,int &k,int &klimit,
bool &gridpoint,double &xc,double &v,
double &h,double &h2,double &err,
double &maxgrowpow)
{
//--- check
if(k>5)
return(Func_lbl_10(state,n,m,i,j,k,klimit,gridpoint,xc,v,h,h2,err,maxgrowpow));
//--- prepare data for the next update of YN/YNS
state.m_x=state.m_xscale*(xc+state.m_rka[k]*h);
for(int i_=0; i_<=n-1; i_++)
state.m_y[i_]=state.m_yc[i_];
//--- calculation
for(j=0; j<=k-1; j++)
{
v=state.m_rkb[k][j];
for(int i_=0; i_<=n-1; i_++)
state.m_y[i_]=state.m_y[i_]+v*state.m_rkk[j][i_];
}
state.m_needdy=true;
state.m_rstate.stage=0;
//--- Saving state
Func_lbl_rcomm(state,n,m,i,j,k,klimit,gridpoint,xc,v,h,h2,err,maxgrowpow);
//--- return result
return(true);
}
//+------------------------------------------------------------------+
//| Auxiliary function for ODESolverIteration. Is a product to get |
//| rid of the operator unconditional jump goto |
//+------------------------------------------------------------------+
bool CODESolver::Func_lbl_10(CODESolverState &state,int &n,int &m,
int &i,int &j,int &k,int &klimit,
bool &gridpoint,double &xc,double &v,
double &h,double &h2,double &err,
double &maxgrowpow)
{
//--- estimate error
err=0;
for(j=0; j<=n-1; j++)
{
//--- check
if(!state.m_fraceps)
{
//--- absolute error is estimated
err=MathMax(err,MathAbs(state.m_yn[j]-state.m_yns[j]));
}
else
{
//--- Relative error is estimated
v=state.m_escale[j];
//--- check
if(v==0.0)
v=1;
err=MathMax(err,MathAbs(state.m_yn[j]-state.m_yns[j])/v);
}
}
//--- calculate new step,restart if necessary
if(maxgrowpow*err<=state.m_eps)
h2=m_odesolvermaxgrow*h;
else
h2=h*MathPow(state.m_eps/err,0.2);
//--- check
if(h2<h/m_odesolvermaxshrink)
h2=h/m_odesolvermaxshrink;
//--- check
if(err>state.m_eps)
{
h=h2;
//--- begin inner iteration
return(Func_lbl_6(state,n,m,i,j,k,klimit,gridpoint,xc,v,h,h2,err,maxgrowpow));
}
//--- advance position
xc=xc+h;
for(int i_=0; i_<=n-1; i_++)
state.m_yc[i_]=state.m_yn[i_];
//--- update H
h=h2;
//--- break on grid point
if(gridpoint)
{
//--- save result
for(int i_=0; i_<=n-1; i_++)
state.m_ytbl.Set(i,i_,state.m_yc[i_]);
i=i+1;
//--- check
if(i>m-1)
{
state.m_repterminationtype=1;
return(false);
}
//--- begin inner iteration
return(Func_lbl_6(state,n,m,i,j,k,klimit,gridpoint,xc,v,h,h2,err,maxgrowpow));
}
//--- begin inner iteration
return(Func_lbl_6(state,n,m,i,j,k,klimit,gridpoint,xc,v,h,h2,err,maxgrowpow));
}
//+------------------------------------------------------------------+