//+------------------------------------------------------------------+
//|                                                 optimization.mqh |
//|            Copyright 2003-2012 Sergey Bochkanov (ALGLIB project) |
//|                   Copyright 2012-2017, MetaQuotes Software Corp. |
//|                                             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 "ap.mqh"
#include "alglibinternal.mqh"
#include "linalg.mqh"
//+------------------------------------------------------------------+
//| This object stores state of the nonlinear CG optimizer.          |
//| You should use ALGLIB functions to work with this object.        |
//+------------------------------------------------------------------+
class CMinCGState
  {
public:
   //--- variables
   int               m_n;
   double            m_epsg;
   double            m_epsf;
   double            m_epsx;
   int               m_maxits;
   double            m_stpmax;
   double            m_suggestedstep;
   bool              m_xrep;
   bool              m_drep;
   int               m_cgtype;
   int               m_prectype;
   int               m_vcnt;
   double            m_diffstep;
   int               m_nfev;
   int               m_mcstage;
   int               m_k;
   double            m_fold;
   double            m_stp;
   double            m_curstpmax;
   double            m_laststep;
   double            m_lastscaledstep;
   int               m_mcinfo;
   bool              m_innerresetneeded;
   bool              m_terminationneeded;
   double            m_trimthreshold;
   int               m_rstimer;
   double            m_f;
   bool              m_needf;
   bool              m_needfg;
   bool              m_xupdated;
   bool              m_algpowerup;
   bool              m_lsstart;
   bool              m_lsend;
   RCommState        m_rstate;
   int               m_repiterationscount;
   int               m_repnfev;
   int               m_repterminationtype;
   int               m_debugrestartscount;
   CLinMinState      m_lstate;
   double            m_fbase;
   double            m_fm2;
   double            m_fm1;
   double            m_fp1;
   double            m_fp2;
   double            m_betahs;
   double            m_betady;
   //--- arrays
   double            m_xk[];
   double            m_dk[];
   double            m_xn[];
   double            m_dn[];
   double            m_d[];
   double            m_x[];
   double            m_yk[];
   double            m_s[];
   double            m_g[];
   double            m_diagh[];
   double            m_diaghl2[];
   double            m_work0[];
   double            m_work1[];
   //--- matrix
   CMatrixDouble     m_vcorr;
   //--- constructor, destructor
                     CMinCGState(void);
                    ~CMinCGState(void);
   //--- copy
   void              Copy(CMinCGState &obj);
  };
//+------------------------------------------------------------------+
//| Constructor without parameters                                   |
//+------------------------------------------------------------------+
CMinCGState::CMinCGState(void)
  {

  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CMinCGState::~CMinCGState(void)
  {

  }
//+------------------------------------------------------------------+
//| Copy                                                             |
//+------------------------------------------------------------------+
void CMinCGState::Copy(CMinCGState &obj)
  {
//--- copy variables
   m_n=obj.m_n;
   m_epsg=obj.m_epsg;
   m_epsf=obj.m_epsf;
   m_epsx=obj.m_epsx;
   m_maxits=obj.m_maxits;
   m_stpmax=obj.m_stpmax;
   m_suggestedstep=obj.m_suggestedstep;
   m_xrep=obj.m_xrep;
   m_drep=obj.m_drep;
   m_cgtype=obj.m_cgtype;
   m_prectype=obj.m_prectype;
   m_vcnt=obj.m_vcnt;
   m_diffstep=obj.m_diffstep;
   m_nfev=obj.m_nfev;
   m_mcstage=obj.m_mcstage;
   m_k=obj.m_k;
   m_fold=obj.m_fold;
   m_stp=obj.m_stp;
   m_curstpmax=obj.m_curstpmax;
   m_laststep=obj.m_laststep;
   m_lastscaledstep=obj.m_lastscaledstep;
   m_mcinfo=obj.m_mcinfo;
   m_innerresetneeded=obj.m_innerresetneeded;
   m_terminationneeded=obj.m_terminationneeded;
   m_trimthreshold=obj.m_trimthreshold;
   m_rstimer=obj.m_rstimer;
   m_f=obj.m_f;
   m_needf=obj.m_needf;
   m_needfg=obj.m_needfg;
   m_xupdated=obj.m_xupdated;
   m_algpowerup=obj.m_algpowerup;
   m_lsstart=obj.m_lsstart;
   m_lsend=obj.m_lsend;
   m_repiterationscount=obj.m_repiterationscount;
   m_repnfev=obj.m_repnfev;
   m_repterminationtype=obj.m_repterminationtype;
   m_debugrestartscount=obj.m_debugrestartscount;
   m_fbase=obj.m_fbase;
   m_fm2=obj.m_fm2;
   m_fm1=obj.m_fm1;
   m_fp1=obj.m_fp1;
   m_fp2=obj.m_fp2;
   m_betahs=obj.m_betahs;
   m_betady=obj.m_betady;
   m_rstate.Copy(obj.m_rstate);
   m_lstate.Copy(obj.m_lstate);
//--- copy arrays
   ArrayCopy(m_xk,obj.m_xk);
   ArrayCopy(m_dk,obj.m_dk);
   ArrayCopy(m_xn,obj.m_xn);
   ArrayCopy(m_dn,obj.m_dn);
   ArrayCopy(m_d,obj.m_d);
   ArrayCopy(m_x,obj.m_x);
   ArrayCopy(m_yk,obj.m_yk);
   ArrayCopy(m_s,obj.m_s);
   ArrayCopy(m_g,obj.m_g);
   ArrayCopy(m_diagh,obj.m_diagh);
   ArrayCopy(m_diaghl2,obj.m_diaghl2);
   ArrayCopy(m_work0,obj.m_work0);
   ArrayCopy(m_work1,obj.m_work1);
//--- matrix
   m_vcorr=obj.m_vcorr;
  }
//+------------------------------------------------------------------+
//| This object stores state of the nonlinear CG optimizer.          |
//| You should use ALGLIB functions to work with this object.        |
//+------------------------------------------------------------------+
class CMinCGStateShell
  {
private:
   CMinCGState       m_innerobj;

public:
   //--- constructors, destructor
                     CMinCGStateShell(void);
                     CMinCGStateShell(CMinCGState &obj);
                    ~CMinCGStateShell(void);
   //--- methods
   bool              GetNeedF(void);
   void              SetNeedF(const bool b);
   bool              GetNeedFG(void);
   void              SetNeedFG(const bool b);
   bool              GetXUpdated(void);
   void              SetXUpdated(const bool b);
   double            GetF(void);
   void              SetF(const double d);
   CMinCGState      *GetInnerObj(void);
  };
//+------------------------------------------------------------------+
//| Constructor without parameters                                   |
//+------------------------------------------------------------------+
CMinCGStateShell::CMinCGStateShell(void)
  {

  }
//+------------------------------------------------------------------+
//| Copy constructor                                                 |
//+------------------------------------------------------------------+
CMinCGStateShell::CMinCGStateShell(CMinCGState &obj)
  {
//--- copy
   m_innerobj.Copy(obj);
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CMinCGStateShell::~CMinCGStateShell(void)
  {

  }
//+------------------------------------------------------------------+
//| Returns the value of the variable needf                          |
//+------------------------------------------------------------------+
bool CMinCGStateShell::GetNeedF(void)
  {
//--- return result
   return(m_innerobj.m_needf);
  }
//+------------------------------------------------------------------+
//| Changing the value of the variable needf                         |
//+------------------------------------------------------------------+
void CMinCGStateShell::SetNeedF(const bool b)
  {
//--- change value
   m_innerobj.m_needf=b;
  }
//+------------------------------------------------------------------+
//| Returns the value of the variable needfg                         |
//+------------------------------------------------------------------+
bool CMinCGStateShell::GetNeedFG(void)
  {
//--- return result
   return(m_innerobj.m_needfg);
  }
//+------------------------------------------------------------------+
//| Changing the value of the variable needfg                        |
//+------------------------------------------------------------------+
void CMinCGStateShell::SetNeedFG(const bool b)
  {
//--- change value
   m_innerobj.m_needfg=b;
  }
//+------------------------------------------------------------------+
//| Returns the value of the variable xupdated                       |
//+------------------------------------------------------------------+
bool CMinCGStateShell::GetXUpdated(void)
  {
//--- return result
   return(m_innerobj.m_xupdated);
  }
//+------------------------------------------------------------------+
//| Changing the value of the variable xupdated                      |
//+------------------------------------------------------------------+
void CMinCGStateShell::SetXUpdated(const bool b)
  {
//--- change value
   m_innerobj.m_xupdated=b;
  }
//+------------------------------------------------------------------+
//| Returns the value of the variable f                              |
//+------------------------------------------------------------------+
double CMinCGStateShell::GetF(void)
  {
//--- return result
   return(m_innerobj.m_f);
  }
//+------------------------------------------------------------------+
//| Changing the value of the variable f                             |
//+------------------------------------------------------------------+
void CMinCGStateShell::SetF(const double d)
  {
//--- change value
   m_innerobj.m_f=d;
  }
//+------------------------------------------------------------------+
//| Return object of class                                           |
//+------------------------------------------------------------------+
CMinCGState *CMinCGStateShell::GetInnerObj(void)
  {
//--- return result
   return(GetPointer(m_innerobj));
  }
//+------------------------------------------------------------------+
//| Auxiliary class for CMinCG                                       |
//+------------------------------------------------------------------+
class CMinCGReport
  {
public:
   int               m_iterationscount;
   int               m_nfev;
   int               m_terminationtype;
   //--- constructor, destructor
                     CMinCGReport(void);
                    ~CMinCGReport(void);
   //--- copy
   void              Copy(CMinCGReport &obj);
  };
//+------------------------------------------------------------------+
//| Constructor without parameters                                   |
//+------------------------------------------------------------------+
CMinCGReport::CMinCGReport(void)
  {

  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CMinCGReport::~CMinCGReport(void)
  {

  }
//+------------------------------------------------------------------+
//| Copy                                                             |
//+------------------------------------------------------------------+
void CMinCGReport::Copy(CMinCGReport &obj)
  {
//--- copy variables
   m_iterationscount=obj.m_iterationscount;
   m_nfev=obj.m_nfev;
   m_terminationtype=obj.m_terminationtype;
  }
//+------------------------------------------------------------------+
//| This class is a shell for class CMinCGReport                     |
//+------------------------------------------------------------------+
class CMinCGReportShell
  {
private:
   CMinCGReport      m_innerobj;
public:
   //--- constructors, destructor
                     CMinCGReportShell(void);
                     CMinCGReportShell(CMinCGReport &obj);
                    ~CMinCGReportShell(void);
   //--- methods
   int               GetIterationsCount(void);
   void              SetIterationsCount(const int i);
   int               GetNFev(void);
   void              SetNFev(const int i);
   int               GetTerminationType(void);
   void              SetTerminationType(const int i);
   CMinCGReport     *GetInnerObj(void);
  };
//+------------------------------------------------------------------+
//| Constructor without parameters                                   |
//+------------------------------------------------------------------+
CMinCGReportShell::CMinCGReportShell(void)
  {

  }
//+------------------------------------------------------------------+
//| Copy constructor                                                 |
//+------------------------------------------------------------------+
CMinCGReportShell::CMinCGReportShell(CMinCGReport &obj)
  {
//--- copy
   m_innerobj.Copy(obj);
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CMinCGReportShell::~CMinCGReportShell(void)
  {

  }
//+------------------------------------------------------------------+
//| Returns the value of the variable iterationscount                |
//+------------------------------------------------------------------+
int CMinCGReportShell::GetIterationsCount(void)
  {
//--- return result
   return(m_innerobj.m_iterationscount);
  }
//+------------------------------------------------------------------+
//| Changing the value of the variable iterationscount               |
//+------------------------------------------------------------------+
void CMinCGReportShell::SetIterationsCount(const int i)
  {
//--- change value
   m_innerobj.m_iterationscount=i;
  }
//+------------------------------------------------------------------+
//| Returns the value of the variable nfev                           |
//+------------------------------------------------------------------+
int CMinCGReportShell::GetNFev(void)
  {
//--- return result
   return(m_innerobj.m_nfev);
  }
//+------------------------------------------------------------------+
//| Changing the value of the variable nfev                          |
//+------------------------------------------------------------------+
void CMinCGReportShell::SetNFev(const int i)
  {
//--- change value
   m_innerobj.m_nfev=i;
  }
//+------------------------------------------------------------------+
//| Returns the value of the variable terminationtype                |
//+------------------------------------------------------------------+
int CMinCGReportShell::GetTerminationType(void)
  {
//--- return result
   return(m_innerobj.m_terminationtype);
  }
//+------------------------------------------------------------------+
//| Changing the value of the variable terminationtype               |
//+------------------------------------------------------------------+
void CMinCGReportShell::SetTerminationType(const int i)
  {
//--- change value
   m_innerobj.m_terminationtype=i;
  }
//+------------------------------------------------------------------+
//| Return object of class                                           |
//+------------------------------------------------------------------+
CMinCGReport *CMinCGReportShell::GetInnerObj(void)
  {
//--- return result
   return(GetPointer(m_innerobj));
  }
//+------------------------------------------------------------------+
//| Conjugate gradient optimizer                                     |
//+------------------------------------------------------------------+
class CMinCG
  {
private:
   //--- private methods
   static void       ClearRequestFields(CMinCGState &state);
   static void       PreconditionedMultiply(CMinCGState &state,double &x[],double &work0[],double &work1[]);
   static double     PreconditionedMultiply2(CMinCGState &state,double &x[],double &y[],double &work0[],double &work1[]);
   static void       MinCGInitInternal(const int n,const double diffstep,CMinCGState &state);
   //--- auxiliary functions for MinCGIteration
   static void       Func_lbl_rcomm(CMinCGState &state,int n,int i,double betak,double v,double vv);
   static bool       Func_lbl_18(CMinCGState &state,int &n,int &i,double &betak,double &v,double &vv);
   static bool       Func_lbl_19(CMinCGState &state,int &n,int &i,double &betak,double &v,double &vv);
   static bool       Func_lbl_22(CMinCGState &state,int &n,int &i,double &betak,double &v,double &vv);
   static bool       Func_lbl_24(CMinCGState &state,int &n,int &i,double &betak,double &v,double &vv);
   static bool       Func_lbl_26(CMinCGState &state,int &n,int &i,double &betak,double &v,double &vv);
   static bool       Func_lbl_28(CMinCGState &state,int &n,int &i,double &betak,double &v,double &vv);
   static bool       Func_lbl_30(CMinCGState &state,int &n,int &i,double &betak,double &v,double &vv);
   static bool       Func_lbl_31(CMinCGState &state,int &n,int &i,double &betak,double &v,double &vv);
   static bool       Func_lbl_33(CMinCGState &state,int &n,int &i,double &betak,double &v,double &vv);
   static bool       Func_lbl_34(CMinCGState &state,int &n,int &i,double &betak,double &v,double &vv);
   static bool       Func_lbl_37(CMinCGState &state,int &n,int &i,double &betak,double &v,double &vv);
   static bool       Func_lbl_39(CMinCGState &state,int &n,int &i,double &betak,double &v,double &vv);
public:
   //--- class constants
   static const int  m_rscountdownlen;
   static const double m_gtol;
   //--- constructor, destructor
                     CMinCG(void);
                    ~CMinCG(void);
   //--- public methods
   static void       MinCGCreate(const int n,double &x[],CMinCGState &state);
   static void       MinCGCreateF(const int n,double &x[],const double diffstep,CMinCGState &state);
   static void       MinCGSetCond(CMinCGState &state,const double epsg,const double epsf,double epsx,const int maxits);
   static void       MinCGSetScale(CMinCGState &state,double &s[]);
   static void       MinCGSetXRep(CMinCGState &state,const bool needxrep);
   static void       MinCGSetDRep(CMinCGState &state,const bool needdrep);
   static void       MinCGSetCGType(CMinCGState &state,int cgtype);
   static void       MinCGSetStpMax(CMinCGState &state,const double stpmax);
   static void       MinCGSuggestStep(CMinCGState &state,const double stp);
   static void       MinCGSetPrecDefault(CMinCGState &state);
   static void       MinCGSetPrecDiag(CMinCGState &state,double &d[]);
   static void       MinCGSetPrecScale(CMinCGState &state);
   static void       MinCGResults(CMinCGState &state,double &x[],CMinCGReport &rep);
   static void       MinCGResultsBuf(CMinCGState &state,double &x[],CMinCGReport &rep);
   static void       MinCGRestartFrom(CMinCGState &state,double &x[]);
   static void       MinCGSetPrecDiagFast(CMinCGState &state,double &d[]);
   static void       MinCGSetPrecLowRankFast(CMinCGState &state,double &d1[],double &c[],CMatrixDouble &v,const int vcnt);
   static void       MinCGSetPrecVarPart(CMinCGState &state,double &d2[]);
   static bool       MinCGIteration(CMinCGState &state);
  };
//+------------------------------------------------------------------+
//| Initialize constants                                             |
//+------------------------------------------------------------------+
const int    CMinCG::m_rscountdownlen=10;
const double CMinCG::m_gtol=0.3;
//+------------------------------------------------------------------+
//| Constructor without parameters                                   |
//+------------------------------------------------------------------+
CMinCG::CMinCG(void)
  {

  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CMinCG::~CMinCG(void)
  {

  }
//+------------------------------------------------------------------+
//|         NONLINEAR CONJUGATE GRADIENT METHOD                      |
//| DESCRIPTION:                                                     |
//| The subroutine minimizes function F(x) of N arguments by using   |
//| one of the nonlinear conjugate gradient methods.                 |
//| These CG methods are globally convergent (even on non-convex     |
//| functions) as long as grad(f) is Lipschitz continuous in a some  |
//| neighborhood of the L = { x : f(x)<=f(x0) }.                     |
//| REQUIREMENTS:                                                    |
//| Algorithm will request following information during its          |
//| operation:                                                       |
//| * function value F and its gradient G (simultaneously) at given  |
//|   point X                                                        |
//| USAGE:                                                           |
//| 1. User initializes algorithm state with MinCGCreate() call      |
//| 2. User tunes solver parameters with MinCGSetCond(),             |
//|    MinCGSetStpMax() and other functions                          |
//| 3. User calls MinCGOptimize() function which takes algorithm     |
//|    state and pointer (delegate, etc.) to callback function which |
//|    calculates F/G.                                               |
//| 4. User calls MinCGResults() to get solution                     |
//| 5. Optionally, user may call MinCGRestartFrom() to solve another |
//|    problem with same N but another starting point and/or another |
//|    function. MinCGRestartFrom() allows to reuse already          |
//|    initialized structure.                                        |
//| INPUT PARAMETERS:                                                |
//|     N       -   problem dimension, N>0:                          |
//|                 * if given, only leading N elements of X are used|
//|                 * if not given, automatically determined from    |
//|                   size of X                                      |
//|     X       -   starting point, array[0..N-1].                   |
//| OUTPUT PARAMETERS:                                               |
//|     State   -   structure which stores algorithm state           |
//+------------------------------------------------------------------+
static void CMinCG::MinCGCreate(const int n,double &x[],CMinCGState &state)
  {
//--- check
   if(!CAp::Assert(n>=1,__FUNCTION__+": N too small!"))
      return;
//--- check
   if(!CAp::Assert(CAp::Len(x)>=n,__FUNCTION__+": Length(X)<N!"))
      return;
//--- check
   if(!CAp::Assert(CApServ::IsFiniteVector(x,n),__FUNCTION__+": X contains infinite or NaN values!"))
      return;
//--- function call
   MinCGInitInternal(n,0.0,state);
//--- function call
   MinCGRestartFrom(state,x);
  }
//+------------------------------------------------------------------+
//| The subroutine is finite difference variant of MinCGCreate().    |
//| It uses finite differences in order to differentiate target      |
//| function.                                                        |
//| Description below contains information which is specific to this |
//| function only. We recommend to read comments on MinCGCreate() in |
//| order to get more information about creation of CG optimizer.    |
//| INPUT PARAMETERS:                                                |
//|     N       -   problem dimension, N>0:                          |
//|                 * if given, only leading N elements of X are     |
//|                   used                                           |
//|                 * if not given, automatically determined from    |
//|                   size of X                                      |
//|     X       -   starting point, array[0..N-1].                   |
//|     DiffStep-   differentiation step, >0                         |
//| OUTPUT PARAMETERS:                                               |
//|     State   -   structure which stores algorithm state           |
//| NOTES:                                                           |
//| 1. algorithm uses 4-point central formula for differentiation.   |
//| 2. differentiation step along I-th axis is equal to              |
//|    DiffStep*S[I] where S[] is scaling vector which can be set by |
//|    MinCGSetScale() call.                                         |
//| 3. we recommend you to use moderate values of differentiation    |
//|    step. Too large step will result in too large truncation      |
//|    errors, while too small step will result in too large         |
//|    numerical errors. 1.0E-6 can be good value to start with.     |
//| 4. Numerical differentiation is very inefficient - one gradient  |
//|    calculation needs 4*N function evaluations. This function will|
//|    work for any N - either small (1...10), moderate (10...100) or|
//|    large  (100...). However, performance penalty will be too     |
//|    severe for any N's except for small ones.                     |
//|    We should also say that code which relies on numerical        |
//|    differentiation is less robust and precise. L-BFGS  needs     |
//|    exact gradient values. Imprecise gradient may slow down       |
//|    convergence, especially on highly nonlinear problems.         |
//|    Thus we recommend to use this function for fast prototyping   |
//|    on small- dimensional problems only, and to implement         |
//|    analytical gradient as soon as possible.                      |
//+------------------------------------------------------------------+
static void CMinCG::MinCGCreateF(const int n,double &x[],const double diffstep,
                                 CMinCGState &state)
  {
//--- check
   if(!CAp::Assert(n>=1,__FUNCTION__+": N too small!"))
      return;
//--- check
   if(!CAp::Assert(CAp::Len(x)>=n,__FUNCTION__+": Length(X)<N!"))
      return;
//--- check
   if(!CAp::Assert(CApServ::IsFiniteVector(x,n),__FUNCTION__+": X contains infinite or NaN values!"))
      return;
//--- check
   if(!CAp::Assert(CMath::IsFinite(diffstep),__FUNCTION__+": DiffStep is infinite or NaN!"))
      return;
//--- check
   if(!CAp::Assert(diffstep>0.0,__FUNCTION__+": DiffStep is non-positive!"))
      return;
//--- function call
   MinCGInitInternal(n,diffstep,state);
//--- function call
   MinCGRestartFrom(state,x);
  }
//+------------------------------------------------------------------+
//| This function sets stopping conditions for CG optimization       |
//| algorithm.                                                       |
//| INPUT PARAMETERS:                                                |
//|     State   -   structure which stores algorithm state           |
//|     EpsG    -   >=0                                              |
//|                 The subroutine finishes its work if the condition|
//|                 |v|<EpsG is satisfied, where:                    |
//|                 * |.| means Euclidian norm                       |
//|                 * v - scaled gradient vector, v[i]=g[i]*s[i]     |
//|                 * g - gradient                                   |
//|                 * s - scaling coefficients set by MinCGSetScale()|
//|     EpsF    -   >=0                                              |
//|                 The subroutine finishes its work if on k+1-th    |
//|                 iteration the condition |F(k+1)-F(k)| <=         |
//|                 <= EpsF*max{|F(k)|,|F(k+1)|,1} is satisfied.     |
//|     EpsX    -   >=0                                              |
//|                 The subroutine finishes its work if on k+1-th    |
//|                 iteration the condition |v|<=EpsX is fulfilled,  |
//|                 where:                                           |
//|                 * |.| means Euclidian norm                       |
//|                 * v - scaled step vector, v[i]=dx[i]/s[i]        |
//|                 * dx - ste pvector, dx=X(k+1)-X(k)               |
//|                 * s - scaling coefficients set by MinCGSetScale()|
//|     MaxIts  -   maximum number of iterations. If MaxIts=0, the   |
//|                 number of iterations is unlimited.               |
//| Passing EpsG=0, EpsF=0, EpsX=0 and MaxIts=0 (simultaneously) will|
//| lead to automatic stopping criterion selection (small EpsX).     |
//+------------------------------------------------------------------+
static void CMinCG::MinCGSetCond(CMinCGState &state,const double epsg,
                                 const double epsf,double epsx,const int maxits)
  {
//--- check
   if(!CAp::Assert(CMath::IsFinite(epsg),__FUNCTION__+": EpsG is not finite number!"))
      return;
//--- check
   if(!CAp::Assert(epsg>=0.0,__FUNCTION__+": negative EpsG!"))
      return;
//--- check
   if(!CAp::Assert(CMath::IsFinite(epsf),__FUNCTION__+": EpsF is not finite number!"))
      return;
//--- check
   if(!CAp::Assert(epsf>=0.0,__FUNCTION__+": negative EpsF!"))
      return;
//--- check
   if(!CAp::Assert(CMath::IsFinite(epsx),__FUNCTION__+": EpsX is not finite number!"))
      return;
//--- check
   if(!CAp::Assert(epsx>=0.0,__FUNCTION__+": negative EpsX!"))
      return;
//--- check
   if(!CAp::Assert(maxits>=0,__FUNCTION__+": negative MaxIts!"))
      return;
//--- check
   if(epsg==0.0 && epsf==0.0 && epsx==0.0 && maxits==0)
      epsx=1.0E-6;
//--- change values
   state.m_epsg=epsg;
   state.m_epsf=epsf;
   state.m_epsx=epsx;
   state.m_maxits=maxits;
  }
//+------------------------------------------------------------------+
//| This function sets scaling coefficients for CG optimizer.        |
//| ALGLIB optimizers use scaling matrices to test stopping          |
//| conditions (step size and gradient are scaled before comparison  |
//| with tolerances). Scale of the I-th variable is a translation    |
//| invariant measure of:                                            |
//| a) "how large" the variable is                                   |
//| b) how large the step should be to make significant changes in   |
//|    the function                                                  |
//| Scaling is also used by finite difference variant of CG          |
//| optimizer - step along I-th axis is equal to DiffStep*S[I].      |
//| In most optimizers (and in the CG too) scaling is NOT a form of  |
//| preconditioning. It just affects stopping conditions. You should |
//| set preconditioner by separate call to one of the                |
//| MinCGSetPrec...() functions.                                     |
//| There is special preconditioning mode, however, which uses       |
//| scaling coefficients to form diagonal preconditioning matrix.    |
//| You can turn this mode on, if you want. But you should understand|
//| that scaling is not the same thing as preconditioning - these are|
//| two different, although related forms of tuning solver.          |
//| INPUT PARAMETERS:                                                |
//|     State   -   structure stores algorithm state                 |
//|     S       -   array[N], non-zero scaling coefficients          |
//|                 S[i] may be negative, sign doesn't matter.       |
//+------------------------------------------------------------------+
static void CMinCG::MinCGSetScale(CMinCGState &state,double &s[])
  {
//--- create a variable
   int i=0;
//--- check
   if(!CAp::Assert(CAp::Len(s)>=state.m_n,__FUNCTION__+": Length(S)<N"))
      return;
   for(i=0;i<=state.m_n-1;i++)
     {
      //--- check
      if(!CAp::Assert(CMath::IsFinite(s[i]),__FUNCTION__+": S contains infinite or NAN elements"))
         return;
      //--- check
      if(!CAp::Assert(s[i]!=0.0,__FUNCTION__+": S contains zero elements"))
         return;
      state.m_s[i]=MathAbs(s[i]);
     }
  }
//+------------------------------------------------------------------+
//| This function turns on/off reporting.                            |
//| INPUT PARAMETERS:                                                |
//|     State   -   structure which stores algorithm state           |
//|     NeedXRep-   whether iteration reports are needed or not      |
//| If NeedXRep is True, algorithm will call rep() callback function |
//| if it is provided to MinCGOptimize().                            |
//+------------------------------------------------------------------+
static void CMinCG::MinCGSetXRep(CMinCGState &state,const bool needxrep)
  {
//--- change value
   state.m_xrep=needxrep;
  }
//+------------------------------------------------------------------+
//| This function turns on/off line search reports.                  |
//| These reports are described in more details in developer-only    | 
//| comments on MinCGState object.                                   |
//| INPUT PARAMETERS:                                                |
//|     State   -   structure which stores algorithm state           |
//|     NeedDRep-   whether line search reports are needed or not    |
//| This function is intended for private use only. Turning it on    |
//| artificially may cause program failure.                          |
//+------------------------------------------------------------------+
static void CMinCG::MinCGSetDRep(CMinCGState &state,const bool needdrep)
  {
//--- change value
   state.m_drep=needdrep;
  }
//+------------------------------------------------------------------+
//| This function sets CG algorithm.                                 |
//| INPUT PARAMETERS:                                                |
//|     State   -   structure which stores algorithm state           |
//|     CGType  -   algorithm type:                                  |
//|                 * -1    automatic selection of the best          |
//|                         algorithm                                |
//|                 * 0     DY (Dai and Yuan) algorithm              |
//|                 * 1     Hybrid DY-HS algorithm                   |
//+------------------------------------------------------------------+
static void CMinCG::MinCGSetCGType(CMinCGState &state,int cgtype)
  {
//--- check
   if(!CAp::Assert(cgtype>=-1 && cgtype<=1,__FUNCTION__+": incorrect CGType!"))
      return;
//--- check
   if(cgtype==-1)
      cgtype=1;
//--- change value
   state.m_cgtype=cgtype;
  }
//+------------------------------------------------------------------+
//| This function sets maximum step length                           |
//| INPUT PARAMETERS:                                                |
//|     State   -   structure which stores algorithm state           |
//|     StpMax  -   maximum step length, >=0. Set StpMax to 0.0, if  |
//|                 you don't want to limit step length.             |
//| Use this subroutine when you optimize target function which      |
//| contains exp() or other fast growing functions, and optimization |
//| algorithm makes too large steps which leads to overflow. This    |
//| function allows us to reject steps that are too large (and       |
//| therefore expose us to the possible overflow) without actually   |
//| calculating function value at the x+stp*d.                       |
//+------------------------------------------------------------------+
static void CMinCG::MinCGSetStpMax(CMinCGState &state,const double stpmax)
  {
//--- check
   if(!CAp::Assert(CMath::IsFinite(stpmax),__FUNCTION__+": StpMax is not finite!"))
      return;
//--- check
   if(!CAp::Assert(stpmax>=0.0,__FUNCTION__+": StpMax<0!"))
      return;
//--- change value
   state.m_stpmax=stpmax;
  }
//+------------------------------------------------------------------+
//| This function allows to suggest initial step length to the CG    |
//| algorithm.                                                       |
//| Suggested step length is used as starting point for the line     |
//| search. It can be useful when you have badly scaled problem, i.e.|
//| when ||grad|| (which is used as initial estimate for the first   |
//| step) is many orders of magnitude different from the desired     |
//| step.                                                            |
//| Line search may fail on such problems without good estimate of   |
//| initial step length. Imagine, for example, problem with          |
//| ||grad||=10^50 and desired step equal to 0.1 Line search         |
//| function will use 10^50 as initial step, then it will decrease   |
//| step length by 2 (up to 20 attempts) and will get 10^44, which is|
//| still too large.                                                 |
//| This function allows us to tell than line search should be       |
//| started from some moderate step length, like 1.0, so algorithm   |
//| will be able to detect desired step length in a several searches.|
//| Default behavior (when no step is suggested) is to use           |
//| preconditioner, if it is available, to generate initial estimate |
//| of step length.                                                  |
//| This function influences only first iteration of algorithm. It   |
//| should be called between MinCGCreate/MinCGRestartFrom() call and |
//| MinCGOptimize call. Suggested step is ignored if you have        |
//| preconditioner.                                                  |
//| INPUT PARAMETERS:                                                |
//|     State   -   structure used to store algorithm state.         |
//|     Stp     -   initial estimate of the step length.             |
//|                 Can be zero (no estimate).                       |
//+------------------------------------------------------------------+
static void CMinCG::MinCGSuggestStep(CMinCGState &state,const double stp)
  {
//--- check
   if(!CAp::Assert(CMath::IsFinite(stp),__FUNCTION__+": Stp is infinite or NAN"))
      return;
//--- check
   if(!CAp::Assert(stp>=0.0,__FUNCTION__+": Stp<0"))
      return;
//--- change value
   state.m_suggestedstep=stp;
  }
//+------------------------------------------------------------------+
//| Modification of the preconditioner: preconditioning is turned    |
//| off.                                                             |
//| INPUT PARAMETERS:                                                |
//|     State   -   structure which stores algorithm state           |
//| NOTE: you can change preconditioner "on the fly", during         |
//| algorithm iterations.                                            |
//+------------------------------------------------------------------+
static void CMinCG::MinCGSetPrecDefault(CMinCGState &state)
  {
//--- change values
   state.m_prectype=0;
   state.m_innerresetneeded=true;
  }
//+------------------------------------------------------------------+
//| Modification of the preconditioner: diagonal of approximate      |
//| Hessian is used.                                                 |
//| INPUT PARAMETERS:                                                |
//|     State   -   structure which stores algorithm state           |
//|     D       -   diagonal of the approximate Hessian,             |
//|                 array[0..N-1], (if larger, only leading N        |
//|                 elements are used).                              |
//| NOTE: you can change preconditioner "on the fly", during         |
//| algorithm iterations.                                            |
//| NOTE 2: D[i] should be positive. Exception will be thrown        |
//| otherwise.                                                       |
//| NOTE 3: you should pass diagonal of approximate Hessian - NOT    |
//| ITS INVERSE.                                                     |
//+------------------------------------------------------------------+
static void CMinCG::MinCGSetPrecDiag(CMinCGState &state,double &d[])
  {
//--- create a variable
   int i=0;
//--- check
   if(!CAp::Assert(CAp::Len(d)>=state.m_n,__FUNCTION__+": D is too short"))
      return;
   for(i=0;i<=state.m_n-1;i++)
     {
      //--- check
      if(!CAp::Assert(CMath::IsFinite(d[i]),__FUNCTION__+": D contains infinite or NAN elements"))
         return;
      //--- check
      if(!CAp::Assert((double)(d[i])>0.0,__FUNCTION__+": D contains non-positive elements"))
         return;
     }
//--- function call
   MinCGSetPrecDiagFast(state,d);
  }
//+------------------------------------------------------------------+
//| Modification of the preconditioner: scale-based diagonal         |
//| preconditioning.                                                 |
//| This preconditioning mode can be useful when you don't have      |
//| approximate diagonal of Hessian, but you know that your variables|
//| are badly scaled (for example, one variable is in [1,10], and    |
//| another in [1000,100000]), and most part of the ill-conditioning |
//| comes from different scales of vars.                             |
//| In this case simple scale-based  preconditioner,                 |
//| with H[i] = 1/(s[i]^2), can greatly improve convergence.         |
//| IMPRTANT: you should set scale of your variables with            |
//| MinCGSetScale() call (before or after MinCGSetPrecScale() call). |
//| Without knowledge of the scale of your variables scale-based     |
//| preconditioner will be just unit matrix.                         |
//| INPUT PARAMETERS:                                                |
//|     State   -   structure which stores algorithm state           |
//| NOTE: you can change preconditioner "on the fly", during         |
//| algorithm iterations.                                            |
//+------------------------------------------------------------------+
static void CMinCG::MinCGSetPrecScale(CMinCGState &state)
  {
//--- change values
   state.m_prectype=3;
   state.m_innerresetneeded=true;
  }
//+------------------------------------------------------------------+
//| Conjugate gradient results                                       |
//| INPUT PARAMETERS:                                                |
//|     State   -   algorithm state                                  |
//| OUTPUT PARAMETERS:                                               |
//|     X       -   array[0..N-1], solution                          |
//|     Rep     -   optimization report:                             |
//|                 * Rep.TerminationType completetion code:         |
//|                     *  1    relative function improvement is no  |
//|                             more than EpsF.                      |
//|                     *  2    relative step is no more than EpsX.  |
//|                     *  4    gradient norm is no more than EpsG   |
//|                     *  5    MaxIts steps was taken               |
//|                     *  7    stopping conditions are too          |
//|                             stringent, further improvement is    |
//|                             impossible, we return best X found   |
//|                             so far                               |
//|                     *  8    terminated by user                   |
//|                 * Rep.IterationsCount contains iterations count  |
//|                 * NFEV countains number of function calculations |
//+------------------------------------------------------------------+
static void CMinCG::MinCGResults(CMinCGState &state,double &x[],CMinCGReport &rep)
  {
//--- reset memory
   ArrayResizeAL(x,0);
//--- function call
   MinCGResultsBuf(state,x,rep);
  }
//+------------------------------------------------------------------+
//| Conjugate gradient results                                       |
//| Buffered implementation of MinCGResults(), which uses            |
//| pre-allocated buffer to store X[]. If buffer size is too small,  |
//| it resizes buffer.It is intended to be used in the inner cycles  |
//| of performance critical algorithms where array reallocation      |
//| penalty is too large to be ignored.                              |
//+------------------------------------------------------------------+
static void CMinCG::MinCGResultsBuf(CMinCGState &state,double &x[],CMinCGReport &rep)
  {
//--- create a variable
   int i_=0;
//--- check
   if(CAp::Len(x)<state.m_n)
      ArrayResizeAL(x,state.m_n);
//--- copy
   for(i_=0;i_<=state.m_n-1;i_++)
      x[i_]=state.m_xn[i_];
//--- change values
   rep.m_iterationscount=state.m_repiterationscount;
   rep.m_nfev=state.m_repnfev;
   rep.m_terminationtype=state.m_repterminationtype;
  }
//+------------------------------------------------------------------+
//| This  subroutine  restarts  CG  algorithm from new point. All    |
//| optimization parameters are left unchanged.                      |
//| This function allows to solve multiple optimization problems     |
//| (which must have same number of dimensions) without object       |
//| reallocation penalty.                                            |
//| INPUT PARAMETERS:                                                |
//|     State   -   structure used to store algorithm state.         |
//|     X       -   new starting point.                              |
//+------------------------------------------------------------------+
static void CMinCG::MinCGRestartFrom(CMinCGState &state,double &x[])
  {
//--- create a variable
   int i_=0;
//--- check
   if(!CAp::Assert(CAp::Len(x)>=state.m_n,__FUNCTION__+": Length(X)<N!"))
      return;
//--- check
   if(!CAp::Assert(CApServ::IsFiniteVector(x,state.m_n),__FUNCTION__+": X contains infinite or NaN values!"))
      return;
//--- copy
   for(i_=0;i_<=state.m_n-1;i_++)
      state.m_x[i_]=x[i_];
//--- function call
   MinCGSuggestStep(state,0.0);
//--- allocation
   ArrayResizeAL(state.m_rstate.ia,2);
   ArrayResizeAL(state.m_rstate.ra,3);
//--- change value
   state.m_rstate.stage=-1;
//--- function call
   ClearRequestFields(state);
  }
//+------------------------------------------------------------------+
//| Faster version of MinCGSetPrecDiag(), for time-critical parts of |
//| code, without safety checks.                                     |
//+------------------------------------------------------------------+
static void CMinCG::MinCGSetPrecDiagFast(CMinCGState &state,double &d[])
  {
//--- create a variable
   int i=0;
//--- function call
   CApServ::RVectorSetLengthAtLeast(state.m_diagh,state.m_n);
//--- function call
   CApServ::RVectorSetLengthAtLeast(state.m_diaghl2,state.m_n);
//--- change values
   state.m_prectype=2;
   state.m_vcnt=0;
   state.m_innerresetneeded=true;
//--- copy
   for(i=0;i<=state.m_n-1;i++)
     {
      state.m_diagh[i]=d[i];
      state.m_diaghl2[i]=0.0;
     }
  }
//+------------------------------------------------------------------+
//| This function sets low-rank preconditioner for Hessian matrix    |
//| H=D+V'*C*V, where:                                               |
//| * H is a Hessian matrix, which is approximated by D/V/C          |
//| * D=D1+D2 is a diagonal matrix, which includes two positive      |
//|   definite terms:                                                |
//|   * constant term D1 (is not updated or infrequently updated)    |
//|   * variable term D2 (can be cheaply updated from iteration to   |
//|     iteration)                                                   |
//| * V is a low-rank correction                                     |
//| * C is a diagonal factor of low-rank correction                  |
//| Preconditioner P is calculated using approximate Woodburry       |
//| formula:                                                         |
//|     P  = D^(-1) - D^(-1)*V'*(C^(-1)+V*D1^(-1)*V')^(-1)*V*D^(-1)  |
//|        = D^(-1) - D^(-1)*VC'*VC*D^(-1),                          |
//| where                                                            |
//|     VC = sqrt(B)*V                                               |
//|     B  = (C^(-1)+V*D1^(-1)*V')^(-1)                              |
//| Note that B is calculated using constant term (D1) only, which   |
//| allows us to update D2 without recalculation of B or VC. Such    |
//| preconditioner is exact when D2 is zero. When D2 is non-zero, it |
//| is only approximation, but very good and cheap one.              |
//| This function accepts D1, V, C.                                  |
//| D2 is set to zero by default.                                    |
//| Cost of this update is O(N*VCnt*VCnt), but D2 can be updated in  |
//| just O(N) by MinCGSetPrecVarPart.                                |
//+------------------------------------------------------------------+
static void CMinCG::MinCGSetPrecLowRankFast(CMinCGState &state,double &d1[],
                                            double &c[],CMatrixDouble &v,
                                            const int vcnt)
  {
//--- create variables
   int    i=0;
   int    i_=0;
   int    j=0;
   int    k=0;
   int    n=0;
   double t=0;
//--- create matrix
   CMatrixDouble b;
//--- check
   if(vcnt==0)
     {
      //--- function call
      MinCGSetPrecDiagFast(state,d1);
      return;
     }
//--- initialization
   n=state.m_n;
   b.Resize(vcnt,vcnt);
//--- function call
   CApServ::RVectorSetLengthAtLeast(state.m_diagh,n);
//--- function call
   CApServ::RVectorSetLengthAtLeast(state.m_diaghl2,n);
//--- function call
   CApServ::RMatrixSetLengthAtLeast(state.m_vcorr,vcnt,n);
   state.m_prectype=2;
   state.m_vcnt=vcnt;
   state.m_innerresetneeded=true;
//--- copy
   for(i=0;i<=n-1;i++)
     {
      state.m_diagh[i]=d1[i];
      state.m_diaghl2[i]=0.0;
     }
//--- calculation
   for(i=0;i<=vcnt-1;i++)
     {
      for(j=i;j<=vcnt-1;j++)
        {
         t=0;
         for(k=0;k<=n-1;k++)
            t=t+v[i][k]*v[j][k]/d1[k];
         b[i].Set(j,t);
        }
      b[i].Set(i,b[i][i]+1.0/c[i]);
     }
//--- check
   if(!CTrFac::SPDMatrixCholeskyRec(b,0,vcnt,true,state.m_work0))
     {
      state.m_vcnt=0;
      return;
     }
//--- calculation
   for(i=0;i<=vcnt-1;i++)
     {
      for(i_=0;i_<=n-1;i_++)
         state.m_vcorr[i].Set(i_,v[i][i_]);
      //--- change values
      for(j=0;j<=i-1;j++)
        {
         t=b[j][i];
         for(i_=0;i_<=n-1;i_++)
            state.m_vcorr[i].Set(i_,state.m_vcorr[i][i_]-t*state.m_vcorr[j][i_]);
        }
      t=1/b[i][i];
      //--- change values
      for(i_=0;i_<=n-1;i_++)
         state.m_vcorr[i].Set(i_,t*state.m_vcorr[i][i_]);
     }
  }
//+------------------------------------------------------------------+
//| This function updates variable part (diagonal matrix D2)         |
//| of low-rank preconditioner.                                      |
//| This update is very cheap and takes just O(N) time.              |
//| It has no effect with default preconditioner.                    |
//+------------------------------------------------------------------+
static void CMinCG::MinCGSetPrecVarPart(CMinCGState &state,double &d2[])
  {
//--- create variables
   int i=0;
   int n=0;
//--- initialization
   n=state.m_n;
//--- copy
   for(i=0;i<=n-1;i++)
      state.m_diaghl2[i]=d2[i];
  }
//+------------------------------------------------------------------+
//| Clears request fileds (to be sure that we don't forgot to clear  |
//| something)                                                       |
//+------------------------------------------------------------------+
static void CMinCG::ClearRequestFields(CMinCGState &state)
  {
//--- change values
   state.m_needf=false;
   state.m_needfg=false;
   state.m_xupdated=false;
   state.m_lsstart=false;
   state.m_lsend=false;
   state.m_algpowerup=false;
  }
//+------------------------------------------------------------------+
//| This function calculates preconditioned product H^(-1)*x and     |
//| stores result back into X. Work0[] and Work1[] are used as       |
//| temporaries (size must be at least N; this function doesn't      |
//| allocate arrays).                                                |
//+------------------------------------------------------------------+
static void CMinCG::PreconditionedMultiply(CMinCGState &state,double &x[],
                                           double &work0[],double &work1[])
  {
//--- create variables
   int    i=0;
   int    n=0;
   int    vcnt=0;
   double v=0;
   int    i_=0;
//--- initialization
   n=state.m_n;
   vcnt=state.m_vcnt;
//--- check
   if(state.m_prectype==0)
      return;
//--- check
   if(state.m_prectype==3)
     {
      for(i=0;i<=n-1;i++)
         x[i]=x[i]*state.m_s[i]*state.m_s[i];
      //--- exit the function
      return;
     }
//--- check
   if(!CAp::Assert(state.m_prectype==2,__FUNCTION__+": internal error (unexpected PrecType)"))
      return;
//--- handle part common for VCnt=0 and VCnt<>0
   for(i=0;i<=n-1;i++)
      x[i]=x[i]/(state.m_diagh[i]+state.m_diaghl2[i]);
//--- if VCnt>0
   if(vcnt>0)
     {
      //--- calculation work0
      for(i=0;i<=vcnt-1;i++)
        {
         v=0.0;
         for(i_=0;i_<=n-1;i_++)
            v+=state.m_vcorr[i][i_]*x[i_];
         work0[i]=v;
        }
      //--- calculation work1
      for(i=0;i<=n-1;i++)
         work1[i]=0;
      for(i=0;i<=vcnt-1;i++)
        {
         v=work0[i];
         for(i_=0;i_<=n-1;i_++)
            state.m_work1[i_]=state.m_work1[i_]+v*state.m_vcorr[i][i_];
        }
      //--- change x
      for(i=0;i<=n-1;i++)
         x[i]=x[i]-state.m_work1[i]/(state.m_diagh[i]+state.m_diaghl2[i]);
     }
  }
//+------------------------------------------------------------------+
//| This function calculates preconditioned product x'*H^(-1)*y.     |
//| Work0[] and Work1[] are used as temporaries (size must be at     |
//| least N; this function doesn't allocate arrays).                 |
//+------------------------------------------------------------------+
static double CMinCG::PreconditionedMultiply2(CMinCGState &state,double &x[],
                                              double &y[],double &work0[],
                                              double &work1[])
  {
//--- create variables
   double result=0;
   int    i=0;
   int    n=0;
   int    vcnt=0;
   double v0=0;
   double v1=0;
   int    i_=0;
//--- initialization
   n=state.m_n;
   vcnt=state.m_vcnt;
//--- no preconditioning
   if(state.m_prectype==0)
     {
      v0=0.0;
      for(i_=0;i_<=n-1;i_++)
         v0+=x[i_]*y[i_];
      //--- return result
      return(v0);
     }
//--- check
   if(state.m_prectype==3)
     {
      result=0;
      for(i=0;i<=n-1;i++)
         result=result+x[i]*state.m_s[i]*state.m_s[i]*y[i];
      //--- return result
      return(result);
     }
//--- check
   if(!CAp::Assert(state.m_prectype==2,__FUNCTION__+": internal error (unexpected PrecType)"))
      return(EMPTY_VALUE);
//--- low rank preconditioning
   result=0.0;
   for(i=0;i<=n-1;i++)
      result=result+x[i]*y[i]/(state.m_diagh[i]+state.m_diaghl2[i]);
//--- check
   if(vcnt>0)
     {
      //--- prepare arrays
      for(i=0;i<=n-1;i++)
        {
         work0[i]=x[i]/(state.m_diagh[i]+state.m_diaghl2[i]);
         work1[i]=y[i]/(state.m_diagh[i]+state.m_diaghl2[i]);
        }
      for(i=0;i<=vcnt-1;i++)
        {
         //--- calculation
         v0=0.0;
         for(i_=0;i_<=n-1;i_++)
            v0+=work0[i_]*state.m_vcorr[i][i_];
         v1=0.0;
         for(i_=0;i_<=n-1;i_++)
            v1+=work1[i_]*state.m_vcorr[i][i_];
         //--- get result
         result=result-v0*v1;
        }
     }
//--- return result
   return(result);
  }
//+------------------------------------------------------------------+
//| Internal initialization subroutine                               |
//+------------------------------------------------------------------+
static void CMinCG::MinCGInitInternal(const int n,const double diffstep,
                                      CMinCGState &state)
  {
//--- create a variable
   int i=0;
//--- initialization
   state.m_n=n;
   state.m_diffstep=diffstep;
//--- function call
   MinCGSetCond(state,0,0,0,0);
//--- function call
   MinCGSetXRep(state,false);
//--- function call
   MinCGSetDRep(state,false);
//--- function call
   MinCGSetStpMax(state,0);
//--- function call
   MinCGSetCGType(state,-1);
//--- function call
   MinCGSetPrecDefault(state);
//--- allocation
   ArrayResizeAL(state.m_xk,n);
   ArrayResizeAL(state.m_dk,n);
   ArrayResizeAL(state.m_xn,n);
   ArrayResizeAL(state.m_dn,n);
   ArrayResizeAL(state.m_x,n);
   ArrayResizeAL(state.m_d,n);
   ArrayResizeAL(state.m_g,n);
   ArrayResizeAL(state.m_work0,n);
   ArrayResizeAL(state.m_work1,n);
   ArrayResizeAL(state.m_yk,n);
   ArrayResizeAL(state.m_s,n);
//--- copy
   for(i=0;i<=n-1;i++)
      state.m_s[i]=1.0;
  }
//+------------------------------------------------------------------+
//| NOTES:                                                           |
//| 1. This function has two different implementations: one which    |
//|    uses exact (analytical) user-supplied  gradient, and one which| 
//|    uses function value only and numerically differentiates       |
//|    function in order to obtain gradient.                         |
//|    Depending on the specific function used to create optimizer   |
//|    object (either MinCGCreate() for analytical gradient or       |
//|    MinCGCreateF() for numerical differentiation) you should      |
//|    choose appropriate variant of MinCGOptimize() - one which     |
//|    accepts function AND gradient or one which accepts function   |
//|    ONLY.                                                         |
//|    Be careful to choose variant of MinCGOptimize() which         |
//|    corresponds to your optimization scheme! Table below lists    |
//|    different combinations of callback (function/gradient) passed |
//|    to MinCGOptimize() and specific function used to create       |
//|    optimizer.                                                    |
//|                   |         USER PASSED TO MinCGOptimize()       |
//|    CREATED WITH   |  function only   |  function and gradient    |
//|    ------------------------------------------------------------  |
//|    MinCGCreateF() |     work                FAIL                 |
//|    MinCGCreate()  |     FAIL                work                 |
//|    Here "FAIL" denotes inappropriate combinations of optimizer   |
//|    creation function and MinCGOptimize() version. Attemps to use |
//|    such combination (for example, to create optimizer with       |
//|    MinCGCreateF() and to pass gradient information to            |
//|    MinCGOptimize()) will lead to exception being thrown. Either  |
//|    you did not pass gradient when it WAS needed or you passed    |
//|    gradient when it was NOT needed.                              |
//+------------------------------------------------------------------+
static bool CMinCG::MinCGIteration(CMinCGState &state)
  {
//--- create variables
   int    n=0;
   int    i=0;
   double betak=0;
   double v=0;
   double vv=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];
      i=state.m_rstate.ia[1];
      betak=state.m_rstate.ra[0];
      v=state.m_rstate.ra[1];
      vv=state.m_rstate.ra[2];
     }
   else
     {
      //--- initialization
      n=-983;
      i=-989;
      betak=-834;
      v=900;
      vv=-287;
     }
//--- check
   if(state.m_rstate.stage==0)
     {
      //--- change value
      state.m_needfg=false;
      //--- function call, return result
      return(Func_lbl_18(state,n,i,betak,v,vv));
     }
//--- check
   if(state.m_rstate.stage==1)
     {
      //--- change values
      state.m_fbase=state.m_f;
      i=0;
      //--- function call, return result
      return(Func_lbl_19(state,n,i,betak,v,vv));
     }
//--- check
   if(state.m_rstate.stage==2)
     {
      //--- change values
      state.m_fm2=state.m_f;
      state.m_x[i]=v-0.5*state.m_diffstep*state.m_s[i];
      state.m_rstate.stage=3;
      //--- Saving state
      Func_lbl_rcomm(state,n,i,betak,v,vv);
      return(true);
     }
//--- check
   if(state.m_rstate.stage==3)
     {
      //--- change values
      state.m_fm1=state.m_f;
      state.m_x[i]=v+0.5*state.m_diffstep*state.m_s[i];
      state.m_rstate.stage=4;
      //--- Saving state
      Func_lbl_rcomm(state,n,i,betak,v,vv);
      return(true);
     }
//--- check
   if(state.m_rstate.stage==4)
     {
      //--- change values
      state.m_fp1=state.m_f;
      state.m_x[i]=v+state.m_diffstep*state.m_s[i];
      state.m_rstate.stage=5;
      //--- Saving state
      Func_lbl_rcomm(state,n,i,betak,v,vv);
      return(true);
     }
//--- check
   if(state.m_rstate.stage==5)
     {
      //--- change values
      state.m_fp2=state.m_f;
      state.m_x[i]=v;
      state.m_g[i]=(8*(state.m_fp1-state.m_fm1)-(state.m_fp2-state.m_fm2))/(6*state.m_diffstep*state.m_s[i]);
      i=i+1;
      //--- function call, return result
      return(Func_lbl_19(state,n,i,betak,v,vv));
     }
//--- check
   if(state.m_rstate.stage==6)
     {
      //--- change value
      state.m_algpowerup=false;
      //--- function call, return result
      return(Func_lbl_22(state,n,i,betak,v,vv));
     }
//--- check
   if(state.m_rstate.stage==7)
     {
      //--- change value
      state.m_xupdated=false;
      //--- function call, return result
      return(Func_lbl_24(state,n,i,betak,v,vv));
     }
//--- check
   if(state.m_rstate.stage==8)
     {
      //--- change value
      state.m_lsstart=false;
      //--- function call, return result
      return(Func_lbl_28(state,n,i,betak,v,vv));
     }
//--- check
   if(state.m_rstate.stage==9)
     {
      //--- change value
      state.m_needfg=false;
      //--- function call, return result
      return(Func_lbl_33(state,n,i,betak,v,vv));
     }
//--- check
   if(state.m_rstate.stage==10)
     {
      //--- change values
      state.m_fbase=state.m_f;
      i=0;
      //--- function call, return result
      return(Func_lbl_34(state,n,i,betak,v,vv));
     }
//--- check
   if(state.m_rstate.stage==11)
     {
      //--- change values
      state.m_fm2=state.m_f;
      state.m_x[i]=v-0.5*state.m_diffstep*state.m_s[i];
      state.m_rstate.stage=12;
      //--- Saving state
      Func_lbl_rcomm(state,n,i,betak,v,vv);
      return(true);
     }
//--- check
   if(state.m_rstate.stage==12)
     {
      //--- change values
      state.m_fm1=state.m_f;
      state.m_x[i]=v+0.5*state.m_diffstep*state.m_s[i];
      state.m_rstate.stage=13;
      //--- Saving state
      Func_lbl_rcomm(state,n,i,betak,v,vv);
      return(true);
     }
//--- check
   if(state.m_rstate.stage==13)
     {
      //--- change values
      state.m_fp1=state.m_f;
      state.m_x[i]=v+state.m_diffstep*state.m_s[i];
      state.m_rstate.stage=14;
      //--- Saving state
      Func_lbl_rcomm(state,n,i,betak,v,vv);
      return(true);
     }
//--- check
   if(state.m_rstate.stage==14)
     {
      //--- change values
      state.m_fp2=state.m_f;
      state.m_x[i]=v;
      state.m_g[i]=(8*(state.m_fp1-state.m_fm1)-(state.m_fp2-state.m_fm2))/(6*state.m_diffstep*state.m_s[i]);
      i=i+1;
      //--- function call, return result
      return(Func_lbl_34(state,n,i,betak,v,vv));
     }
//--- check
   if(state.m_rstate.stage==15)
     {
      //--- change value
      state.m_lsend=false;
      //--- function call, return result
      return(Func_lbl_37(state,n,i,betak,v,vv));
     }
//--- check
   if(state.m_rstate.stage==16)
     {
      //--- change value
      state.m_xupdated=false;
      //--- function call, return result
      return(Func_lbl_39(state,n,i,betak,v,vv));
     }
//--- Routine body
//--- Prepare
   n=state.m_n;
   state.m_repterminationtype=0;
   state.m_repiterationscount=0;
   state.m_repnfev=0;
   state.m_debugrestartscount=0;
//--- Preparations continue:
//--- * set XK
//--- * calculate F/G
//--- * set DK to -G
//--- * powerup algo (it may change preconditioner)
//--- * apply preconditioner to DK
//--- * report update of X
//--- * check stopping conditions for G
   for(i_=0;i_<=n-1;i_++)
      state.m_xk[i_]=state.m_x[i_];
//--- change value
   state.m_terminationneeded=false;
//--- function call
   ClearRequestFields(state);
//--- check
   if(state.m_diffstep!=0.0)
     {
      state.m_needf=true;
      state.m_rstate.stage=1;
      //--- Saving state
      Func_lbl_rcomm(state,n,i,betak,v,vv);
      //--- return result
      return(true);
     }
//--- change values
   state.m_needfg=true;
   state.m_rstate.stage=0;
//--- Saving state
   Func_lbl_rcomm(state,n,i,betak,v,vv);
//--- return result
   return(true);
  }
//+------------------------------------------------------------------+
//| Auxiliary function for MinCGIteration. Is a product to get rid of|
//| the operator unconditional jump goto.                            |
//+------------------------------------------------------------------+
static void CMinCG::Func_lbl_rcomm(CMinCGState &state,int n,int i,
                                   double betak,double v,double vv)
  {
//--- save
   state.m_rstate.ia[0]=n;
   state.m_rstate.ia[1]=i;
   state.m_rstate.ra[0]=betak;
   state.m_rstate.ra[1]=v;
   state.m_rstate.ra[2]=vv;
  }
//+------------------------------------------------------------------+
//| Auxiliary function for MinCGIteration. Is a product to get rid of|
//| the operator unconditional jump goto.                            |
//+------------------------------------------------------------------+
static bool CMinCG::Func_lbl_18(CMinCGState &state,int &n,int &i,
                                double &betak,double &v,double &vv)
  {
//--- check
   if(!state.m_drep)
      return(Func_lbl_22(state,n,i,betak,v,vv));
//--- Report algorithm powerup (if needed)
   ClearRequestFields(state);
//--- change values
   state.m_algpowerup=true;
   state.m_rstate.stage=6;
//--- Saving state
   Func_lbl_rcomm(state,n,i,betak,v,vv);
//--- return result
   return(true);
  }
//+------------------------------------------------------------------+
//| Auxiliary function for MinCGIteration. Is a product to get rid of|
//| the operator unconditional jump goto.                            |
//+------------------------------------------------------------------+
static bool CMinCG::Func_lbl_19(CMinCGState &state,int &n,int &i,
                                double &betak,double &v,double &vv)
  {
//--- check
   if(i>n-1)
     {
      state.m_f=state.m_fbase;
      state.m_needf=false;
      //--- function call, return result
      return(Func_lbl_18(state,n,i,betak,v,vv));
     }
//--- change values
   v=state.m_x[i];
   state.m_x[i]=v-state.m_diffstep*state.m_s[i];
   state.m_rstate.stage=2;
//--- Saving state
   Func_lbl_rcomm(state,n,i,betak,v,vv);
//--- return result
   return(true);
  }
//+------------------------------------------------------------------+
//| Auxiliary function for MinCGIteration. Is a product to get rid of|
//| the operator unconditional jump goto.                            |
//+------------------------------------------------------------------+
static bool CMinCG::Func_lbl_22(CMinCGState &state,int &n,int &i,
                                double &betak,double &v,double &vv)
  {
//--- function call
   COptServ::TrimPrepare(state.m_f,state.m_trimthreshold);
   for(int i_=0;i_<=n-1;i_++)
      state.m_dk[i_]=-state.m_g[i_];
//--- function call
   PreconditionedMultiply(state,state.m_dk,state.m_work0,state.m_work1);
//--- check
   if(!state.m_xrep)
      return(Func_lbl_24(state,n,i,betak,v,vv));
//--- function call
   ClearRequestFields(state);
//--- change values
   state.m_xupdated=true;
   state.m_rstate.stage=7;
//--- Saving state
   Func_lbl_rcomm(state,n,i,betak,v,vv);
//--- return result
   return(true);
  }
//+------------------------------------------------------------------+
//| Auxiliary function for MinCGIteration. Is a product to get rid of|
//| the operator unconditional jump goto.                            |
//+------------------------------------------------------------------+
static bool CMinCG::Func_lbl_24(CMinCGState &state,int &n,int &i,
                                double &betak,double &v,double &vv)
  {
//--- check
   if(state.m_terminationneeded)
     {
      for(int i_=0;i_<=n-1;i_++)
         state.m_xn[i_]=state.m_xk[i_];
      state.m_repterminationtype=8;
      //--- return result
      return(false);
     }
//--- change value
   v=0;
   for(i=0;i<=n-1;i++)
      v=v+CMath::Sqr(state.m_g[i]*state.m_s[i]);
//--- check
   if(MathSqrt(v)<=state.m_epsg)
     {
      for(int i_=0;i_<=n-1;i_++)
         state.m_xn[i_]=state.m_xk[i_];
      state.m_repterminationtype=4;
      //--- return result
      return(false);
     }
//--- change values
   state.m_repnfev=1;
   state.m_k=0;
   state.m_fold=state.m_f;
//--- Choose initial step.
//--- Apply preconditioner,if we have something other than default.
   if(state.m_prectype==2||state.m_prectype==3)
     {
      //--- because we use preconditioner,step length must be equal
      //--- to the norm of DK
      v=0.0;
      for(int i_=0;i_<=n-1;i_++)
         v+=state.m_dk[i_]*state.m_dk[i_];
      state.m_laststep=MathSqrt(v);
     }
   else
     {
      //--- No preconditioner is used,we try to use suggested step
      if(state.m_suggestedstep>0.0)
         state.m_laststep=state.m_suggestedstep;
      else
        {
         //--- change value
         v=0.0;
         for(int i_=0;i_<=n-1;i_++)
            v+=state.m_g[i_]*state.m_g[i_];
         v=MathSqrt(v);
         //--- check
         if(state.m_stpmax==0.0)
            state.m_laststep=MathMin(1.0/v,1);
         else
            state.m_laststep=MathMin(1.0/v,state.m_stpmax);
        }
     }
//--- Main cycle
   state.m_rstimer=m_rscountdownlen;
//--- function call, return result
   return(Func_lbl_26(state,n,i,betak,v,vv));
  }
//+------------------------------------------------------------------+
//| Auxiliary function for MinCGIteration. Is a product to get rid of|
//| the operator unconditional jump goto.                            |
//+------------------------------------------------------------------+
static bool CMinCG::Func_lbl_26(CMinCGState &state,int &n,int &i,
                                double &betak,double &v,double &vv)
  {
//--- * clear reset flag
//--- * clear termination flag
//--- * store G[k] for later calculation of Y[k]
//--- * prepare starting point and direction and step length for line search
   state.m_innerresetneeded=false;
   state.m_terminationneeded=false;
   for(int i_=0;i_<=n-1;i_++)
      state.m_yk[i_]=-state.m_g[i_];
   for(int i_=0;i_<=n-1;i_++)
      state.m_d[i_]=state.m_dk[i_];
   for(int i_=0;i_<=n-1;i_++)
      state.m_x[i_]=state.m_xk[i_];
//--- change values
   state.m_mcstage=0;
   state.m_stp=1.0;
//--- function call
   CLinMin::LinMinNormalized(state.m_d,state.m_stp,n);
//--- check
   if(state.m_laststep!=0.0)
      state.m_stp=state.m_laststep;
   state.m_curstpmax=state.m_stpmax;
//--- Report beginning of line search (if needed)
//--- Terminate algorithm,if user request was detected
   if(!state.m_drep)
      return(Func_lbl_28(state,n,i,betak,v,vv));
//--- function call
   ClearRequestFields(state);
//--- change values
   state.m_lsstart=true;
   state.m_rstate.stage=8;
//--- Saving state
   Func_lbl_rcomm(state,n,i,betak,v,vv);
//--- return result
   return(true);
  }
//+------------------------------------------------------------------+
//| Auxiliary function for MinCGIteration. Is a product to get rid of|
//| the operator unconditional jump goto.                            |
//+------------------------------------------------------------------+
static bool CMinCG::Func_lbl_28(CMinCGState &state,int &n,int &i,
                                double &betak,double &v,double &vv)
  {
//--- check
   if(state.m_terminationneeded)
     {
      for(int i_=0;i_<=n-1;i_++)
         state.m_xn[i_]=state.m_x[i_];
      state.m_repterminationtype=8;
      //--- return result
      return(false);
     }
//--- Minimization along D
   CLinMin::MCSrch(n,state.m_x,state.m_f,state.m_g,state.m_d,state.m_stp,state.m_curstpmax,m_gtol,state.m_mcinfo,state.m_nfev,state.m_work0,state.m_lstate,state.m_mcstage);
//--- function call, return result
   return(Func_lbl_30(state,n,i,betak,v,vv));
  }
//+------------------------------------------------------------------+
//| Auxiliary function for MinCGIteration. Is a product to get rid of|
//| the operator unconditional jump goto.                            |
//+------------------------------------------------------------------+
static bool CMinCG::Func_lbl_30(CMinCGState &state,int &n,int &i,
                                double &betak,double &v,double &vv)
  {
//--- check
   if(state.m_mcstage==0)
      return(Func_lbl_31(state,n,i,betak,v,vv));
//--- Calculate function/gradient using either
//--- analytical gradient supplied by user
//--- or finite difference approximation.
//--- "Trim" function in order to handle near-singularity points.
   ClearRequestFields(state);
//--- check
   if((double)(state.m_diffstep)!=0.0)
     {
      state.m_needf=true;
      state.m_rstate.stage=10;
      //--- Saving state
      Func_lbl_rcomm(state,n,i,betak,v,vv);
      //--- return result
      return(true);
     }
//--- change values
   state.m_needfg=true;
   state.m_rstate.stage=9;
//--- Saving state
   Func_lbl_rcomm(state,n,i,betak,v,vv);
//--- return result
   return(true);
  }
//+------------------------------------------------------------------+
//| Auxiliary function for MinCGIteration. Is a product to get rid of|
//| the operator unconditional jump goto.                            |
//+------------------------------------------------------------------+
static bool CMinCG::Func_lbl_31(CMinCGState &state,int &n,int &i,
                                double &betak,double &v,double &vv)
  {
//--- * report end of line search
//--- * store current point to XN
//--- * report iteration
//--- * terminate algorithm if user request was detected
   if(!state.m_drep)
      return(Func_lbl_37(state,n,i,betak,v,vv));
//--- Report end of line search (if needed)
   ClearRequestFields(state);
//--- change values
   state.m_lsend=true;
   state.m_rstate.stage=15;
//--- Saving state
   Func_lbl_rcomm(state,n,i,betak,v,vv);
//--- return result
   return(true);
  }
//+------------------------------------------------------------------+
//| Auxiliary function for MinCGIteration. Is a product to get rid of|
//| the operator unconditional jump goto.                            |
//+------------------------------------------------------------------+
static bool CMinCG::Func_lbl_33(CMinCGState &state,int &n,int &i,
                                double &betak,double &v,double &vv)
  {
//--- function call
   COptServ::TrimFunction(state.m_f,state.m_g,n,state.m_trimthreshold);
//--- Call MCSRCH again
   CLinMin::MCSrch(n,state.m_x,state.m_f,state.m_g,state.m_d,state.m_stp,state.m_curstpmax,m_gtol,state.m_mcinfo,state.m_nfev,state.m_work0,state.m_lstate,state.m_mcstage);
//--- function call, return result
   return(Func_lbl_30(state,n,i,betak,v,vv));
  }
//+------------------------------------------------------------------+
//| Auxiliary function for MinCGIteration. Is a product to get rid of|
//| the operator unconditional jump goto.                            |
//+------------------------------------------------------------------+
static bool CMinCG::Func_lbl_34(CMinCGState &state,int &n,int &i,
                                double &betak,double &v,double &vv)
  {
//--- check
   if(i>n-1)
     {
      state.m_f=state.m_fbase;
      state.m_needf=false;
      //--- function call, return result
      return(Func_lbl_33(state,n,i,betak,v,vv));
     }
//--- change values
   v=state.m_x[i];
   state.m_x[i]=v-state.m_diffstep*state.m_s[i];
   state.m_rstate.stage=11;
//--- Saving state
   Func_lbl_rcomm(state,n,i,betak,v,vv);
//--- return result
   return(true);
  }
//+------------------------------------------------------------------+
//| Auxiliary function for MinCGIteration. Is a product to get rid of|
//| the operator unconditional jump goto.                            |
//+------------------------------------------------------------------+
static bool CMinCG::Func_lbl_37(CMinCGState &state,int &n,int &i,
                                double &betak,double &v,double &vv)
  {
//--- copy
   for(int i_=0;i_<=n-1;i_++)
      state.m_xn[i_]=state.m_x[i_];
//--- check
   if(!state.m_xrep)
      return(Func_lbl_39(state,n,i,betak,v,vv));
//--- function call
   ClearRequestFields(state);
//--- change values
   state.m_xupdated=true;
   state.m_rstate.stage=16;
//--- Saving state
   Func_lbl_rcomm(state,n,i,betak,v,vv);
//--- return result
   return(true);
  }
//+------------------------------------------------------------------+
//| Auxiliary function for MinCGIteration. Is a product to get rid of|
//| the operator unconditional jump goto.                            |
//+------------------------------------------------------------------+
static bool CMinCG::Func_lbl_39(CMinCGState &state,int &n,int &i,
                                double &betak,double &v,double &vv)
  {
//--- check
   if(state.m_terminationneeded)
     {
      for(int i_=0;i_<=n-1;i_++)
         state.m_xn[i_]=state.m_x[i_];
      state.m_repterminationtype=8;
      //--- return result
      return(false);
     }
//--- Line search is finished.
//--- * calculate BetaK
//--- * calculate DN
//--- * update timers
//--- * calculate step length
   if(state.m_mcinfo==1 && !state.m_innerresetneeded)
     {
      //--- Standard Wolfe conditions hold
      //--- Calculate Y[K] and D[K]'*Y[K]
      for(int i_=0;i_<=n-1;i_++)
         state.m_yk[i_]=state.m_yk[i_]+state.m_g[i_];
      //--- change value
      vv=0.0;
      for(int i_=0;i_<=n-1;i_++)
         vv+=state.m_yk[i_]*state.m_dk[i_];
      //--- Calculate BetaK according to DY formula
      v=PreconditionedMultiply2(state,state.m_g,state.m_g,state.m_work0,state.m_work1);
      state.m_betady=v/vv;
      //--- Calculate BetaK according to HS formula
      v=PreconditionedMultiply2(state,state.m_g,state.m_yk,state.m_work0,state.m_work1);
      state.m_betahs=v/vv;
      //--- Choose BetaK
      if(state.m_cgtype==0)
         betak=state.m_betady;
      //--- check
      if(state.m_cgtype==1)
         betak=MathMax(0,MathMin(state.m_betady,state.m_betahs));
     }
   else
     {
      //--- Something is wrong (may be function is too wild or too flat)
      //--- or we just have to restart algo.
      //--- We'll set BetaK=0,which will restart CG algorithm.
      //--- We can stop later (during normal checks) if stopping conditions are met.
      betak=0;
      state.m_debugrestartscount=state.m_debugrestartscount+1;
     }
//--- check
   if(state.m_repiterationscount>0&&state.m_repiterationscount%(3+n)==0)
     {
      //--- clear Beta every N iterations
      betak=0;
     }
//--- check
   if(state.m_mcinfo==1||state.m_mcinfo==5)
      state.m_rstimer=m_rscountdownlen;
   else
      state.m_rstimer=state.m_rstimer-1;
   for(int i_=0;i_<=n-1;i_++)
      state.m_dn[i_]=-state.m_g[i_];
//--- function call
   PreconditionedMultiply(state,state.m_dn,state.m_work0,state.m_work1);
   for(int i_=0;i_<=n-1;i_++)
      state.m_dn[i_]=state.m_dn[i_]+betak*state.m_dk[i_];
//--- change values
   state.m_laststep=0;
   state.m_lastscaledstep=0.0;
   for(i=0;i<=n-1;i++)
     {
      state.m_laststep=state.m_laststep+CMath::Sqr(state.m_d[i]);
      state.m_lastscaledstep=state.m_lastscaledstep+CMath::Sqr(state.m_d[i]/state.m_s[i]);
     }
//--- change values
   state.m_laststep=state.m_stp*MathSqrt(state.m_laststep);
   state.m_lastscaledstep=state.m_stp*MathSqrt(state.m_lastscaledstep);
//--- Update information.
//--- Check stopping conditions.
   state.m_repnfev=state.m_repnfev+state.m_nfev;
   state.m_repiterationscount=state.m_repiterationscount+1;
//--- check
   if(state.m_repiterationscount>=state.m_maxits&&state.m_maxits>0)
     {
      //--- Too many iterations
      state.m_repterminationtype=5;
      //--- return result
      return(false);
     }
//--- change value
   v=0;
   for(i=0;i<=n-1;i++)
      v=v+CMath::Sqr(state.m_g[i]*state.m_s[i]);
//--- check
   if(MathSqrt(v)<=state.m_epsg)
     {
      //--- Gradient is small enough
      state.m_repterminationtype=4;
      //--- return result
      return(false);
     }
//--- check
   if(!state.m_innerresetneeded)
     {
      //--- These conditions are checked only when no inner reset was requested by user
      if(state.m_fold-state.m_f<=state.m_epsf*MathMax(MathAbs(state.m_fold),MathMax(MathAbs(state.m_f),1.0)))
        {
         //--- F(k+1)-F(k) is small enough
         state.m_repterminationtype=1;
         //--- return result
         return(false);
        }
      //--- check
      if(state.m_lastscaledstep<=state.m_epsx)
        {
         //--- X(k+1)-X(k) is small enough
         state.m_repterminationtype=2;
         //--- return result
         return(false);
        }
     }
//--- check
   if(state.m_rstimer<=0)
     {
      //--- Too many subsequent restarts
      state.m_repterminationtype=7;
      //--- return result
      return(false);
     }
//--- Shift Xk/Dk,update other information
   for(int i_=0;i_<=n-1;i_++)
      state.m_xk[i_]=state.m_xn[i_];
   for(int i_=0;i_<=n-1;i_++)
      state.m_dk[i_]=state.m_dn[i_];
//--- change values
   state.m_fold=state.m_f;
   state.m_k=state.m_k+1;
//--- function call, return result
   return(Func_lbl_26(state,n,i,betak,v,vv));
  }
//+------------------------------------------------------------------+
//| This object stores nonlinear optimizer state.                    |
//| You should use functions provided by MinBLEIC subpackage to work |
//| with this object                                                 |
//+------------------------------------------------------------------+
class CMinBLEICState
  {
public:
   //--- variables
   int               m_nmain;
   int               m_nslack;
   double            m_innerepsg;
   double            m_innerepsf;
   double            m_innerepsx;
   double            m_outerepsx;
   double            m_outerepsi;
   int               m_maxits;
   bool              m_xrep;
   double            m_stpmax;
   double            m_diffstep;
   int               m_prectype;
   double            m_f;
   bool              m_needf;
   bool              m_needfg;
   bool              m_xupdated;
   RCommState        m_rstate;
   int               m_repinneriterationscount;
   int               m_repouteriterationscount;
   int               m_repnfev;
   int               m_repterminationtype;
   double            m_repdebugeqerr;
   double            m_repdebugfs;
   double            m_repdebugff;
   double            m_repdebugdx;
   int               m_itsleft;
   double            m_trimthreshold;
   int               m_cecnt;
   int               m_cedim;
   double            m_v0;
   double            m_v1;
   double            m_v2;
   double            m_t;
   double            m_errfeas;
   double            m_gnorm;
   double            m_mpgnorm;
   double            m_mba;
   int               m_variabletofreeze;
   double            m_valuetofreeze;
   double            m_fbase;
   double            m_fm2;
   double            m_fm1;
   double            m_fp1;
   double            m_fp2;
   double            m_xm1;
   double            m_xp1;
   CMinCGState       m_cgstate;
   CMinCGReport      m_cgrep;
   int               m_optdim;
   //--- arrays
   double            m_diaghoriginal[];
   double            m_diagh[];
   double            m_x[];
   double            m_g[];
   double            m_xcur[];
   double            m_xprev[];
   double            m_xstart[];
   double            m_xend[];
   double            m_lastg[];
   int               m_ct[];
   double            m_xe[];
   bool              m_hasbndl[];
   bool              m_hasbndu[];
   double            m_bndloriginal[];
   double            m_bnduoriginal[];
   double            m_bndleffective[];
   double            m_bndueffective[];
   bool              m_activeconstraints[];
   double            m_constrainedvalues[];
   double            m_transforms[];
   double            m_seffective[];
   double            m_soriginal[];
   double            m_w[];
   double            m_tmp0[];
   double            m_tmp1[];
   double            m_tmp2[];
   double            m_r[];
   //--- matrix
   CMatrixDouble     m_ceoriginal;
   CMatrixDouble     m_ceeffective;
   CMatrixDouble     m_cecurrent;
   CMatrixDouble     m_lmmatrix;
   //--- constructor, destructor
                     CMinBLEICState(void);
                    ~CMinBLEICState(void);
   //--- copy
   void              Copy(CMinBLEICState &obj);
  };
//+------------------------------------------------------------------+
//| Constructor without parameters                                   |
//+------------------------------------------------------------------+
CMinBLEICState::CMinBLEICState(void)
  {

  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CMinBLEICState::~CMinBLEICState(void)
  {

  }
//+------------------------------------------------------------------+
//| Copy                                                             |
//+------------------------------------------------------------------+
void CMinBLEICState::Copy(CMinBLEICState &obj)
  {
//--- copy variables
   m_nmain=obj.m_nmain;
   m_nslack=obj.m_nslack;
   m_innerepsg=obj.m_innerepsg;
   m_innerepsf=obj.m_innerepsf;
   m_innerepsx=obj.m_innerepsx;
   m_outerepsx=obj.m_outerepsx;
   m_outerepsi=obj.m_outerepsi;
   m_maxits=obj.m_maxits;
   m_xrep=obj.m_xrep;
   m_stpmax=obj.m_stpmax;
   m_diffstep=obj.m_diffstep;
   m_prectype=obj.m_prectype;
   m_f=obj.m_f;
   m_needf=obj.m_needf;
   m_needfg=obj.m_needfg;
   m_xupdated=obj.m_xupdated;
   m_repinneriterationscount=obj.m_repinneriterationscount;
   m_repouteriterationscount=obj.m_repouteriterationscount;
   m_repnfev=obj.m_repnfev;
   m_repterminationtype=obj.m_repterminationtype;
   m_repdebugeqerr=obj.m_repdebugeqerr;
   m_repdebugfs=obj.m_repdebugfs;
   m_repdebugff=obj.m_repdebugff;
   m_repdebugdx=obj.m_repdebugdx;
   m_itsleft=obj.m_itsleft;
   m_trimthreshold=obj.m_trimthreshold;
   m_cecnt=obj.m_cecnt;
   m_cedim=obj.m_cedim;
   m_v0=obj.m_v0;
   m_v1=obj.m_v1;
   m_v2=obj.m_v2;
   m_t=obj.m_t;
   m_errfeas=obj.m_errfeas;
   m_gnorm=obj.m_gnorm;
   m_mpgnorm=obj.m_mpgnorm;
   m_mba=obj.m_mba;
   m_variabletofreeze=obj.m_variabletofreeze;
   m_valuetofreeze=obj.m_valuetofreeze;
   m_fbase=obj.m_fbase;
   m_fm2=obj.m_fm2;
   m_fm1=obj.m_fm1;
   m_fp1=obj.m_fp1;
   m_fp2=obj.m_fp2;
   m_xm1=obj.m_xm1;
   m_xp1=obj.m_xp1;
   m_optdim=obj.m_optdim;
   m_rstate.Copy(obj.m_rstate);
   m_cgstate.Copy(obj.m_cgstate);
   m_cgrep.Copy(obj.m_cgrep);
//--- copy arrays
   ArrayCopy(m_diaghoriginal,obj.m_diaghoriginal);
   ArrayCopy(m_diagh,obj.m_diagh);
   ArrayCopy(m_x,obj.m_x);
   ArrayCopy(m_g,obj.m_g);
   ArrayCopy(m_xcur,obj.m_xcur);
   ArrayCopy(m_xprev,obj.m_xprev);
   ArrayCopy(m_xstart,obj.m_xstart);
   ArrayCopy(m_xend,obj.m_xend);
   ArrayCopy(m_lastg,obj.m_lastg);
   ArrayCopy(m_ct,obj.m_ct);
   ArrayCopy(m_xe,obj.m_xe);
   ArrayCopy(m_hasbndl,obj.m_hasbndl);
   ArrayCopy(m_hasbndu,obj.m_hasbndu);
   ArrayCopy(m_bndloriginal,obj.m_bndloriginal);
   ArrayCopy(m_bnduoriginal,obj.m_bnduoriginal);
   ArrayCopy(m_bndleffective,obj.m_bndleffective);
   ArrayCopy(m_bndueffective,obj.m_bndueffective);
   ArrayCopy(m_activeconstraints,obj.m_activeconstraints);
   ArrayCopy(m_constrainedvalues,obj.m_constrainedvalues);
   ArrayCopy(m_transforms,obj.m_transforms);
   ArrayCopy(m_seffective,obj.m_seffective);
   ArrayCopy(m_soriginal,obj.m_soriginal);
   ArrayCopy(m_w,obj.m_w);
   ArrayCopy(m_tmp0,obj.m_tmp0);
   ArrayCopy(m_tmp1,obj.m_tmp1);
   ArrayCopy(m_tmp2,obj.m_tmp2);
   ArrayCopy(m_r,obj.m_r);
//--- copy matrix
   m_ceoriginal=obj.m_ceoriginal;
   m_ceeffective=obj.m_ceeffective;
   m_cecurrent=obj.m_cecurrent;
   m_lmmatrix=obj.m_lmmatrix;
  }
//+------------------------------------------------------------------+
//| This object stores nonlinear optimizer state.                    |
//| You should use functions provided by MinBLEIC subpackage to work |
//| with this object                                                 |
//+------------------------------------------------------------------+
class CMinBLEICStateShell
  {
private:
   CMinBLEICState    m_innerobj;
public:
   //--- constructors, destructor
                     CMinBLEICStateShell(void);
                     CMinBLEICStateShell(CMinBLEICState &obj);
                    ~CMinBLEICStateShell(void);
   //--- methods
   bool              GetNeedF(void);
   void              SetNeedF(const bool b);
   bool              GetNeedFG(void);
   void              SetNeedFG(const bool b);
   bool              GetXUpdated(void);
   void              SetXUpdated(const bool b);
   double            GetF(void);
   void              SetF(const double d);
   CMinBLEICState   *GetInnerObj(void);
  };
//+------------------------------------------------------------------+
//| Constructor without parameters                                   |
//+------------------------------------------------------------------+
CMinBLEICStateShell::CMinBLEICStateShell(void)
  {

  }
//+------------------------------------------------------------------+
//| Copy constructor                                                 |
//+------------------------------------------------------------------+
CMinBLEICStateShell::CMinBLEICStateShell(CMinBLEICState &obj)
  {
//--- copy
   m_innerobj.Copy(obj);
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CMinBLEICStateShell::~CMinBLEICStateShell(void)
  {

  }
//+------------------------------------------------------------------+
//| Returns the value of the variable needf                          |
//+------------------------------------------------------------------+
bool CMinBLEICStateShell::GetNeedF(void)
  {
//--- return result
   return(m_innerobj.m_needf);
  }
//+------------------------------------------------------------------+
//| Changing the value of the variable needf                         |
//+------------------------------------------------------------------+
void CMinBLEICStateShell::SetNeedF(const bool b)
  {
//--- change value
   m_innerobj.m_needf=b;
  }
//+------------------------------------------------------------------+
//| Returns the value of the variable needfg                         |
//+------------------------------------------------------------------+
bool CMinBLEICStateShell::GetNeedFG(void)
  {
//--- return result
   return(m_innerobj.m_needfg);
  }
//+------------------------------------------------------------------+
//| Changing the value of the variable needfg                        |
//+------------------------------------------------------------------+
void CMinBLEICStateShell::SetNeedFG(const bool b)
  {
//--- change value
   m_innerobj.m_needfg=b;
  }
//+------------------------------------------------------------------+
//| Returns the value of the variable xupdated                       |
//+------------------------------------------------------------------+
bool CMinBLEICStateShell::GetXUpdated(void)
  {
//--- return result
   return(m_innerobj.m_xupdated);
  }
//+------------------------------------------------------------------+
//| Changing the value of the variable xupdated                      |
//+------------------------------------------------------------------+
void CMinBLEICStateShell::SetXUpdated(const bool b)
  {
//--- change value
   m_innerobj.m_xupdated=b;
  }
//+------------------------------------------------------------------+
//| Returns the value of the variable f                              |
//+------------------------------------------------------------------+
double CMinBLEICStateShell::GetF(void)
  {
//--- return result
   return(m_innerobj.m_f);
  }
//+------------------------------------------------------------------+
//| Changing the value of the variable f                             |
//+------------------------------------------------------------------+
void CMinBLEICStateShell::SetF(const double d)
  {
//--- change value
   m_innerobj.m_f=d;
  }
//+------------------------------------------------------------------+
//| Return object of class                                           |
//+------------------------------------------------------------------+
CMinBLEICState *CMinBLEICStateShell::GetInnerObj(void)
  {
//--- return result
   return(GetPointer(m_innerobj));
  }
//+------------------------------------------------------------------+
//| This structure stores optimization report:                       |
//| * InnerIterationsCount      number of inner iterations           |
//| * OuterIterationsCount      number of outer iterations           |
//| * NFEV                      number of gradient evaluations       |
//| * TerminationType           termination type (see below)         |
//| TERMINATION CODES                                                |
//| TerminationType field contains completion code,which can be:     |
//|   -10   unsupported combination of algorithm settings:           |
//|         1) StpMax is set to non-zero value,                      |
//|         AND 2) non-default preconditioner is used.               |
//|         You can't use both features at the same moment,          |
//|         so you have to choose one of them (and to turn           |
//|         off another one).                                        |
//|   -3    inconsistent constraints. Feasible point is              |
//|         either nonexistent or too hard to find. Try to           |
//|         restart optimizer with better initial                    |
//|         approximation                                            |
//|    4    conditions on constraints are fulfilled                  |
//|         with error less than or equal to EpsC                    |
//|    5    MaxIts steps was taken                                   |
//|    7    stopping conditions are too stringent,                   |
//|         further improvement is impossible,                       |
//|         X contains best point found so far.                      |
//| ADDITIONAL FIELDS                                                |
//| There are additional fields which can be used for debugging:     |
//| * DebugEqErr                error in the equality constraints    |
//|                             (2-norm)                             |
//| * DebugFS                   f,calculated at projection of initial|
//|                             point to the feasible set            |
//| * DebugFF                   f,calculated at the final point      |
//| * DebugDX                   |X_start-X_final|                    |
//+------------------------------------------------------------------+
class CMinBLEICReport
  {
public:
   //--- variables
   int               m_inneriterationscount;
   int               m_outeriterationscount;
   int               m_nfev;
   int               m_terminationtype;
   double            m_debugeqerr;
   double            m_debugfs;
   double            m_debugff;
   double            m_debugdx;
   //--- constructor, destructor
                     CMinBLEICReport(void);
                    ~CMinBLEICReport(void);
   //--- copy
   void              Copy(CMinBLEICReport &obj);
  };
//+------------------------------------------------------------------+
//| Constructor without parameters                                   |
//+------------------------------------------------------------------+
CMinBLEICReport::CMinBLEICReport(void)
  {

  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CMinBLEICReport::~CMinBLEICReport(void)
  {

  }
//+------------------------------------------------------------------+
//| Copy                                                             |
//+------------------------------------------------------------------+
void CMinBLEICReport::Copy(CMinBLEICReport &obj)
  {
//--- copy variables
   m_inneriterationscount=obj.m_inneriterationscount;
   m_outeriterationscount=obj.m_outeriterationscount;
   m_nfev=obj.m_nfev;
   m_terminationtype=obj.m_terminationtype;
   m_debugeqerr=obj.m_debugeqerr;
   m_debugfs=obj.m_debugfs;
   m_debugff=obj.m_debugff;
   m_debugdx=obj.m_debugdx;
  }
//+------------------------------------------------------------------+
//| This structure stores optimization report:                       |
//| * InnerIterationsCount      number of inner iterations           |
//| * OuterIterationsCount      number of outer iterations           |
//| * NFEV                      number of gradient evaluations       |
//| * TerminationType           termination type (see below)         |
//| TERMINATION CODES                                                |
//| TerminationType field contains completion code,which can be:     |
//|   -10   unsupported combination of algorithm settings:           |
//|         1) StpMax is set to non-zero value,                      |
//|         AND 2) non-default preconditioner is used.               |
//|         You can't use both features at the same moment,          |
//|         so you have to choose one of them (and to turn           |
//|         off another one).                                        |
//|   -3    inconsistent constraints. Feasible point is              |
//|         either nonexistent or too hard to find. Try to           |
//|         restart optimizer with better initial                    |
//|         approximation                                            |
//|    4    conditions on constraints are fulfilled                  |
//|         with error less than or equal to EpsC                    |
//|    5    MaxIts steps was taken                                   |
//|    7    stopping conditions are too stringent,                   |
//|         further improvement is impossible,                       |
//|         X contains best point found so far.                      |
//| ADDITIONAL FIELDS                                                |
//| There are additional fields which can be used for debugging:     |
//| * DebugEqErr                error in the equality constraints    |
//|                             (2-norm)                             |
//| * DebugFS                   f,calculated at projection of initial|
//|                             point to the feasible set            |
//| * DebugFF                   f,calculated at the final point      |
//| * DebugDX                   |X_start-X_final|                    |
//+------------------------------------------------------------------+
class CMinBLEICReportShell
  {
private:
   CMinBLEICReport   m_innerobj;
public:
   //--- constructors, destructor
                     CMinBLEICReportShell(void);
                     CMinBLEICReportShell(CMinBLEICReport &obj);
                    ~CMinBLEICReportShell(void);
   //--- methods
   int               GetInnerIterationsCount(void);
   void              SetInnerIterationsCount(const int i);
   int               GetOuterIterationsCount(void);
   void              SetOuterIterationsCount(const int i);
   int               GetNFev(void);
   void              SetNFev(const int i);
   int               GetTerminationType(void);
   void              SetTerminationType(const int i);
   double            GetDebugEqErr(void);
   void              SetDebugEqErr(const double d);
   double            GetDebugFS(void);
   void              SetDebugFS(const double d);
   double            GetDebugFF(void);
   void              SetDebugFF(const double d);
   double            GetDebugDX(void);
   void              SetDebugDX(const double d);
   CMinBLEICReport *GetInnerObj(void);
  };
//+------------------------------------------------------------------+
//| Constructor without parameters                                   |
//+------------------------------------------------------------------+
CMinBLEICReportShell::CMinBLEICReportShell(void)
  {

  }
//+------------------------------------------------------------------+
//| Copy constructor                                                 |
//+------------------------------------------------------------------+
CMinBLEICReportShell::CMinBLEICReportShell(CMinBLEICReport &obj)
  {
//--- copy
   m_innerobj.Copy(obj);
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CMinBLEICReportShell::~CMinBLEICReportShell(void)
  {

  }
//+------------------------------------------------------------------+
//| Returns the value of the variable inneriterationscount           |
//+------------------------------------------------------------------+
int CMinBLEICReportShell::GetInnerIterationsCount(void)
  {
//--- return result
   return(m_innerobj.m_inneriterationscount);
  }
//+------------------------------------------------------------------+
//| Changing the value of the variable inneriterationscount          |
//+------------------------------------------------------------------+
void CMinBLEICReportShell::SetInnerIterationsCount(const int i)
  {
//--- change value
   m_innerobj.m_inneriterationscount=i;
  }
//+------------------------------------------------------------------+
//| Returns the value of the variable outeriterationscount           |
//+------------------------------------------------------------------+
int CMinBLEICReportShell::GetOuterIterationsCount(void)
  {
//--- return result
   return(m_innerobj.m_outeriterationscount);
  }
//+------------------------------------------------------------------+
//| Changing the value of the variable outeriterationscount          |
//+------------------------------------------------------------------+
void CMinBLEICReportShell::SetOuterIterationsCount(const int i)
  {
//--- change value
   m_innerobj.m_outeriterationscount=i;
  }
//+------------------------------------------------------------------+
//| Returns the value of the variable nfev                           |
//+------------------------------------------------------------------+
int CMinBLEICReportShell::GetNFev(void)
  {
//--- return result
   return(m_innerobj.m_nfev);
  }
//+------------------------------------------------------------------+
//| Changing the value of the variable nfev                          |
//+------------------------------------------------------------------+
void CMinBLEICReportShell::SetNFev(const int i)
  {
//--- change value
   m_innerobj.m_nfev=i;
  }
//+------------------------------------------------------------------+
//| Returns the value of the variable terminationtype                |
//+------------------------------------------------------------------+
int CMinBLEICReportShell::GetTerminationType(void)
  {
//--- return result
   return(m_innerobj.m_terminationtype);
  }
//+------------------------------------------------------------------+
//| Changing the value of the variable terminationtype               |
//+------------------------------------------------------------------+
void CMinBLEICReportShell::SetTerminationType(const int i)
  {
//--- change value
   m_innerobj.m_terminationtype=i;
  }
//+------------------------------------------------------------------+
//| Returns the value of the variable debugeqerr                     |
//+------------------------------------------------------------------+
double CMinBLEICReportShell::GetDebugEqErr(void)
  {
//--- return result
   return(m_innerobj.m_debugeqerr);
  }
//+------------------------------------------------------------------+
//| Changing the value of the variable debugeqerr                    |
//+------------------------------------------------------------------+
void CMinBLEICReportShell::SetDebugEqErr(const double d)
  {
//--- change value
   m_innerobj.m_debugeqerr=d;
  }
//+------------------------------------------------------------------+
//| Returns the value of the variable debugfs                        |
//+------------------------------------------------------------------+
double CMinBLEICReportShell::GetDebugFS(void)
  {
//--- return result
   return(m_innerobj.m_debugfs);
  }
//+------------------------------------------------------------------+
//| Changing the value of the variable debugfs                       |
//+------------------------------------------------------------------+
void CMinBLEICReportShell::SetDebugFS(const double d)
  {
//--- change value
   m_innerobj.m_debugfs=d;
  }
//+------------------------------------------------------------------+
//| Returns the value of the variable debugff                        |
//+------------------------------------------------------------------+
double CMinBLEICReportShell::GetDebugFF(void)
  {
//--- return result
   return(m_innerobj.m_debugff);
  }
//+------------------------------------------------------------------+
//| Changing the value of the variable debugff                       |
//+------------------------------------------------------------------+
void CMinBLEICReportShell::SetDebugFF(const double d)
  {
//--- change value
   m_innerobj.m_debugff=d;
  }
//+------------------------------------------------------------------+
//| Returns the value of the variable debugdx                        |
//+------------------------------------------------------------------+
double CMinBLEICReportShell::GetDebugDX(void)
  {
//--- return result
   return(m_innerobj.m_debugdx);
  }
//+------------------------------------------------------------------+
//| Changing the value of the variable debugdx                       |
//+------------------------------------------------------------------+
void CMinBLEICReportShell::SetDebugDX(const double d)
  {
//--- change value
   m_innerobj.m_debugdx=d;
  }
//+------------------------------------------------------------------+
//| Return object of class                                           |
//+------------------------------------------------------------------+
CMinBLEICReport *CMinBLEICReportShell::GetInnerObj(void)
  {
//--- return result
   return(GetPointer(m_innerobj));
  }
//+------------------------------------------------------------------+
//| Bound constrained optimization with additional linear equality   |
//| and inequality constraints                                       |
//+------------------------------------------------------------------+
class CMinBLEIC
  {
private:
   //--- private methods
   static void       ClearRequestFields(CMinBLEICState &state);
   static void       UnscalePoint(CMinBLEICState &state,double &xscaled[],double &xunscaled[]);
   static void       ProjectPointAndUnscale(CMinBLEICState &state,double &xscaled[],double &xunscaled[],double &rscaled[],double &rnorm2);
   static void       ScaleGradientAndExpand(CMinBLEICState &state,double &gunscaled[],double &gscaled[]);
   static void       ModifyTargetFunction(CMinBLEICState &state,double &x[],double &r[],const double rnorm2,double &f,double &g[],double &gnorm,double &mpgnorm);
   static bool       AdditionalCheckForConstraints(CMinBLEICState &state,double &x[]);
   static void       RebuildCEXE(CMinBLEICState &state);
   static void       MakeGradientProjection(CMinBLEICState &state,double &pg[]);
   static bool       PrepareConstraintMatrix(CMinBLEICState &state,double &x[],double &g[],double &px[],double &pg[]);
   static void       MinBLEICInitInternal(const int n,double &x[],const double diffstep,CMinBLEICState &state);
   //--- auxiliary functions for MinBLEICIteration
   static void       Func_lbl_rcomm(CMinBLEICState &state,int nmain,int nslack,int m,int i,int j,bool b,double v,double vv);
   static bool       Func_lbl_14(CMinBLEICState &state,int &nmain,int &nslack,int &m,int &i,int &j,bool &b,double &v,double &vv);
   static bool       Func_lbl_15(CMinBLEICState &state,int &nmain,int &nslack,int &m,int &i,int &j,bool &b,double &v,double &vv);
   static bool       Func_lbl_16(CMinBLEICState &state,int &nmain,int &nslack,int &m,int &i,int &j,bool &b,double &v,double &vv);
   static bool       Func_lbl_17(CMinBLEICState &state,int &nmain,int &nslack,int &m,int &i,int &j,bool &b,double &v,double &vv);
   static bool       Func_lbl_18(CMinBLEICState &state,int &nmain,int &nslack,int &m,int &i,int &j,bool &b,double &v,double &vv);
   static bool       Func_lbl_19(CMinBLEICState &state,int &nmain,int &nslack,int &m,int &i,int &j,bool &b,double &v,double &vv);
   static bool       Func_lbl_22(CMinBLEICState &state,int &nmain,int &nslack,int &m,int &i,int &j,bool &b,double &v,double &vv);
   static bool       Func_lbl_23(CMinBLEICState &state,int &nmain,int &nslack,int &m,int &i,int &j,bool &b,double &v,double &vv);
   static bool       Func_lbl_31(CMinBLEICState &state,int &nmain,int &nslack,int &m,int &i,int &j,bool &b,double &v,double &vv);
public:
   //--- class constants
   static const double m_svdtol;
   static const double m_maxouterits;
   //--- constructor, destructor
                     CMinBLEIC(void);
                    ~CMinBLEIC(void);
   //--- public methods
   static void       MinBLEICCreate(const int n,double &x[],CMinBLEICState &state);
   static void       MinBLEICCreateF(const int n,double &x[],const double diffstep,CMinBLEICState &state);
   static void       MinBLEICSetBC(CMinBLEICState &state,double &bndl[],double &bndu[]);
   static void       MinBLEICSetLC(CMinBLEICState &state,CMatrixDouble &c,int &ct[],const int k);
   static void       MinBLEICSetInnerCond(CMinBLEICState &state,const double epsg,const double epsf,const double epsx);
   static void       MinBLEICSetOuterCond(CMinBLEICState &state,const double epsx,const double epsi);
   static void       MinBLEICSetScale(CMinBLEICState &state,double &s[]);
   static void       MinBLEICSetPrecDefault(CMinBLEICState &state);
   static void       MinBLEICSetPrecDiag(CMinBLEICState &state,double &d[]);
   static void       MinBLEICSetPrecScale(CMinBLEICState &state);
   static void       MinBLEICSetMaxIts(CMinBLEICState &state,const int maxits);
   static void       MinBLEICSetXRep(CMinBLEICState &state,const bool needxrep);
   static void       MinBLEICSetStpMax(CMinBLEICState &state,const double stpmax);
   static void       MinBLEICResults(CMinBLEICState &state,double &x[],CMinBLEICReport &rep);
   static void       MinBLEICResultsBuf(CMinBLEICState &state,double &x[],CMinBLEICReport &rep);
   static void       MinBLEICRestartFrom(CMinBLEICState &state,double &x[]);
   static bool       MinBLEICIteration(CMinBLEICState &state);
  };
//+------------------------------------------------------------------+
//| Initialize constants                                             |
//+------------------------------------------------------------------+
const double CMinBLEIC::m_svdtol=100;
const double CMinBLEIC::m_maxouterits=20;
//+------------------------------------------------------------------+
//| Constructor without parameters                                   |
//+------------------------------------------------------------------+
CMinBLEIC::CMinBLEIC(void)
  {

  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CMinBLEIC::~CMinBLEIC(void)
  {

  }
//+------------------------------------------------------------------+
//|                      BOUND CONSTRAINED OPTIMIZATION              |
//|        WITH ADDITIONAL LINEAR EQUALITY AND INEQUALITY CONSTRAINTS|
//| DESCRIPTION:                                                     |
//| The subroutine minimizes function F(x) of N arguments subject to |
//| any combination of:                                              |
//| * bound constraints                                              |
//| * linear inequality constraints                                  |
//| * linear equality constraints                                    |
//| REQUIREMENTS:                                                    |
//| * user must provide function value and gradient                  |
//| * starting point X0 must be feasible or                          |
//|   not too far away from the feasible set                         |
//| * grad(f) must be Lipschitz continuous on a level set:           |
//|   L = { x : f(x)<=f(x0) }                                        |
//| * function must be defined everywhere on the feasible set F      |
//| USAGE:                                                           |
//| Constrained optimization if far more complex than the            |
//| unconstrained one. Here we give very brief outline of the BLEIC  |
//| optimizer. We strongly recommend you to read examples in the     |
//| ALGLIB Reference Manual and to read ALGLIB User Guide on         |
//| optimization, which is available at                              |
//| http://www.alglib.net/optimization/                              |
//| 1. User initializes algorithm state with MinBLEICCreate() call   |
//| 2. USer adds boundary and/or linear constraints by calling       |
//|    MinBLEICSetBC() and MinBLEICSetLC() functions.                |
//| 3. User sets stopping conditions for underlying unconstrained    |
//|    solver with MinBLEICSetInnerCond() call.                      |
//|    This function controls accuracy of underlying optimization    |
//|    algorithm.                                                    |
//| 4. User sets stopping conditions for outer iteration by calling  |
//|    MinBLEICSetOuterCond() function.                              |
//|    This function controls handling of boundary and inequality    |
//|    constraints.                                                  |
//| 5. Additionally, user may set limit on number of internal        |
//|    iterations by MinBLEICSetMaxIts() call.                       |
//|    This function allows to prevent algorithm from looping        |
//|    forever.                                                      |
//| 6. User calls MinBLEICOptimize() function which takes algorithm  |
//|    state and pointer (delegate, etc.) to callback function       |
//|    which calculates F/G.                                         |
//| 7. User calls MinBLEICResults() to get solution                  |
//| 8. Optionally user may call MinBLEICRestartFrom() to solve       |
//|    another problem with same N but another starting point.       |
//|    MinBLEICRestartFrom() allows to reuse already initialized     |
//|    structure.                                                    |
//| INPUT PARAMETERS:                                                |
//|     N       -   problem dimension, N>0:                          |
//|                 * if given, only leading N elements of X are     |
//|                   used                                           |
//|                 * if not given, automatically determined from    |
//|                   size ofX                                       |
//|     X       -   starting point, array[N]:                        |
//|                 * it is better to set X to a feasible point      |
//|                 * but X can be infeasible, in which case         |
//|                   algorithm will try to find feasible point      |
//|                   first, using X as initial approximation.       |
//| OUTPUT PARAMETERS:                                               |
//|     State   -   structure stores algorithm state                 |
//+------------------------------------------------------------------+
static void CMinBLEIC::MinBLEICCreate(const int n,double &x[],CMinBLEICState &state)
  {
//--- create matrix
   CMatrixDouble c;
//--- create array
   int ct[];
//--- check
   if(!CAp::Assert(n>=1,__FUNCTION__+": N<1"))
      return;
//--- check
   if(!CAp::Assert(CAp::Len(x)>=n,__FUNCTION__+": Length(X)<N"))
      return;
//--- check
   if(!CAp::Assert(CApServ::IsFiniteVector(x,n),__FUNCTION__+": X contains infinite or NaN values!"))
      return;
//--- function call
   MinBLEICInitInternal(n,x,0.0,state);
  }
//+------------------------------------------------------------------+
//| The subroutine is finite difference variant of MinBLEICCreate(). |
//| It uses finite differences in order to differentiate target      |
//| function.                                                        |
//| Description below contains information which is specific to this |
//| function only. We recommend to read comments on MinBLEICCreate() |
//| in order to get more information about creation of BLEIC         |
//| optimizer.                                                       |
//| INPUT PARAMETERS:                                                |
//|     N       -   problem dimension, N>0:                          |
//|                 * if given, only leading N elements of X are used|
//|                 * if not given, automatically determined from    |
//|                   size of X                                      |
//|     X       -   starting point, array[0..N-1].                   |
//|     DiffStep-   differentiation step, >0                         |
//| OUTPUT PARAMETERS:                                               |
//|     State   -   structure which stores algorithm state           |
//| NOTES:                                                           |
//| 1. algorithm uses 4-point central formula for differentiation.   |
//| 2. differentiation step along I-th axis is equal to DiffStep*S[I]|
//|    where S[] is scaling vector which can be set by               |
//|    MinBLEICSetScale() call.                                      |
//| 3. we recommend you to use moderate values of differentiation    |
//|    step. Too large step will result in too large truncation      |
//|    errors, while too small step will result in too large         |
//|    numerical errors. 1.0E-6 can be good value to start with.     |
//| 4. Numerical differentiation is very inefficient - one  gradient |
//|    calculation needs 4*N function evaluations. This function will|
//|    work for any N - either small (1...10), moderate (10...100) or|
//|    large (100...). However, performance penalty will be too      |
//|    severe for any N's except for small ones.                     |
//|    We should also say that code which relies on numerical        |
//|    differentiation is less robust and precise. CG needs exact    |
//|    gradient values. Imprecise gradient may slow down convergence,|
//|    especially on highly nonlinear problems.                      |
//|    Thus we recommend to use this function for fast prototyping on|
//|    small - dimensional problems only, and to implement analytical|
//|    gradient as soon as possible.                                 |
//+------------------------------------------------------------------+
static void CMinBLEIC::MinBLEICCreateF(const int n,double &x[],
                                       const double diffstep,
                                       CMinBLEICState &state)
  {
//--- create matrix
   CMatrixDouble c;
//--- create array
   int ct[];
//--- check
   if(!CAp::Assert(n>=1,__FUNCTION__+": N<1"))
      return;
//--- check
   if(!CAp::Assert(CAp::Len(x)>=n,__FUNCTION__+": Length(X)<N"))
      return;
//--- check
   if(!CAp::Assert(CApServ::IsFiniteVector(x,n),__FUNCTION__+": X contains infinite or NaN values!"))
      return;
//--- check
   if(!CAp::Assert(CMath::IsFinite(diffstep),__FUNCTION__+": DiffStep is infinite or NaN!"))
      return;
//--- check
   if(!CAp::Assert(diffstep>0.0,__FUNCTION__+": DiffStep is non-positive!"))
      return;
//--- function call
   MinBLEICInitInternal(n,x,diffstep,state);
  }
//+------------------------------------------------------------------+
//| This function sets boundary constraints for BLEIC optimizer.     |
//| Boundary constraints are inactive by default (after initial      |
//| creation). They are preserved after algorithm restart with       |
//| MinBLEICRestartFrom().                                           |
//| INPUT PARAMETERS:                                                |
//|     State   -   structure stores algorithm state                 |
//|     BndL    -   lower bounds, array[N].                          |
//|                 If some (all) variables are unbounded, you may   |
//|                 specify very small number or -INF.               |
//|     BndU    -   upper bounds, array[N].                          |
//|                 If some (all) variables are unbounded, you may   |
//|                 specify very large number or +INF.               |
//| NOTE 1: it is possible to specify BndL[i]=BndU[i]. In this case  |
//| I-th variable will be "frozen" at X[i]=BndL[i]=BndU[i].          |
//| NOTE 2: this solver has following useful properties:             |
//| * bound constraints are always satisfied exactly                 |
//| * function is evaluated only INSIDE area specified by bound      |
//|   constraints, even when numerical differentiation is used       |
//|   (algorithm adjusts nodes according to boundary constraints)    |
//+------------------------------------------------------------------+
static void CMinBLEIC::MinBLEICSetBC(CMinBLEICState &state,double &bndl[],
                                     double &bndu[])
  {
//--- create variables
   int i=0;
   int n=0;
//--- initialization
   n=state.m_nmain;
//--- check
   if(!CAp::Assert(CAp::Len(bndl)>=n,__FUNCTION__+": Length(BndL)<N"))
      return;
//--- check
   if(!CAp::Assert(CAp::Len(bndu)>=n,__FUNCTION__+": Length(BndU)<N"))
      return;
   for(i=0;i<=n-1;i++)
     {
      //--- check
      if(!CAp::Assert(CMath::IsFinite(bndl[i]) || CInfOrNaN::IsNegativeInfinity(bndl[i]),__FUNCTION__+": BndL contains NAN or +INF"))
         return;
      //--- check
      if(!CAp::Assert(CMath::IsFinite(bndu[i]) || CInfOrNaN::IsPositiveInfinity(bndu[i]),__FUNCTION__+": BndU contains NAN or -INF"))
         return;
      //--- change values
      state.m_bndloriginal[i]=bndl[i];
      state.m_hasbndl[i]=CMath::IsFinite(bndl[i]);
      state.m_bnduoriginal[i]=bndu[i];
      state.m_hasbndu[i]=CMath::IsFinite(bndu[i]);
     }
  }
//+------------------------------------------------------------------+
//| This function sets linear constraints for BLEIC optimizer.       |
//| Linear constraints are inactive by default (after initial        |
//| creation). They are preserved after algorithm restart with       |
//| MinBLEICRestartFrom().                                           |
//| INPUT PARAMETERS:                                                |
//|     State   -   structure previously allocated with              |
//|                MinBLEICCreate call.                              |
//|     C       -   linear constraints, array[K,N+1].                |
//|                 Each row of C represents one constraint, either  |
//|                 equality or inequality (see below):              |
//|                 * first N elements correspond to coefficients,   |
//|                 * last element corresponds to the right part.    |
//|                 All elements of C (including right part) must be |
//|                 finite.                                          |
//|     CT      -   type of constraints, array[K]:                   |
//|                 * if CT[i]>0, then I-th constraint is            |
//|                   C[i,*]*x >= C[i,n+1]                           |
//|                 * if CT[i]=0, then I-th constraint is            |
//|                   C[i,*]*x  = C[i,n+1]                           |
//|                 * if CT[i]<0, then I-th constraint is            |
//|                   C[i,*]*x <= C[i,n+1]                           |
//|     K       -   number of equality/inequality constraints, K>=0: |
//|                 * if given, only leading K elements of C/CT are  |
//|                   used                                           |
//|                 * if not given, automatically determined from    |
//|                   sizes of C/CT                                  |
//| NOTE 1: linear (non-bound) constraints are satisfied only        |
//| approximately:                                                   |
//| * there always exists some minor violation (about Epsilon in     |
//|   magnitude) due to rounding errors                              |
//| * numerical differentiation, if used, may lead to function       |
//|   evaluations outside of the feasible area, because algorithm    |
//|   does NOT change numerical differentiation formula according to |
//|   linear constraints.                                            |
//| If you want constraints to be satisfied exactly, try to          |
//| reformulate your problem in such manner that all constraints will|
//| become boundary ones (this kind of constraints is always         |
//| satisfied exactly, both in the final solution and in all         |
//| intermediate points).                                            |
//+------------------------------------------------------------------+
static void CMinBLEIC::MinBLEICSetLC(CMinBLEICState &state,CMatrixDouble &c,
                                     int &ct[],const int k)
  {
//--- create variables
   int nmain=0;
   int i=0;
   int i_=0;
//--- initialization
   nmain=state.m_nmain;
//--- First,check for errors in the inputs
   if(!CAp::Assert(k>=0,__FUNCTION__+": K<0"))
      return;
//--- check
   if(!CAp::Assert(CAp::Cols(c)>=nmain+1||k==0,__FUNCTION__+": Cols(C)<N+1"))
      return;
//--- check
   if(!CAp::Assert(CAp::Rows(c)>=k,__FUNCTION__+": Rows(C)<K"))
      return;
//--- check
   if(!CAp::Assert(CAp::Len(ct)>=k,__FUNCTION__+": Length(CT)<K"))
      return;
//--- check
   if(!CAp::Assert(CApServ::IsFiniteMatrix(c,k,nmain+1),__FUNCTION__+": C contains infinite or NaN values!"))
      return;
//--- Determine number of constraints,
//--- allocate space and copy
   state.m_cecnt=k;
//--- function call
   CApServ::RMatrixSetLengthAtLeast(state.m_ceoriginal,state.m_cecnt,nmain+1);
//--- function call
   CApServ::IVectorSetLengthAtLeast(state.m_ct,state.m_cecnt);
//--- calculation
   for(i=0;i<=k-1;i++)
     {
      state.m_ct[i]=ct[i];
      for(i_=0;i_<=nmain;i_++)
         state.m_ceoriginal[i].Set(i_,c[i][i_]);
     }
  }
//+------------------------------------------------------------------+
//| This function sets stopping conditions for the underlying        |
//| nonlinear CG optimizer. It controls overall accuracy of solution.|
//| These conditions should be strict enough in order for algorithm  |
//| to converge.                                                     |
//| INPUT PARAMETERS:                                                |
//|     State   -   structure which stores algorithm state           |
//|     EpsG    -   >=0                                              |
//|                 The subroutine finishes its work if the condition|
//|                 |v|<EpsG is satisfied, where:                    |
//|                 * |.| means Euclidian norm                       |
//|                 * v - scaled gradient vector, v[i]=g[i]*s[i]     |
//|                 * g - gradient                                   |
//|                 * s - scaling coefficients set by                |
//|                       MinBLEICSetScale()                         |
//|     EpsF    -   >=0                                              |
//|                 The subroutine finishes its work if on k+1-th    |
//|                 iteration the condition |F(k+1)-F(k)| <=         |
//|                 <= EpsF*max{|F(k)|,|F(k+1)|,1} is satisfied.     |
//|     EpsX    -   >=0                                              |
//|                 The subroutine finishes its work if on k+1-th    |
//|                 iteration the condition |v|<=EpsX is fulfilled,  |
//|                 where:                                           |
//|                 * |.| means Euclidian norm                       |
//|                 * v - scaled step vector, v[i]=dx[i]/s[i]        |
//|                 * dx - ste pvector, dx=X(k+1)-X(k)               |
//|                 * s - scaling coefficients set by                |
//|                       MinBLEICSetScale()                         |
//| Passing EpsG=0, EpsF=0 and EpsX=0 (simultaneously) will lead to  |
//| automatic stopping criterion selection.                          |
//| These conditions are used to terminate inner iterations. However,|
//| you need to tune termination conditions for outer iterations too.|
//+------------------------------------------------------------------+
static void CMinBLEIC::MinBLEICSetInnerCond(CMinBLEICState &state,const double epsg,
                                            const double epsf,const double epsx)
  {
//--- check
   if(!CAp::Assert(CMath::IsFinite(epsg),__FUNCTION__+": EpsG is not finite number"))
      return;
//--- check
   if(!CAp::Assert(epsg>=0.0,__FUNCTION__+": negative EpsG"))
      return;
//--- check
   if(!CAp::Assert(CMath::IsFinite(epsf),__FUNCTION__+": EpsF is not finite number"))
      return;
//--- check
   if(!CAp::Assert(epsf>=0.0,__FUNCTION__+": negative EpsF"))
      return;
//--- check
   if(!CAp::Assert(CMath::IsFinite(epsx),__FUNCTION__+": EpsX is not finite number"))
      return;
//--- check
   if(!CAp::Assert(epsx>=0.0,__FUNCTION__+": negative EpsX"))
      return;
//--- change values
   state.m_innerepsg=epsg;
   state.m_innerepsf=epsf;
   state.m_innerepsx=epsx;
  }
//+------------------------------------------------------------------+
//| This function sets stopping conditions for outer iteration of    |
//| BLEIC algo.                                                      |
//| These conditions control accuracy of constraint handling and     |
//| amount of infeasibility allowed in the solution.                 |
//| INPUT PARAMETERS:                                                |
//|     State   -   structure which stores algorithm state           |
//|     EpsX    -   >0, stopping condition on outer iteration step   |
//|                     length                                       |
//|     EpsI    -   >0, stopping condition on infeasibility          |
//| Both EpsX and EpsI must be non-zero.                             |
//| MEANING OF EpsX                                                  |
//| EpsX is a stopping condition for outer iterations. Algorithm will|
//| stop when solution of the current modified subproblem will be    |
//| within EpsX (using 2-norm) of the previous solution.             |
//| MEANING OF EpsI                                                  |
//| EpsI controls feasibility properties - algorithm won't stop until|
//| all inequality constraints will be satisfied with error (distance|
//| from current point to the feasible area) at most EpsI.           |
//+------------------------------------------------------------------+
static void CMinBLEIC::MinBLEICSetOuterCond(CMinBLEICState &state,const double epsx,
                                            const double epsi)
  {
//--- check
   if(!CAp::Assert(CMath::IsFinite(epsx),__FUNCTION__+": EpsX is not finite number"))
      return;
//--- check
   if(!CAp::Assert(epsx>0.0,__FUNCTION__+": non-positive EpsX"))
      return;
//--- check
   if(!CAp::Assert(CMath::IsFinite(epsi),__FUNCTION__+": EpsI is not finite number"))
      return;
//--- check
   if(!CAp::Assert((double)(epsi)>0.0,__FUNCTION__+": non-positive EpsI"))
      return;
//--- change values
   state.m_outerepsx=epsx;
   state.m_outerepsi=epsi;
  }
//+------------------------------------------------------------------+
//| This function sets scaling coefficients for BLEIC optimizer.     |
//| ALGLIB optimizers use scaling matrices to test stopping          |
//| conditions (step size and gradient are scaled before comparison  |
//| with tolerances). Scale of the I-th variable is a translation    |
//| invariant measure of:                                            |
//| a) "how large" the variable is                                   |
//| b) how large the step should be to make significant changes in   |
//| the function                                                     |
//| Scaling is also used by finite difference variant of the         |
//| optimizer - step along I-th axis is equal to DiffStep*S[I].      |
//| In most optimizers (and in the BLEIC too) scaling is NOT a form  |
//| of preconditioning. It just affects stopping conditions. You     |
//| should set preconditioner by separate call to one of the         |
//| MinBLEICSetPrec...() functions.                                  |
//| There is a special preconditioning mode, however, which uses     |
//| scaling coefficients to form diagonal preconditioning matrix.    |
//| You can turn this mode on, if you want. But you should understand|
//| that scaling is not the same thing as preconditioning - these are|
//| two different, although related forms of tuning solver.          |
//| INPUT PARAMETERS:                                                |
//|     State   -   structure stores algorithm state                 |
//|     S       -   array[N], non-zero scaling coefficients          |
//|                 S[i] may be negative, sign doesn't matter.       |
//+------------------------------------------------------------------+
static void CMinBLEIC::MinBLEICSetScale(CMinBLEICState &state,double &s[])
  {
//--- create a variable
   int i=0;
//--- check
   if(!CAp::Assert(CAp::Len(s)>=state.m_nmain,__FUNCTION__+": Length(S)<N"))
      return;
   for(i=0;i<=state.m_nmain-1;i++)
     {
      //--- check
      if(!CAp::Assert(CMath::IsFinite(s[i]),__FUNCTION__+": S contains infinite or NAN elements"))
         return;
      //--- check
      if(!CAp::Assert(s[i]!=0.0,__FUNCTION__+": S contains zero elements"))
         return;
      //--- change values
      state.m_soriginal[i]=MathAbs(s[i]);
     }
  }
//+------------------------------------------------------------------+
//| Modification of the preconditioner: preconditioning is turned    |
//| off.                                                             |
//| INPUT PARAMETERS:                                                |
//|     State   -   structure which stores algorithm state           |
//+------------------------------------------------------------------+
static void CMinBLEIC::MinBLEICSetPrecDefault(CMinBLEICState &state)
  {
//--- change value
   state.m_prectype=0;
  }
//+------------------------------------------------------------------+
//| Modification of the preconditioner: diagonal of approximate      |
//| Hessian is used.                                                 |
//| INPUT PARAMETERS:                                                |
//|     State   -   structure which stores algorithm state           |
//|     D       -   diagonal of the approximate Hessian,             |
//|                 array[0..N-1], (if larger, only leading N        |
//|                 elements are used).                              |
//| NOTE 1: D[i] should be positive. Exception will be thrown        |
//|         otherwise.                                               |
//| NOTE 2: you should pass diagonal of approximate Hessian - NOT    |
//|         ITS INVERSE.                                             |
//+------------------------------------------------------------------+
static void CMinBLEIC::MinBLEICSetPrecDiag(CMinBLEICState &state,double &d[])
  {
//--- create a variable
   int i=0;
//--- check
   if(!CAp::Assert(CAp::Len(d)>=state.m_nmain,__FUNCTION__+": D is too short"))
      return;
   for(i=0;i<=state.m_nmain-1;i++)
     {
      //--- check
      if(!CAp::Assert(CMath::IsFinite(d[i]),__FUNCTION__+": D contains infinite or NAN elements"))
         return;
      //--- check
      if(!CAp::Assert((double)(d[i])>0.0,__FUNCTION__+": D contains non-positive elements"))
         return;
     }
//--- function call
   CApServ::RVectorSetLengthAtLeast(state.m_diaghoriginal,state.m_nmain);
   state.m_prectype=2;
//--- copy
   for(i=0;i<=state.m_nmain-1;i++)
      state.m_diaghoriginal[i]=d[i];
  }
//+------------------------------------------------------------------+
//| Modification of the preconditioner: scale-based diagonal         |
//| preconditioning.                                                 |
//| This preconditioning mode can be useful when you don't have      |
//| approximate diagonal of Hessian, but you know that your variables|
//| are badly scaled (for example, one variable is in [1,10], and    |
//| another in [1000,100000]), and most part of the ill-conditioning |
//| comes from different scales of vars.                             |
//| In this case simple scale-based preconditioner, with H[i] =      |
//| = 1/(s[i]^2), can greatly improve convergence.                   |
//| IMPRTANT: you should set scale of your variables with            |
//| MinBLEICSetScale() call (before or after MinBLEICSetPrecScale()  |
//| call). Without knowledge of the scale of your variables          |
//| scale-based preconditioner will be just unit matrix.             |
//| INPUT PARAMETERS:                                                |
//|     State   -   structure which stores algorithm state           |
//+------------------------------------------------------------------+
static void CMinBLEIC::MinBLEICSetPrecScale(CMinBLEICState &state)
  {
//--- change value
   state.m_prectype=3;
  }
//+------------------------------------------------------------------+
//| This function allows to stop algorithm after specified number of |
//| inner iterations.                                                |
//| INPUT PARAMETERS:                                                |
//|     State   -   structure which stores algorithm state           |
//|     MaxIts  -   maximum number of inner iterations.              |
//|                 If MaxIts=0, the number of iterations is         |
//|                 unlimited.                                       |
//+------------------------------------------------------------------+
static void CMinBLEIC::MinBLEICSetMaxIts(CMinBLEICState &state,
                                         const int maxits)
  {
//--- check
   if(!CAp::Assert(maxits>=0,__FUNCTION__+": negative MaxIts!"))
      return;
//--- change value
   state.m_maxits=maxits;
  }
//+------------------------------------------------------------------+
//| This function turns on/off reporting.                            |
//| INPUT PARAMETERS:                                                |
//|     State   -   structure which stores algorithm state           |
//|     NeedXRep-   whether iteration reports are needed or not      |
//| If NeedXRep is True, algorithm will call rep() callback function |
//| if it is provided to MinBLEICOptimize().                         |
//+------------------------------------------------------------------+
static void CMinBLEIC::MinBLEICSetXRep(CMinBLEICState &state,
                                       const bool needxrep)
  {
//--- change value
   state.m_xrep=needxrep;
  }
//+------------------------------------------------------------------+
//| This function sets maximum step length                           |
//| IMPORTANT: this feature is hard to combine with preconditioning. |
//| You can't set upper limit on step length, when you solve         |
//| optimization problem with linear (non-boundary) constraints AND  |
//| preconditioner turned on.                                        |
//| When non-boundary constraints are present, you have to either a) |
//| use preconditioner, or b) use upper limit on step length. YOU    |
//| CAN'T USE BOTH! In this case algorithm will terminate with       |
//| appropriate error code.                                          |
//| INPUT PARAMETERS:                                                |
//|     State   -   structure which stores algorithm state           |
//|     StpMax  -   maximum step length, >=0. Set StpMax to 0.0, if  |
//|                 you don't want to limit step length.             |
//| Use this subroutine when you optimize target function which      |
//| contains exp() or other fast growing functions, and optimization |
//| algorithm makes too large steps which lead to overflow. This     |
//| function allows us to reject steps that are too large (and       |
//| therefore expose us to the possible overflow) without actually   |
//| calculating function value at the x+stp*d.                       |
//+------------------------------------------------------------------+
static void CMinBLEIC::MinBLEICSetStpMax(CMinBLEICState &state,
                                         const double stpmax)
  {
//--- check
   if(!CAp::Assert(CMath::IsFinite(stpmax),__FUNCTION__+": StpMax is not finite!"))
      return;
//--- check
   if(!CAp::Assert(stpmax>=0.0,__FUNCTION__+": StpMax<0!"))
      return;
//--- change value
   state.m_stpmax=stpmax;
  }
//+------------------------------------------------------------------+
//| BLEIC results                                                    |
//| INPUT PARAMETERS:                                                |
//|     State   -   algorithm state                                  |
//| OUTPUT PARAMETERS:                                               |
//|     X       -   array[0..N-1], solution                          |
//|     Rep     -   optimization report. You should check Rep.       |
//|                 TerminationType in order to distinguish          |
//|                 successful termination from unsuccessful one.    |
//|                 More information about fields of this structure  |
//|                 can be found in the comments on MinBLEICReport   |
//|                 datatype.                                        |
//+------------------------------------------------------------------+
static void CMinBLEIC::MinBLEICResults(CMinBLEICState &state,double &x[],
                                       CMinBLEICReport &rep)
  {
//--- reset memory
   ArrayResizeAL(x,0);
//--- function call
   MinBLEICResultsBuf(state,x,rep);
  }
//+------------------------------------------------------------------+
//| BLEIC results                                                    |
//| Buffered implementation of MinBLEICResults() which uses          |
//| pre-allocated buffer to store X[]. If buffer size is too small,  |
//| it resizes buffer. It is intended to be used in the inner cycles |
//| of performance critical algorithms where array reallocation      |
//| penalty is too large to be ignored.                              |
//+------------------------------------------------------------------+
static void CMinBLEIC::MinBLEICResultsBuf(CMinBLEICState &state,double &x[],
                                          CMinBLEICReport &rep)
  {
//--- create variables
   int i=0;
   int i_=0;
//--- check
   if(CAp::Len(x)<state.m_nmain)
      ArrayResizeAL(x,state.m_nmain);
//--- change values
   rep.m_inneriterationscount=state.m_repinneriterationscount;
   rep.m_outeriterationscount=state.m_repouteriterationscount;
   rep.m_nfev=state.m_repnfev;
   rep.m_terminationtype=state.m_repterminationtype;
//--- check
   if(state.m_repterminationtype>0)
     {
      for(i_=0;i_<=state.m_nmain-1;i_++)
         x[i_]=state.m_xend[i_];
     }
   else
     {
      for(i=0;i<=state.m_nmain-1;i++)
         x[i]=CInfOrNaN::NaN();
     }
//--- change values
   rep.m_debugeqerr=state.m_repdebugeqerr;
   rep.m_debugfs=state.m_repdebugfs;
   rep.m_debugff=state.m_repdebugff;
   rep.m_debugdx=state.m_repdebugdx;
  }
//+------------------------------------------------------------------+
//| This subroutine restarts algorithm from new point.               |
//| All optimization parameters (including constraints) are left     |
//| unchanged.                                                       |
//| This function allows to solve multiple optimization problems     |
//| (which must have same number of dimensions) without object       |
//| reallocation penalty.                                            |
//| INPUT PARAMETERS:                                                |
//|     State   -   structure previously allocated with              |
//|                 MinBLEICCreate call.                             |
//|     X       -   new starting point.                              |
//+------------------------------------------------------------------+
static void CMinBLEIC::MinBLEICRestartFrom(CMinBLEICState &state,double &x[])
  {
//--- create variables
   int n=0;
   int i_=0;
//--- initialization
   n=state.m_nmain;
//--- First,check for errors in the inputs
   if(!CAp::Assert(CAp::Len(x)>=n,__FUNCTION__+": Length(X)<N"))
      return;
//--- check
   if(!CAp::Assert(CApServ::IsFiniteVector(x,n),__FUNCTION__+": X contains infinite or NaN values!"))
      return;
//--- Set XC
   for(i_=0;i_<=n-1;i_++)
      state.m_xstart[i_]=x[i_];
//--- prepare RComm facilities
   ArrayResizeAL(state.m_rstate.ia,5);
   ArrayResizeAL(state.m_rstate.ba,1);
   ArrayResizeAL(state.m_rstate.ra,2);
   state.m_rstate.stage=-1;
//--- function call
   ClearRequestFields(state);
  }
//+------------------------------------------------------------------+
//| Clears request fileds (to be sure that we don't forget to clear  |
//| something)                                                       |
//+------------------------------------------------------------------+
static void CMinBLEIC::ClearRequestFields(CMinBLEICState &state)
  {
//--- change values
   state.m_needf=false;
   state.m_needfg=false;
   state.m_xupdated=false;
  }
//+------------------------------------------------------------------+
//| This functions "unscales" point, i.e. it makes transformation    |
//| from scaled variables to unscaled ones. Only leading NMain       |
//| variables are copied from XUnscaled to XScaled.                  |
//+------------------------------------------------------------------+
static void CMinBLEIC::UnscalePoint(CMinBLEICState &state,double &xscaled[],
                                    double &xunscaled[])
  {
//--- create variables
   int    i=0;
   double v=0;
//--- calculation
   for(i=0;i<=state.m_nmain-1;i++)
     {
      v=xscaled[i]*state.m_transforms[i];
      //--- check
      if(state.m_hasbndl[i])
        {
         //--- check
         if(v<state.m_bndloriginal[i])
            v=state.m_bndloriginal[i];
        }
      //--- check
      if(state.m_hasbndu[i])
        {
         //--- check
         if(v>state.m_bnduoriginal[i])
            v=state.m_bnduoriginal[i];
        }
      xunscaled[i]=v;
     }
  }
//+------------------------------------------------------------------+
//| This function:                                                   |
//| 1. makes projection of XScaled into equality constrained subspace|
//|    (X is modified in-place)                                      |
//| 2. stores residual from the projection into R                    |
//| 3. unscales projected XScaled and stores result into XUnscaled   |
//|    with additional enforcement                                   |
//| It calculates set of additional values which are used later for  |
//| modification of the target function F.                           |
//| INPUT PARAMETERS:                                                |
//|     State   -   optimizer state (we use its fields to get        |
//|                 information about constraints)                   |
//|     X       -   vector being projected                           |
//|     R       -   preallocated buffer, used to store residual from |
//|                 projection                                       |
//| OUTPUT PARAMETERS:                                               |
//|     X       -   projection of input X                            |
//|     R       -   residual                                         |
//|     RNorm   -   residual norm squared, used later to modify      |
//|                 target function                                  |
//+------------------------------------------------------------------+
static void CMinBLEIC::ProjectPointAndUnscale(CMinBLEICState &state,
                                              double &xscaled[],double &xunscaled[],
                                              double &rscaled[],double &rnorm2)
  {
//--- create variables
   double v=0;
   int    i=0;
   int    nmain=0;
   int    nslack=0;
   int    i_=0;
//--- initialization
   rnorm2=0;
   nmain=state.m_nmain;
   nslack=state.m_nslack;
//--- * subtract XE from XScaled
//--- * project XScaled
//--- * calculate norm of deviation from null space,store it in RNorm2
//--- * calculate residual from projection,store it in R
//--- * add XE to XScaled
//--- * unscale variables
   for(i_=0;i_<=nmain+nslack-1;i_++)
      xscaled[i_]=xscaled[i_]-state.m_xe[i_];
   rnorm2=0;
   for(i=0;i<=nmain+nslack-1;i++)
      rscaled[i]=0;
//--- change values
   for(i=0;i<=nmain+nslack-1;i++)
     {
      //--- check
      if(state.m_activeconstraints[i])
        {
         v=xscaled[i];
         xscaled[i]=0;
         rscaled[i]=rscaled[i]+v;
         rnorm2=rnorm2+CMath::Sqr(v);
        }
     }
//--- calculation
   for(i=0;i<=state.m_cecnt-1;i++)
     {
      v=0.0;
      for(i_=0;i_<=nmain+nslack-1;i_++)
         v+=xscaled[i_]*state.m_cecurrent[i][i_];
      for(i_=0;i_<=nmain+nslack-1;i_++)
         xscaled[i_]=xscaled[i_]-v*state.m_cecurrent[i][i_];
      for(i_=0;i_<=nmain+nslack-1;i_++)
         rscaled[i_]=rscaled[i_]+v*state.m_cecurrent[i][i_];
      rnorm2=rnorm2+CMath::Sqr(v);
     }
   for(i_=0;i_<=nmain+nslack-1;i_++)
      xscaled[i_]=xscaled[i_]+state.m_xe[i_];
//--- function call
   UnscalePoint(state,xscaled,xunscaled);
  }
//+------------------------------------------------------------------+
//| This function scales and copies NMain elements of GUnscaled into |
//| GScaled. Other NSlack components of GScaled are set to zero.     |
//+------------------------------------------------------------------+
static void CMinBLEIC::ScaleGradientAndExpand(CMinBLEICState &state,
                                              double &gunscaled[],
                                              double &gscaled[])
  {
//--- create a variable
   int i=0;
//--- change values
   for(i=0;i<=state.m_nmain-1;i++)
      gscaled[i]=gunscaled[i]*state.m_transforms[i];
   for(i=0;i<=state.m_nslack-1;i++)
      gscaled[state.m_nmain+i]=0;
  }
//+------------------------------------------------------------------+
//| This subroutine applies modifications to the target function     |
//| given by its value F and gradient G at the projected point X     |
//| which lies in the equality constrained subspace.                 |
//| Following modifications are applied:                             |
//| * modified barrier functions to handle inequality constraints    |
//|   (both F and G are modified)                                    |
//| * projection of gradient into equality constrained subspace      |
//|   (only G is modified)                                           |
//| * quadratic penalty for deviations from equality constrained     |
//|   subspace (both F and G are modified)                           |
//| It also calculates gradient norm (three different norms for three|
//| different types of gradient), feasibility and complementary      |
//| slackness errors.                                                |
//| INPUT PARAMETERS:                                                |
//|     State   -   optimizer state (we use its fields to get        |
//|                 information about constraints)                   |
//|     X       -   point (projected into equality constrained       |
//|                 subspace)                                        |
//|     R       -   residual from projection                         |
//|     RNorm2  -   residual norm squared                            |
//|     F       -   function value at X                              |
//|     G       -   function gradient at X                           |
//| OUTPUT PARAMETERS:                                               |
//|     F       -   modified function value at X                     |
//|     G       -   modified function gradient at X                  |
//|     GNorm   -   2-norm of unmodified G                           |
//|     MPGNorm -   2-norm of modified G                             |
//|     MBA     -   minimum argument of barrier functions.           |
//|                 If X is strictly feasible, it is greater than    |
//|                 zero.                                            |
//|                 If X lies on a boundary, it is zero.             |
//|                 It is negative for infeasible X.                 |
//|     FIErr   -   2-norm of feasibility error with respect to      |
//|                 inequality/bound constraints                     |
//|     CSErr   -   2-norm of complementarity slackness error        |
//+------------------------------------------------------------------+
static void CMinBLEIC::ModifyTargetFunction(CMinBLEICState &state,double &x[],
                                            double &r[],const double rnorm2,
                                            double &f,double &g[],
                                            double &gnorm,double &mpgnorm)
  {
//--- create variables
   double v=0;
   int    i=0;
   int    nmain=0;
   int    nslack=0;
   bool   hasconstraints;
   int    i_=0;
//--- initialization
   gnorm=0;
   mpgnorm=0;
   nmain=state.m_nmain;
   nslack=state.m_nslack;
   hasconstraints=false;
//--- GNorm
   v=0.0;
   for(i_=0;i_<=nmain+nslack-1;i_++)
      v+=g[i_]*g[i_];
   gnorm=MathSqrt(v);
//--- Process equality constraints:
//--- * modify F to handle penalty term for equality constraints
//--- * project gradient on null space of equality constraints
//--- * add penalty term for equality constraints to gradient
   f=f+rnorm2;
   for(i=0;i<=nmain+nslack-1;i++)
     {
      //--- check
      if(state.m_activeconstraints[i])
         g[i]=0;
     }
   for(i=0;i<=state.m_cecnt-1;i++)
     {
      v=0.0;
      //--- change values
      for(i_=0;i_<=nmain+nslack-1;i_++)
         v+=g[i_]*state.m_cecurrent[i][i_];
      for(i_=0;i_<=nmain+nslack-1;i_++)
         g[i_]=g[i_]-v*state.m_cecurrent[i][i_];
     }
   for(i_=0;i_<=nmain+nslack-1;i_++)
      g[i_]=g[i_]+2*r[i_];
//--- MPGNorm
   v=0.0;
   for(i_=0;i_<=nmain+nslack-1;i_++)
      v+=g[i_]*g[i_];
   mpgnorm=MathSqrt(v);
  }
//+------------------------------------------------------------------+
//| This function makes additional check for constraints which can be|
//| activated.                                                       |
//| We try activate constraints one by one, but it is possible that  |
//| several constraints should be activated during one iteration. It |
//| this case only one of them (probably last) will be activated.    |
//| This function will fix it - it will pass through constraints and |
//| activate those which are at the boundary or beyond it.           |
//| It will return True, if at least one constraint was activated by |
//| this function.                                                   |
//+------------------------------------------------------------------+
static bool CMinBLEIC::AdditionalCheckForConstraints(CMinBLEICState &state,
                                                     double &x[])
  {
//--- create variables
   bool result;
   int  i=0;
   int  nmain=0;
   int  nslack=0;
//--- initialization
   result=false;
   nmain=state.m_nmain;
   nslack=state.m_nslack;
//--- calculation
   for(i=0;i<=nmain-1;i++)
     {
      //--- check
      if(!state.m_activeconstraints[i])
        {
         //--- check
         if(state.m_hasbndl[i])
           {
            //--- check
            if(x[i]<=state.m_bndleffective[i])
              {
               state.m_activeconstraints[i]=true;
               state.m_constrainedvalues[i]=state.m_bndleffective[i];
               result=true;
              }
           }
         //--- check
         if(state.m_hasbndu[i])
           {
            //--- check
            if(x[i]>=state.m_bndueffective[i])
              {
               state.m_activeconstraints[i]=true;
               state.m_constrainedvalues[i]=state.m_bndueffective[i];
               result=true;
              }
           }
        }
     }
   for(i=0;i<=nslack-1;i++)
     {
      //--- check
      if(!state.m_activeconstraints[nmain+i])
        {
         //--- check
         if(x[nmain+i]<=0.0)
           {
            state.m_activeconstraints[nmain+i]=true;
            state.m_constrainedvalues[nmain+i]=0;
            result=true;
           }
        }
     }
//--- return result
   return(result);
  }
//+------------------------------------------------------------------+
//| This function rebuilds CECurrent and XE according to current set |
//| of active bound constraints.                                     |
//+------------------------------------------------------------------+
static void CMinBLEIC::RebuildCEXE(CMinBLEICState &state)
  {
//--- create variables
   int    i=0;
   int    j=0;
   int    k=0;
   int    nmain=0;
   int    nslack=0;
   double v=0;
   int    i_=0;
//--- initialization
   nmain=state.m_nmain;
   nslack=state.m_nslack;
//--- function call
   CAblas::RMatrixCopy(state.m_cecnt,nmain+nslack+1,state.m_ceeffective,0,0,state.m_cecurrent,0,0);
//--- calculation
   for(i=0;i<=state.m_cecnt-1;i++)
     {
      //--- "Subtract" active bound constraints from I-th linear constraint
      for(j=0;j<=nmain+nslack-1;j++)
        {
         //--- check
         if(state.m_activeconstraints[j])
           {
            state.m_cecurrent[i].Set(nmain+nslack,state.m_cecurrent[i][nmain+nslack]-state.m_cecurrent[i][j]*state.m_constrainedvalues[j]);
            state.m_cecurrent[i].Set(j,0.0);
           }
        }
      //--- Reorthogonalize I-th constraint with respect to previous ones
      //--- NOTE: we also update right part,which is CECurrent[...,NMain+NSlack].
      for(k=0;k<=i-1;k++)
        {
         v=0.0;
         for(i_=0;i_<=nmain+nslack-1;i_++)
            v+=state.m_cecurrent[k][i_]*state.m_cecurrent[i][i_];
         for(i_=0;i_<=nmain+nslack;i_++)
            state.m_cecurrent[i].Set(i_,state.m_cecurrent[i][i_]-v*state.m_cecurrent[k][i_]);
        }
      //--- Calculate norm of I-th row of CECurrent. Fill by zeros,if it is
      //--- too small. Normalize otherwise.
      //--- NOTE: we also scale last column of CECurrent (right part)
      v=0.0;
      for(i_=0;i_<=nmain+nslack-1;i_++)
         v+=state.m_cecurrent[i][i_]*state.m_cecurrent[i][i_];
      v=MathSqrt(v);
      //--- check
      if(v>10000*CMath::m_machineepsilon)
        {
         v=1/v;
         for(i_=0;i_<=nmain+nslack;i_++)
            state.m_cecurrent[i].Set(i_,v*state.m_cecurrent[i][i_]);
        }
      else
        {
         for(j=0;j<=nmain+nslack;j++)
            state.m_cecurrent[i].Set(j,0);
        }
     }
//--- change values
   for(j=0;j<=nmain+nslack-1;j++)
      state.m_xe[j]=0;
   for(i=0;i<=nmain+nslack-1;i++)
     {
      //--- check
      if(state.m_activeconstraints[i])
         state.m_xe[i]=state.m_xe[i]+state.m_constrainedvalues[i];
     }
//--- change values
   for(i=0;i<=state.m_cecnt-1;i++)
     {
      v=state.m_cecurrent[i][nmain+nslack];
      for(i_=0;i_<=nmain+nslack-1;i_++)
         state.m_xe[i_]=state.m_xe[i_]+v*state.m_cecurrent[i][i_];
     }
  }
//+------------------------------------------------------------------+
//| This function projects gradient onto equality constrained        |
//| subspace                                                         |
//+------------------------------------------------------------------+
static void CMinBLEIC::MakeGradientProjection(CMinBLEICState &state,
                                              double &pg[])
  {
//--- create variables
   int    i=0;
   int    nmain=0;
   int    nslack=0;
   double v=0;
   int    i_=0;
//--- initialization
   nmain=state.m_nmain;
   nslack=state.m_nslack;
   for(i=0;i<=nmain+nslack-1;i++)
     {
      //--- check
      if(state.m_activeconstraints[i])
         pg[i]=0;
     }
//--- calculation
   for(i=0;i<=state.m_cecnt-1;i++)
     {
      v=0.0;
      for(i_=0;i_<=nmain+nslack-1;i_++)
         v+=pg[i_]*state.m_cecurrent[i][i_];
      for(i_=0;i_<=nmain+nslack-1;i_++)
         pg[i_]=pg[i_]-v*state.m_cecurrent[i][i_];
     }
  }
//+------------------------------------------------------------------+
//| This function prepares equality constrained subproblem:          |
//| 1. X is used to activate constraints (if there are ones which are|
//|    still inactive, but should be activated).                     |
//| 2. constraints matrix CEOrt is copied to CECurrent and modified  | 
//|    according to the list of active bound constraints             |
//|    (corresponding elements are filled by zeros and               |
//|    reorthogonalized).                                            |
//| 3. XE - least squares solution of equality constraints - is      |
//|    recalculated                                                  |
//| 4. X is copied to PX and projected onto equality constrained     |
//|    subspace                                                      |
//| 5. inactive constraints are checked against PX - if there is at  |
//|    least one which should be activated, we activate it and move  |
//|    back to (2)                                                   |
//| 6. as result, PX is feasible with respect to bound constraints - |
//|    step (5) guarantees it. But PX can be infeasible with respect |
//|    to equality ones, because step (2) is done without checks for |
//|    consistency. As the final step, we check that PX is feasible. |
//|    If not, we return False. True is returned otherwise.          |
//| If this algorithm returned True, then:                           |
//| * X is not changed                                               |
//| * PX contains projection of X onto constrained subspace          |
//| * G is not changed                                               |
//| * PG contains projection of G onto constrained subspace          |
//| * PX is feasible with respect to all constraints                 |
//| * all constraints which are active at PX, are activated          |
//+------------------------------------------------------------------+
static bool CMinBLEIC::PrepareConstraintMatrix(CMinBLEICState &state,double &x[],
                                               double &g[],double &px[],double &pg[])
  {
//--- create variables
   int    i=0;
   int    nmain=0;
   int    nslack=0;
   double v=0;
   double ferr=0;
   int    i_=0;
//--- initialization
   nmain=state.m_nmain;
   nslack=state.m_nslack;
//--- Step 1
   AdditionalCheckForConstraints(state,x);
//--- Steps 2-5
   do
     {
      //--- Steps 2-3
      RebuildCEXE(state);
      //--- Step 4
      //--- Calculate PX,PG
      for(i_=0;i_<=nmain+nslack-1;i_++)
         px[i_]=x[i_];
      for(i_=0;i_<=nmain+nslack-1;i_++)
         px[i_]=px[i_]-state.m_xe[i_];
      for(i_=0;i_<=nmain+nslack-1;i_++)
         pg[i_]=g[i_];
      for(i=0;i<=nmain+nslack-1;i++)
        {
         //--- check
         if(state.m_activeconstraints[i])
           {
            px[i]=0;
            pg[i]=0;
           }
        }
      //--- calculation
      for(i=0;i<=state.m_cecnt-1;i++)
        {
         //--- change values
         v=0.0;
         for(i_=0;i_<=nmain+nslack-1;i_++)
            v+=px[i_]*state.m_cecurrent[i][i_];
         for(i_=0;i_<=nmain+nslack-1;i_++)
            px[i_]=px[i_]-v*state.m_cecurrent[i][i_];
         //--- change values
         v=0.0;
         for(i_=0;i_<=nmain+nslack-1;i_++)
            v+=pg[i_]*state.m_cecurrent[i][i_];
         for(i_=0;i_<=nmain+nslack-1;i_++)
            pg[i_]=pg[i_]-v*state.m_cecurrent[i][i_];
        }
      for(i_=0;i_<=nmain+nslack-1;i_++)
         px[i_]=px[i_]+state.m_xe[i_];
      //--- Step 5 (loop condition below)
     }
   while(AdditionalCheckForConstraints(state,px));
//--- Step 6
   ferr=0;
   for(i=0;i<=state.m_cecnt-1;i++)
     {
      v=0.0;
      for(i_=0;i_<=nmain+nslack-1;i_++)
         v+=px[i_]*state.m_ceeffective[i][i_];
      //--- change values
      v=v-state.m_ceeffective[i][nmain+nslack];
      ferr=MathMax(ferr,MathAbs(v));
     }
//--- check
   if(ferr<=state.m_outerepsi)
      return(true);
//--- return result
   return(false);
  }
//+------------------------------------------------------------------+
//| Internal initialization subroutine                               |
//+------------------------------------------------------------------+
static void CMinBLEIC::MinBLEICInitInternal(const int n,double &x[],
                                            const double diffstep,
                                            CMinBLEICState &state)
  {
//--- create a variable
   int i=0;
//--- create matrix
   CMatrixDouble c;
//--- create array
   int ct[];
//--- initialization
   state.m_nmain=n;
   state.m_optdim=0;
   state.m_diffstep=diffstep;
//--- allocation
   ArrayResizeAL(state.m_bndloriginal,n);
   ArrayResizeAL(state.m_bndleffective,n);
   ArrayResizeAL(state.m_hasbndl,n);
   ArrayResizeAL(state.m_bnduoriginal,n);
   ArrayResizeAL(state.m_bndueffective,n);
   ArrayResizeAL(state.m_hasbndu,n);
   ArrayResizeAL(state.m_xstart,n);
   ArrayResizeAL(state.m_soriginal,n);
   ArrayResizeAL(state.m_x,n);
   ArrayResizeAL(state.m_g,n);
   for(i=0;i<=n-1;i++)
     {
      state.m_bndloriginal[i]=CInfOrNaN::NegativeInfinity();
      state.m_hasbndl[i]=false;
      state.m_bnduoriginal[i]=CInfOrNaN::PositiveInfinity();
      state.m_hasbndu[i]=false;
      state.m_soriginal[i]=1.0;
     }
//--- function call
   MinBLEICSetLC(state,c,ct,0);
//--- function call
   MinBLEICSetInnerCond(state,0.0,0.0,0.0);
//--- function call
   MinBLEICSetOuterCond(state,1.0E-6,1.0E-6);
//--- function call
   MinBLEICSetMaxIts(state,0);
//--- function call
   MinBLEICSetXRep(state,false);
//--- function call
   MinBLEICSetStpMax(state,0.0);
//--- function call
   MinBLEICSetPrecDefault(state);
//--- function call
   MinBLEICRestartFrom(state,x);
  }
//+------------------------------------------------------------------+
//| NOTES:                                                           |
//| 1. This function has two different implementations: one which    |
//|    uses exact (analytical) user-supplied gradient, and one which |
//|    uses function value only and numerically differentiates       |
//|    function in order to obtain gradient.                         |
//|    Depending on the specific function used to create optimizer   |
//|    object (either MinBLEICCreate() for analytical gradient or    |
//|    MinBLEICCreateF() for numerical differentiation) you should   |
//|    choose appropriate variant of MinBLEICOptimize() - one which  |
//|    accepts function AND gradient or one which accepts function   |
//|    ONLY.                                                         |
//|    Be careful to choose variant of MinBLEICOptimize() which      |
//|    corresponds to your optimization scheme! Table below lists    |
//|    different combinations of callback (function/gradient) passed |
//|    to MinBLEICOptimize() and specific function used to create    |
//|    optimizer.                                                    |
//|                      |         USER PASSED TO MinBLEICOptimize() |
//|    CREATED WITH      |  function only   |  function and gradient |
//|    ------------------------------------------------------------  |
//|    MinBLEICCreateF() |     work                FAIL              |
//|    MinBLEICCreate()  |     FAIL                work              |
//|    Here "FAIL" denotes inappropriate combinations of optimizer   |
//|    creation function and MinBLEICOptimize() version. Attemps to  |
//|    use such combination (for example, to create optimizer with   |
//|    MinBLEICCreateF() and to pass gradient information to         |
//|    MinCGOptimize()) will lead to exception being thrown. Either  |
//|    you did not pass gradient when it WAS needed or you passed    |
//|    gradient when it was NOT needed.                              |
//+------------------------------------------------------------------+
static bool CMinBLEIC::MinBLEICIteration(CMinBLEICState &state)
  {
//--- create variables
   int    nmain=0;
   int    nslack=0;
   int    m=0;
   int    i=0;
   int    j=0;
   double v=0;
   double vv=0;
   bool   b;
   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
      nmain=state.m_rstate.ia[0];
      nslack=state.m_rstate.ia[1];
      m=state.m_rstate.ia[2];
      i=state.m_rstate.ia[3];
      j=state.m_rstate.ia[4];
      b=state.m_rstate.ba[0];
      v=state.m_rstate.ra[0];
      vv=state.m_rstate.ra[1];
     }
   else
     {
      //--- initialization
      nmain=-983;
      nslack=-989;
      m=-834;
      i=900;
      j=-287;
      b=false;
      v=214;
      vv=-338;
     }
//--- check
   if(state.m_rstate.stage==0)
     {
      //--- change value
      state.m_needfg=false;
      //--- function call, return result
      return(Func_lbl_14(state,nmain,nslack,m,i,j,b,v,vv));
     }
//--- check
   if(state.m_rstate.stage==1)
     {
      //--- change value
      state.m_needf=false;
      //--- function call, return result
      return(Func_lbl_14(state,nmain,nslack,m,i,j,b,v,vv));
     }
//--- check
   if(state.m_rstate.stage==2)
     {
      //--- change value
      state.m_needfg=false;
      //--- function call, return result
      return(Func_lbl_22(state,nmain,nslack,m,i,j,b,v,vv));
     }
//--- check
   if(state.m_rstate.stage==3)
     {
      //--- change values
      state.m_fbase=state.m_f;
      i=0;
      //--- function call, return result
      return(Func_lbl_23(state,nmain,nslack,m,i,j,b,v,vv));
     }
//--- check
   if(state.m_rstate.stage==4)
     {
      //--- change values
      state.m_fm2=state.m_f;
      state.m_x[i]=v-0.5*state.m_diffstep*state.m_soriginal[i];
      state.m_rstate.stage=5;
      //--- Saving state
      Func_lbl_rcomm(state,nmain,nslack,m,i,j,b,v,vv);
      //--- return result
      return(true);
     }
//--- check
   if(state.m_rstate.stage==5)
     {
      //--- change values
      state.m_fm1=state.m_f;
      state.m_x[i]=v+0.5*state.m_diffstep*state.m_soriginal[i];
      state.m_rstate.stage=6;
      //--- Saving state
      Func_lbl_rcomm(state,nmain,nslack,m,i,j,b,v,vv);
      //--- return result
      return(true);
     }
//--- check
   if(state.m_rstate.stage==6)
     {
      //--- change values
      state.m_fp1=state.m_f;
      state.m_x[i]=v+state.m_diffstep*state.m_soriginal[i];
      state.m_rstate.stage=7;
      //--- Saving state
      Func_lbl_rcomm(state,nmain,nslack,m,i,j,b,v,vv);
      //--- return result
      return(true);
     }
//--- check
   if(state.m_rstate.stage==7)
     {
      //--- change values
      state.m_fp2=state.m_f;
      state.m_g[i]=(8*(state.m_fp1-state.m_fm1)-(state.m_fp2-state.m_fm2))/(6*state.m_diffstep*state.m_soriginal[i]);
      state.m_x[i]=v;
      i=i+1;
      //--- function call, return result
      return(Func_lbl_23(state,nmain,nslack,m,i,j,b,v,vv));
     }
//--- check
   if(state.m_rstate.stage==8)
     {
      //--- change values
      state.m_fm1=state.m_f;
      state.m_xp1=MathMin(v+state.m_diffstep*state.m_soriginal[i],state.m_bnduoriginal[i]);
      state.m_x[i]=state.m_xp1;
      state.m_rstate.stage=9;
      //--- Saving state
      Func_lbl_rcomm(state,nmain,nslack,m,i,j,b,v,vv);
      //--- return result
      return(true);
     }
//--- check
   if(state.m_rstate.stage==9)
     {
      //--- change values
      state.m_fp1=state.m_f;
      state.m_g[i]=(state.m_fp1-state.m_fm1)/(state.m_xp1-state.m_xm1);
      state.m_x[i]=v;
      i=i+1;
      //--- function call, return result
      return(Func_lbl_23(state,nmain,nslack,m,i,j,b,v,vv));
     }
//--- check
   if(state.m_rstate.stage==10)
     {
      //--- change value
      state.m_xupdated=false;
      //--- function call, return result
      return(Func_lbl_17(state,nmain,nslack,m,i,j,b,v,vv));
     }
//--- check
   if(state.m_rstate.stage==11)
     {
      //--- change value
      state.m_needfg=false;
      //--- function call, return result
      return(Func_lbl_31(state,nmain,nslack,m,i,j,b,v,vv));
     }
//--- check
   if(state.m_rstate.stage==12)
     {
      //--- change value
      state.m_needf=false;
      //--- function call, return result
      return(Func_lbl_31(state,nmain,nslack,m,i,j,b,v,vv));
     }
//--- Routine body
//--- Prepare:
//--- * calculate number of slack variables
//--- * initialize locals
//--- * initialize debug fields
//--- * make quick check
   nmain=state.m_nmain;
   nslack=0;
   for(i=0;i<=state.m_cecnt-1;i++)
     {
      //--- check
      if(state.m_ct[i]!=0)
         nslack=nslack+1;
     }
//--- change values
   state.m_nslack=nslack;
   state.m_repterminationtype=0;
   state.m_repinneriterationscount=0;
   state.m_repouteriterationscount=0;
   state.m_repnfev=0;
   state.m_repdebugeqerr=0.0;
   state.m_repdebugfs=CInfOrNaN::NaN();
   state.m_repdebugff=CInfOrNaN::NaN();
   state.m_repdebugdx=CInfOrNaN::NaN();
//--- check
   if(state.m_stpmax!=0.0 && state.m_prectype!=0)
     {
      state.m_repterminationtype=-10;
      //--- return result
      return(false);
     }
//--- allocate
   CApServ::RVectorSetLengthAtLeast(state.m_r,nmain+nslack);
   CApServ::RVectorSetLengthAtLeast(state.m_diagh,nmain+nslack);
   CApServ::RVectorSetLengthAtLeast(state.m_tmp0,nmain+nslack);
   CApServ::RVectorSetLengthAtLeast(state.m_tmp1,nmain+nslack);
   CApServ::RVectorSetLengthAtLeast(state.m_tmp2,nmain+nslack);
   CApServ::RMatrixSetLengthAtLeast(state.m_cecurrent,state.m_cecnt,nmain+nslack+1);
   CApServ::BVectorSetLengthAtLeast(state.m_activeconstraints,nmain+nslack);
   CApServ::RVectorSetLengthAtLeast(state.m_constrainedvalues,nmain+nslack);
   CApServ::RVectorSetLengthAtLeast(state.m_lastg,nmain+nslack);
   CApServ::RVectorSetLengthAtLeast(state.m_xe,nmain+nslack);
   CApServ::RVectorSetLengthAtLeast(state.m_xcur,nmain+nslack);
   CApServ::RVectorSetLengthAtLeast(state.m_xprev,nmain+nslack);
   CApServ::RVectorSetLengthAtLeast(state.m_xend,nmain);
//--- Create/restart optimizer.
//--- State.OptDim is used to determine current state of optimizer.
   if(state.m_optdim!=nmain+nslack)
     {
      for(i=0;i<=nmain+nslack-1;i++)
         state.m_tmp1[i]=0.0;
      //--- function call
      CMinCG::MinCGCreate(nmain+nslack,state.m_tmp1,state.m_cgstate);
      state.m_optdim=nmain+nslack;
     }
//--- Prepare transformation.
//--- MinBLEIC's handling of preconditioner matrix is somewhat unusual -
//--- instead of incorporating it into algorithm and making implicit
//--- scaling (as most optimizers do) BLEIC optimizer uses explicit
//--- scaling - it solves problem in the scaled parameters space S,
//--- making transition between scaled (S) and unscaled (X) variables
//--- every time we ask for function value.
//--- Following fields are calculated here:
//--- * TransformS         X[i]=TransformS[i]*S[i],array[NMain]
//--- * SEffective         "effective" scale of the variables after
//---                      transformation,array[NMain+NSlack]
   CApServ::RVectorSetLengthAtLeast(state.m_transforms,nmain);
   for(i=0;i<=nmain-1;i++)
     {
      //--- check
      if(state.m_prectype==2)
        {
         state.m_transforms[i]=1/MathSqrt(state.m_diaghoriginal[i]);
         continue;
        }
      //--- check
      if(state.m_prectype==3)
        {
         state.m_transforms[i]=state.m_soriginal[i];
         continue;
        }
      state.m_transforms[i]=1;
     }
//--- function call
   CApServ::RVectorSetLengthAtLeast(state.m_seffective,nmain+nslack);
   for(i=0;i<=nmain-1;i++)
      state.m_seffective[i]=state.m_soriginal[i]/state.m_transforms[i];
   for(i=0;i<=nslack-1;i++)
      state.m_seffective[nmain+i]=1;
//--- function call
   CMinCG::MinCGSetScale(state.m_cgstate,state.m_seffective);
//--- Pre-process constraints
//--- * check consistency of bound constraints
//--- * add slack vars,convert problem to the bound/equality
//---   constrained one
//--- We calculate here:
//--- * BndLEffective - lower bounds after transformation of variables (see above)
//--- * BndUEffective - upper bounds after transformation of variables (see above)
//--- * CEEffective - matrix of equality constraints for transformed variables
   for(i=0;i<=nmain-1;i++)
     {
      //--- check
      if(state.m_hasbndl[i])
         state.m_bndleffective[i]=state.m_bndloriginal[i]/state.m_transforms[i];
      //--- check
      if(state.m_hasbndu[i])
         state.m_bndueffective[i]=state.m_bnduoriginal[i]/state.m_transforms[i];
     }
   for(i=0;i<=nmain-1;i++)
     {
      //--- check
      if(state.m_hasbndl[i] && state.m_hasbndu[i])
        {
         //--- check
         if(state.m_bndleffective[i]>state.m_bndueffective[i])
           {
            state.m_repterminationtype=-3;
            //--- return result
            return(false);
           }
        }
     }
//--- function call
   CApServ::RMatrixSetLengthAtLeast(state.m_ceeffective,state.m_cecnt,nmain+nslack+1);
//--- change value
   m=0;
//--- calculation
   for(i=0;i<=state.m_cecnt-1;i++)
     {
      //--- NOTE: when we add slack variable,we use V=max(abs(CE[i,...])) as
      //--- coefficient before it in order to make linear equations better
      //--- conditioned.
      v=0;
      for(j=0;j<=nmain-1;j++)
        {
         state.m_ceeffective[i].Set(j,state.m_ceoriginal[i][j]*state.m_transforms[j]);
         v=MathMax(v,MathAbs(state.m_ceeffective[i][j]));
        }
      //--- check
      if(v==0.0)
         v=1;
      for(j=0;j<=nslack-1;j++)
         state.m_ceeffective[i].Set(nmain+j,0.0);
      state.m_ceeffective[i].Set(nmain+nslack,state.m_ceoriginal[i][nmain]);
      //--- check
      if(state.m_ct[i]<0)
        {
         state.m_ceeffective[i].Set(nmain+m,v);
         m=m+1;
        }
      //--- check
      if(state.m_ct[i]>0)
        {
         state.m_ceeffective[i].Set(nmain+m,-v);
         m=m+1;
        }
     }
//--- Find feasible point.
//--- 0. Convert from unscaled values (as stored in XStart) to scaled
//---    ones
//--- 1. calculate values of slack variables such that starting
//---    point satisfies inequality constraints (after conversion to
//---    equality ones) as much as possible.
//--- 2. use PrepareConstraintMatrix() function,which forces X
//---    to be strictly feasible.
   for(i=0;i<=nmain-1;i++)
      state.m_tmp0[i]=state.m_xstart[i]/state.m_transforms[i];
//--- change value
   m=0;
//--- calculation
   for(i=0;i<=state.m_cecnt-1;i++)
     {
      v=0.0;
      for(i_=0;i_<=nmain-1;i_++)
         v+=state.m_ceeffective[i][i_]*state.m_tmp0[i_];
      //--- check
      if(state.m_ct[i]<0)
        {
         state.m_tmp0[nmain+m]=state.m_ceeffective[i][nmain+nslack]-v;
         m=m+1;
        }
      //--- check
      if(state.m_ct[i]>0)
        {
         state.m_tmp0[nmain+m]=v-state.m_ceeffective[i][nmain+nslack];
         m=m+1;
        }
     }
//--- change values
   for(i=0;i<=nmain+nslack-1;i++)
      state.m_tmp1[i]=0;
   for(i=0;i<=nmain+nslack-1;i++)
      state.m_activeconstraints[i]=false;
//--- function call
   b=PrepareConstraintMatrix(state,state.m_tmp0,state.m_tmp1,state.m_xcur,state.m_tmp2);
   state.m_repdebugeqerr=0.0;
//--- calculation
   for(i=0;i<=state.m_cecnt-1;i++)
     {
      v=0.0;
      for(i_=0;i_<=nmain+nslack-1;i_++)
         v+=state.m_ceeffective[i][i_]*state.m_xcur[i_];
      state.m_repdebugeqerr=state.m_repdebugeqerr+CMath::Sqr(v-state.m_ceeffective[i][nmain+nslack]);
     }
   state.m_repdebugeqerr=MathSqrt(state.m_repdebugeqerr);
//--- check
   if(!b)
     {
      state.m_repterminationtype=-3;
      //--- return result
      return(false);
     }
//--- Initialize RepDebugFS with function value at initial point
   UnscalePoint(state,state.m_xcur,state.m_x);
   ClearRequestFields(state);
//--- check
   if(state.m_diffstep!=0.0)
     {
      state.m_needf=true;
      state.m_rstate.stage=1;
      //--- Saving state
      Func_lbl_rcomm(state,nmain,nslack,m,i,j,b,v,vv);
      //--- return result
      return(true);
     }
//--- change values
   state.m_needfg=true;
   state.m_rstate.stage=0;
//--- Saving state
   Func_lbl_rcomm(state,nmain,nslack,m,i,j,b,v,vv);
//--- return result
   return(true);
  }
//+------------------------------------------------------------------+
//| Auxiliary function for MinBLEICIteration. Is a product to get rid|
//| of the operator unconditional jump goto.                         |
//+------------------------------------------------------------------+
static void CMinBLEIC::Func_lbl_rcomm(CMinBLEICState &state,int nmain,
                                      int nslack,int m,int i,int j,
                                      bool b,double v,double vv)
  {
//--- save
   state.m_rstate.ia[0]=nmain;
   state.m_rstate.ia[1]=nslack;
   state.m_rstate.ia[2]=m;
   state.m_rstate.ia[3]=i;
   state.m_rstate.ia[4]=j;
   state.m_rstate.ba[0]=b;
   state.m_rstate.ra[0]=v;
   state.m_rstate.ra[1]=vv;
  }
//+------------------------------------------------------------------+
//| Auxiliary function for MinBLEICIteration. Is a product to get rid|
//| of the operator unconditional jump goto.                         |
//+------------------------------------------------------------------+
static bool CMinBLEIC::Func_lbl_14(CMinBLEICState &state,int &nmain,
                                   int &nslack,int &m,int &i,int &j,
                                   bool &b,double &v,double &vv)
  {
//--- function call
   COptServ::TrimPrepare(state.m_f,state.m_trimthreshold);
   state.m_repnfev=state.m_repnfev+1;
   state.m_repdebugfs=state.m_f;
//--- Outer cycle
   state.m_itsleft=state.m_maxits;
//--- copy
   for(int i_=0;i_<=nmain+nslack-1;i_++)
      state.m_xprev[i_]=state.m_xcur[i_];
//--- function call, return result
   return(Func_lbl_15(state,nmain,nslack,m,i,j,b,v,vv));
  }
//+------------------------------------------------------------------+
//| Auxiliary function for MinBLEICIteration. Is a product to get rid|
//| of the operator unconditional jump goto.                         |
//+------------------------------------------------------------------+
static bool CMinBLEIC::Func_lbl_15(CMinBLEICState &state,int &nmain,
                                   int &nslack,int &m,int &i,int &j,
                                   bool &b,double &v,double &vv)
  {
//--- check
   if(!CAp::Assert(state.m_prectype==0 || state.m_stpmax==0.0,"MinBLEIC: internal error (-10)"))
      return(false);
//--- Inner cycle: CG with projections and penalty functions
   for(int i_=0;i_<=nmain+nslack-1;i_++)
      state.m_tmp0[i_]=state.m_xcur[i_];
   for(i=0;i<=nmain+nslack-1;i++)
     {
      state.m_tmp1[i]=0;
      state.m_activeconstraints[i]=false;
     }
//--- check
   if(!PrepareConstraintMatrix(state,state.m_tmp0,state.m_tmp1,state.m_xcur,state.m_tmp2))
     {
      state.m_repterminationtype=-3;
      //--- return result
      return(false);
     }
   for(i=0;i<=nmain+nslack-1;i++)
      state.m_activeconstraints[i]=false;
   RebuildCEXE(state);
//--- function call
   CMinCG::MinCGRestartFrom(state.m_cgstate,state.m_xcur);
//--- function call
   CMinCG::MinCGSetCond(state.m_cgstate,state.m_innerepsg,state.m_innerepsf,state.m_innerepsx,state.m_itsleft);
//--- function call
   CMinCG::MinCGSetXRep(state.m_cgstate,state.m_xrep);
//--- function call
   CMinCG::MinCGSetDRep(state.m_cgstate,true);
//--- function call
   CMinCG::MinCGSetStpMax(state.m_cgstate,state.m_stpmax);
//--- function call, return result
   return(Func_lbl_17(state,nmain,nslack,m,i,j,b,v,vv));
  }
//+------------------------------------------------------------------+
//| Auxiliary function for MinBLEICIteration. Is a product to get rid|
//| of the operator unconditional jump goto.                         |
//+------------------------------------------------------------------+
static bool CMinBLEIC::Func_lbl_16(CMinBLEICState &state,int &nmain,
                                   int &nslack,int &m,int &i,int &j,
                                   bool &b,double &v,double &vv)
  {
//--- We've stopped,fill debug information
   state.m_repdebugeqerr=0.0;
   for(i=0;i<=state.m_cecnt-1;i++)
     {
      //--- change value
      v=0.0;
      for(int i_=0;i_<=nmain+nslack-1;i_++)
         v+=state.m_ceeffective[i][i_]*state.m_xcur[i_];
      state.m_repdebugeqerr=state.m_repdebugeqerr+CMath::Sqr(v-state.m_ceeffective[i][nmain+nslack]);
     }
//--- change values
   state.m_repdebugeqerr=MathSqrt(state.m_repdebugeqerr);
   state.m_repdebugdx=0;
   for(i=0;i<=nmain-1;i++)
      state.m_repdebugdx=state.m_repdebugdx+CMath::Sqr(state.m_xcur[i]-state.m_xstart[i]);
   state.m_repdebugdx=MathSqrt(state.m_repdebugdx);
//--- return result
   return(false);
  }
//+------------------------------------------------------------------+
//| Auxiliary function for MinBLEICIteration. Is a product to get rid|
//| of the operator unconditional jump goto.                         |
//+------------------------------------------------------------------+
static bool CMinBLEIC::Func_lbl_17(CMinBLEICState &state,int &nmain,
                                   int &nslack,int &m,int &i,int &j,
                                   bool &b,double &v,double &vv)
  {
//--- check
   if(!CMinCG::MinCGIteration(state.m_cgstate))
      return(Func_lbl_18(state,nmain,nslack,m,i,j,b,v,vv));
//--- process different requests/reports of inner optimizer
   if(state.m_cgstate.m_algpowerup)
     {
      for(i=0;i<=nmain+nslack-1;i++)
         state.m_activeconstraints[i]=false;
      //--- cycle
      do
        {
         //--- function call
         RebuildCEXE(state);
         for(int i_=0;i_<=nmain+nslack-1;i_++)
            state.m_tmp1[i_]=state.m_cgstate.m_g[i_];
         //--- function call
         MakeGradientProjection(state,state.m_tmp1);
         b=false;
         for(i=0;i<=nmain-1;i++)
           {
            //--- check
            if(!state.m_activeconstraints[i])
              {
               //--- check
               if(state.m_hasbndl[i])
                 {
                  //--- check
                  if(state.m_cgstate.m_x[i]==state.m_bndleffective[i] && state.m_tmp1[i]>=0.0)
                    {
                     //--- change values
                     state.m_activeconstraints[i]=true;
                     state.m_constrainedvalues[i]=state.m_bndleffective[i];
                     b=true;
                    }
                 }
               //--- check
               if(state.m_hasbndu[i])
                 {
                  //--- check
                  if(state.m_cgstate.m_x[i]==state.m_bndueffective[i] && state.m_tmp1[i]<=0.0)
                    {
                     //--- change values
                     state.m_activeconstraints[i]=true;
                     state.m_constrainedvalues[i]=state.m_bndueffective[i];
                     b=true;
                    }
                 }
              }
           }
         for(i=0;i<=nslack-1;i++)
           {
            //--- check
            if(!state.m_activeconstraints[nmain+i])
              {
               //--- check
               if(state.m_cgstate.m_x[nmain+i]==0.0 && state.m_tmp1[nmain+i]>=0.0)
                 {
                  //--- change values
                  state.m_activeconstraints[nmain+i]=true;
                  state.m_constrainedvalues[nmain+i]=0;
                  b=true;
                 }
              }
           }
        }
      while(b);
      //--- copy
      for(int i_=0;i_<=nmain+nslack-1;i_++)
         state.m_cgstate.m_g[i_]=state.m_tmp1[i_];
      //--- function call, return result
      return(Func_lbl_17(state,nmain,nslack,m,i,j,b,v,vv));
     }
//--- check
   if(state.m_cgstate.m_lsstart)
     {
      //--- Beginning of the line search: set upper limit on step size
      //--- to prevent algo from leaving feasible area.
      state.m_variabletofreeze=-1;
      //--- check
      if((double)(state.m_cgstate.m_curstpmax)==0.0)
         state.m_cgstate.m_curstpmax=1.0E50;
      for(i=0;i<=nmain-1;i++)
        {
         //--- check
         if(state.m_hasbndl[i] && state.m_cgstate.m_d[i]<0.0)
           {
            //--- change values
            v=state.m_cgstate.m_curstpmax;
            vv=state.m_cgstate.m_x[i]-state.m_bndleffective[i];
            //--- check
            if(vv<0.0)
               vv=0;
            state.m_cgstate.m_curstpmax=CApServ::SafeMinPosRV(vv,-state.m_cgstate.m_d[i],state.m_cgstate.m_curstpmax);
            //--- check
            if(state.m_cgstate.m_curstpmax<v)
              {
               state.m_variabletofreeze=i;
               state.m_valuetofreeze=state.m_bndleffective[i];
              }
           }
         //--- check
         if(state.m_hasbndu[i] && state.m_cgstate.m_d[i]>0.0)
           {
            //--- change values
            v=state.m_cgstate.m_curstpmax;
            vv=state.m_bndueffective[i]-state.m_cgstate.m_x[i];
            //--- check
            if(vv<0.0)
               vv=0;
            state.m_cgstate.m_curstpmax=CApServ::SafeMinPosRV(vv,state.m_cgstate.m_d[i],state.m_cgstate.m_curstpmax);
            //--- check
            if(state.m_cgstate.m_curstpmax<v)
              {
               state.m_variabletofreeze=i;
               state.m_valuetofreeze=state.m_bndueffective[i];
              }
           }
        }
      for(i=0;i<=nslack-1;i++)
        {
         //--- check
         if(state.m_cgstate.m_d[nmain+i]<0.0)
           {
            //--- change values
            v=state.m_cgstate.m_curstpmax;
            vv=state.m_cgstate.m_x[nmain+i];
            //--- check
            if(vv<0.0)
               vv=0;
            state.m_cgstate.m_curstpmax=CApServ::SafeMinPosRV(vv,-state.m_cgstate.m_d[nmain+i],state.m_cgstate.m_curstpmax);
            //--- check
            if(state.m_cgstate.m_curstpmax<v)
              {
               state.m_variabletofreeze=nmain+i;
               state.m_valuetofreeze=0;
              }
           }
        }
      //--- check
      if(state.m_cgstate.m_curstpmax==0.0)
        {
         //--- change values
         state.m_activeconstraints[state.m_variabletofreeze]=true;
         state.m_constrainedvalues[state.m_variabletofreeze]=state.m_valuetofreeze;
         state.m_cgstate.m_x[state.m_variabletofreeze]=state.m_valuetofreeze;
         state.m_cgstate.m_terminationneeded=true;
        }
      //--- function call, return result
      return(Func_lbl_17(state,nmain,nslack,m,i,j,b,v,vv));
     }
//--- check
   if(state.m_cgstate.m_lsend)
     {
      //--- Line search just finished.
      //--- Maybe we should activate some constraints?
      b=state.m_cgstate.m_stp>=state.m_cgstate.m_curstpmax && state.m_variabletofreeze>=0;
      //--- check
      if(b)
        {
         state.m_activeconstraints[state.m_variabletofreeze]=true;
         state.m_constrainedvalues[state.m_variabletofreeze]=state.m_valuetofreeze;
        }
      //--- Additional activation of constraints
      b=b || AdditionalCheckForConstraints(state,state.m_cgstate.m_x);
      //--- If at least one constraint was activated we have to rebuild constraint matrices
      if(b)
        {
         //--- copy
         for(int i_=0;i_<=nmain+nslack-1;i_++)
            state.m_tmp0[i_]=state.m_cgstate.m_x[i_];
         for(int i_=0;i_<=nmain+nslack-1;i_++)
            state.m_tmp1[i_]=state.m_lastg[i_];
         //--- check
         if(!PrepareConstraintMatrix(state,state.m_tmp0,state.m_tmp1,state.m_cgstate.m_x,state.m_cgstate.m_g))
           {
            state.m_repterminationtype=-3;
            //--- return result
            return(false);
           }
         state.m_cgstate.m_innerresetneeded=true;
        }
      //--- function call, return result
      return(Func_lbl_17(state,nmain,nslack,m,i,j,b,v,vv));
     }
//--- check
   if(!state.m_cgstate.m_needfg)
      return(Func_lbl_19(state,nmain,nslack,m,i,j,b,v,vv));
//--- copy
   for(int i_=0;i_<=nmain+nslack-1;i_++)
      state.m_tmp1[i_]=state.m_cgstate.m_x[i_];
//--- function call
   ProjectPointAndUnscale(state,state.m_tmp1,state.m_x,state.m_r,vv);
//--- function call
   ClearRequestFields(state);
//--- check
   if(state.m_diffstep!=0.0)
     {
      //--- change values
      state.m_needf=true;
      state.m_rstate.stage=3;
      //--- Saving state
      Func_lbl_rcomm(state,nmain,nslack,m,i,j,b,v,vv);
      //--- return result
      return(true);
     }
//--- change values
   state.m_needfg=true;
   state.m_rstate.stage=2;
//--- Saving state
   Func_lbl_rcomm(state,nmain,nslack,m,i,j,b,v,vv);
//--- return result
   return(true);
  }
//+------------------------------------------------------------------+
//| Auxiliary function for MinBLEICIteration. Is a product to get rid|
//| of the operator unconditional jump goto.                         |
//+------------------------------------------------------------------+
static bool CMinBLEIC::Func_lbl_18(CMinBLEICState &state,int &nmain,
                                   int &nslack,int &m,int &i,int &j,
                                   bool &b,double &v,double &vv)
  {
//--- function call
   CMinCG::MinCGResults(state.m_cgstate,state.m_xcur,state.m_cgrep);
//--- function call
   UnscalePoint(state,state.m_xcur,state.m_xend);
//--- change values
   state.m_repinneriterationscount=state.m_repinneriterationscount+state.m_cgrep.m_iterationscount;
   state.m_repouteriterationscount=state.m_repouteriterationscount+1;
   state.m_repnfev=state.m_repnfev+state.m_cgrep.m_nfev;
//--- Update RepDebugFF with function value at current point
   UnscalePoint(state,state.m_xcur,state.m_x);
   ClearRequestFields(state);
//--- check
   if(state.m_diffstep!=0.0)
     {
      //--- change values
      state.m_needf=true;
      state.m_rstate.stage=12;
      //--- Saving state
      Func_lbl_rcomm(state,nmain,nslack,m,i,j,b,v,vv);
      //--- return result
      return(true);
     }
//--- change values
   state.m_needfg=true;
   state.m_rstate.stage=11;
//--- Saving state
   Func_lbl_rcomm(state,nmain,nslack,m,i,j,b,v,vv);
//--- return result
   return(true);
  }
//+------------------------------------------------------------------+
//| Auxiliary function for MinBLEICIteration. Is a product to get rid|
//| of the operator unconditional jump goto.                         |
//+------------------------------------------------------------------+
static bool CMinBLEIC::Func_lbl_19(CMinBLEICState &state,int &nmain,
                                   int &nslack,int &m,int &i,int &j,
                                   bool &b,double &v,double &vv)
  {
//--- check
   if(!state.m_cgstate.m_xupdated)
      return(Func_lbl_17(state,nmain,nslack,m,i,j,b,v,vv));
//--- Report
   UnscalePoint(state,state.m_cgstate.m_x,state.m_x);
   state.m_f=state.m_cgstate.m_f;
//--- function call
   ClearRequestFields(state);
//--- change values
   state.m_xupdated=true;
   state.m_rstate.stage=10;
//--- Saving state
   Func_lbl_rcomm(state,nmain,nslack,m,i,j,b,v,vv);
//--- return result
   return(true);
  }
//+------------------------------------------------------------------+
//| Auxiliary function for MinBLEICIteration. Is a product to get rid|
//| of the operator unconditional jump goto.                         |
//+------------------------------------------------------------------+
static bool CMinBLEIC::Func_lbl_22(CMinBLEICState &state,int &nmain,
                                   int &nslack,int &m,int &i,int &j,
                                   bool &b,double &v,double &vv)
  {
//--- check
   if(state.m_f<state.m_trimthreshold)
     {
      //--- normal processing
      state.m_cgstate.m_f=state.m_f;
      //--- function call
      ScaleGradientAndExpand(state,state.m_g,state.m_cgstate.m_g);
      //--- copy
      for(int i_=0;i_<=nmain+nslack-1;i_++)
         state.m_lastg[i_]=state.m_cgstate.m_g[i_];
      //--- function call
      ModifyTargetFunction(state,state.m_tmp1,state.m_r,vv,state.m_cgstate.m_f,state.m_cgstate.m_g,state.m_gnorm,state.m_mpgnorm);
     }
   else
     {
      //--- function value is too high,trim it
      state.m_cgstate.m_f=state.m_trimthreshold;
      for(i=0;i<=nmain+nslack-1;i++)
         state.m_cgstate.m_g[i]=0.0;
     }
//--- function call, return result
   return(Func_lbl_17(state,nmain,nslack,m,i,j,b,v,vv));
  }
//+------------------------------------------------------------------+
//| Auxiliary function for MinBLEICIteration. Is a product to get rid|
//| of the operator unconditional jump goto.                         |
//+------------------------------------------------------------------+
static bool CMinBLEIC::Func_lbl_23(CMinBLEICState &state,int &nmain,
                                   int &nslack,int &m,int &i,int &j,
                                   bool &b,double &v,double &vv)
  {
//--- check
   if(i>nmain-1)
     {
      //--- change values
      state.m_f=state.m_fbase;
      state.m_needf=false;
      //--- function call, return result
      return(Func_lbl_22(state,nmain,nslack,m,i,j,b,v,vv));
     }
//--- change values
   v=state.m_x[i];
   b=false;
//--- check
   if(state.m_hasbndl[i])
      b=b || v-state.m_diffstep*state.m_soriginal[i]<state.m_bndloriginal[i];
//--- check
   if(state.m_hasbndu[i])
      b=b || v+state.m_diffstep*state.m_soriginal[i]>state.m_bnduoriginal[i];
//--- check
   if(b)
     {
      //--- change values
      state.m_xm1=MathMax(v-state.m_diffstep*state.m_soriginal[i],state.m_bndloriginal[i]);
      state.m_x[i]=state.m_xm1;
      state.m_rstate.stage=8;
      //--- Saving state
      Func_lbl_rcomm(state,nmain,nslack,m,i,j,b,v,vv);
      //--- return result
      return(true);
     }
//--- change values
   state.m_x[i]=v-state.m_diffstep*state.m_soriginal[i];
   state.m_rstate.stage=4;
//--- Saving state
   Func_lbl_rcomm(state,nmain,nslack,m,i,j,b,v,vv);
//--- return result
   return(true);
  }
//+------------------------------------------------------------------+
//| Auxiliary function for MinBLEICIteration. Is a product to get rid|
//| of the operator unconditional jump goto.                         |
//+------------------------------------------------------------------+
static bool CMinBLEIC::Func_lbl_31(CMinBLEICState &state,int &nmain,
                                   int &nslack,int &m,int &i,int &j,
                                   bool &b,double &v,double &vv)
  {
//--- change values
   state.m_repnfev=state.m_repnfev+1;
   state.m_repdebugff=state.m_f;
//--- Check for stopping:
//--- * "normal",outer step size is small enough,infeasibility is within bounds
//--- * "inconsistent", if Lagrange multipliers increased beyond threshold given by MaxLagrangeMul
//--- * "too stringent",in other cases
   v=0;
   for(i=0;i<=nmain-1;i++)
      v=v+CMath::Sqr((state.m_xcur[i]-state.m_xprev[i])/state.m_seffective[i]);
   v=MathSqrt(v);
//--- check
   if(v<=(double)(state.m_outerepsx))
     {
      state.m_repterminationtype=4;
      //--- function call, return result
      return(Func_lbl_16(state,nmain,nslack,m,i,j,b,v,vv));
     }
//--- check
   if(state.m_maxits>0)
     {
      state.m_itsleft=state.m_itsleft-state.m_cgrep.m_iterationscount;
      //--- check
      if(state.m_itsleft<=0)
        {
         state.m_repterminationtype=5;
         //--- function call, return result
         return(Func_lbl_16(state,nmain,nslack,m,i,j,b,v,vv));
        }
     }
//--- check
   if(state.m_repouteriterationscount>=m_maxouterits)
     {
      state.m_repterminationtype=5;
      //--- function call, return result
      return(Func_lbl_16(state,nmain,nslack,m,i,j,b,v,vv));
     }
//--- Next iteration
   for(int i_=0;i_<=nmain+nslack-1;i_++)
      state.m_xprev[i_]=state.m_xcur[i_];
//--- function call, return result
   return(Func_lbl_15(state,nmain,nslack,m,i,j,b,v,vv));
  }
//+------------------------------------------------------------------+
//| Auxiliary class for CMinLBFGS                                    |
//+------------------------------------------------------------------+
class CMinLBFGSState
  {
public:
   //--- variables
   int               m_n;
   int               m_m;
   double            m_epsg;
   double            m_epsf;
   double            m_epsx;
   int               m_maxits;
   bool              m_xrep;
   double            m_stpmax;
   double            m_diffstep;
   int               m_nfev;
   int               m_mcstage;
   int               m_k;
   int               m_q;
   int               m_p;
   double            m_stp;
   double            m_fold;
   double            m_trimthreshold;
   int               m_prectype;
   double            m_gammak;
   double            m_fbase;
   double            m_fm2;
   double            m_fm1;
   double            m_fp1;
   double            m_fp2;
   double            m_f;
   bool              m_needf;
   bool              m_needfg;
   bool              m_xupdated;
   RCommState        m_rstate;
   int               m_repiterationscount;
   int               m_repnfev;
   int               m_repterminationtype;
   CLinMinState      m_lstate;
   //--- arrays
   double            m_s[];
   double            m_rho[];
   double            m_theta[];
   double            m_d[];
   double            m_work[];
   double            m_diagh[];
   double            m_autobuf[];
   double            m_x[];
   double            m_g[];
   //--- matrix
   CMatrixDouble     m_yk;
   CMatrixDouble     m_sk;
   CMatrixDouble     m_denseh;
   //--- constructor, destructor
                     CMinLBFGSState(void);
                    ~CMinLBFGSState(void);
   //--- copy
   void              Copy(CMinLBFGSState &obj);
  };
//+------------------------------------------------------------------+
//| Constructor without parameters                                   |
//+------------------------------------------------------------------+
CMinLBFGSState::CMinLBFGSState(void)
  {

  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CMinLBFGSState::~CMinLBFGSState(void)
  {

  }
//+------------------------------------------------------------------+
//| Copy                                                             |
//+------------------------------------------------------------------+
void CMinLBFGSState::Copy(CMinLBFGSState &obj)
  {
//--- copy variables
   m_n=obj.m_n;
   m_m=obj.m_m;
   m_epsg=obj.m_epsg;
   m_epsf=obj.m_epsf;
   m_epsx=obj.m_epsx;
   m_maxits=obj.m_maxits;
   m_xrep=obj.m_xrep;
   m_stpmax=obj.m_stpmax;
   m_diffstep=obj.m_diffstep;
   m_nfev=obj.m_nfev;
   m_mcstage=obj.m_mcstage;
   m_k=obj.m_k;
   m_q=obj.m_q;
   m_p=obj.m_p;
   m_stp=obj.m_stp;
   m_fold=obj.m_fold;
   m_trimthreshold=obj.m_trimthreshold;
   m_prectype=obj.m_prectype;
   m_gammak=obj.m_gammak;
   m_fbase=obj.m_fbase;
   m_fm2=obj.m_fm2;
   m_fm1=obj.m_fm1;
   m_fp1=obj.m_fp1;
   m_fp2=obj.m_fp2;
   m_f=obj.m_f;
   m_needf=obj.m_needf;
   m_needfg=obj.m_needfg;
   m_xupdated=obj.m_xupdated;
   m_repiterationscount=obj.m_repiterationscount;
   m_repnfev=obj.m_repnfev;
   m_repterminationtype=obj.m_repterminationtype;
   m_rstate.Copy(obj.m_rstate);
   m_lstate.Copy(obj.m_lstate);
//--- copy arrays
   ArrayCopy(m_s,obj.m_s);
   ArrayCopy(m_rho,obj.m_rho);
   ArrayCopy(m_theta,obj.m_theta);
   ArrayCopy(m_d,obj.m_d);
   ArrayCopy(m_work,obj.m_work);
   ArrayCopy(m_diagh,obj.m_diagh);
   ArrayCopy(m_autobuf,obj.m_autobuf);
   ArrayCopy(m_x,obj.m_x);
   ArrayCopy(m_g,obj.m_g);
//--- copy matrix
   m_yk=obj.m_yk;
   m_sk=obj.m_sk;
   m_denseh=obj.m_denseh;
  }
//+------------------------------------------------------------------+
//| This class is a shell for class CMinLBFGSState                   |
//+------------------------------------------------------------------+
class CMinLBFGSStateShell
  {
private:
   CMinLBFGSState    m_innerobj;
public:
   //--- constructors, destructor
                     CMinLBFGSStateShell(void);
                     CMinLBFGSStateShell(CMinLBFGSState &obj);
                    ~CMinLBFGSStateShell(void);
   //--- methods
   bool              GetNeedF(void);
   void              SetNeedF(const bool b);
   bool              GetNeedFG(void);
   void              SetNeedFG(const bool b);
   bool              GetXUpdated(void);
   void              SetXUpdated(const bool b);
   double            GetF(void);
   void              SetF(const double d);
   CMinLBFGSState   *GetInnerObj(void);
  };
//+------------------------------------------------------------------+
//| Constructor without parameters                                   |
//+------------------------------------------------------------------+
CMinLBFGSStateShell::CMinLBFGSStateShell(void)
  {

  }
//+------------------------------------------------------------------+
//| Copy constructor                                                 |
//+------------------------------------------------------------------+
CMinLBFGSStateShell::CMinLBFGSStateShell(CMinLBFGSState &obj)
  {
//--- copy
   m_innerobj.Copy(obj);
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CMinLBFGSStateShell::~CMinLBFGSStateShell(void)
  {

  }
//+------------------------------------------------------------------+
//| Returns the value of the variable needf                          |
//+------------------------------------------------------------------+
bool CMinLBFGSStateShell::GetNeedF(void)
  {
//--- return result
   return(m_innerobj.m_needf);
  }
//+------------------------------------------------------------------+
//| Changing the value of the variable needf                         |
//+------------------------------------------------------------------+
void CMinLBFGSStateShell::SetNeedF(const bool b)
  {
//--- change value
   m_innerobj.m_needf=b;
  }
//+------------------------------------------------------------------+
//| Returns the value of the variable needfg                         |
//+------------------------------------------------------------------+
bool CMinLBFGSStateShell::GetNeedFG(void)
  {
//--- return result
   return(m_innerobj.m_needfg);
  }
//+------------------------------------------------------------------+
//| Changing the value of the variable needfg                        |
//+------------------------------------------------------------------+
void CMinLBFGSStateShell::SetNeedFG(const bool b)
  {
//--- change value
   m_innerobj.m_needfg=b;
  }
//+------------------------------------------------------------------+
//| Returns the value of the variable xupdated                       |
//+------------------------------------------------------------------+
bool CMinLBFGSStateShell::GetXUpdated(void)
  {
//--- return result
   return(m_innerobj.m_xupdated);
  }
//+------------------------------------------------------------------+
//| Changing the value of the variable xupdated                      |
//+------------------------------------------------------------------+
void CMinLBFGSStateShell::SetXUpdated(const bool b)
  {
//--- change value
   m_innerobj.m_xupdated=b;
  }
//+------------------------------------------------------------------+
//| Returns the value of the variable f                              |
//+------------------------------------------------------------------+
double CMinLBFGSStateShell::GetF(void)
  {
//--- return result
   return(m_innerobj.m_f);
  }
//+------------------------------------------------------------------+
//| Changing the value of the variable f                             |
//+------------------------------------------------------------------+
void CMinLBFGSStateShell::SetF(const double d)
  {
//--- change value
   m_innerobj.m_f=d;
  }
//+------------------------------------------------------------------+
//| Return object of class                                           |
//+------------------------------------------------------------------+
CMinLBFGSState *CMinLBFGSStateShell::GetInnerObj(void)
  {
//--- return result
   return(GetPointer(m_innerobj));
  }
//+------------------------------------------------------------------+
//| Auxiliary class for CMinLFBFGS                                   |
//+------------------------------------------------------------------+
class CMinLBFGSReport
  {
public:
   //--- variables
   int               m_iterationscount;
   int               m_nfev;
   int               m_terminationtype;
   //--- constructor, destructor
                     CMinLBFGSReport(void);
                    ~CMinLBFGSReport(void);
   //--- copy
   void              Copy(CMinLBFGSReport &obj);
  };
//+------------------------------------------------------------------+
//| Constructor without parameters                                   |
//+------------------------------------------------------------------+
CMinLBFGSReport::CMinLBFGSReport(void)
  {

  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CMinLBFGSReport::~CMinLBFGSReport(void)
  {

  }
//+------------------------------------------------------------------+
//| Copy                                                             |
//+------------------------------------------------------------------+
void CMinLBFGSReport::Copy(CMinLBFGSReport &obj)
  {
//--- copy variables
   m_iterationscount=obj.m_iterationscount;
   m_nfev=obj.m_nfev;
   m_terminationtype=obj.m_terminationtype;
  }
//+------------------------------------------------------------------+
//| This class is a shell for class CMinLBFGSReport                  |
//+------------------------------------------------------------------+
class CMinLBFGSReportShell
  {
private:
   CMinLBFGSReport   m_innerobj;
public:
   //--- constructors, destructor
                     CMinLBFGSReportShell(void);
                     CMinLBFGSReportShell(CMinLBFGSReport &obj);
                    ~CMinLBFGSReportShell(void);
   //--- methods
   int               GetIterationsCount(void);
   void              SetIterationsCount(const int i);
   int               GetNFev(void);
   void              SetNFev(const int i);
   int               GetTerminationType(void);
   void              SetTerminationType(const int i);
   CMinLBFGSReport *GetInnerObj(void);
  };
//+------------------------------------------------------------------+
//| Constructor without parameters                                   |
//+------------------------------------------------------------------+
CMinLBFGSReportShell::CMinLBFGSReportShell(void)
  {

  }
//+------------------------------------------------------------------+
//| Copy constructor                                                 |
//+------------------------------------------------------------------+
CMinLBFGSReportShell::CMinLBFGSReportShell(CMinLBFGSReport &obj)
  {
//--- copy
   m_innerobj.Copy(obj);
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CMinLBFGSReportShell::~CMinLBFGSReportShell(void)
  {

  }
//+------------------------------------------------------------------+
//| Returns the value of the variable iterationscount                |
//+------------------------------------------------------------------+
int CMinLBFGSReportShell::GetIterationsCount(void)
  {
//--- return result
   return(m_innerobj.m_iterationscount);
  }
//+------------------------------------------------------------------+
//| Changing the value of the variable iterationscount               |
//+------------------------------------------------------------------+
void CMinLBFGSReportShell::SetIterationsCount(const int i)
  {
//--- change value
   m_innerobj.m_iterationscount=i;
  }
//+------------------------------------------------------------------+
//| Returns the value of the variable nfev                           |
//+------------------------------------------------------------------+
int CMinLBFGSReportShell::GetNFev(void)
  {
//--- return result
   return(m_innerobj.m_nfev);
  }
//+------------------------------------------------------------------+
//| Changing the value of the variable nfev                          |
//+------------------------------------------------------------------+
void CMinLBFGSReportShell::SetNFev(const int i)
  {
//--- change value
   m_innerobj.m_nfev=i;
  }
//+------------------------------------------------------------------+
//| Returns the value of the variable terminationtype                |
//+------------------------------------------------------------------+
int CMinLBFGSReportShell::GetTerminationType(void)
  {
//--- return result
   return(m_innerobj.m_terminationtype);
  }
//+------------------------------------------------------------------+
//| Changing the value of the variable terminationtype               |
//+------------------------------------------------------------------+
void CMinLBFGSReportShell::SetTerminationType(const int i)
  {
//--- change value
   m_innerobj.m_terminationtype=i;
  }
//+------------------------------------------------------------------+
//| Return object of class                                           |
//+------------------------------------------------------------------+
CMinLBFGSReport *CMinLBFGSReportShell::GetInnerObj(void)
  {
//--- return result
   return(GetPointer(m_innerobj));
  }
//+------------------------------------------------------------------+
//| Limited memory BFGS method for large scale optimization          |
//+------------------------------------------------------------------+
class CMinLBFGS
  {
private:
   //--- private method
   static void       ClearRequestFields(CMinLBFGSState &state);
   //--- auxiliary functions for MinLBFGSiteration
   static void       Func_lbl_rcomm(CMinLBFGSState &state,int n,int m,int i,int j,int ic,int mcinfo,double v,double vv);
   static bool       Func_lbl_16(CMinLBFGSState &state,int &n,int &m,int &i,int &j,int &ic,int &mcinfo,double &v,double &vv);
   static bool       Func_lbl_19(CMinLBFGSState &state,int &n,int &m,int &i,int &j,int &ic,int &mcinfo,double &v,double &vv);
   static bool       Func_lbl_21(CMinLBFGSState &state,int &n,int &m,int &i,int &j,int &ic,int &mcinfo,double &v,double &vv);
   static bool       Func_lbl_23(CMinLBFGSState &state,int &n,int &m,int &i,int &j,int &ic,int &mcinfo,double &v,double &vv);
   static bool       Func_lbl_27(CMinLBFGSState &state,int &n,int &m,int &i,int &j,int &ic,int &mcinfo,double &v,double &vv);
   static bool       Func_lbl_30(CMinLBFGSState &state,int &n,int &m,int &i,int &j,int &ic,int &mcinfo,double &v,double &vv);
public:
   //--- constant
   static const double m_gtol;
   //--- constructor, destructor
                     CMinLBFGS(void);
                    ~CMinLBFGS(void);
   //--- public methods
   static void       MinLBFGSCreate(const int n,const int m,double &x[],CMinLBFGSState &state);
   static void       MinLBFGSCreateF(const int n,const int m,double &x[],const double diffstep,CMinLBFGSState &state);
   static void       MinLBFGSSetCond(CMinLBFGSState &state,const double epsg,const double epsf,double epsx,const int maxits);
   static void       MinLBFGSSetXRep(CMinLBFGSState &state,const bool needxrep);
   static void       MinLBFGSSetStpMax(CMinLBFGSState &state,const double stpmax);
   static void       MinLBFGSSetScale(CMinLBFGSState &state,double &s[]);
   static void       MinLBFGSCreateX(const int n,const int m,double &x[],int flags,const double diffstep,CMinLBFGSState &state);
   static void       MinLBFGSSetPrecDefault(CMinLBFGSState &state);
   static void       MinLBFGSSetPrecCholesky(CMinLBFGSState &state,CMatrixDouble &p,const bool isupper);
   static void       MinLBFGSSetPrecDiag(CMinLBFGSState &state,double &d[]);
   static void       MinLBFGSSetPrecScale(CMinLBFGSState &state);
   static void       MinLBFGSResults(CMinLBFGSState &state,double &x[],CMinLBFGSReport &rep);
   static void       MinLBFGSresultsbuf(CMinLBFGSState &state,double &x[],CMinLBFGSReport &rep);
   static void       MinLBFGSRestartFrom(CMinLBFGSState &state,double &x[]);
   static bool       MinLBFGSIteration(CMinLBFGSState &state);
  };
//+------------------------------------------------------------------+
//| Initialize constants                                             |
//+------------------------------------------------------------------+
const double CMinLBFGS::m_gtol=0.4;
//+------------------------------------------------------------------+
//| Constructor without parameters                                   |
//+------------------------------------------------------------------+
CMinLBFGS::CMinLBFGS(void)
  {

  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CMinLBFGS::~CMinLBFGS(void)
  {

  }
//+------------------------------------------------------------------+
//|         LIMITED MEMORY BFGS METHOD FOR LARGE SCALE OPTIMIZATION  |
//| DESCRIPTION:                                                     |
//| The subroutine minimizes function F(x) of N arguments by using a |
//| quasi - Newton method (LBFGS scheme) which is optimized to use a |
//| minimum  amount of memory.                                       |
//| The subroutine generates the approximation of an inverse Hessian |
//| matrix by using information about the last M steps of the        |
//| algorithm (instead of N). It lessens a required amount of memory |
//| from a value of order N^2 to a value of order 2*N*M.             |
//| REQUIREMENTS:                                                    |
//| Algorithm will request following information during its          |
//| operation:                                                       |
//| * function value F and its gradient G (simultaneously) at given  |
//| point X                                                          |
//| USAGE:                                                           |
//| 1. User initializes algorithm state with MinLBFGSCreate() call   |
//| 2. User tunes solver parameters with MinLBFGSSetCond()           |
//|    MinLBFGSSetStpMax() and other functions                       |
//| 3. User calls MinLBFGSOptimize() function which takes algorithm  |
//|    state and pointer (delegate, etc.) to callback function which |
//|    calculates F/G.                                               |
//| 4. User calls MinLBFGSResults() to get solution                  |
//| 5. Optionally user may call MinLBFGSRestartFrom() to solve       |
//|    another problem with same N/M but another starting point      |
//|    and/or another function. MinLBFGSRestartFrom() allows to reuse|
//|    already initialized structure.                                |
//| INPUT PARAMETERS:                                                |
//|     N       -   problem dimension. N>0                           |
//|     M       -   number of corrections in the BFGS scheme of      |
//|                 Hessian approximation update. Recommended value: |
//|                 3<=M<=7. The smaller value causes worse          |
//|                 convergence, the bigger will not cause a         |
//|                 considerably better convergence, but will cause  |
//|                 a fall in  the performance. M<=N.                |
//|     X       -   initial solution approximation, array[0..N-1].   |
//| OUTPUT PARAMETERS:                                               |
//|     State   -   structure which stores algorithm state           |
//| NOTES:                                                           |
//| 1. you may tune stopping conditions with MinLBFGSSetCond()       |
//|    function                                                      |
//| 2. if target function contains exp() or other fast growing       |
//|    functions, and optimization algorithm makes too large steps   |
//|    which leads to overflow, use MinLBFGSSetStpMax() function to  |
//|    bound algorithm's steps. However, L-BFGS rarely needs such a  |
//|    tuning.                                                       |
//+------------------------------------------------------------------+
static void CMinLBFGS::MinLBFGSCreate(const int n,const int m,double &x[],
                                      CMinLBFGSState &state)
  {
//--- check
   if(!CAp::Assert(n>=1,__FUNCTION__+": N<1!"))
      return;
//--- check
   if(!CAp::Assert(m>=1,__FUNCTION__+": M<1"))
      return;
//--- check
   if(!CAp::Assert(m<=n,__FUNCTION__+": M>N"))
      return;
//--- check
   if(!CAp::Assert(CAp::Len(x)>=n,__FUNCTION__+": Length(X)<N!"))
      return;
//--- check
   if(!CAp::Assert(CApServ::IsFiniteVector(x,n),__FUNCTION__+": X contains infinite or NaN values!"))
      return;
//--- function call
   MinLBFGSCreateX(n,m,x,0,0.0,state);
  }
//+------------------------------------------------------------------+
//| The subroutine is finite difference variant of MinLBFGSCreate(). |
//| It uses finite differences in order to differentiate target      |
//| function.                                                        |
//| Description below contains information which is specific to this |
//| function only. We recommend to read comments on MinLBFGSCreate() |
//| in order to get more information about creation of LBFGS         |
//| optimizer.                                                       |
//| INPUT PARAMETERS:                                                |
//|     N       -   problem dimension, N>0:                          |
//|                 * if given, only leading N elements of X are used|
//|                 * if not given, automatically determined from    |
//|                   size of X                                      |
//|     M       -   number of corrections in the BFGS scheme of      |
//|                 Hessian approximation update. Recommended value: |
//|                 3<=M<=7. The smaller value causes worse          |
//|                 convergence, the bigger will not cause a         |
//|                 considerably better convergence, but will cause a|
//|                 fall in  the performance. M<=N.                  |
//|     X       -   starting point, array[0..N-1].                   |
//|     DiffStep-   differentiation step, >0                         |
//| OUTPUT PARAMETERS:                                               |
//|     State   -   structure which stores algorithm state           |
//| NOTES:                                                           |
//| 1. algorithm uses 4-point central formula for differentiation.   |
//| 2. differentiation step along I-th axis is equal to DiffStep*S[I]|
//|    where S[] is scaling vector which can be set by               |
//|    MinLBFGSSetScale() call.                                      |
//| 3. we recommend you to use moderate values of differentiation    |
//|    step. Too large step will result in too large truncation      |
//|    errors, while too small step will result in too large         |
//|    numerical errors. 1.0E-6 can be good value to start with.     |
//| 4. Numerical differentiation is very inefficient - one gradient  |
//|    calculation needs 4*N function evaluations. This function will|
//|    work for any N - either small (1...10), moderate (10...100) or|
//|    large (100...). However, performance penalty will be too      |
//|    severe for any N's except for small ones.                     |
//|    We should also say that code which relies on numerical        |
//|    differentiation is less robust and precise. LBFGS needs exact |
//|    gradient values. Imprecise gradient may slow down convergence,|
//|    especially on highly nonlinear problems.                      |
//|    Thus we recommend to use this function for fast prototyping on|
//|    small- dimensional problems only, and to implement analytical |
//|    gradient as soon as possible.                                 |
//+------------------------------------------------------------------+
static void CMinLBFGS::MinLBFGSCreateF(const int n,const int m,double &x[],
                                       const double diffstep,CMinLBFGSState &state)
  {
//--- check
   if(!CAp::Assert(n>=1,__FUNCTION__+": N too small!"))
      return;
//--- check
   if(!CAp::Assert(m>=1,__FUNCTION__+": M<1"))
      return;
//--- check
   if(!CAp::Assert(m<=n,__FUNCTION__+": M>N"))
      return;
//--- check
   if(!CAp::Assert(CAp::Len(x)>=n,__FUNCTION__+": Length(X)<N!"))
      return;
//--- check
   if(!CAp::Assert(CApServ::IsFiniteVector(x,n),__FUNCTION__+": X contains infinite or NaN values!"))
      return;
//--- check
   if(!CAp::Assert(CMath::IsFinite(diffstep),__FUNCTION__+": DiffStep is infinite or NaN!"))
      return;
//--- check
   if(!CAp::Assert(diffstep>0.0,__FUNCTION__+": DiffStep is non-positive!"))
      return;
//--- function call
   MinLBFGSCreateX(n,m,x,0,diffstep,state);
  }
//+------------------------------------------------------------------+
//| This function sets stopping conditions for L-BFGS optimization   |
//| algorithm.                                                       |
//| INPUT PARAMETERS:                                                |
//|     State   -   structure which stores algorithm state           |
//|     EpsG    -   >=0                                              |
//|                 The subroutine finishes its work if the condition|
//|                 |v|<EpsG is satisfied, where:                    |
//|                 * |.| means Euclidian norm                       |
//|                 * v - scaled gradient vector, v[i]=g[i]*s[i]     |
//|                 * g - gradient                                   |
//|                 * s - scaling coefficients set by                |
//|                       MinLBFGSSetScale()                         |
//|     EpsF    -   >=0                                              |
//|                 The subroutine finishes its work if on k+1-th    |
//|                 iteration the condition |F(k+1)-F(k)| <=         |
//|                 <= EpsF*max{|F(k)|,|F(k+1)|,1} is satisfied.     |
//|     EpsX    -   >=0                                              |
//|                 The subroutine finishes its work if on k+1-th    |
//|                 iteration the condition |v|<=EpsX is fulfilled,  |
//|                 where:                                           |
//|                 * |.| means Euclidian norm                       |
//|                 * v - scaled step vector, v[i]=dx[i]/s[i]        |
//|                 * dx - ste pvector, dx=X(k+1)-X(k)               |
//|                 * s - scaling coefficients set by                |
//|                   MinLBFGSSetScale()                             |
//|     MaxIts  -   maximum number of iterations. If MaxIts=0, the   |
//|                 number of iterations is unlimited.               |
//| Passing EpsG=0, EpsF=0, EpsX=0 and MaxIts=0 (simultaneously) will|
//| lead to automatic stopping criterion selection (small EpsX).     |
//+------------------------------------------------------------------+
static void CMinLBFGS::MinLBFGSSetCond(CMinLBFGSState &state,const double epsg,
                                       const double epsf,double epsx,
                                       const int maxits)
  {
//--- check
   if(!CAp::Assert(CMath::IsFinite(epsg),__FUNCTION__+": EpsG is not finite number!"))
      return;
//--- check
   if(!CAp::Assert(epsg>=0.0,__FUNCTION__+": negative EpsG!"))
      return;
//--- check
   if(!CAp::Assert(CMath::IsFinite(epsf),__FUNCTION__+": EpsF is not finite number!"))
      return;
//--- check
   if(!CAp::Assert(epsf>=0.0,__FUNCTION__+": negative EpsF!"))
      return;
//--- check
   if(!CAp::Assert(CMath::IsFinite(epsx),__FUNCTION__+": EpsX is not finite number!"))
      return;
//--- check
   if(!CAp::Assert(epsx>=0.0,__FUNCTION__+": negative EpsX!"))
      return;
//--- check
   if(!CAp::Assert(maxits>=0,__FUNCTION__+": negative MaxIts!"))
      return;
//--- check
   if(((epsg==0.0 && epsf==0.0) && epsx==0.0) && maxits==0)
      epsx=1.0E-6;
//--- change values
   state.m_epsg=epsg;
   state.m_epsf=epsf;
   state.m_epsx=epsx;
   state.m_maxits=maxits;
  }
//+------------------------------------------------------------------+
//| This function turns on/off reporting.                            |
//| INPUT PARAMETERS:                                                |
//|     State   -   structure which stores algorithm state           |
//|     NeedXRep-   whether iteration reports are needed or not      |
//| If NeedXRep is True, algorithm will call rep() callback function |
//| if it is provided to MinLBFGSOptimize().                         |
//+------------------------------------------------------------------+
static void CMinLBFGS::MinLBFGSSetXRep(CMinLBFGSState &state,const bool needxrep)
  {
//--- change value
   state.m_xrep=needxrep;
  }
//+------------------------------------------------------------------+
//| This function sets maximum step length                           |
//| INPUT PARAMETERS:                                                |
//|     State   -   structure which stores algorithm state           |
//|     StpMax  -   maximum step length, >=0. Set StpMax to 0.0      |
//|                 (default), if you don't want to limit step       |
//|                 length.                                          |
//| Use this subroutine when you optimize target function which      |
//| contains exp() or other fast growing functions, and optimization |
//| algorithm makes too large steps which leads to overflow. This    |
//| function allows us to reject steps that are too large (and       |
//| therefore expose us to the possible overflow) without actually   |
//| calculating function value at the x+stp*d.                       |
//+------------------------------------------------------------------+
static void CMinLBFGS::MinLBFGSSetStpMax(CMinLBFGSState &state,
                                         const double stpmax)
  {
//--- check
   if(!CAp::Assert(CMath::IsFinite(stpmax),__FUNCTION__+": StpMax is not finite!"))
      return;
//--- check
   if(!CAp::Assert(stpmax>=0.0,__FUNCTION__+": StpMax<0!"))
      return;
//--- change value
   state.m_stpmax=stpmax;
  }
//+------------------------------------------------------------------+
//| This function sets scaling coefficients for LBFGS optimizer.     |
//| ALGLIB optimizers use scaling matrices to test stopping          |
//| conditions (step size and gradient are scaled before comparison  |
//| with tolerances). Scale of the I-th variable is a translation    |
//| invariant measure of:                                            |
//| a) "how large" the variable is                                   |
//| b) how large the step should be to make significant changes in   |
//|    the function                                                  |
//| Scaling is also used by finite difference variant of the         |
//| optimizer - step along I-th axis is equal to DiffStep*S[I].      |
//| In most optimizers (and in the LBFGS too) scaling is NOT a form  |
//| of preconditioning. It just affects stopping conditions. You     |
//| should set preconditioner by separate call to one of the         |
//| MinLBFGSSetPrec...() functions.                                  |
//| There is special preconditioning mode, however, which uses       |
//| scaling coefficients to form diagonal preconditioning matrix.    |
//| You can turn this mode on, if you want. But  you should          |
//| understand that scaling is not the same thing as                 |
//| preconditioning - these are two different, although related      |
//| forms of tuning solver.                                          |
//| INPUT PARAMETERS:                                                |
//|     State   -   structure stores algorithm state                 |
//|     S       -   array[N], non-zero scaling coefficients          |
//|                 S[i] may be negative, sign doesn't matter.       |
//+------------------------------------------------------------------+
static void CMinLBFGS::MinLBFGSSetScale(CMinLBFGSState &state,double &s[])
  {
//--- create a variable
   int i=0;
//--- check
   if(!CAp::Assert(CAp::Len(s)>=state.m_n,__FUNCTION__+": Length(S)<N"))
      return;
   for(i=0;i<=state.m_n-1;i++)
     {
      //--- check
      if(!CAp::Assert(CMath::IsFinite(s[i]),__FUNCTION__+": S contains infinite or NAN elements"))
         return;
      //--- check
      if(!CAp::Assert(s[i]!=0.0,__FUNCTION__+": S contains zero elements"))
         return;
      state.m_s[i]=MathAbs(s[i]);
     }
  }
//+------------------------------------------------------------------+
//| Extended subroutine for internal use only.                       |
//| Accepts additional parameters:                                   |
//|     Flags - additional settings:                                 |
//|             * Flags = 0     means no additional settings         |
//|             * Flags = 1     "do not allocate memory". used when  |
//|                             solving a many subsequent tasks with |
//|                             same N/M values. First call MUST be  |
//|                             without this flag bit set, subsequent|
//|                             calls of MinLBFGS with same          |
//|                             MinLBFGSState structure can set Flags|
//|                             to 1.                                |
//|     DiffStep - numerical differentiation step                    |
//+------------------------------------------------------------------+
static void CMinLBFGS::MinLBFGSCreateX(const int n,const int m,double &x[],
                                       int flags,const double diffstep,
                                       CMinLBFGSState &state)
  {
//--- create variables
   bool allocatemem;
   int  i=0;
//--- check
   if(!CAp::Assert(n>=1,__FUNCTION__+": N too small!"))
      return;
//--- check
   if(!CAp::Assert(m>=1,__FUNCTION__+": M too small!"))
      return;
//--- check
   if(!CAp::Assert(m<=n,__FUNCTION__+": M too large!"))
      return;
//--- Initialize
   state.m_diffstep=diffstep;
   state.m_n=n;
   state.m_m=m;
   allocatemem=flags%2==0;
   flags=flags/2;
//--- check
   if(allocatemem)
     {
      //--- allocation
      ArrayResizeAL(state.m_rho,m);
      ArrayResizeAL(state.m_theta,m);
      state.m_yk.Resize(m,n);
      state.m_sk.Resize(m,n);
      ArrayResizeAL(state.m_d,n);
      ArrayResizeAL(state.m_x,n);
      ArrayResizeAL(state.m_s,n);
      ArrayResizeAL(state.m_g,n);
      ArrayResizeAL(state.m_work,n);
     }
//--- function call
   MinLBFGSSetCond(state,0,0,0,0);
//--- function call
   MinLBFGSSetXRep(state,false);
//--- function call
   MinLBFGSSetStpMax(state,0);
//--- function call
   MinLBFGSRestartFrom(state,x);
//--- change values
   for(i=0;i<=n-1;i++)
      state.m_s[i]=1.0;
   state.m_prectype=0;
  }
//+------------------------------------------------------------------+
//| Modification of the preconditioner: default preconditioner       |
//| (simple scaling, same for all elements of X) is used.            |
//| INPUT PARAMETERS:                                                |
//|     State   -   structure which stores algorithm state           |
//| NOTE: you can change preconditioner "on the fly", during         |
//| algorithm iterations.                                            |
//+------------------------------------------------------------------+
static void CMinLBFGS::MinLBFGSSetPrecDefault(CMinLBFGSState &state)
  {
//--- change value
   state.m_prectype=0;
  }
//+------------------------------------------------------------------+
//| Modification of the preconditioner: Cholesky factorization of    |
//| approximate Hessian is used.                                     |
//| INPUT PARAMETERS:                                                |
//|     State   -   structure which stores algorithm state           |
//|     P       -   triangular preconditioner, Cholesky factorization|
//|                 of the approximate Hessian. array[0..N-1,0..N-1],|
//|                 (if larger, only leading N elements are used).   |
//|     IsUpper -   whether upper or lower triangle of P is given    |
//|                 (other triangle is not referenced)               |
//| After call to this function preconditioner is changed to P (P is |
//| copied into the internal buffer).                                |
//| NOTE: you can change preconditioner "on the fly", during         |
//| algorithm iterations.                                            |
//| NOTE 2: P should be nonsingular. Exception will be thrown        |
//| otherwise.                                                       |
//+------------------------------------------------------------------+
static void CMinLBFGS::MinLBFGSSetPrecCholesky(CMinLBFGSState &state,
                                               CMatrixDouble &p,
                                               const bool isupper)
  {
//--- create variables
   int    i=0;
   double mx=0;
//--- check
   if(!CAp::Assert(CApServ::IsFiniteRTrMatrix(p,state.m_n,isupper),__FUNCTION__+": P contains infinite or NAN values!"))
      return;
//--- initialization
   mx=0;
   for(i=0;i<=state.m_n-1;i++)
      mx=MathMax(mx,MathAbs(p[i][i]));
//--- check
   if(!CAp::Assert((double)(mx)>0.0,__FUNCTION__+": P is strictly singular!"))
      return;
//--- check
   if(CAp::Rows(state.m_denseh)<state.m_n||CAp::Cols(state.m_denseh)<state.m_n)
      state.m_denseh.Resize(state.m_n,state.m_n);
//--- initialization
   state.m_prectype=1;
//--- check
   if(isupper)
      CAblas::RMatrixCopy(state.m_n,state.m_n,p,0,0,state.m_denseh,0,0);
   else
      CAblas::RMatrixTranspose(state.m_n,state.m_n,p,0,0,state.m_denseh,0,0);
  }
//+------------------------------------------------------------------+
//| Modification of the preconditioner: diagonal of approximate      |
//| Hessian is used.                                                 |
//| INPUT PARAMETERS:                                                |
//|     State   -   structure which stores algorithm state           |
//|     D       -   diagonal of the approximate Hessian,             |
//|                 array[0..N-1], (if larger, only leading N        |
//|                 elements are used).                              |
//| NOTE: you can change preconditioner "on the fly", during         |
//| algorithm iterations.                                            |
//| NOTE 2: D[i] should be positive. Exception will be thrown        |
//| otherwise.                                                       |
//| NOTE 3: you should pass diagonal of approximate Hessian - NOT    |
//| ITS INVERSE.                                                     |
//+------------------------------------------------------------------+
static void CMinLBFGS::MinLBFGSSetPrecDiag(CMinLBFGSState &state,double &d[])
  {
//--- create a variable
   int i=0;
//--- check
   if(!CAp::Assert(CAp::Len(d)>=state.m_n,__FUNCTION__+": D is too short"))
      return;
   for(i=0;i<=state.m_n-1;i++)
     {
      //--- check
      if(!CAp::Assert(CMath::IsFinite(d[i]),__FUNCTION__+": D contains infinite or NAN elements"))
         return;
      //--- check
      if(!CAp::Assert((double)(d[i])>0.0,__FUNCTION__+": D contains non-positive elements"))
         return;
     }
//--- function call
   CApServ::RVectorSetLengthAtLeast(state.m_diagh,state.m_n);
//--- change values
   state.m_prectype=2;
   for(i=0;i<=state.m_n-1;i++)
      state.m_diagh[i]=d[i];
  }
//+------------------------------------------------------------------+
//| Modification of the preconditioner: scale-based diagonal         |
//| preconditioning.                                                 |
//| This preconditioning mode can be useful when you don't have      |
//| approximate diagonal of Hessian, but you know that your variables|
//| are badly scaled (for example, one variable is in [1,10], and    |
//| another in [1000,100000]), and most part of the ill-conditioning |
//| comes from different scales of vars.                             |
//| In this case simple scale-based preconditioner, with H[i] =      |
//| = 1/(s[i]^2), can greatly improve convergence.                   |
//| IMPRTANT: you should set scale of your variables with            |
//| MinLBFGSSetScale() call (before or after MinLBFGSSetPrecScale()  |
//| call). Without knowledge of the scale of your variables          |
//| scale-based preconditioner will be just unit matrix.             |
//| INPUT PARAMETERS:                                                |
//|     State   -   structure which stores algorithm state           |
//+------------------------------------------------------------------+
static void CMinLBFGS::MinLBFGSSetPrecScale(CMinLBFGSState &state)
  {
//--- change values
   state.m_prectype=3;
  }
//+------------------------------------------------------------------+
//| L-BFGS algorithm results                                         |
//| INPUT PARAMETERS:                                                |
//|     State   -   algorithm state                                  |
//| OUTPUT PARAMETERS:                                               |
//|     X       -   array[0..N-1], solution                          |
//|     Rep     -   optimization report:                             |
//|                 * Rep.TerminationType completetion code:         |
//|                     * -2    rounding errors prevent further      |
//|                             improvement. X contains best point   |
//|                             found.                               |
//|                     * -1    incorrect parameters were specified  |
//|                     *  1    relative function improvement is no  |
//|                             more than EpsF.                      |
//|                     *  2    relative step is no more than EpsX.  |
//|                     *  4    gradient norm is no more than EpsG   |
//|                     *  5    MaxIts steps was taken               |
//|                     *  7    stopping conditions are too          |
//|                             stringent, further improvement is    |
//|                             impossible                           |
//|                 * Rep.IterationsCount contains iterations count  |
//|                 * NFEV countains number of function calculations |
//+------------------------------------------------------------------+
static void CMinLBFGS::MinLBFGSResults(CMinLBFGSState &state,double &x[],
                                       CMinLBFGSReport &rep)
  {
//--- reset memory
   ArrayResizeAL(x,0);
//--- function call
   MinLBFGSresultsbuf(state,x,rep);
  }
//+------------------------------------------------------------------+
//| L-BFGS algorithm results                                         |
//| Buffered implementation of MinLBFGSResults which uses            |
//| pre-allocated buffer to store X[]. If buffer size is too small,  |
//| it resizes buffer. It is intended to be used in the inner cycles |
//| of performance critical algorithms where array reallocation      |
//| penalty is too large to be ignored.                              |
//+------------------------------------------------------------------+
static void CMinLBFGS::MinLBFGSresultsbuf(CMinLBFGSState &state,double &x[],
                                          CMinLBFGSReport &rep)
  {
//--- create a variable
   int i_=0;
//--- check
   if(CAp::Len(x)<state.m_n)
      ArrayResizeAL(x,state.m_n);
//--- copy
   for(i_=0;i_<=state.m_n-1;i_++)
      x[i_]=state.m_x[i_];
//--- change values
   rep.m_iterationscount=state.m_repiterationscount;
   rep.m_nfev=state.m_repnfev;
   rep.m_terminationtype=state.m_repterminationtype;
  }
//+------------------------------------------------------------------+
//| This  subroutine restarts LBFGS algorithm from new point. All    |
//| optimization parameters are left unchanged.                      |
//| This function allows to solve multiple optimization problems     |
//| (which must have same number of dimensions) without object       |
//| reallocation penalty.                                            |
//| INPUT PARAMETERS:                                                |
//|     State   -   structure used to store algorithm state          |
//|     X       -   new starting point.                              |
//+------------------------------------------------------------------+
static void CMinLBFGS::MinLBFGSRestartFrom(CMinLBFGSState &state,double &x[])
  {
//--- create a variable
   int i_=0;
//--- check
   if(!CAp::Assert(CAp::Len(x)>=state.m_n,__FUNCTION__+": Length(X)<N!"))
      return;
//--- check
   if(!CAp::Assert(CApServ::IsFiniteVector(x,state.m_n),__FUNCTION__+": X contains infinite or NaN values!"))
      return;
//--- copy
   for(i_=0;i_<=state.m_n-1;i_++)
      state.m_x[i_]=x[i_];
//--- allocation
   ArrayResizeAL(state.m_rstate.ia,6);
   ArrayResizeAL(state.m_rstate.ra,2);
   state.m_rstate.stage=-1;
//--- function call
   ClearRequestFields(state);
  }
//+------------------------------------------------------------------+
//| Clears request fileds (to be sure that we don't forgot to clear  |
//| something)                                                       |
//+------------------------------------------------------------------+
static void CMinLBFGS::ClearRequestFields(CMinLBFGSState &state)
  {
//--- change values
   state.m_needf=false;
   state.m_needfg=false;
   state.m_xupdated=false;
  }
//+------------------------------------------------------------------+
//| NOTES:                                                           |
//| 1. This function has two different implementations: one which    |
//|    uses exact (analytical) user-supplied gradient, and one which |
//|    uses function value only and numerically differentiates       |
//|    function in order to obtain gradient.                         |
//|    Depending on the specific function used to create optimizer   |
//|    object (either MinLBFGSCreate() for analytical gradient or    |
//|    MinLBFGSCreateF() for numerical differentiation) you should   |
//|    choose appropriate variant of MinLBFGSOptimize() - one which  |
//|    accepts function AND gradient or one which accepts function   |
//|    ONLY.                                                         |
//|    Be careful to choose variant of MinLBFGSOptimize() which      |
//|    corresponds to your optimization scheme! Table below lists    |
//|    different combinations of callback (function/gradient) passed |
//|    to MinLBFGSOptimize() and specific function used to create    |
//|    optimizer.                                                    |
//|                      |         USER PASSED TO MinLBFGSOptimize() |
//|    CREATED WITH      |  function only   |  function and gradient |
//|    ------------------------------------------------------------  |
//|    MinLBFGSCreateF() |     work                FAIL              |
//|    MinLBFGSCreate()  |     FAIL                work              |
//|    Here "FAIL" denotes inappropriate combinations of optimizer   |
//|    creation function and MinLBFGSOptimize() version. Attemps to  |
//|    use such combination (for example, to create optimizer with   |
//|    MinLBFGSCreateF() and to pass gradient information to         |
//|    MinCGOptimize()) will lead to exception being thrown. Either  |
//|    you did not pass gradient when it WAS needed or you passed    |
//|    gradient when it was NOT needed.                              |
//+------------------------------------------------------------------+
static bool CMinLBFGS::MinLBFGSIteration(CMinLBFGSState &state)
  {
//--- create variables
   int    n=0;
   int    m=0;
   int    i=0;
   int    j=0;
   int    ic=0;
   int    mcinfo=0;
   double v=0;
   double vv=0;
   int    i_=0;
//--- Reverse communication preparations
//--- I know it looks ugly, but it works the same way
//--- anywhere from C++ to Python.
//--- 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];
      ic=state.m_rstate.ia[4];
      mcinfo=state.m_rstate.ia[5];
      v=state.m_rstate.ra[0];
      vv=state.m_rstate.ra[1];
     }
   else
     {
      //--- initialization
      n=-983;
      m=-989;
      i=-834;
      j=900;
      ic=-287;
      mcinfo=364;
      v=214;
      vv=-338;
     }
//--- check
   if(state.m_rstate.stage==0)
     {
      //--- change value
      state.m_needfg=false;
      //--- function call
      COptServ::TrimPrepare(state.m_f,state.m_trimthreshold);
      //--- check
      if(!state.m_xrep)
         return(Func_lbl_19(state,n,m,i,j,ic,mcinfo,v,vv));
      //--- function call
      ClearRequestFields(state);
      //--- change values
      state.m_xupdated=true;
      state.m_rstate.stage=6;
      //--- Saving state
      Func_lbl_rcomm(state,n,m,i,j,ic,mcinfo,v,vv);
      //--- return result
      return(true);
     }
//--- check
   if(state.m_rstate.stage==1)
     {
      //--- change values
      state.m_fbase=state.m_f;
      i=0;
      //--- function call, return result
      return(Func_lbl_16(state,n,m,i,j,ic,mcinfo,v,vv));
     }
//--- check
   if(state.m_rstate.stage==2)
     {
      //--- change values
      state.m_fm2=state.m_f;
      state.m_x[i]=v-0.5*state.m_diffstep*state.m_s[i];
      state.m_rstate.stage=3;
      //--- Saving state
      Func_lbl_rcomm(state,n,m,i,j,ic,mcinfo,v,vv);
      //--- return result
      return(true);
     }
//--- check
   if(state.m_rstate.stage==3)
     {
      //--- change values
      state.m_fm1=state.m_f;
      state.m_x[i]=v+0.5*state.m_diffstep*state.m_s[i];
      state.m_rstate.stage=4;
      //--- Saving state
      Func_lbl_rcomm(state,n,m,i,j,ic,mcinfo,v,vv);
      //--- return result
      return(true);
     }
//--- check
   if(state.m_rstate.stage==4)
     {
      //--- change values
      state.m_fp1=state.m_f;
      state.m_x[i]=v+state.m_diffstep*state.m_s[i];
      state.m_rstate.stage=5;
      //--- Saving state
      Func_lbl_rcomm(state,n,m,i,j,ic,mcinfo,v,vv);
      //--- return result
      return(true);
     }
//--- check
   if(state.m_rstate.stage==5)
     {
      //--- change values
      state.m_fp2=state.m_f;
      state.m_x[i]=v;
      state.m_g[i]=(8*(state.m_fp1-state.m_fm1)-(state.m_fp2-state.m_fm2))/(6*state.m_diffstep*state.m_s[i]);
      i=i+1;
      //--- function call, return result
      return(Func_lbl_16(state,n,m,i,j,ic,mcinfo,v,vv));
     }
//--- check
   if(state.m_rstate.stage==6)
     {
      //--- change value
      state.m_xupdated=false;
      //--- function call, return result
      return(Func_lbl_19(state,n,m,i,j,ic,mcinfo,v,vv));
     }
//--- check
   if(state.m_rstate.stage==7)
     {
      //--- change value
      state.m_needfg=false;
      //--- function call
      COptServ::TrimFunction(state.m_f,state.m_g,n,state.m_trimthreshold);
      //--- function call
      CLinMin::MCSrch(n,state.m_x,state.m_f,state.m_g,state.m_d,state.m_stp,state.m_stpmax,m_gtol,mcinfo,state.m_nfev,state.m_work,state.m_lstate,state.m_mcstage);
      //--- function call, return result
      return(Func_lbl_23(state,n,m,i,j,ic,mcinfo,v,vv));
     }
//--- check
   if(state.m_rstate.stage==8)
     {
      //--- change values
      state.m_fbase=state.m_f;
      i=0;
      //--- function call, return result
      return(Func_lbl_27(state,n,m,i,j,ic,mcinfo,v,vv));
     }
//--- check
   if(state.m_rstate.stage==9)
     {
      //--- change values
      state.m_fm2=state.m_f;
      state.m_x[i]=v-0.5*state.m_diffstep*state.m_s[i];
      state.m_rstate.stage=10;
      //--- Saving state
      Func_lbl_rcomm(state,n,m,i,j,ic,mcinfo,v,vv);
      //--- return result
      return(true);
     }
//--- check
   if(state.m_rstate.stage==10)
     {
      //--- change values
      state.m_fm1=state.m_f;
      state.m_x[i]=v+0.5*state.m_diffstep*state.m_s[i];
      state.m_rstate.stage=11;
      //--- Saving state
      Func_lbl_rcomm(state,n,m,i,j,ic,mcinfo,v,vv);
      //--- return result
      return(true);
     }
//--- check
   if(state.m_rstate.stage==11)
     {
      //--- change values
      state.m_fp1=state.m_f;
      state.m_x[i]=v+state.m_diffstep*state.m_s[i];
      state.m_rstate.stage=12;
      //--- Saving state
      Func_lbl_rcomm(state,n,m,i,j,ic,mcinfo,v,vv);
      //--- return result
      return(true);
     }
//--- check
   if(state.m_rstate.stage==12)
     {
      //--- change values
      state.m_fp2=state.m_f;
      state.m_x[i]=v;
      state.m_g[i]=(8*(state.m_fp1-state.m_fm1)-(state.m_fp2-state.m_fm2))/(6*state.m_diffstep*state.m_s[i]);
      i=i+1;
      //--- function call, return result
      return(Func_lbl_27(state,n,m,i,j,ic,mcinfo,v,vv));
     }
//--- check
   if(state.m_rstate.stage==13)
     {
      //--- change value
      state.m_xupdated=false;
      //--- function call, return result
      return(Func_lbl_30(state,n,m,i,j,ic,mcinfo,v,vv));
     }
//--- Routine body
//--- Unload frequently used variables from State structure
//--- (just for typing convinience)
   n=state.m_n;
   m=state.m_m;
   state.m_repterminationtype=0;
   state.m_repiterationscount=0;
   state.m_repnfev=0;
//--- Calculate F/G at the initial point
   ClearRequestFields(state);
//--- check
   if(state.m_diffstep!=0.0)
     {
      //--- change values
      state.m_needf=true;
      state.m_rstate.stage=1;
      //--- Saving state
      Func_lbl_rcomm(state,n,m,i,j,ic,mcinfo,v,vv);
      //--- return result
      return(true);
     }
//--- change values
   state.m_needfg=true;
   state.m_rstate.stage=0;
//--- Saving state
   Func_lbl_rcomm(state,n,m,i,j,ic,mcinfo,v,vv);
//--- return result
   return(true);
  }
//+------------------------------------------------------------------+
//| Auxiliary function for MinLBFGSIteration. Is a product to get    |
//| rid of the operator unconditional jump goto.                     |
//+------------------------------------------------------------------+
static void CMinLBFGS::Func_lbl_rcomm(CMinLBFGSState &state,int n,int m,
                                      int i,int j,int ic,int mcinfo,
                                      double v,double vv)
  {
//--- save
   state.m_rstate.ia[0]=n;
   state.m_rstate.ia[1]=m;
   state.m_rstate.ia[2]=i;
   state.m_rstate.ia[3]=j;
   state.m_rstate.ia[4]=ic;
   state.m_rstate.ia[5]=mcinfo;
   state.m_rstate.ra[0]=v;
   state.m_rstate.ra[1]=vv;
  }
//+------------------------------------------------------------------+
//| Auxiliary function for MinLBFGSIteration. Is a product to get    |
//| rid of the operator unconditional jump goto.                     |
//+------------------------------------------------------------------+
static bool CMinLBFGS::Func_lbl_16(CMinLBFGSState &state,int &n,int &m,
                                   int &i,int &j,int &ic,int &mcinfo,
                                   double &v,double &vv)
  {
//--- check
   if(i>n-1)
     {
      //--- change values
      state.m_f=state.m_fbase;
      state.m_needf=false;
      //--- function call
      COptServ::TrimPrepare(state.m_f,state.m_trimthreshold);
      //--- check
      if(!state.m_xrep)
         return(Func_lbl_19(state,n,m,i,j,ic,mcinfo,v,vv));
      //--- function call
      ClearRequestFields(state);
      //--- change values
      state.m_xupdated=true;
      state.m_rstate.stage=6;
      //--- Saving state
      Func_lbl_rcomm(state,n,m,i,j,ic,mcinfo,v,vv);
      //--- return result
      return(true);
     }
//--- change values
   v=state.m_x[i];
   state.m_x[i]=v-state.m_diffstep*state.m_s[i];
   state.m_rstate.stage=2;
//--- Saving state
   Func_lbl_rcomm(state,n,m,i,j,ic,mcinfo,v,vv);
//--- return result
   return(true);
  }
//+------------------------------------------------------------------+
//| Auxiliary function for MinLBFGSIteration. Is a product to get    |
//| rid of the operator unconditional jump goto.                     |
//+------------------------------------------------------------------+
static bool CMinLBFGS::Func_lbl_19(CMinLBFGSState &state,int &n,int &m,
                                   int &i,int &j,int &ic,int &mcinfo,
                                   double &v,double &vv)
  {
//--- change values
   state.m_repnfev=1;
   state.m_fold=state.m_f;
//--- calculation
   v=0;
   for(i=0;i<=n-1;i++)
      v=v+CMath::Sqr(state.m_g[i]*state.m_s[i]);
//--- check
   if(MathSqrt(v)<=state.m_epsg)
     {
      state.m_repterminationtype=4;
      //--- return result
      return(false);
     }
//--- Choose initial step and direction.
//--- Apply preconditioner, if we have something other than default.
   for(int i_=0;i_<=n-1;i_++)
      state.m_d[i_]=-state.m_g[i_];
//--- check
   if(state.m_prectype==0)
     {
      //--- Default preconditioner is used, but we can't use it before iterations will start
      v=0.0;
      for(int i_=0;i_<=n-1;i_++)
         v+=state.m_g[i_]*state.m_g[i_];
      v=MathSqrt(v);
      //--- check
      if(state.m_stpmax==0.0)
         state.m_stp=MathMin(1.0/v,1);
      else
         state.m_stp=MathMin(1.0/v,state.m_stpmax);
     }
//--- check
   if(state.m_prectype==1)
     {
      //--- Cholesky preconditioner is used
      CFbls::FblsCholeskySolve(state.m_denseh,1.0,n,true,state.m_d,state.m_autobuf);
      state.m_stp=1;
     }
//--- check
   if(state.m_prectype==2)
     {
      //--- diagonal approximation is used
      for(i=0;i<=n-1;i++)
         state.m_d[i]=state.m_d[i]/state.m_diagh[i];
      state.m_stp=1;
     }
//--- check
   if(state.m_prectype==3)
     {
      //--- scale-based preconditioner is used
      for(i=0;i<=n-1;i++)
         state.m_d[i]=state.m_d[i]*state.m_s[i]*state.m_s[i];
      state.m_stp=1;
     }
//--- Main cycle
   state.m_k=0;
//--- function call, return result
   return(Func_lbl_21(state,n,m,i,j,ic,mcinfo,v,vv));
  }
//+------------------------------------------------------------------+
//| Auxiliary function for MinLBFGSIteration. Is a product to get    |
//| rid of the operator unconditional jump goto.                     |
//+------------------------------------------------------------------+
static bool CMinLBFGS::Func_lbl_21(CMinLBFGSState &state,int &n,int &m,
                                   int &i,int &j,int &ic,int &mcinfo,
                                   double &v,double &vv)
  {
//--- Main cycle: prepare to 1-D line search
   state.m_p=state.m_k % m;
   state.m_q=MathMin(state.m_k, m-1);
//--- Store X[k], G[k]
   for(int i_=0;i_<=n-1;i_++)
      state.m_sk[state.m_p].Set(i_,-state.m_x[i_]);
   for(int i_=0;i_<=n-1;i_++)
      state.m_yk[state.m_p].Set(i_,-state.m_g[i_]);
//--- Minimize F(x+alpha*d)
//--- Calculate S[k], Y[k]
   state.m_mcstage=0;
//--- check
   if(state.m_k!=0)
      state.m_stp=1.0;
//--- function call
   CLinMin::LinMinNormalized(state.m_d,state.m_stp,n);
//--- function call
   CLinMin::MCSrch(n,state.m_x,state.m_f,state.m_g,state.m_d,state.m_stp,state.m_stpmax,m_gtol,mcinfo,state.m_nfev,state.m_work,state.m_lstate,state.m_mcstage);
//--- function call, return result
   return(Func_lbl_23(state,n,m,i,j,ic,mcinfo,v,vv));
  }
//+------------------------------------------------------------------+
//| Auxiliary function for MinLBFGSIteration. Is a product to get    |
//| rid of the operator unconditional jump goto.                     |
//+------------------------------------------------------------------+
static bool CMinLBFGS::Func_lbl_23(CMinLBFGSState &state,int &n,int &m,
                                   int &i,int &j,int &ic,int &mcinfo,
                                   double &v,double &vv)
  {
//--- check
   if(state.m_mcstage==0)
     {
      //--- check
      if(!state.m_xrep)
         return(Func_lbl_30(state,n,m,i,j,ic,mcinfo,v,vv));
      //--- report
      ClearRequestFields(state);
      //--- change values
      state.m_xupdated=true;
      state.m_rstate.stage=13;
      //--- Saving state
      Func_lbl_rcomm(state,n,m,i,j,ic,mcinfo,v,vv);
      //--- return result
      return(true);
     }
//--- function call
   ClearRequestFields(state);
//--- check
   if((double)(state.m_diffstep)!=0.0)
     {
      //--- change values
      state.m_needf=true;
      state.m_rstate.stage=8;
      //--- Saving state
      Func_lbl_rcomm(state,n,m,i,j,ic,mcinfo,v,vv);
      //--- return result
      return(true);
     }
//--- change values
   state.m_needfg=true;
   state.m_rstate.stage=7;
//--- Saving state
   Func_lbl_rcomm(state,n,m,i,j,ic,mcinfo,v,vv);
//--- return result
   return(true);
  }
//+------------------------------------------------------------------+
//| Auxiliary function for MinLBFGSIteration. Is a product to get    |
//| rid of the operator unconditional jump goto.                     |
//+------------------------------------------------------------------+
static bool CMinLBFGS::Func_lbl_27(CMinLBFGSState &state,int &n,int &m,
                                   int &i,int &j,int &ic,int &mcinfo,
                                   double &v,double &vv)
  {
//--- check
   if(i>n-1)
     {
      //--- change values
      state.m_f=state.m_fbase;
      state.m_needf=false;
      //--- function call
      COptServ::TrimFunction(state.m_f,state.m_g,n,state.m_trimthreshold);
      //--- function call
      CLinMin::MCSrch(n,state.m_x,state.m_f,state.m_g,state.m_d,state.m_stp,state.m_stpmax,m_gtol,mcinfo,state.m_nfev,state.m_work,state.m_lstate,state.m_mcstage);
      //--- function call, return result
      return(Func_lbl_23(state,n,m,i,j,ic,mcinfo,v,vv));
     }
//--- change values
   v=state.m_x[i];
   state.m_x[i]=v-state.m_diffstep*state.m_s[i];
   state.m_rstate.stage=9;
//--- Saving state
   Func_lbl_rcomm(state,n,m,i,j,ic,mcinfo,v,vv);
//--- return result
   return(true);
  }
//+------------------------------------------------------------------+
//| Auxiliary function for MinLBFGSIteration. Is a product to get    |
//| rid of the operator unconditional jump goto.                     |
//+------------------------------------------------------------------+
static bool CMinLBFGS::Func_lbl_30(CMinLBFGSState &state,int &n,int &m,
                                   int &i,int &j,int &ic,int &mcinfo,
                                   double &v,double &vv)
  {
//--- change values
   state.m_repnfev=state.m_repnfev+state.m_nfev;
   state.m_repiterationscount=state.m_repiterationscount+1;
//--- calculation
   for(int i_=0;i_<=n-1;i_++)
      state.m_sk[state.m_p].Set(i_,state.m_sk[state.m_p][i_]+state.m_x[i_]);
   for(int i_=0;i_<=n-1;i_++)
      state.m_yk[state.m_p].Set(i_,state.m_yk[state.m_p][i_]+state.m_g[i_]);
//--- Stopping conditions
   if(state.m_repiterationscount>=state.m_maxits&&state.m_maxits>0)
     {
      //--- Too many iterations
      state.m_repterminationtype=5;
      //--- return result
      return(false);
     }
//--- change value
   v=0;
   for(i=0;i<=n-1;i++)
      v=v+CMath::Sqr(state.m_g[i]*state.m_s[i]);
//--- check
   if(MathSqrt(v)<=state.m_epsg)
     {
      //--- Gradient is small enough
      state.m_repterminationtype=4;
      //--- return result
      return(false);
     }
//--- check
   if(state.m_fold-state.m_f<=state.m_epsf*MathMax(MathAbs(state.m_fold),MathMax(MathAbs(state.m_f),1.0)))
     {
      //--- F(k+1)-F(k) is small enough
      state.m_repterminationtype=1;
      //--- return result
      return(false);
     }
//--- change value
   v=0;
   for(i=0;i<=n-1;i++)
      v=v+CMath::Sqr(state.m_sk[state.m_p][i]/state.m_s[i]);
//--- check
   if((double)(MathSqrt(v))<=(double)(state.m_epsx))
     {
      //--- X(k+1)-X(k) is small enough
      state.m_repterminationtype=2;
      //--- return result
      return(false);
     }
//--- If Wolfe conditions are satisfied, we can update
//--- limited memory model.
//--- However, if conditions are not satisfied (NFEV limit is met,
//--- function is too wild, ...), we'll skip L-BFGS update
   if(mcinfo!=1)
     {
      //--- Skip update.
      //--- In such cases we'll initialize search direction by
      //--- antigradient vector, because it  leads to more
      //--- transparent code with less number of special cases
      state.m_fold=state.m_f;
      for(int i_=0;i_<=n-1;i_++)
         state.m_d[i_]=-state.m_g[i_];
     }
   else
     {
      //--- Calculate Rho[k], GammaK
      v=0.0;
      for(int i_=0;i_<=n-1;i_++)
         v+=state.m_yk[state.m_p][i_]*state.m_sk[state.m_p][i_];
      //--- change value
      vv=0.0;
      for(int i_=0;i_<=n-1;i_++)
         vv+=state.m_yk[state.m_p][i_]*state.m_yk[state.m_p][i_];
      //--- check
      if(v==0.0 || vv==0.0)
        {
         //--- Rounding errors make further iterations impossible.
         state.m_repterminationtype=-2;
         //--- return result
         return(false);
        }
      //--- change values
      state.m_rho[state.m_p]=1/v;
      state.m_gammak=v/vv;
      //---  Calculate d(k+1)=-H(k+1)*g(k+1)
      //---  for I:=K downto K-Q do
      //---      V=s(i)^T * work(iteration:I)
      //---      theta(i)=V
      //---      work(iteration:I+1)=work(iteration:I)-V*Rho(i)*y(i)
      //---  work(last iteration)=H0*work(last iteration)-preconditioner
      //---  for I:=K-Q to K do
      //---      V=y(i)^T*work(iteration:I)
      //---      work(iteration:I+1)=work(iteration:I) +(-V+theta(i))*Rho(i)*s(i)
      //---  NOW WORK CONTAINS d(k+1)
      for(int i_=0;i_<=n-1;i_++)
         state.m_work[i_]=state.m_g[i_];
      for(i=state.m_k;i>=state.m_k-state.m_q;i--)
        {
         ic=i%m;
         v=0.0;
         for(int i_=0;i_<=n-1;i_++)
            v+=state.m_sk[ic][i_]*state.m_work[i_];
         //--- change values
         state.m_theta[ic]=v;
         vv=v*state.m_rho[ic];
         for(int i_=0;i_<=n-1;i_++)
            state.m_work[i_]=state.m_work[i_]-vv*state.m_yk[ic][i_];
        }
      //--- check
      if(state.m_prectype==0)
        {
         //--- Simple preconditioner is used
         v=state.m_gammak;
         for(int i_=0;i_<=n-1;i_++)
            state.m_work[i_]=v*state.m_work[i_];
        }
      //--- check
      if(state.m_prectype==1)
        {
         //--- Cholesky preconditioner is used
         CFbls::FblsCholeskySolve(state.m_denseh,1,n,true,state.m_work,state.m_autobuf);
        }
      //--- check
      if(state.m_prectype==2)
        {
         //--- diagonal approximation is used
         for(i=0;i<=n-1;i++)
           {
            state.m_work[i]=state.m_work[i]/state.m_diagh[i];
           }
        }
      //--- check
      if(state.m_prectype==3)
        {
         //--- scale-based preconditioner is used
         for(i=0;i<=n-1;i++)
            state.m_work[i]=state.m_work[i]*state.m_s[i]*state.m_s[i];
        }
      //--- calculation
      for(i=state.m_k-state.m_q;i<=state.m_k;i++)
        {
         ic=i%m;
         v=0.0;
         for(int i_=0;i_<=n-1;i_++)
            v+=state.m_yk[ic][i_]*state.m_work[i_];
         //--- change value
         vv=state.m_rho[ic]*(-v+state.m_theta[ic]);
         for(int i_=0;i_<=n-1;i_++)
           {
            state.m_work[i_]=state.m_work[i_]+vv*state.m_sk[ic][i_];
           }
        }
      for(int i_=0;i_<=n-1;i_++)
         state.m_d[i_]=-state.m_work[i_];
      //--- Next step
      state.m_fold=state.m_f;
      state.m_k=state.m_k+1;
     }
//--- function call, return result
   return(Func_lbl_21(state,n,m,i,j,ic,mcinfo,v,vv));
  }
//+------------------------------------------------------------------+
//| This object stores nonlinear optimizer state.                    |
//| You should use functions provided by MinQP subpackage to work    |
//| with this object                                                 |
//+------------------------------------------------------------------+
class CMinQPState
  {
public:
   //--- variables
   int               m_n;
   int               m_algokind;
   int               m_akind;
   bool              m_havex;
   double            m_constterm;
   int               m_repinneriterationscount;
   int               m_repouteriterationscount;
   int               m_repncholesky;
   int               m_repnmv;
   int               m_repterminationtype;
   CApBuff           m_buf;
   //--- arrays
   double            m_diaga[];
   double            m_b[];
   double            m_bndl[];
   double            m_bndu[];
   bool              m_havebndl[];
   bool              m_havebndu[];
   double            m_xorigin[];
   double            m_startx[];
   double            m_xc[];
   double            m_gc[];
   int               m_activeconstraints[];
   int               m_prevactiveconstraints[];
   double            m_workbndl[];
   double            m_workbndu[];
   double            m_tmp0[];
   double            m_tmp1[];
   int               m_itmp0[];
   int               m_p2[];
   double            m_bufb[];
   double            m_bufx[];
   //--- matrix
   CMatrixDouble     m_densea;
   CMatrixDouble     m_bufa;
   //--- constructor, destructor
                     CMinQPState(void);
                    ~CMinQPState(void);
   //--- copy
   void              Copy(CMinQPState &obj);
  };
//+------------------------------------------------------------------+
//| Constructor without parameters                                   |
//+------------------------------------------------------------------+
CMinQPState::CMinQPState(void)
  {

  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CMinQPState::~CMinQPState(void)
  {

  }
//+------------------------------------------------------------------+
//| Copy                                                             |
//+------------------------------------------------------------------+
void CMinQPState::Copy(CMinQPState &obj)
  {
//--- copy variables
   m_n=obj.m_n;
   m_algokind=obj.m_algokind;
   m_akind=obj.m_akind;
   m_havex=obj.m_havex;
   m_constterm=obj.m_constterm;
   m_repinneriterationscount=obj.m_repinneriterationscount;
   m_repouteriterationscount=obj.m_repouteriterationscount;
   m_repncholesky=obj.m_repncholesky;
   m_repnmv=obj.m_repnmv;
   m_repterminationtype=obj.m_repterminationtype;
   m_buf.Copy(obj.m_buf);
//--- copy arrays
   ArrayCopy(m_diaga,obj.m_diaga);
   ArrayCopy(m_b,obj.m_b);
   ArrayCopy(m_bndl,obj.m_bndl);
   ArrayCopy(m_bndu,obj.m_bndu);
   ArrayCopy(m_havebndl,obj.m_havebndl);
   ArrayCopy(m_havebndu,obj.m_havebndu);
   ArrayCopy(m_xorigin,obj.m_xorigin);
   ArrayCopy(m_startx,obj.m_startx);
   ArrayCopy(m_xc,obj.m_xc);
   ArrayCopy(m_gc,obj.m_gc);
   ArrayCopy(m_activeconstraints,obj.m_activeconstraints);
   ArrayCopy(m_prevactiveconstraints,obj.m_prevactiveconstraints);
   ArrayCopy(m_workbndl,obj.m_workbndl);
   ArrayCopy(m_workbndu,obj.m_workbndu);
   ArrayCopy(m_tmp0,obj.m_tmp0);
   ArrayCopy(m_tmp1,obj.m_tmp1);
   ArrayCopy(m_itmp0,obj.m_itmp0);
   ArrayCopy(m_p2,obj.m_p2);
   ArrayCopy(m_bufb,obj.m_bufb);
   ArrayCopy(m_bufx,obj.m_bufx);
//--- copy matrix
   m_densea=obj.m_densea;
   m_bufa=obj.m_bufa;
  }
//+------------------------------------------------------------------+
//| This object stores nonlinear optimizer state.                    |
//| You should use functions provided by MinQP subpackage to work    |
//| with this object                                                 |
//+------------------------------------------------------------------+
class CMinQPStateShell
  {
private:
   CMinQPState       m_innerobj;
public:
   //--- constructors, destructor
                     CMinQPStateShell(void);
                     CMinQPStateShell(CMinQPState &obj);
                    ~CMinQPStateShell(void);
   //--- method
   CMinQPState      *GetInnerObj(void);
  };
//+------------------------------------------------------------------+
//| Constructor without parameters                                   |
//+------------------------------------------------------------------+
CMinQPStateShell::CMinQPStateShell(void)
  {

  }
//+------------------------------------------------------------------+
//| Copy constructor                                                 |
//+------------------------------------------------------------------+
CMinQPStateShell::CMinQPStateShell(CMinQPState &obj)
  {
//--- copy
   m_innerobj.Copy(obj);
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CMinQPStateShell::~CMinQPStateShell(void)
  {

  }
//+------------------------------------------------------------------+
//| Return object of class                                           |
//+------------------------------------------------------------------+
CMinQPState *CMinQPStateShell::GetInnerObj(void)
  {
//--- return result
   return(GetPointer(m_innerobj));
  }
//+------------------------------------------------------------------+
//| This structure stores optimization report:                       |
//| * InnerIterationsCount      number of inner iterations           |
//| * OuterIterationsCount      number of outer iterations           |
//| * NCholesky                 number of Cholesky decomposition     |
//| * NMV                       number of matrix-vector products     |
//|                             (only products calculated as part of |
//|                             iterative process are counted)       |
//| * TerminationType           completion code (see below)          |
//| Completion codes:                                                |
//| * -5    inappropriate solver was used:                           |
//|         * Cholesky solver for semidefinite or indefinite problems|
//|         * Cholesky solver for problems with non-boundary         |
//|           constraints                                            |
//| * -3    inconsistent constraints (or, maybe, feasible point is   |
//|         too hard to find). If you are sure that constraints are  |
//|         feasible, try to restart optimizer with better initial   |
//|         approximation.                                           |
//| *  4    successful completion                                    |
//| *  5    MaxIts steps was taken                                   |
//| *  7    stopping conditions are too stringent,                   |
//|         further improvement is impossible,                       |
//|         X contains best point found so far.                      |
//+------------------------------------------------------------------+
class CMinQPReport
  {
public:
   //--- variables
   int               m_inneriterationscount;
   int               m_outeriterationscount;
   int               m_nmv;
   int               m_ncholesky;
   int               m_terminationtype;
   //--- constructor, destructor
                     CMinQPReport(void);
                    ~CMinQPReport(void);
   //--- copy
   void              Copy(CMinQPReport &obj);
  };
//+------------------------------------------------------------------+
//| Constructor without parameters                                   |
//+------------------------------------------------------------------+
CMinQPReport::CMinQPReport(void)
  {

  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CMinQPReport::~CMinQPReport(void)
  {

  }
//+------------------------------------------------------------------+
//| Copy                                                             |
//+------------------------------------------------------------------+
void CMinQPReport::Copy(CMinQPReport &obj)
  {
//--- copy variables
   m_inneriterationscount=obj.m_inneriterationscount;
   m_outeriterationscount=obj.m_outeriterationscount;
   m_nmv=obj.m_nmv;
   m_ncholesky=obj.m_ncholesky;
   m_terminationtype=obj.m_terminationtype;
  }
//+------------------------------------------------------------------+
//| This structure stores optimization report:                       |
//| * InnerIterationsCount      number of inner iterations           |
//| * OuterIterationsCount      number of outer iterations           |
//| * NCholesky                 number of Cholesky decomposition     |
//| * NMV                       number of matrix-vector products     |
//|                             (only products calculated as part of |
//|                             iterative process are counted)       |
//| * TerminationType           completion code (see below)          |
//| Completion codes:                                                |
//| * -5    inappropriate solver was used:                           |
//|         * Cholesky solver for semidefinite or indefinite problems|
//|         * Cholesky solver for problems with non-boundary         |
//|           constraints                                            |
//| * -3    inconsistent constraints (or, maybe, feasible point is   |
//|         too hard to find). If you are sure that constraints are  |
//|         feasible, try to restart optimizer with better initial   |
//|         approximation.                                           |
//| *  4    successful completion                                    |
//| *  5    MaxIts steps was taken                                   |
//| *  7    stopping conditions are too stringent,                   |
//|         further improvement is impossible,                       |
//|         X contains best point found so far.                      |
//+------------------------------------------------------------------+
class CMinQPReportShell
  {
private:
   CMinQPReport      m_innerobj;
public:
   //--- constructors, destructor
                     CMinQPReportShell(void);
                     CMinQPReportShell(CMinQPReport &obj);
                    ~CMinQPReportShell(void);
   //--- methods
   int               GetInnerIterationsCount(void);
   void              SetInnerIterationsCount(const int i);
   int               GetOuterIterationsCount(void);
   void              SetOuterIterationsCount(const int i);
   int               GetNMV(void);
   void              SetNMV(const int i);
   int               GetNCholesky(void);
   void              SetNCholesky(const int i);
   int               GetTerminationType(void);
   void              SetTerminationType(const int i);
   CMinQPReport     *GetInnerObj(void);
  };
//+------------------------------------------------------------------+
//| Constructor without parameters                                   |
//+------------------------------------------------------------------+
CMinQPReportShell::CMinQPReportShell(void)
  {

  }
//+------------------------------------------------------------------+
//| Copy constructor                                                 |
//+------------------------------------------------------------------+
CMinQPReportShell::CMinQPReportShell(CMinQPReport &obj)
  {
//--- copy
   m_innerobj.Copy(obj);
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CMinQPReportShell::~CMinQPReportShell(void)
  {

  }
//+------------------------------------------------------------------+
//| Returns the value of the variable inneriterationscount           |
//+------------------------------------------------------------------+
int CMinQPReportShell::GetInnerIterationsCount(void)
  {
//--- return result
   return(m_innerobj.m_inneriterationscount);
  }
//+------------------------------------------------------------------+
//| Changing the value of the variable inneriterationscount          |
//+------------------------------------------------------------------+
void CMinQPReportShell::SetInnerIterationsCount(const int i)
  {
//--- change value
   m_innerobj.m_inneriterationscount=i;
  }
//+------------------------------------------------------------------+
//| Returns the value of the variable outeriterationscount           |
//+------------------------------------------------------------------+
int CMinQPReportShell::GetOuterIterationsCount(void)
  {
//--- return result
   return(m_innerobj.m_outeriterationscount);
  }
//+------------------------------------------------------------------+
//| Changing the value of the variable outeriterationscount          |
//+------------------------------------------------------------------+
void CMinQPReportShell::SetOuterIterationsCount(const int i)
  {
//--- change value
   m_innerobj.m_outeriterationscount=i;
  }
//+------------------------------------------------------------------+
//| Returns the value of the variable nmv                            |
//+------------------------------------------------------------------+
int CMinQPReportShell::GetNMV(void)
  {
//--- return result
   return(m_innerobj.m_nmv);
  }
//+------------------------------------------------------------------+
//| Changing the value of the variable nmv                           |
//+------------------------------------------------------------------+
void CMinQPReportShell::SetNMV(const int i)
  {
//--- change value
   m_innerobj.m_nmv=i;
  }
//+------------------------------------------------------------------+
//| Returns the value of the variable ncholesky                      |
//+------------------------------------------------------------------+
int CMinQPReportShell::GetNCholesky(void)
  {
//--- return result
   return(m_innerobj.m_ncholesky);
  }
//+------------------------------------------------------------------+
//| Changing the value of the variable ncholesky                     |
//+------------------------------------------------------------------+
void CMinQPReportShell::SetNCholesky(const int i)
  {
//--- change value
   m_innerobj.m_ncholesky=i;
  }
//+------------------------------------------------------------------+
//| Returns the value of the variable terminationtype                |
//+------------------------------------------------------------------+
int CMinQPReportShell::GetTerminationType(void)
  {
//--- return result
   return(m_innerobj.m_terminationtype);
  }
//+------------------------------------------------------------------+
//| Changing the value of the variable terminationtype               |
//+------------------------------------------------------------------+
void CMinQPReportShell::SetTerminationType(const int i)
  {
//--- change value
   m_innerobj.m_terminationtype=i;
  }
//+------------------------------------------------------------------+
//| Return object of class                                           |
//+------------------------------------------------------------------+
CMinQPReport *CMinQPReportShell::GetInnerObj(void)
  {
//--- return result
   return(GetPointer(m_innerobj));
  }
//+------------------------------------------------------------------+
//| Constrained quadratic programming                                |
//+------------------------------------------------------------------+
class CMinQP
  {
private:
   //--- private methods
   static void       MinQPGrad(CMinQPState &state);
   static double     MinQPXTAX(CMinQPState &state,double &x[]);
public:
   //--- constructor, destructor
                     CMinQP(void);
                    ~CMinQP(void);
   //--- public methods
   static void       MinQPCreate(const int n,CMinQPState &state);
   static void       MinQPSetLinearTerm(CMinQPState &state,double &b[]);
   static void       MinQPSetQuadraticTerm(CMinQPState &state,CMatrixDouble &a,const bool isupper);
   static void       MinQPSetStartingPoint(CMinQPState &state,double &x[]);
   static void       MinQPSetOrigin(CMinQPState &state,double &xorigin[]);
   static void       MinQPSetAlgoCholesky(CMinQPState &state);
   static void       MinQPSetBC(CMinQPState &state,double &bndl[],double &bndu[]);
   static void       MinQPOptimize(CMinQPState &state);
   static void       MinQPResults(CMinQPState &state,double &x[],CMinQPReport &rep);
   static void       MinQPResultsBuf(CMinQPState &state,double &x[],CMinQPReport &rep);
   static void       MinQPSetLinearTermFast(CMinQPState &state,double &b[]);
   static void       MinQPSetQuadraticTermFast(CMinQPState &state,CMatrixDouble &a,const bool isupper,const double s);
   static void       MinQPRewriteDiagonal(CMinQPState &state,double &s[]);
   static void       MinQPSetStartingPointFast(CMinQPState &state,double &x[]);
   static void       MinQPSetOriginFast(CMinQPState &state,double &xorigin[]);
  };
//+------------------------------------------------------------------+
//| Constructor without parameters                                   |
//+------------------------------------------------------------------+
CMinQP::CMinQP(void)
  {

  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CMinQP::~CMinQP(void)
  {

  }
//+------------------------------------------------------------------+
//|                     CONSTRAINED QUADRATIC PROGRAMMING            |
//| The subroutine creates QP optimizer. After initial creation, it  |
//| contains default optimization problem with zero quadratic and    |
//| linear terms and no constraints. You should set quadratic/linear |
//| terms with calls to functions provided by MinQP subpackage.      |
//| INPUT PARAMETERS:                                                |
//|     N       -   problem size                                     |
//| OUTPUT PARAMETERS:                                               |
//|     State   -   optimizer with zero quadratic/linear terms       |
//|                 and no constraints                               |
//+------------------------------------------------------------------+
static void CMinQP::MinQPCreate(const int n,CMinQPState &state)
  {
//--- create a variable
   int i=0;
//--- check
   if(!CAp::Assert(n>=1,__FUNCTION__+": N<1"))
      return;
//--- initialize QP solver
   state.m_n=n;
   state.m_akind=-1;
   state.m_repterminationtype=0;
//--- allocation
   ArrayResizeAL(state.m_b,n);
   ArrayResizeAL(state.m_bndl,n);
   ArrayResizeAL(state.m_bndu,n);
   ArrayResizeAL(state.m_workbndl,n);
   ArrayResizeAL(state.m_workbndu,n);
   ArrayResizeAL(state.m_havebndl,n);
   ArrayResizeAL(state.m_havebndu,n);
   ArrayResizeAL(state.m_startx,n);
   ArrayResizeAL(state.m_xorigin,n);
   ArrayResizeAL(state.m_xc,n);
   ArrayResizeAL(state.m_gc,n);
//--- initialization
   for(i=0;i<=n-1;i++)
     {
      state.m_b[i]=0.0;
      state.m_workbndl[i]=CInfOrNaN::NegativeInfinity();
      state.m_workbndu[i]=CInfOrNaN::PositiveInfinity();
      state.m_havebndl[i]=false;
      state.m_havebndu[i]=false;
      state.m_startx[i]=0.0;
      state.m_xorigin[i]=0.0;
     }
   state.m_havex=false;
//--- function call
   MinQPSetAlgoCholesky(state);
  }
//+------------------------------------------------------------------+
//| This function sets linear term for QP solver.                    |
//| By default, linear term is zero.                                 |
//| INPUT PARAMETERS:                                                |
//|     State   -   structure which stores algorithm state           |
//|     B       -   linear term, array[N].                           |
//+------------------------------------------------------------------+
static void CMinQP::MinQPSetLinearTerm(CMinQPState &state,double &b[])
  {
//--- create a variable
   int n=0;
//--- initialization
   n=state.m_n;
//--- check
   if(!CAp::Assert(CAp::Len(b)>=n,__FUNCTION__+": Length(B)<N"))
      return;
//--- check
   if(!CAp::Assert(CApServ::IsFiniteVector(b,n),__FUNCTION__+": B contains infinite or NaN elements"))
      return;
//--- function call
   MinQPSetLinearTermFast(state,b);
  }
//+------------------------------------------------------------------+
//| This function sets quadratic term for QP solver.                 |
//| By default quadratic term is zero.                               |
//| IMPORTANT: this solver minimizes following  function:            |
//|     f(x) = 0.5*x'*A*x + b'*x.                                    |
//| Note that quadratic term has 0.5 before it. So if you want to    |
//| minimize                                                         |
//|     f(x) = x^2 + x                                               |
//| you should rewrite your problem as follows:                      |
//|     f(x) = 0.5*(2*x^2) + x                                       |
//| and your matrix A will be equal to [[2.0]], not to [[1.0]]       |
//| INPUT PARAMETERS:                                                |
//|     State   -   structure which stores algorithm state           |
//|     A       -   matrix, array[N,N]                               |
//|     IsUpper -   (optional) storage type:                         |
//|                 * if True, symmetric matrix A is given by its    |
//|                   upper triangle, and the lower triangle isn?t   |
//|                   used                                           |
//|                 * if False, symmetric matrix A is given by its   |
//|                   lower triangle, and the upper triangle isn?t   |
//|                   used                                           |
//|                 * if not given, both lower and upper triangles   |
//|                   must be filled.                                |
//+------------------------------------------------------------------+
static void CMinQP::MinQPSetQuadraticTerm(CMinQPState &state,CMatrixDouble &a,
                                          const bool isupper)
  {
//--- create a variable
   int n=0;
//--- initialization
   n=state.m_n;
//--- check
   if(!CAp::Assert(CAp::Rows(a)>=n,__FUNCTION__+": Rows(A)<N"))
      return;
//--- check
   if(!CAp::Assert(CAp::Cols(a)>=n,__FUNCTION__+": Cols(A)<N"))
      return;
//--- check
   if(!CAp::Assert(CApServ::IsFiniteRTrMatrix(a,n,isupper),__FUNCTION__+": A contains infinite or NaN elements"))
      return;
//--- function call
   MinQPSetQuadraticTermFast(state,a,isupper,0.0);
  }
//+------------------------------------------------------------------+
//| This function sets starting point for QP solver. It is useful to |
//| have good initial approximation to the solution, because it will |
//| increase speed of convergence and identification of active       |
//| constraints.                                                     |
//| INPUT PARAMETERS:                                                |
//|     State   -   structure which stores algorithm state           |
//|     X       -   starting point, array[N].                        |
//+------------------------------------------------------------------+
static void CMinQP::MinQPSetStartingPoint(CMinQPState &state,double &x[])
  {
//--- create a variable
   int n=0;
//--- initialization
   n=state.m_n;
//--- check
   if(!CAp::Assert(CAp::Len(x)>=n,__FUNCTION__+": Length(B)<N"))
      return;
//--- check
   if(!CAp::Assert(CApServ::IsFiniteVector(x,n),__FUNCTION__+": X contains infinite or NaN elements"))
      return;
//--- function call
   MinQPSetStartingPointFast(state,x);
  }
//+------------------------------------------------------------------+
//| This  function sets origin for QP solver. By default, following  |
//| QP program is solved:                                            |
//|     min(0.5*x'*A*x+b'*x)                                         |
//| This function allows to solve different problem:                 |
//|     min(0.5*(x-x_origin)'*A*(x-x_origin)+b'*(x-x_origin))        |
//| INPUT PARAMETERS:                                                |
//|     State   -   structure which stores algorithm state           |
//|     XOrigin -   origin, array[N].                                |
//+------------------------------------------------------------------+
static void CMinQP::MinQPSetOrigin(CMinQPState &state,double &xorigin[])
  {
//--- create a variable
   int n=0;
//--- initialization
   n=state.m_n;
//--- check
   if(!CAp::Assert(CAp::Len(xorigin)>=n,__FUNCTION__+": Length(B)<N"))
      return;
//--- check
   if(!CAp::Assert(CApServ::IsFiniteVector(xorigin,n),__FUNCTION__+": B contains infinite or NaN elements"))
      return;
//--- function call
   MinQPSetOriginFast(state,xorigin);
  }
//+------------------------------------------------------------------+
//| This function tells solver to use Cholesky-based algorithm.      |
//| Cholesky-based algorithm can be used when:                       |
//| * problem is convex                                              |
//| * there is no constraints or only boundary constraints are       |
//|   present                                                        |
//| This algorithm has O(N^3) complexity for unconstrained problem   |
//| and is up to several times slower on bound constrained problems  |
//| (these additional iterations are needed to identify active       |
//| constraints).                                                    |
//| INPUT PARAMETERS:                                                |
//|     State   -   structure which stores algorithm state           |
//+------------------------------------------------------------------+
static void CMinQP::MinQPSetAlgoCholesky(CMinQPState &state)
  {
//--- change value
   state.m_algokind=1;
  }
//+------------------------------------------------------------------+
//| This function sets boundary constraints for QP solver            |
//| Boundary constraints are inactive by default (after initial      |
//| creation). After being set, they are preserved until explicitly  |
//| turned off with another SetBC() call.                            |
//| INPUT PARAMETERS:                                                |
//|     State   -   structure stores algorithm state                 |
//|     BndL    -   lower bounds, array[N].                          |
//|                 If some (all) variables are unbounded, you may   |
//|                 specify very small number or -INF (latter is     |
//|                 recommended because it will allow solver to use  |
//|                 better algorithm).                               |
//|     BndU    -   upper bounds, array[N].                          |
//|                 If some (all) variables are unbounded, you may   |
//|                 specify very large number or +INF (latter is     |
//|                 recommended because it will allow solver to use  |
//|                 better algorithm).                               |
//| NOTE: it is possible to specify BndL[i]=BndU[i]. In this case    |
//| I-th variable will be "frozen" at X[i]=BndL[i]=BndU[i].          |
//+------------------------------------------------------------------+
static void CMinQP::MinQPSetBC(CMinQPState &state,double &bndl[],double &bndu[])
  {
//--- create variables
   int i=0;
   int n=0;
//--- initialization
   n=state.m_n;
//--- check
   if(!CAp::Assert(CAp::Len(bndl)>=n,__FUNCTION__+": Length(BndL)<N"))
      return;
//--- check
   if(!CAp::Assert(CAp::Len(bndu)>=n,__FUNCTION__+": Length(BndU)<N"))
      return;
//--- change values
   for(i=0;i<=n-1;i++)
     {
      //--- check
      if(!CAp::Assert(CMath::IsFinite(bndl[i]) || CInfOrNaN::IsNegativeInfinity(bndl[i]),__FUNCTION__+": BndL contains NAN or +INF"))
         return;
      //--- check
      if(!CAp::Assert(CMath::IsFinite(bndu[i]) || CInfOrNaN::IsPositiveInfinity(bndu[i]),__FUNCTION__+": BndU contains NAN or -INF"))
         return;
      //--- change values
      state.m_bndl[i]=bndl[i];
      state.m_havebndl[i]=CMath::IsFinite(bndl[i]);
      state.m_bndu[i]=bndu[i];
      state.m_havebndu[i]=CMath::IsFinite(bndu[i]);
     }
  }
//+------------------------------------------------------------------+
//| This function solves quadratic programming problem.              |
//| You should call it after setting solver options with             |
//| MinQPSet...() calls.                                             |
//| INPUT PARAMETERS:                                                |
//|     State   -   algorithm state                                  |
//| You should use MinQPResults() function to access results after   |
//| calls to this function.                                          |
//+------------------------------------------------------------------+
static void CMinQP::MinQPOptimize(CMinQPState &state)
  {
//--- create variables
   int    n=0;
   int    i=0;
   int    j=0;
   int    k=0;
   int    nbc=0;
   int    nlc=0;
   int    nactive=0;
   int    nfree=0;
   double f=0;
   double fprev=0;
   double v=0;
   bool   b;
   int    i_=0;
//--- initialization
   n=state.m_n;
   state.m_repterminationtype=-5;
   state.m_repinneriterationscount=0;
   state.m_repouteriterationscount=0;
   state.m_repncholesky=0;
   state.m_repnmv=0;
//--- check correctness of constraints
   for(i=0;i<=n-1;i++)
     {
      //--- check
      if(state.m_havebndl[i] && state.m_havebndu[i])
        {
         //--- check
         if(state.m_bndl[i]>state.m_bndu[i])
           {
            state.m_repterminationtype=-3;
            return;
           }
        }
     }
//--- count number of bound and linear constraints
   nbc=0;
   nlc=0;
   for(i=0;i<=n-1;i++)
     {
      //--- check
      if(state.m_havebndl[i])
         nbc=nbc+1;
      //--- check
      if(state.m_havebndu[i])
         nbc=nbc+1;
     }
//--- Our formulation of quadratic problem includes origin point,
//--- i.m_e. we have F(x-x_origin) which is minimized subject to
//--- constraints on x,instead of having simply F(x).
//--- Here we make transition from non-zero origin to zero one.
//--- In order to make such transition we have to:
//--- 1. subtract x_origin from x_start
//--- 2. modify constraints
//--- 3. solve problem
//--- 4. add x_origin to solution
//--- There is alternate solution - to modify quadratic function
//--- by expansion of multipliers containing (x-x_origin),but
//--- we prefer to modify constraints,because it is a) more precise
//--- and b) easier to to.
//--- Parts (1)-(2) are done here. After this block is over,
//--- we have:
//--- * XC,which stores shifted XStart (if we don't have XStart,
//---   value of XC will be ignored later)
//--- * WorkBndL,WorkBndU,which store modified boundary constraints.
   for(i=0;i<=n-1;i++)
     {
      state.m_xc[i]=state.m_startx[i]-state.m_xorigin[i];
      //--- check
      if(state.m_havebndl[i])
         state.m_workbndl[i]=state.m_bndl[i]-state.m_xorigin[i];
      //--- check
      if(state.m_havebndu[i])
         state.m_workbndu[i]=state.m_bndu[i]-state.m_xorigin[i];
     }
//--- modify starting point XC according to boundary constraints
   if(state.m_havex)
     {
      //--- We have starting point in XC,so we just have to bound it
      for(i=0;i<=n-1;i++)
        {
         //--- check
         if(state.m_havebndl[i])
           {
            //--- check
            if(state.m_xc[i]<state.m_workbndl[i])
               state.m_xc[i]=state.m_workbndl[i];
           }
         //--- check
         if(state.m_havebndu[i])
           {
            //--- check
            if(state.m_xc[i]>state.m_workbndu[i])
               state.m_xc[i]=state.m_workbndu[i];
           }
        }
     }
   else
     {
      //--- We don't have starting point,so we deduce it from
      //--- constraints (if they are present).
      //--- NOTE: XC contains some meaningless values from previous block
      //--- which are ignored by code below.
      for(i=0;i<=n-1;i++)
        {
         //--- check
         if(state.m_havebndl[i] && state.m_havebndu[i])
           {
            state.m_xc[i]=0.5*(state.m_workbndl[i]+state.m_workbndu[i]);
            //--- check
            if(state.m_xc[i]<state.m_workbndl[i])
               state.m_xc[i]=state.m_workbndl[i];
            //--- check
            if(state.m_xc[i]>state.m_workbndu[i])
               state.m_xc[i]=state.m_workbndu[i];
            //--- continue iteration
            continue;
           }
         //--- check
         if(state.m_havebndl[i])
           {
            state.m_xc[i]=state.m_workbndl[i];
            continue;
           }
         //--- check
         if(state.m_havebndu[i])
           {
            state.m_xc[i]=state.m_workbndu[i];
            continue;
           }
         state.m_xc[i]=0;
        }
     }
//--- Select algo
   if(state.m_algokind==1 && state.m_akind==0)
     {
      //--- Cholesky-based algorithm for dense bound constrained problems.
      //--- This algorithm exists in two variants:
      //--- * unconstrained one,which can solve problem using only one NxN
      //---   double matrix
      //--- * bound constrained one,which needs two NxN matrices
      //--- We will try to solve problem using unconstrained algorithm,
      //--- and will use bound constrained version only when constraints
      //--- are actually present
      if(nbc==0 && nlc==0)
        {
         //--- "Simple" unconstrained version
         CApServ::RVectorSetLengthAtLeast(state.m_tmp0,n);
         //--- function call
         CApServ::RVectorSetLengthAtLeast(state.m_bufb,n);
         //--- calculation
         state.m_densea[0].Set(0,state.m_diaga[0]);
         for(k=1;k<=n-1;k++)
           {
            for(i_=0;i_<=k-1;i_++)
               state.m_densea[i_].Set(k,state.m_densea[k][i_]);
            state.m_densea[k].Set(k,state.m_diaga[k]);
           }
         //--- change values
         for(i_=0;i_<=n-1;i_++)
            state.m_bufb[i_]=state.m_b[i_];
         state.m_repncholesky=1;
         //--- check
         if(!CTrFac::SPDMatrixCholeskyRec(state.m_densea,0,n,true,state.m_tmp0))
           {
            state.m_repterminationtype=-5;
            return;
           }
         //--- function call
         CFbls::FblsCholeskySolve(state.m_densea,1.0,n,true,state.m_bufb,state.m_tmp0);
         for(i_=0;i_<=n-1;i_++)
            state.m_xc[i_]=-state.m_bufb[i_];
         for(i_=0;i_<=n-1;i_++)
            state.m_xc[i_]=state.m_xc[i_]+state.m_xorigin[i_];
         //--- change values
         state.m_repouteriterationscount=1;
         state.m_repterminationtype=4;
         //--- exit the function
         return;
        }
      //--- General bound constrained algo
      CApServ::RMatrixSetLengthAtLeast(state.m_bufa,n,n);
      //--- function call
      CApServ::RVectorSetLengthAtLeast(state.m_bufb,n);
      //--- function call
      CApServ::RVectorSetLengthAtLeast(state.m_bufx,n);
      //--- function call
      CApServ::IVectorSetLengthAtLeast(state.m_activeconstraints,n);
      //--- function call
      CApServ::IVectorSetLengthAtLeast(state.m_prevactiveconstraints,n);
      //--- function call
      CApServ::RVectorSetLengthAtLeast(state.m_tmp0,n);
      //--- Prepare constraints vectors:
      //--- * ActiveConstraints - constraints active at current step
      //--- * PrevActiveConstraints - constraints which were active at previous step
      //--- Elements of constraints vectors can be:
      //--- *  0 - inactive
      //--- *  1 - active
      //--- * -1 - undefined (used to initialize PrevActiveConstraints before first iteration)
      for(i=0;i<=n-1;i++)
         state.m_prevactiveconstraints[i]=-1;
      //--- Main cycle
      fprev=CMath::m_maxrealnumber;
      while(true)
        {
         //--- * calculate gradient at XC
         //--- * determine active constraints
         //--- * break if there is no free variables or
         //---   there were no changes in the list of active constraints
         MinQPGrad(state);
         nactive=0;
         for(i=0;i<=n-1;i++)
           {
            state.m_activeconstraints[i]=0;
            //--- check
            if(state.m_havebndl[i])
              {
               //--- check
               if(state.m_xc[i]<=state.m_workbndl[i] && state.m_gc[i]>=0.0)
                  state.m_activeconstraints[i]=1;
              }
            //--- check
            if(state.m_havebndu[i])
              {
               //--- check
               if(state.m_xc[i]>=state.m_workbndu[i] && state.m_gc[i]<=0.0)
                  state.m_activeconstraints[i]=1;
              }
            //--- check
            if(state.m_havebndl[i] && state.m_havebndu[i])
              {
               //--- check
               if(state.m_workbndl[i]==state.m_workbndu[i])
                  state.m_activeconstraints[i]=1;
              }
            //--- check
            if(state.m_activeconstraints[i]>0)
               nactive=nactive+1;
           }
         nfree=n-nactive;
         //--- check
         if(nfree==0)
            break;
         b=false;
         for(i=0;i<=n-1;i++)
           {
            //--- check
            if(state.m_activeconstraints[i]!=state.m_prevactiveconstraints[i])
               b=true;
           }
         //--- check
         if(!b)
            break;
         //--- * copy A,B and X to buffer
         //--- * rearrange BufA,BufB and BufX,in such way that active variables come first,
         //---   inactive are moved to the tail. We use sorting subroutine
         //---   to solve this problem.
         state.m_bufa[0].Set(0,state.m_diaga[0]);
         for(k=1;k<=n-1;k++)
           {
            for(i_=0;i_<=k-1;i_++)
               state.m_bufa[k].Set(i_,state.m_densea[k][i_]);
            for(i_=0;i_<=k-1;i_++)
               state.m_bufa[i_].Set(k,state.m_densea[k][i_]);
            state.m_bufa[k].Set(k,state.m_diaga[k]);
           }
         //--- change values
         for(i_=0;i_<=n-1;i_++)
            state.m_bufb[i_]=state.m_b[i_];
         for(i_=0;i_<=n-1;i_++)
            state.m_bufx[i_]=state.m_xc[i_];
         for(i=0;i<=n-1;i++)
            state.m_tmp0[i]=state.m_activeconstraints[i];
         //--- function call
         CTSort::TagSortBuf(state.m_tmp0,n,state.m_itmp0,state.m_p2,state.m_buf);
         for(k=0;k<=n-1;k++)
           {
            //--- check
            if(state.m_p2[k]!=k)
              {
               //--- swap
               v=state.m_bufb[k];
               state.m_bufb[k]=state.m_bufb[state.m_p2[k]];
               state.m_bufb[state.m_p2[k]]=v;
               v=state.m_bufx[k];
               state.m_bufx[k]=state.m_bufx[state.m_p2[k]];
               state.m_bufx[state.m_p2[k]]=v;
              }
           }
         for(i=0;i<=n-1;i++)
           {
            for(i_=0;i_<=n-1;i_++)
               state.m_tmp0[i_]=state.m_bufa[i][i_];
            for(k=0;k<=n-1;k++)
              {
               //--- check
               if(state.m_p2[k]!=k)
                 {
                  //--- swap
                  v=state.m_tmp0[k];
                  state.m_tmp0[k]=state.m_tmp0[state.m_p2[k]];
                  state.m_tmp0[state.m_p2[k]]=v;
                 }
              }
            for(i_=0;i_<=n-1;i_++)
               state.m_bufa[i].Set(i_,state.m_tmp0[i_]);
           }
         for(i=0;i<=n-1;i++)
           {
            //--- check
            if(state.m_p2[i]!=i)
              {
               for(i_=0;i_<=n-1;i_++)
                  state.m_tmp0[i_]=state.m_bufa[i][i_];
               for(i_=0;i_<=n-1;i_++)
                  state.m_bufa[i].Set(i_,state.m_bufa[state.m_p2[i]][i_]);
               for(i_=0;i_<=n-1;i_++)
                  state.m_bufa[state.m_p2[i]].Set(i_,state.m_tmp0[i_]);
              }
           }
         //--- Now we have A and B in BufA and BufB,variables are rearranged
         //--- into two groups: Xf - free variables,Xc - active (fixed) variables,
         //--- and our quadratic problem can be written as
         //---                         ( Af  Ac  )   ( Xf )                 ( Xf )
         //--- F(X)=0.5* ( Xf' Xc' ) * (         ) * (    ) + ( Bf' Bc' ) * (    )
         //---                         ( Ac' Acc )   ( Xc )                 ( Xc )
         //--- we want to convert to the optimization with respect to Xf,
         //--- treating Xc as constant term. After expansion of expression above
         //--- we get
         //--- F(Xf)=0.5*Xf'*Af*Xf + (Bf+Ac*Xc)'*Xf + 0.5*Xc'*Acc*Xc
         //--- We will update BufB using this expression and calculate
         //--- constant term.
         CAblas::RMatrixMVect(nfree,nactive,state.m_bufa,0,nfree,0,state.m_bufx,nfree,state.m_tmp0,0);
         for(i_=0;i_<=nfree-1;i_++)
            state.m_bufb[i_]=state.m_bufb[i_]+state.m_tmp0[i_];
         state.m_constterm=0.0;
         for(i=nfree;i<=n-1;i++)
           {
            state.m_constterm=state.m_constterm+0.5*state.m_bufx[i]*state.m_bufa[i][i]*state.m_bufx[i];
            for(j=i+1;j<=n-1;j++)
               state.m_constterm=state.m_constterm+state.m_bufx[i]*state.m_bufa[i][j]*state.m_bufx[j];
           }
         //--- Now we are ready to minimize F(Xf)...
         state.m_repncholesky=state.m_repncholesky+1;
         //--- check
         if(!CTrFac::SPDMatrixCholeskyRec(state.m_bufa,0,nfree,true,state.m_tmp0))
           {
            state.m_repterminationtype=-5;
            return;
           }
         //--- function call
         CFbls::FblsCholeskySolve(state.m_bufa,1.0,nfree,true,state.m_bufb,state.m_tmp0);
         for(i_=0;i_<=nfree-1;i_++)
            state.m_bufx[i_]=-state.m_bufb[i_];
         //--- ...m_and to copy results back to XC.
         //--- It is done in several steps:
         //--- * original order of variables is restored
         //--- * result is copied back to XC
         //--- * XC is bounded with respect to bound constraints
         for(k=n-1;k>=0;k--)
           {
            //--- check
            if(state.m_p2[k]!=k)
              {
               v=state.m_bufx[k];
               state.m_bufx[k]=state.m_bufx[state.m_p2[k]];
               state.m_bufx[state.m_p2[k]]=v;
              }
           }
         for(i_=0;i_<=n-1;i_++)
            state.m_xc[i_]=state.m_bufx[i_];
         for(i=0;i<=n-1;i++)
           {
            //--- check
            if(state.m_havebndl[i])
              {
               //--- check
               if(state.m_xc[i]<state.m_workbndl[i])
                  state.m_xc[i]=state.m_workbndl[i];
              }
            //--- check
            if(state.m_havebndu[i])
              {
               //--- check
               if(state.m_xc[i]>state.m_workbndu[i])
                  state.m_xc[i]=state.m_workbndu[i];
              }
           }
         //--- Calculate F,compare it with FPrev.
         //--- Break if F>=FPrev
         //--- (sometimes possible at extremum due to numerical noise).
         f=0.0;
         for(i_=0;i_<=n-1;i_++)
            f+=state.m_b[i_]*state.m_xc[i_];
         f=f+MinQPXTAX(state,state.m_xc);
         //--- check
         if(f>=fprev)
            break;
         fprev=f;
         //--- Update PrevActiveConstraints
         for(i=0;i<=n-1;i++)
            state.m_prevactiveconstraints[i]=state.m_activeconstraints[i];
         //--- Update report-related fields
         state.m_repouteriterationscount=state.m_repouteriterationscount+1;
        }
      //--- change values
      state.m_repterminationtype=4;
      for(i_=0;i_<=n-1;i_++)
         state.m_xc[i_]=state.m_xc[i_]+state.m_xorigin[i_];
      //--- exit the function
      return;
     }
  }
//+------------------------------------------------------------------+
//| QP solver results                                                |
//| INPUT PARAMETERS:                                                |
//|     State   -   algorithm state                                  |
//| OUTPUT PARAMETERS:                                               |
//|     X       -   array[0..N-1], solution                          |
//|     Rep     -   optimization report. You should check Rep.       |
//|                 TerminationType, which contains completion code, |
//|                 and you may check another fields which contain   |
//|                 another information about algorithm functioning. |
//+------------------------------------------------------------------+
static void CMinQP::MinQPResults(CMinQPState &state,double &x[],CMinQPReport &rep)
  {
//--- reset memory
   ArrayResizeAL(x,0);
//--- function call
   MinQPResultsBuf(state,x,rep);
  }
//+------------------------------------------------------------------+
//| QP results                                                       |
//| Buffered implementation of MinQPResults() which uses             |
//| pre-allocated  buffer to store X[]. If buffer size is too small, |
//| it resizes buffer. It is intended to be used in the inner cycles |
//| of performance critical algorithms where array reallocation      |
//| penalty is too large to be ignored.                              |
//+------------------------------------------------------------------+
static void CMinQP::MinQPResultsBuf(CMinQPState &state,double &x[],
                                    CMinQPReport &rep)
  {
//--- create a variable
   int i_=0;
//--- check
   if(CAp::Len(x)<state.m_n)
      ArrayResizeAL(x,state.m_n);
//--- copy
   for(i_=0;i_<=state.m_n-1;i_++)
      x[i_]=state.m_xc[i_];
//--- change values
   rep.m_inneriterationscount=state.m_repinneriterationscount;
   rep.m_outeriterationscount=state.m_repouteriterationscount;
   rep.m_nmv=state.m_repnmv;
   rep.m_terminationtype=state.m_repterminationtype;
  }
//+------------------------------------------------------------------+
//| Fast version of MinQPSetLinearTerm(), which doesn't check its    |
//| arguments. For internal use only.                                |
//+------------------------------------------------------------------+
static void CMinQP::MinQPSetLinearTermFast(CMinQPState &state,double &b[])
  {
//--- create variables
   int n=0;
   int i_=0;
//--- initialization
   n=state.m_n;
   for(i_=0;i_<=n-1;i_++)
      state.m_b[i_]=b[i_];
  }
//+------------------------------------------------------------------+
//| Fast version of MinQPSetQuadraticTerm(), which doesn't check its |
//| arguments.                                                       |
//| It accepts additional parameter - shift S, which allows to       |
//| "shift" matrix A by adding s*I to A. S must be positive (although|
//| it is not checked).                                              |
//| For internal use only.                                           |
//+------------------------------------------------------------------+
static void CMinQP::MinQPSetQuadraticTermFast(CMinQPState &state,CMatrixDouble &a,
                                              const bool isupper,const double s)
  {
//--- create variables
   int k=0;
   int n=0;
   int i_=0;
//--- We store off-diagonal part of A in the lower triangle of DenseA.
//--- Diagonal elements of A are stored in the DiagA.
//--- Diagonal of DenseA and uppper triangle are used as temporaries.
//--- Why such complex storage? Because it:
//--- 1. allows us to easily recover from exceptions (lower triangle
//---    is unmodified during execution as well as DiagA,and on entry
//---    we will always find unmodified matrix)
//--- 2. allows us to make Cholesky decomposition in the upper triangle
//---    of DenseA or to do other SPD-related operations.
   n=state.m_n;
   state.m_akind=0;
//--- function call
   CApServ::RMatrixSetLengthAtLeast(state.m_densea,n,n);
//--- function call
   CApServ::RVectorSetLengthAtLeast(state.m_diaga,n);
//--- check
   if(isupper)
     {
      for(k=0;k<=n-2;k++)
        {
         //--- change values
         state.m_diaga[k]=a[k][k]+s;
         for(i_=k+1;i_<=n-1;i_++)
            state.m_densea[i_].Set(k,a[k][i_]);
        }
      state.m_diaga[n-1]=a[n-1][n-1]+s;
     }
   else
     {
      state.m_diaga[0]=a[0][0]+s;
      for(k=1;k<=n-1;k++)
        {
         //--- change values
         for(i_=0;i_<=k-1;i_++)
            state.m_densea[k].Set(i_,a[k][i_]);
         state.m_diaga[k]=a[k][k]+s;
        }
     }
  }
//+------------------------------------------------------------------+
//| Interna lfunction which allows to rewrite diagonal of quadratic  |
//| term. For internal use only.                                     |
//| This function can be used only when you have dense A and already |
//| made MinQPSetQuadraticTerm(Fast) call.                           |
//+------------------------------------------------------------------+
static void CMinQP::MinQPRewriteDiagonal(CMinQPState &state,double &s[])
  {
//--- create variables
   int k=0;
   int n=0;
//--- check
   if(!CAp::Assert(state.m_akind==0,__FUNCTION__+": internal error (AKind<>0)"))
      return;
//--- initialization
   n=state.m_n;
   for(k=0;k<=n-1;k++)
      state.m_diaga[k]=s[k];
  }
//+------------------------------------------------------------------+
//| Fast version of MinQPSetStartingPoint(), which doesn't check its |
//| arguments. For internal use only.                                |
//+------------------------------------------------------------------+
static void CMinQP::MinQPSetStartingPointFast(CMinQPState &state,double &x[])
  {
//--- create variables
   int n=0;
   int i_=0;
//--- initialization
   n=state.m_n;
   for(i_=0;i_<=n-1;i_++)
      state.m_startx[i_]=x[i_];
   state.m_havex=true;
  }
//+------------------------------------------------------------------+
//| Fast version of MinQPSetOrigin(), which doesn't check its        |
//| arguments. For internal use only.                                |
//+------------------------------------------------------------------+
static void CMinQP::MinQPSetOriginFast(CMinQPState &state,double &xorigin[])
  {
//--- create variables
   int n=0;
   int i_=0;
//--- initialization
   n=state.m_n;
   for(i_=0;i_<=n-1;i_++)
      state.m_xorigin[i_]=xorigin[i_];
  }
//+------------------------------------------------------------------+
//| This function calculates gradient of quadratic function at XC and|
//| stores it in the GC.                                             |
//+------------------------------------------------------------------+
static void CMinQP::MinQPGrad(CMinQPState &state)
  {
//--- create variables
   int    n=0;
   int    i=0;
   double v=0;
   int    i_=0;
//--- initialization
   n=state.m_n;
//--- check
   if(!CAp::Assert(state.m_akind==-1||state.m_akind==0,__FUNCTION__+": internal error"))
      return;
//--- zero A
   if(state.m_akind==-1)
     {
      for(i_=0;i_<=n-1;i_++)
         state.m_gc[i_]=state.m_b[i_];
      //--- exit the function
      return;
     }
//--- dense A
   if(state.m_akind==0)
     {
      for(i_=0;i_<=n-1;i_++)
         state.m_gc[i_]=state.m_b[i_];
      state.m_gc[0]=state.m_gc[0]+state.m_diaga[0]*state.m_xc[0];
      //--- calculation
      for(i=1;i<=n-1;i++)
        {
         v=0.0;
         for(i_=0;i_<=i-1;i_++)
            v+=state.m_densea[i][i_]*state.m_xc[i_];
         state.m_gc[i]=state.m_gc[i]+v+state.m_diaga[i]*state.m_xc[i];
         v=state.m_xc[i];
         //--- change values
         for(i_=0;i_<=i-1;i_++)
            state.m_gc[i_]=state.m_gc[i_]+v*state.m_densea[i][i_];
        }
      //--- exit the function
      return;
     }
  }
//+------------------------------------------------------------------+
//| This function calculates x'*A*x for given X.                     |
//+------------------------------------------------------------------+
static double CMinQP::MinQPXTAX(CMinQPState &state,double &x[])
  {
//--- create variables
   double result=0;
   int    n=0;
   int    i=0;
   int    j=0;
//--- initialization
   n=state.m_n;
//--- check
   if(!CAp::Assert(state.m_akind==-1 || state.m_akind==0,__FUNCTION__+": internal error"))
      return(EMPTY_VALUE);
   result=0;
//--- zero A
   if(state.m_akind==-1)
      return(0.0);
//--- dense A
   if(state.m_akind==0)
     {
      result=0;
      for(i=0;i<=n-1;i++)
        {
         for(j=0;j<=i-1;j++)
            result=result+state.m_densea[i][j]*x[i]*x[j];
         //--- get result
         result=result+0.5*state.m_diaga[i]*CMath::Sqr(x[i]);
        }
      //--- return result
      return(result);
     }
//--- return result
   return(result);
  }
//+------------------------------------------------------------------+
//| Levenberg-Marquardt optimizer.                                   |
//| This structure should be created using one of the                |
//| MinLMCreate() functions. You should not access its fields        |
//| directly; use ALGLIB functions to work with it.                  |
//+------------------------------------------------------------------+
class CMinLMState
  {
public:
   //--- variables
   int               m_n;
   int               m_m;
   double            m_diffstep;
   double            m_epsg;
   double            m_epsf;
   double            m_epsx;
   int               m_maxits;
   bool              m_xrep;
   double            m_stpmax;
   int               m_maxmodelage;
   bool              m_makeadditers;
   double            m_f;
   bool              m_needf;
   bool              m_needfg;
   bool              m_needfgh;
   bool              m_needfij;
   bool              m_needfi;
   bool              m_xupdated;
   int               m_algomode;
   bool              m_hasf;
   bool              m_hasfi;
   bool              m_hasg;
   double            m_fbase;
   double            m_lambdav;
   double            m_nu;
   int               m_modelage;
   bool              m_deltaxready;
   bool              m_deltafready;
   int               m_repiterationscount;
   int               m_repterminationtype;
   int               m_repnfunc;
   int               m_repnjac;
   int               m_repngrad;
   int               m_repnhess;
   int               m_repncholesky;
   RCommState        m_rstate;
   double            m_actualdecrease;
   double            m_predicteddecrease;
   double            m_xm1;
   double            m_xp1;
   CMinLBFGSState    m_internalstate;
   CMinLBFGSReport   m_internalrep;
   CMinQPState       m_qpstate;
   CMinQPReport      m_qprep;
   //--- arrays
   double            m_x[];
   double            m_fi[];
   double            m_g[];
   double            m_xbase[];
   double            m_fibase[];
   double            m_gbase[];
   double            m_bndl[];
   double            m_bndu[];
   bool              m_havebndl[];
   bool              m_havebndu[];
   double            m_s[];
   double            m_xdir[];
   double            m_deltax[];
   double            m_deltaf[];
   double            m_choleskybuf[];
   double            m_tmp0[];
   double            m_fm1[];
   double            m_fp1[];
   //--- matrix
   CMatrixDouble     m_j;
   CMatrixDouble     m_h;
   CMatrixDouble     m_quadraticmodel;
   //--- constructor, destructor
                     CMinLMState(void);
                    ~CMinLMState(void);
   //--- copy
   void              Copy(CMinLMState &obj);
  };
//+------------------------------------------------------------------+
//| Constructor without parameters                                   |
//+------------------------------------------------------------------+
CMinLMState::CMinLMState(void)
  {

  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CMinLMState::~CMinLMState(void)
  {

  }
//+------------------------------------------------------------------+
//| Copy                                                             |
//+------------------------------------------------------------------+
void CMinLMState::Copy(CMinLMState &obj)
  {
//--- copy variables
   m_n=obj.m_n;
   m_m=obj.m_m;
   m_diffstep=obj.m_diffstep;
   m_epsg=obj.m_epsg;
   m_epsf=obj.m_epsf;
   m_epsx=obj.m_epsx;
   m_maxits=obj.m_maxits;
   m_xrep=obj.m_xrep;
   m_stpmax=obj.m_stpmax;
   m_maxmodelage=obj.m_maxmodelage;
   m_makeadditers=obj.m_makeadditers;
   m_f=obj.m_f;
   m_needf=obj.m_needf;
   m_needfg=obj.m_needfg;
   m_needfgh=obj.m_needfgh;
   m_needfij=obj.m_needfij;
   m_needfi=obj.m_needfi;
   m_xupdated=obj.m_xupdated;
   m_algomode=obj.m_algomode;
   m_hasf=obj.m_hasf;
   m_hasfi=obj.m_hasfi;
   m_hasg=obj.m_hasg;
   m_fbase=obj.m_fbase;
   m_lambdav=obj.m_lambdav;
   m_nu=obj.m_nu;
   m_modelage=obj.m_modelage;
   m_deltaxready=obj.m_deltaxready;
   m_deltafready=obj.m_deltafready;
   m_repiterationscount=obj.m_repiterationscount;
   m_repterminationtype=obj.m_repterminationtype;
   m_repnfunc=obj.m_repnfunc;
   m_repnjac=obj.m_repnjac;
   m_repngrad=obj.m_repngrad;
   m_repnhess=obj.m_repnhess;
   m_repncholesky=obj.m_repncholesky;
   m_actualdecrease=obj.m_actualdecrease;
   m_predicteddecrease=obj.m_predicteddecrease;
   m_xm1=obj.m_xm1;
   m_xp1=obj.m_xp1;
   m_rstate.Copy(obj.m_rstate);
   m_internalstate.Copy(obj.m_internalstate);
   m_internalrep.Copy(obj.m_internalrep);
   m_qpstate.Copy(obj.m_qpstate);
   m_qprep.Copy(obj.m_qprep);
//--- copy arrays
   ArrayCopy(m_x,obj.m_x);
   ArrayCopy(m_fi,obj.m_fi);
   ArrayCopy(m_g,obj.m_g);
   ArrayCopy(m_xbase,obj.m_xbase);
   ArrayCopy(m_fibase,obj.m_fibase);
   ArrayCopy(m_gbase,obj.m_gbase);
   ArrayCopy(m_bndl,obj.m_bndl);
   ArrayCopy(m_bndu,obj.m_bndu);
   ArrayCopy(m_havebndl,obj.m_havebndl);
   ArrayCopy(m_havebndu,obj.m_havebndu);
   ArrayCopy(m_s,obj.m_s);
   ArrayCopy(m_xdir,obj.m_xdir);
   ArrayCopy(m_deltax,obj.m_deltax);
   ArrayCopy(m_deltaf,obj.m_deltaf);
   ArrayCopy(m_choleskybuf,obj.m_choleskybuf);
   ArrayCopy(m_tmp0,obj.m_tmp0);
   ArrayCopy(m_fm1,obj.m_fm1);
   ArrayCopy(m_fp1,obj.m_fp1);
//--- copy matrix
   m_j=obj.m_j;
   m_h=obj.m_h;
   m_quadraticmodel=obj.m_quadraticmodel;
  }
//+------------------------------------------------------------------+
//| Levenberg-Marquardt optimizer.                                   |
//| This structure should be created using one of the                |
//| MinLMCreate() functions. You should not access its fields        |
//| directly; use ALGLIB functions to work with it.                  |
//+------------------------------------------------------------------+
class CMinLMStateShell
  {
private:
   CMinLMState       m_innerobj;
public:
   //--- constructors, destructor
                     CMinLMStateShell(void);
                     CMinLMStateShell(CMinLMState &obj);
                    ~CMinLMStateShell(void);
   //--- methods
   bool              GetNeedF(void);
   void              SetNeedF(const bool b);
   bool              GetNeedFG(void);
   void              SetNeedFG(const bool b);
   bool              GetNeedFGH(void);
   void              SetNeedFGH(const bool b);
   bool              GetNeedFI(void);
   void              SetNeedFI(const bool b);
   bool              GetNeedFIJ(void);
   void              SetNeedFIJ(const bool b);
   bool              GetXUpdated(void);
   void              SetXUpdated(const bool b);
   double            GetF(void);
   void              SetF(const double d);
   CMinLMState      *GetInnerObj(void);
  };
//+------------------------------------------------------------------+
//| Constructor without parameters                                   |
//+------------------------------------------------------------------+
CMinLMStateShell::CMinLMStateShell(void)
  {

  }
//+------------------------------------------------------------------+
//| Copy constructor                                                 |
//+------------------------------------------------------------------+
CMinLMStateShell::CMinLMStateShell(CMinLMState &obj)
  {
//--- copy
   m_innerobj.Copy(obj);
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CMinLMStateShell::~CMinLMStateShell(void)
  {

  }
//+------------------------------------------------------------------+
//| Returns the value of the variable needf                          |
//+------------------------------------------------------------------+
bool CMinLMStateShell::GetNeedF(void)
  {
//--- return result
   return(m_innerobj.m_needf);
  }
//+------------------------------------------------------------------+
//| Changing the value of the variable needf                         |
//+------------------------------------------------------------------+
void CMinLMStateShell::SetNeedF(const bool b)
  {
//--- change value
   m_innerobj.m_needf=b;
  }
//+------------------------------------------------------------------+
//| Returns the value of the variable needfg                         |
//+------------------------------------------------------------------+
bool CMinLMStateShell::GetNeedFG(void)
  {
//--- return result
   return(m_innerobj.m_needfg);
  }
//+------------------------------------------------------------------+
//| Changing the value of the variable needfg                        |
//+------------------------------------------------------------------+
void CMinLMStateShell::SetNeedFG(const bool b)
  {
//--- change value
   m_innerobj.m_needfg=b;
  }
//+------------------------------------------------------------------+
//| Returns the value of the variable needfgh                        |
//+------------------------------------------------------------------+
bool CMinLMStateShell::GetNeedFGH(void)
  {
//--- return result
   return(m_innerobj.m_needfgh);
  }
//+------------------------------------------------------------------+
//| Changing the value of the variable needfgh                       |
//+------------------------------------------------------------------+
void CMinLMStateShell::SetNeedFGH(const bool b)
  {
//--- change value
   m_innerobj.m_needfgh=b;
  }
//+------------------------------------------------------------------+
//| Returns the value of the variable needfi                         |
//+------------------------------------------------------------------+
bool CMinLMStateShell::GetNeedFI(void)
  {
//--- return result
   return(m_innerobj.m_needfi);
  }
//+------------------------------------------------------------------+
//| Changing the value of the variable needfi                        |
//+------------------------------------------------------------------+
void CMinLMStateShell::SetNeedFI(const bool b)
  {
//--- change value
   m_innerobj.m_needfi=b;
  }
//+------------------------------------------------------------------+
//| Returns the value of the variable needfij                        |
//+------------------------------------------------------------------+
bool CMinLMStateShell::GetNeedFIJ(void)
  {
//--- return result
   return(m_innerobj.m_needfij);
  }
//+------------------------------------------------------------------+
//| Changing the value of the variable needfij                       |
//+------------------------------------------------------------------+
void CMinLMStateShell::SetNeedFIJ(const bool b)
  {
//--- change value
   m_innerobj.m_needfij=b;
  }
//+------------------------------------------------------------------+
//| Returns the value of the variable xupdated                       |
//+------------------------------------------------------------------+
bool CMinLMStateShell::GetXUpdated(void)
  {
//--- return result
   return(m_innerobj.m_xupdated);
  }
//+------------------------------------------------------------------+
//| Changing the value of the variable xupdated                      |
//+------------------------------------------------------------------+
void CMinLMStateShell::SetXUpdated(const bool b)
  {
//--- change value
   m_innerobj.m_xupdated=b;
  }
//+------------------------------------------------------------------+
//| Returns the value of the variable f                              |
//+------------------------------------------------------------------+
double CMinLMStateShell::GetF(void)
  {
//--- return result
   return(m_innerobj.m_f);
  }
//+------------------------------------------------------------------+
//| Changing the value of the variable f                             |
//+------------------------------------------------------------------+
void CMinLMStateShell::SetF(const double d)
  {
//--- change value
   m_innerobj.m_f=d;
  }
//+------------------------------------------------------------------+
//| Return object of class                                           |
//+------------------------------------------------------------------+
CMinLMState *CMinLMStateShell::GetInnerObj(void)
  {
//--- return result
   return(GetPointer(m_innerobj));
  }
//+------------------------------------------------------------------+
//| Optimization report, filled by MinLMResults() function           |
//| FIELDS:                                                          |
//| * TerminationType, completetion code:                            |
//|     * -9    derivative correctness check failed;                 |
//|             see Rep.WrongNum, Rep.WrongI, Rep.WrongJ for         |
//|             more information.                                    |
//|     *  1    relative function improvement is no more than        |
//|             EpsF.                                                |
//|     *  2    relative step is no more than EpsX.                  |
//|     *  4    gradient is no more than EpsG.                       |
//|     *  5    MaxIts steps was taken                               |
//|     *  7    stopping conditions are too stringent,               |
//|             further improvement is impossible                    |
//| * IterationsCount, contains iterations count                     |
//| * NFunc, number of function calculations                         |
//| * NJac, number of Jacobi matrix calculations                     |
//| * NGrad, number of gradient calculations                         |
//| * NHess, number of Hessian calculations                          |
//| * NCholesky, number of Cholesky decomposition calculations       |
//+------------------------------------------------------------------+
class CMinLMReport
  {
public:
   //--- variables
   int               m_iterationscount;
   int               m_terminationtype;
   int               m_nfunc;
   int               m_njac;
   int               m_ngrad;
   int               m_nhess;
   int               m_ncholesky;
   //--- constructor, destructor
                     CMinLMReport(void);
                    ~CMinLMReport(void);
   //--- copy
   void              Copy(CMinLMReport &obj);
  };
//+------------------------------------------------------------------+
//| Constructor without parameters                                   |
//+------------------------------------------------------------------+
CMinLMReport::CMinLMReport(void)
  {

  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CMinLMReport::~CMinLMReport(void)
  {

  }
//+------------------------------------------------------------------+
//| Copy                                                             |
//+------------------------------------------------------------------+
void CMinLMReport::Copy(CMinLMReport &obj)
  {
//--- copy variables
   m_iterationscount=obj.m_iterationscount;
   m_terminationtype=obj.m_terminationtype;
   m_nfunc=obj.m_nfunc;
   m_njac=obj.m_njac;
   m_ngrad=obj.m_ngrad;
   m_nhess=obj.m_nhess;
   m_ncholesky=obj.m_ncholesky;
  }
//+------------------------------------------------------------------+
//| Optimization report, filled by MinLMResults() function           |
//| FIELDS:                                                          |
//| * TerminationType, completetion code:                            |
//|     * -9    derivative correctness check failed;                 |
//|             see Rep.WrongNum, Rep.WrongI, Rep.WrongJ for         |
//|             more information.                                    |
//|     *  1    relative function improvement is no more than        |
//|             EpsF.                                                |
//|     *  2    relative step is no more than EpsX.                  |
//|     *  4    gradient is no more than EpsG.                       |
//|     *  5    MaxIts steps was taken                               |
//|     *  7    stopping conditions are too stringent,               |
//|             further improvement is impossible                    |
//| * IterationsCount, contains iterations count                     |
//| * NFunc, number of function calculations                         |
//| * NJac, number of Jacobi matrix calculations                     |
//| * NGrad, number of gradient calculations                         |
//| * NHess, number of Hessian calculations                          |
//| * NCholesky, number of Cholesky decomposition calculations       |
//+------------------------------------------------------------------+
class CMinLMReportShell
  {
private:
   CMinLMReport      m_innerobj;
public:
   //--- constructors, destructor
                     CMinLMReportShell(void);
                     CMinLMReportShell(CMinLMReport &obj);
                    ~CMinLMReportShell(void);
   //--- methods
   int               GetIterationsCount(void);
   void              SetIterationsCount(const int i);
   int               GetTerminationType(void);
   void              SetTerminationType(const int i);
   int               GetNFunc(void);
   void              SetNFunc(const int i);
   int               GetNJAC(void);
   void              SetNJAC(const int i);
   int               GetNGrad(void);
   void              SetNGrad(const int i);
   int               GetNHess(void);
   void              SetNHess(const int i);
   int               GetNCholesky(void);
   void              SetNCholesky(const int i);
   CMinLMReport     *GetInnerObj(void);
  };
//+------------------------------------------------------------------+
//| Constructor without parameters                                   |
//+------------------------------------------------------------------+
CMinLMReportShell::CMinLMReportShell(void)
  {

  }
//+------------------------------------------------------------------+
//| Copy constructor                                                 |
//+------------------------------------------------------------------+
CMinLMReportShell::CMinLMReportShell(CMinLMReport &obj)
  {
//--- copy
   m_innerobj.Copy(obj);
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CMinLMReportShell::~CMinLMReportShell(void)
  {

  }
//+------------------------------------------------------------------+
//| Returns the value of the variable iterationscount                |
//+------------------------------------------------------------------+
int CMinLMReportShell::GetIterationsCount(void)
  {
//--- return result
   return(m_innerobj.m_iterationscount);
  }
//+------------------------------------------------------------------+
//| Changing the value of the variable iterationscount               |
//+------------------------------------------------------------------+
void CMinLMReportShell::SetIterationsCount(const int i)
  {
//--- change value
   m_innerobj.m_iterationscount=i;
  }
//+------------------------------------------------------------------+
//| Returns the value of the variable terminationtype                |
//+------------------------------------------------------------------+
int CMinLMReportShell::GetTerminationType(void)
  {
//--- return result
   return(m_innerobj.m_terminationtype);
  }
//+------------------------------------------------------------------+
//| Changing the value of the variable terminationtype               |
//+------------------------------------------------------------------+
void CMinLMReportShell::SetTerminationType(const int i)
  {
//--- change value
   m_innerobj.m_terminationtype=i;
  }
//+------------------------------------------------------------------+
//| Returns the value of the variable nfunc                          |
//+------------------------------------------------------------------+
int CMinLMReportShell::GetNFunc(void)
  {
//--- return result
   return(m_innerobj.m_nfunc);
  }
//+------------------------------------------------------------------+
//| Changing the value of the variable nfunc                         |
//+------------------------------------------------------------------+
void CMinLMReportShell::SetNFunc(const int i)
  {
//--- change value
   m_innerobj.m_nfunc=i;
  }
//+------------------------------------------------------------------+
//| Returns the value of the variable njac                           |
//+------------------------------------------------------------------+
int CMinLMReportShell::GetNJAC(void)
  {
//--- return result
   return(m_innerobj.m_njac);
  }
//+------------------------------------------------------------------+
//| Changing the value of the variable njac                          |
//+------------------------------------------------------------------+
void CMinLMReportShell::SetNJAC(const int i)
  {
//--- change value
   m_innerobj.m_njac=i;
  }
//+------------------------------------------------------------------+
//| Returns the value of the variable ngrad                          |
//+------------------------------------------------------------------+
int CMinLMReportShell::GetNGrad(void)
  {
//--- return result
   return(m_innerobj.m_ngrad);
  }
//+------------------------------------------------------------------+
//| Changing the value of the variable ngrad                         |
//+------------------------------------------------------------------+
void CMinLMReportShell::SetNGrad(const int i)
  {
//--- change value
   m_innerobj.m_ngrad=i;
  }
//+------------------------------------------------------------------+
//| Returns the value of the variable nhess                          |
//+------------------------------------------------------------------+
int CMinLMReportShell::GetNHess(void)
  {
//--- return result
   return(m_innerobj.m_nhess);
  }
//+------------------------------------------------------------------+
//| Changing the value of the variable nhess                         |
//+------------------------------------------------------------------+
void CMinLMReportShell::SetNHess(const int i)
  {
//--- change value
   m_innerobj.m_nhess=i;
  }
//+------------------------------------------------------------------+
//| Returns the value of the variable ncholesky                      |
//+------------------------------------------------------------------+
int CMinLMReportShell::GetNCholesky(void)
  {
//--- return result
   return(m_innerobj.m_ncholesky);
  }
//+------------------------------------------------------------------+
//| Changing the value of the variable ncholesky                     |
//+------------------------------------------------------------------+
void CMinLMReportShell::SetNCholesky(const int i)
  {
//--- change value
   m_innerobj.m_ncholesky=i;
  }
//+------------------------------------------------------------------+
//| Return object of class                                           |
//+------------------------------------------------------------------+
CMinLMReport *CMinLMReportShell::GetInnerObj(void)
  {
//--- return result
   return(GetPointer(m_innerobj));
  }
//+------------------------------------------------------------------+
//| Levenberg-Marquardt method                                       |
//+------------------------------------------------------------------+
class CMinLM
  {
private:
   //--- private methods
   static void       LMPRepare(const int n,const int m,bool havegrad,CMinLMState &state);
   static void       ClearRequestFields(CMinLMState &state);
   static bool       IncreaseLambda(double &lambdav,double &nu);
   static void       DecreaseLambda(double &lambdav,double &nu);
   static double     BoundedScaledAntigradNorm(CMinLMState &state,double &x[],double &g[]);
   //--- auxiliary functions for MinLMIteration
   static void       Func_lbl_rcomm(CMinLMState &state,int n,int m,int iflag,int i,int k,bool bflag,double v,double s,double t);
   static bool       Func_lbl_16(CMinLMState &state,int &n,int &m,int &iflag,int &i,int &k,bool &bflag,double &v,double &s,double &t);
   static bool       Func_lbl_19(CMinLMState &state,int &n,int &m,int &iflag,int &i,int &k,bool &bflag,double &v,double &s,double &t);
   static bool       Func_lbl_20(CMinLMState &state,int &n,int &m,int &iflag,int &i,int &k,bool &bflag,double &v,double &s,double &t);
   static bool       Func_lbl_21(CMinLMState &state,int &n,int &m,int &iflag,int &i,int &k,bool &bflag,double &v,double &s,double &t);
   static bool       Func_lbl_22(CMinLMState &state,int &n,int &m,int &iflag,int &i,int &k,bool &bflag,double &v,double &s,double &t);
   static bool       Func_lbl_24(CMinLMState &state,int &n,int &m,int &iflag,int &i,int &k,bool &bflag,double &v,double &s,double &t);
   static bool       Func_lbl_25(CMinLMState &state,int &n,int &m,int &iflag,int &i,int &k,bool &bflag,double &v,double &s,double &t);
   static bool       Func_lbl_28(CMinLMState &state,int &n,int &m,int &iflag,int &i,int &k,bool &bflag,double &v,double &s,double &t);
   static bool       Func_lbl_31(CMinLMState &state,int &n,int &m,int &iflag,int &i,int &k,bool &bflag,double &v,double &s,double &t);
   static bool       Func_lbl_39(CMinLMState &state,int &n,int &m,int &iflag,int &i,int &k,bool &bflag,double &v,double &s,double &t);
   static bool       Func_lbl_40(CMinLMState &state,int &n,int &m,int &iflag,int &i,int &k,bool &bflag,double &v,double &s,double &t);
   static bool       Func_lbl_41(CMinLMState &state,int &n,int &m,int &iflag,int &i,int &k,bool &bflag,double &v,double &s,double &t);
   static bool       Func_lbl_48(CMinLMState &state,int &n,int &m,int &iflag,int &i,int &k,bool &bflag,double &v,double &s,double &t);
   static bool       Func_lbl_49(CMinLMState &state,int &n,int &m,int &iflag,int &i,int &k,bool &bflag,double &v,double &s,double &t);
   static bool       Func_lbl_55(CMinLMState &state,int &n,int &m,int &iflag,int &i,int &k,bool &bflag,double &v,double &s,double &t);
public:
   //--- class constants
   static const int  m_lmmodefj;
   static const int  m_lmmodefgj;
   static const int  m_lmmodefgh;
   static const int  m_lmflagnopreLBFGS;
   static const int  m_lmflagnointLBFGS;
   static const int  m_lmpreLBFGSm;
   static const int  m_lmintLBFGSits;
   static const int  m_lbfgsnorealloc;
   static const double m_lambdaup;
   static const double m_lambdadown;
   static const double m_suspiciousnu;
   static const int  m_smallmodelage;
   static const int  m_additers;
   //--- constructor, destructor
                     CMinLM(void);
                    ~CMinLM(void);
   //--- public methods
   static void       MinLMCreateVJ(const int n,const int m,double &x[],CMinLMState &state);
   static void       MinLMCreateV(const int n,const int m,double &x[],const double diffstep,CMinLMState &state);
   static void       MinLMCreateFGH(const int n,double &x[],CMinLMState &state);
   static void       MinLMSetCond(CMinLMState &state,const double epsg,const double epsf,double epsx,const int maxits);
   static void       MinLMSetXRep(CMinLMState &state,const bool needxrep);
   static void       MinLMSetStpMax(CMinLMState &state,const double stpmax);
   static void       MinLMSetScale(CMinLMState &state,double &s[]);
   static void       MinLMSetBC(CMinLMState &state,double &bndl[],double &bndu[]);
   static void       MinLMSetAccType(CMinLMState &state,int acctype);
   static void       MinLMResults(CMinLMState &state,double &x[],CMinLMReport &rep);
   static void       MinLMResultsBuf(CMinLMState &state,double &x[],CMinLMReport &rep);
   static void       MinLMRestartFrom(CMinLMState &state,double &x[]);
   static void       MinLMCreateVGJ(const int n,const int m,double &x[],CMinLMState &state);
   static void       MinLMCreateFGJ(const int n,const int m,double &x[],CMinLMState &state);
   static void       MinLMCreateFJ(const int n,const int m,double &x[],CMinLMState &state);
   static bool       MinLMIteration(CMinLMState &state);
  };
//+------------------------------------------------------------------+
//| Initialize constants                                             |
//+------------------------------------------------------------------+
const int    CMinLM::m_lmmodefj=0;
const int    CMinLM::m_lmmodefgj=1;
const int    CMinLM::m_lmmodefgh=2;
const int    CMinLM::m_lmflagnopreLBFGS=1;
const int    CMinLM::m_lmflagnointLBFGS=2;
const int    CMinLM::m_lmpreLBFGSm=5;
const int    CMinLM::m_lmintLBFGSits=5;
const int    CMinLM::m_lbfgsnorealloc=1;
const double CMinLM::m_lambdaup=2.0;
const double CMinLM::m_lambdadown=0.33;
const double CMinLM::m_suspiciousnu=16;
const int    CMinLM::m_smallmodelage=3;
const int    CMinLM::m_additers=5;
//+------------------------------------------------------------------+
//| Constructor without parameters                                   |
//+------------------------------------------------------------------+
CMinLM::CMinLM(void)
  {

  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CMinLM::~CMinLM(void)
  {

  }
//+------------------------------------------------------------------+
//|                 IMPROVED LEVENBERG-MARQUARDT METHOD FOR          |
//|                  NON-LINEAR LEAST SQUARES OPTIMIZATION           |
//| DESCRIPTION:                                                     |
//| This function is used to find minimum of function which is       |
//| represented as sum of squares:                                   |
//|     F(x) = f[0]^2(x[0],...,x[n-1]) + ... +                       |
//|     + f[m-1]^2(x[0],...,x[n-1])                                  |
//| using value of function vector f[] and Jacobian of f[].          |
//| REQUIREMENTS:                                                    |
//| This algorithm will request following information during its     |
//| operation:                                                       |
//| * function vector f[] at given point X                           |
//| * function vector f[] and Jacobian of f[] (simultaneously) at    |
//| given point                                                      |
//| There are several overloaded versions of MinLMOptimize()         |
//| function which correspond to different LM-like optimization      |
//| algorithms provided by this unit. You should choose version which|
//| accepts fvec() and jac() callbacks. First one is used to         |
//| calculate f[] at given point, second one calculates f[] and      |
//| Jacobian df[i]/dx[j].                                            |
//| You can try to initialize MinLMState structure with VJ function  |
//| and then use incorrect version  of  MinLMOptimize() (for example,|
//| version which works with general form function and does not      |
//| provide Jacobian), but it will lead to exception being thrown    |
//| after first attempt to calculate Jacobian.                       |
//| USAGE:                                                           |
//| 1. User initializes algorithm state with MinLMCreateVJ() call    |
//| 2. User tunes solver parameters with MinLMSetCond(),             |
//|    MinLMSetStpMax() and other functions                          |
//| 3. User calls MinLMOptimize() function which takes algorithm     |
//|    state and callback functions.                                 |
//| 4. User calls MinLMResults() to get solution                     |
//| 5. Optionally, user may call MinLMRestartFrom() to solve another |
//|    problem with same N/M but another starting point and/or       |
//|    another function. MinLMRestartFrom() allows to reuse already  |
//|    initialized structure.                                        |
//| INPUT PARAMETERS:                                                |
//|     N       -   dimension, N>1                                   |
//|                 * if given, only leading N elements of X are     |
//|                   used                                           |
//|                 * if not given, automatically determined from    |
//|                   size of X                                      |
//|     M       -   number of functions f[i]                         |
//|     X       -   initial solution, array[0..N-1]                  |
//| OUTPUT PARAMETERS:                                               |
//|     State   -   structure which stores algorithm state           |
//| NOTES:                                                           |
//| 1. you may tune stopping conditions with MinLMSetCond() function |
//| 2. if target function contains exp() or other fast growing       |
//|    functions, and optimization algorithm makes too large steps   |
//|    which leads to overflow, use MinLMSetStpMax() function to     |
//|    bound algorithm's steps.                                      |
//+------------------------------------------------------------------+
static void CMinLM::MinLMCreateVJ(const int n,const int m,double &x[],
                                  CMinLMState &state)
  {
//--- check
   if(!CAp::Assert(n>=1,__FUNCTION__+": N<1!"))
      return;
//--- check
   if(!CAp::Assert(m>=1,__FUNCTION__+": M<1!"))
      return;
//--- check
   if(!CAp::Assert(CAp::Len(x)>=n,__FUNCTION__+": Length(X)<N!"))
      return;
//--- check
   if(!CAp::Assert(CApServ::IsFiniteVector(x,n),__FUNCTION__+": X contains infinite or NaN values!"))
      return;
//--- initialize,check parameters
   state.m_n=n;
   state.m_m=m;
   state.m_algomode=1;
   state.m_hasf=false;
   state.m_hasfi=true;
   state.m_hasg=false;
//--- second stage of initialization
   LMPRepare(n,m,false,state);
   MinLMSetAccType(state,0);
   MinLMSetCond(state,0,0,0,0);
   MinLMSetXRep(state,false);
   MinLMSetStpMax(state,0);
   MinLMRestartFrom(state,x);
  }
//+------------------------------------------------------------------+
//|                 IMPROVED LEVENBERG-MARQUARDT METHOD FOR          |
//|                  NON-LINEAR LEAST SQUARES OPTIMIZATION           |
//| DESCRIPTION:                                                     |
//| This function is used to find minimum of function which is       |
//| represented as sum of squares:                                   |
//|     F(x) = f[0]^2(x[0],...,x[n-1]) + ... +                       |
//|     + f[m-1]^2(x[0],...,x[n-1])                                  |
//| using value of function vector f[] only. Finite differences are  |
//| used to calculate Jacobian.                                      |
//| REQUIREMENTS:                                                    |
//| This algorithm will request following information during its     |
//| operation:                                                       |
//| * function vector f[] at given point X                           |
//| There are several overloaded versions of MinLMOptimize() function|
//| which correspond to different LM-like optimization algorithms    |
//| provided by this unit. You should choose version which accepts   |
//| fvec() callback.                                                 |
//| You can try to initialize MinLMState structure with VJ function  |
//| and then use incorrect version of MinLMOptimize() (for example,  |
//| version which works with general form function and does not      |
//| accept function vector), but it will lead to exception being     |
//| thrown after first attempt to calculate Jacobian.                |
//| USAGE:                                                           |
//| 1. User initializes algorithm state with MinLMCreateV() call     |
//| 2. User tunes solver parameters with MinLMSetCond(),             |
//|    MinLMSetStpMax() and other functions                          |
//| 3. User calls MinLMOptimize() function which takes algorithm     |
//|    state and callback functions.                                 |
//| 4. User calls MinLMResults() to get solution                     |
//| 5. Optionally, user may call MinLMRestartFrom() to solve another |
//|    problem with same N/M but another starting point and/or       |
//|    another function. MinLMRestartFrom() allows to reuse already  |
//|    initialized structure.                                        |
//| INPUT PARAMETERS:                                                |
//|     N       -   dimension, N>1                                   |
//|                 * if given, only leading N elements of X are     |
//|                   used                                           |
//|                 * if not given, automatically determined from    |
//|                   size of X                                      |
//|     M       -   number of functions f[i]                         |
//|     X       -   initial solution, array[0..N-1]                  |
//|     DiffStep-   differentiation step, >0                         |
//| OUTPUT PARAMETERS:                                               |
//|     State   -   structure which stores algorithm state           |
//| See also MinLMIteration, MinLMResults.                           |
//| NOTES:                                                           |
//| 1. you may tune stopping conditions with MinLMSetCond() function |
//| 2. if target function contains exp() or other fast growing       |
//|    functions, and optimization algorithm makes too large steps   |
//|    which leads to overflow, use MinLMSetStpMax() function to     |
//|    bound algorithm's steps.                                      |
//+------------------------------------------------------------------+
static void CMinLM::MinLMCreateV(const int n,const int m,double &x[],
                                 const double diffstep,CMinLMState &state)
  {
//--- check
   if(!CAp::Assert(CMath::IsFinite(diffstep),__FUNCTION__+": DiffStep is not finite!"))
      return;
//--- check
   if(!CAp::Assert(diffstep>0.0,__FUNCTION__+": DiffStep<=0!"))
      return;
//--- check
   if(!CAp::Assert(n>=1,__FUNCTION__+": N<1!"))
      return;
//--- check
   if(!CAp::Assert(m>=1,__FUNCTION__+": M<1!"))
      return;
//--- check
   if(!CAp::Assert(CAp::Len(x)>=n,__FUNCTION__+": Length(X)<N!"))
      return;
//--- check
   if(!CAp::Assert(CApServ::IsFiniteVector(x,n),__FUNCTION__+": X contains infinite or NaN values!"))
      return;
//--- initialize
   state.m_n=n;
   state.m_m=m;
   state.m_algomode=0;
   state.m_hasf=false;
   state.m_hasfi=true;
   state.m_hasg=false;
   state.m_diffstep=diffstep;
//--- second stage of initialization
   LMPRepare(n,m,false,state);
   MinLMSetAccType(state,1);
   MinLMSetCond(state,0,0,0,0);
   MinLMSetXRep(state,false);
   MinLMSetStpMax(state,0);
   MinLMRestartFrom(state,x);
  }
//+------------------------------------------------------------------+
//|     LEVENBERG-MARQUARDT-LIKE METHOD FOR NON-LINEAR OPTIMIZATION  |
//| DESCRIPTION:                                                     |
//| This function is used to find minimum of general form (not       |
//| "sum-of-squares") function                                       |
//|     F = F(x[0], ..., x[n-1])                                     |
//| using its gradient and Hessian. Levenberg-Marquardt modification |
//| with L-BFGS pre-optimization and internal pre-conditioned L-BFGS |
//| optimization after each Levenberg-Marquardt step is used.        |
//| REQUIREMENTS:                                                    |
//| This algorithm will request following information during its     |
//| operation:                                                       |
//| * function value F at given point X                              |
//| * F and gradient G (simultaneously) at given point X             |
//| * F, G and Hessian H (simultaneously) at given point X           |
//| There are several overloaded versions of  MinLMOptimize()        |
//| function which correspond to different LM-like optimization      |
//| algorithms provided by this unit. You should choose version which|
//| accepts func(), grad() and hess() function pointers. First       |
//| pointer is used to calculate F at given point, second one        |
//| calculates F(x) and grad F(x), third one calculates F(x), grad   |
//| F(x), hess F(x).                                                 |
//| You can try to initialize MinLMState structure with FGH-function |
//| and then use incorrect version of MinLMOptimize() (for example,  |
//| version which does not provide Hessian matrix), but it will lead |
//| to exception being thrown after first attempt to calculate       |
//| Hessian.                                                         |
//| USAGE:                                                           |
//| 1. User initializes algorithm state with MinLMCreateFGH() call   |
//| 2. User tunes solver parameters with MinLMSetCond(),             |
//|    MinLMSetStpMax() and other functions                          |
//| 3. User calls MinLMOptimize() function which takes algorithm     |
//|    state and pointers (delegates, etc.) to callback functions.   |
//| 4. User calls MinLMResults() to get solution                     |
//| 5. Optionally, user may call MinLMRestartFrom() to solve another |
//|    problem with same N but another starting point and/or another |
//|    function. MinLMRestartFrom() allows to reuse already          |
//|    initialized structure.                                        |
//| INPUT PARAMETERS:                                                |
//|     N       -   dimension, N>1                                   |
//|                 * if given, only leading N elements of X are     |
//|                   used                                           |
//|                 * if not given, automatically determined from    |
//|                   size of X                                      |
//|     X       -   initial solution, array[0..N-1]                  |
//| OUTPUT PARAMETERS:                                               |
//|     State   -   structure which stores algorithm state           |
//| NOTES:                                                           |
//| 1. you may tune stopping conditions with MinLMSetCond() function |
//| 2. if target function contains exp() or other fast growing       |
//|    functions, and optimization algorithm makes too large steps   |
//|    which leads to overflow, use MinLMSetStpMax() function to     |
//|    bound algorithm's steps.                                      |
//+------------------------------------------------------------------+
static void CMinLM::MinLMCreateFGH(const int n,double &x[],CMinLMState &state)
  {
//--- check
   if(!CAp::Assert(n>=1,__FUNCTION__+": N<1!"))
      return;
//--- check
   if(!CAp::Assert(CAp::Len(x)>=n,__FUNCTION__+": Length(X)<N!"))
      return;
//--- check
   if(!CAp::Assert(CApServ::IsFiniteVector(x,n),__FUNCTION__+": X contains infinite or NaN values!"))
      return;
//--- initialize
   state.m_n=n;
   state.m_m=0;
   state.m_algomode=2;
   state.m_hasf=true;
   state.m_hasfi=false;
   state.m_hasg=true;
//--- init2
   LMPRepare(n,0,true,state);
   MinLMSetAccType(state,2);
   MinLMSetCond(state,0,0,0,0);
   MinLMSetXRep(state,false);
   MinLMSetStpMax(state,0);
   MinLMRestartFrom(state,x);
  }
//+------------------------------------------------------------------+
//| This function sets stopping conditions for Levenberg-Marquardt   |
//| optimization algorithm.                                          |
//| INPUT PARAMETERS:                                                |
//|     State   -   structure which stores algorithm state           |
//|     EpsG    -   >=0                                              |
//|                 The  subroutine  finishes its work if the        |
//|                 condition |v|<EpsG is satisfied, where:          |
//|                 * |.| means Euclidian norm                       |
//|                 * v - scaled gradient vector, v[i]=g[i]*s[i]     |
//|                 * g - gradient                                   |
//|                 * s - scaling coefficients set by MinLMSetScale()|
//|     EpsF    -   >=0                                              |
//|                 The  subroutine  finishes  its work if on k+1-th |
//|                 iteration the condition |F(k+1)-F(k)| <=         |
//|                 <= EpsF*max{|F(k)|,|F(k+1)|,1} is satisfied.     |
//|     EpsX    -   >=0                                              |
//|                 The subroutine finishes its work if on k+1-th    |
//|                 iteration the condition |v|<=EpsX is fulfilled,  |
//|                 where:                                           |
//|                 * |.| means Euclidian norm                       |
//|                 * v - scaled step vector, v[i]=dx[i]/s[i]        |
//|                 * dx - ste pvector, dx=X(k+1)-X(k)               |
//|                 * s - scaling coefficients set by MinLMSetScale()|
//|     MaxIts  -   maximum number of iterations. If MaxIts=0, the   |
//|                 number of iterations is unlimited. Only          |
//|                 Levenberg-Marquardt iterations are counted       |
//|                 (L-BFGS/CG iterations are NOT counted because    |
//|                 their cost is very low compared to that of LM).  |
//| Passing EpsG=0, EpsF=0, EpsX=0 and MaxIts=0 (simultaneously) will|
//| lead to automatic stopping criterion selection (small EpsX).     |
//+------------------------------------------------------------------+
static void CMinLM::MinLMSetCond(CMinLMState &state,const double epsg,
                                 const double epsf,double epsx,
                                 const int maxits)
  {
//--- check
   if(!CAp::Assert(CMath::IsFinite(epsg),__FUNCTION__+": EpsG is not finite number!"))
      return;
//--- check
   if(!CAp::Assert(epsg>=0.0,__FUNCTION__+": negative EpsG!"))
      return;
//--- check
   if(!CAp::Assert(CMath::IsFinite(epsf),__FUNCTION__+": EpsF is not finite number!"))
      return;
//--- check
   if(!CAp::Assert(epsf>=0.0,__FUNCTION__+": negative EpsF!"))
      return;
//--- check
   if(!CAp::Assert(CMath::IsFinite(epsx),__FUNCTION__+": EpsX is not finite number!"))
      return;
//--- check
   if(!CAp::Assert(epsx>=0.0,__FUNCTION__+": negative EpsX!"))
      return;
//--- check
   if(!CAp::Assert(maxits>=0,__FUNCTION__+": negative MaxIts!"))
      return;
//--- check
   if(((epsg==0.0 && epsf==0.0) && epsx==0.0) && maxits==0)
      epsx=1.0E-6;
//--- change values
   state.m_epsg=epsg;
   state.m_epsf=epsf;
   state.m_epsx=epsx;
   state.m_maxits=maxits;
  }
//+------------------------------------------------------------------+
//| This function turns on/off reporting.                            |
//| INPUT PARAMETERS:                                                |
//|     State   -   structure which stores algorithm state           |
//|     NeedXRep-   whether iteration reports are needed or not      |
//| If NeedXRep is True, algorithm will call rep() callback function |
//| if it is provided to MinLMOptimize(). Both Levenberg-Marquardt   |
//| and internal L-BFGS iterations are reported.                     |
//+------------------------------------------------------------------+
static void CMinLM::MinLMSetXRep(CMinLMState &state,const bool needxrep)
  {
//--- change value
   state.m_xrep=needxrep;
  }
//+------------------------------------------------------------------+
//| This function sets maximum step length                           |
//| INPUT PARAMETERS:                                                |
//|     State   -   structure which stores algorithm state           |
//|     StpMax  -   maximum step length, >=0. Set StpMax to 0.0, if  |
//|                 you don't want to limit step length.             |
//| Use this subroutine when you optimize target function which      |
//| contains exp() or other fast growing functions, and optimization |
//| algorithm makes too large steps which leads to overflow. This    |
//| function allows us to reject steps that are too large (and       |
//| therefore expose us to the possible overflow) without actually   |
//| calculating function value at the x+stp*d.                       |
//| NOTE: non-zero StpMax leads to moderate performance degradation  |
//| because intermediate step of preconditioned L-BFGS optimization  |
//| is incompatible with limits on step size.                        |
//+------------------------------------------------------------------+
static void CMinLM::MinLMSetStpMax(CMinLMState &state,const double stpmax)
  {
//--- check
   if(!CAp::Assert(CMath::IsFinite(stpmax),__FUNCTION__+": StpMax is not finite!"))
      return;
//--- check
   if(!CAp::Assert(stpmax>=0.0,__FUNCTION__+": StpMax<0!"))
      return;
//--- change value
   state.m_stpmax=stpmax;
  }
//+------------------------------------------------------------------+
//| This function sets scaling coefficients for LM optimizer.        |
//| ALGLIB optimizers use scaling matrices to test stopping          |
//| conditions (step size and gradient are scaled before comparison  |
//| with tolerances). Scale of the I-th variable is a translation    |
//| invariant measure of:                                            |
//| a) "how large" the variable is                                   |
//| b) how large the step should be to make significant changes in   |
//| the function                                                     |
//| Generally, scale is NOT considered to be a form of               |
//| preconditioner. But LM optimizer is unique in that it uses       |
//| scaling matrix both in the stopping condition tests and as       |
//| Marquardt damping factor.                                        |
//| Proper scaling is very important for the algorithm performance.  |
//| It is less important for the quality of results, but still has   |
//| some influence (it is easier to converge when variables are      |
//| properly scaled, so premature stopping is possible when very     |
//| badly scalled variables are combined with relaxed stopping       |
//| conditions).                                                     |
//| INPUT PARAMETERS:                                                |
//|     State   -   structure stores algorithm state                 |
//|     S       -   array[N], non-zero scaling coefficients          |
//|                 S[i] may be negative, sign doesn't matter.       |
//+------------------------------------------------------------------+
static void CMinLM::MinLMSetScale(CMinLMState &state,double &s[])
  {
//--- create a variable
   int i=0;
//--- check
   if(!CAp::Assert(CAp::Len(s)>=state.m_n,__FUNCTION__+": Length(S)<N"))
      return;
   for(i=0;i<=state.m_n-1;i++)
     {
      //--- check
      if(!CAp::Assert(CMath::IsFinite(s[i]),__FUNCTION__+": S contains infinite or NAN elements"))
         return;
      //--- check
      if(!CAp::Assert(s[i]!=0.0,__FUNCTION__+": S contains zero elements"))
         return;
      //--- change value
      state.m_s[i]=MathAbs(s[i]);
     }
  }
//+------------------------------------------------------------------+
//| This function sets boundary constraints for LM optimizer         |
//| Boundary constraints are inactive by default (after initial      |
//| creation). They are preserved until explicitly turned off with   |
//| another SetBC() call.                                            |
//| INPUT PARAMETERS:                                                |
//|     State   -   structure stores algorithm state                 |
//|     BndL    -   lower bounds, array[N].                          |
//|                 If some (all) variables are unbounded, you may   |
//|                 specify very small number or -INF (latter is     |
//|                 recommended because it will allow solver to use  |
//|                 better algorithm).                               |
//|     BndU    -   upper bounds, array[N].                          |
//|                 If some (all) variables are unbounded, you may   |
//|                 specify very large number or +INF (latter is     |
//|                 recommended because it will allow solver to use  |
//|                 better algorithm).                               |
//| NOTE 1: it is possible to specify BndL[i]=BndU[i]. In this case  |
//| I-th variable will be "frozen" at X[i]=BndL[i]=BndU[i].          |
//| NOTE 2: this solver has following useful properties:             |
//| * bound constraints are always satisfied exactly                 |
//| * function is evaluated only INSIDE area specified by bound      |
//|   constraints or at its boundary                                 |
//+------------------------------------------------------------------+
static void CMinLM::MinLMSetBC(CMinLMState &state,double &bndl[],double &bndu[])
  {
//--- create variables
   int i=0;
   int n=0;
//--- initialization
   n=state.m_n;
//--- check
   if(!CAp::Assert(CAp::Len(bndl)>=n,__FUNCTION__+": Length(BndL)<N"))
      return;
//--- check
   if(!CAp::Assert(CAp::Len(bndu)>=n,__FUNCTION__+": Length(BndU)<N"))
      return;
   for(i=0;i<=n-1;i++)
     {
      //--- check
      if(!CAp::Assert(CMath::IsFinite(bndl[i]) || CInfOrNaN::IsNegativeInfinity(bndl[i]),"MinLMSetBC: BndL contains NAN or +INF"))
         return;
      //--- check
      if(!CAp::Assert(CMath::IsFinite(bndu[i]) || CInfOrNaN::IsPositiveInfinity(bndu[i]),"MinLMSetBC: BndU contains NAN or -INF"))
         return;
      //--- change values
      state.m_bndl[i]=bndl[i];
      state.m_havebndl[i]=CMath::IsFinite(bndl[i]);
      state.m_bndu[i]=bndu[i];
      state.m_havebndu[i]=CMath::IsFinite(bndu[i]);
     }
  }
//+------------------------------------------------------------------+
//| This function is used to change acceleration settings            |
//| You can choose between three acceleration strategies:            |
//| * AccType=0, no acceleration.                                    |
//| * AccType=1, secant updates are used to update quadratic model   |
//|   after each iteration. After fixed number of iterations (or     |
//|   after model breakdown) we recalculate quadratic model using    |
//|   analytic Jacobian or finite differences. Number of secant-based|
//|   iterations depends on optimization settings: about 3           |
//|   iterations - when we have analytic Jacobian, up to 2*N         |
//|   iterations - when we use finite differences to calculate       |
//|   Jacobian.                                                      |
//| AccType=1 is recommended when Jacobian calculation cost is       |
//| prohibitive high (several Mx1 function vector calculations       |
//| followed by several NxN Cholesky factorizations are faster than  |
//| calculation of one M*N  Jacobian). It should also be used when we|
//| have no Jacobian, because finite difference approximation takes  |
//| too much time to compute.                                        |
//| Table below list optimization protocols (XYZ protocol corresponds|
//| to MinLMCreateXYZ) and acceleration types they support (and use  |
//| by default).                                                     |
//| ACCELERATION TYPES SUPPORTED BY OPTIMIZATION PROTOCOLS:          |
//| protocol    0   1   comment                                      |
//| V           +   +                                                |
//| VJ          +   +                                                |
//| FGH         +                                                    |
//| DAFAULT VALUES:                                                  |
//| protocol    0   1   comment                                      |
//| V               x   without acceleration it is so slooooooooow   |
//| VJ          x                                                    |
//| FGH         x                                                    |
//| NOTE: this  function should be called before optimization.       |
//| Attempt to call it during algorithm iterations may result in     |
//| unexpected behavior.                                             |
//| NOTE: attempt to call this function with unsupported             |
//| protocol/acceleration combination will result in exception being |
//| thrown.                                                          |
//+------------------------------------------------------------------+
static void CMinLM::MinLMSetAccType(CMinLMState &state,int acctype)
  {
//--- check
   if(!CAp::Assert((acctype==0||acctype==1)||acctype==2,__FUNCTION__+": incorrect AccType!"))
      return;
//--- check
   if(acctype==2)
      acctype=0;
//--- check
   if(acctype==0)
     {
      state.m_maxmodelage=0;
      state.m_makeadditers=false;
      //--- exit the function
      return;
     }
//--- check
   if(acctype==1)
     {
      //--- check
      if(!CAp::Assert(state.m_hasfi,__FUNCTION__+": AccType=1 is incompatible with current protocol!"))
         return;
      //--- check
      if(state.m_algomode==0)
         state.m_maxmodelage=2*state.m_n;
      else
         state.m_maxmodelage=m_smallmodelage;
      state.m_makeadditers=false;
      //--- exit the function
      return;
     }
  }
//+------------------------------------------------------------------+
//| Levenberg-Marquardt algorithm results                            |
//| INPUT PARAMETERS:                                                |
//|     State   -   algorithm state                                  |
//| OUTPUT PARAMETERS:                                               |
//|     X       -   array[0..N-1], solution                          |
//|     Rep     -   optimization report;                             |
//|                 see comments for this structure for more info.   |
//+------------------------------------------------------------------+
static void CMinLM::MinLMResults(CMinLMState &state,double &x[],
                                 CMinLMReport &rep)
  {
//--- reset memory
   ArrayResizeAL(x,0);
//--- function call
   MinLMResultsBuf(state,x,rep);
  }
//+------------------------------------------------------------------+
//| Levenberg-Marquardt algorithm results                            |
//| Buffered implementation of MinLMResults(), which uses            |
//| pre-allocated buffer to store X[]. If buffer size is too small,  |
//| it resizes buffer. It is intended to be used in the inner cycles |
//| of performance critical algorithms where array reallocation      |
//| penalty is too large to be ignored.                              |
//+------------------------------------------------------------------+
static void CMinLM::MinLMResultsBuf(CMinLMState &state,double &x[],
                                    CMinLMReport &rep)
  {
//--- create a variable
   int i_=0;
//--- check
   if(CAp::Len(x)<state.m_n)
      ArrayResizeAL(x,state.m_n);
//--- copy
   for(i_=0;i_<=state.m_n-1;i_++)
      x[i_]=state.m_x[i_];
//--- change values
   rep.m_iterationscount=state.m_repiterationscount;
   rep.m_terminationtype=state.m_repterminationtype;
   rep.m_nfunc=state.m_repnfunc;
   rep.m_njac=state.m_repnjac;
   rep.m_ngrad=state.m_repngrad;
   rep.m_nhess=state.m_repnhess;
   rep.m_ncholesky=state.m_repncholesky;
  }
//+------------------------------------------------------------------+
//| This subroutine restarts LM algorithm from new point. All        |
//| optimization parameters are left unchanged.                      |
//| This function allows to solve multiple optimization problems     |
//| (which must have same number of dimensions) without object       |
//| reallocation penalty.                                            |
//| INPUT PARAMETERS:                                                |
//|     State   -   structure used for reverse communication         |
//|                 previously allocated with MinLMCreateXXX call.   |
//|     X       -   new starting point.                              |
//+------------------------------------------------------------------+
static void CMinLM::MinLMRestartFrom(CMinLMState &state,double &x[])
  {
//--- create a variable
   int i_=0;
//--- check
   if(!CAp::Assert(CAp::Len(x)>=state.m_n,__FUNCTION__+": Length(X)<N!"))
      return;
//--- check
   if(!CAp::Assert(CApServ::IsFiniteVector(x,state.m_n),__FUNCTION__+": X contains infinite or NaN values!"))
      return;
//--- copy
   for(i_=0;i_<=state.m_n-1;i_++)
      state.m_xbase[i_]=x[i_];
//--- allocation
   ArrayResizeAL(state.m_rstate.ia,5);
   ArrayResizeAL(state.m_rstate.ba,1);
   ArrayResizeAL(state.m_rstate.ra,3);
   state.m_rstate.stage=-1;
//--- function call
   ClearRequestFields(state);
  }
//+------------------------------------------------------------------+
//| This is obsolete function.                                       |
//| Since ALGLIB 3.3 it is equivalent to MinLMCreateVJ().            |
//+------------------------------------------------------------------+
static void CMinLM::MinLMCreateVGJ(const int n,const int m,double &x[],
                                   CMinLMState &state)
  {
//--- function call
   MinLMCreateVJ(n,m,x,state);
  }
//+------------------------------------------------------------------+
//| This is obsolete function.                                       |
//| Since ALGLIB 3.3 it is equivalent to MinLMCreateFJ().            |
//+------------------------------------------------------------------+
static void CMinLM::MinLMCreateFGJ(const int n,const int m,double &x[],
                                   CMinLMState &state)
  {
//--- function call
   MinLMCreateFJ(n,m,x,state);
  }
//+------------------------------------------------------------------+
//| This function is considered obsolete since ALGLIB 3.1.0 and is   |
//| present for backward compatibility only. We recommend to use     |
//| MinLMCreateVJ, which provides similar, but more consistent and   |
//| feature-rich interface.                                          |
//+------------------------------------------------------------------+
static void CMinLM::MinLMCreateFJ(const int n,const int m,double &x[],
                                  CMinLMState &state)
  {
//--- check
   if(!CAp::Assert(n>=1,__FUNCTION__+": N<1!"))
      return;
//--- check
   if(!CAp::Assert(m>=1,__FUNCTION__+": M<1!"))
      return;
//--- check
   if(!CAp::Assert(CAp::Len(x)>=n,__FUNCTION__+": Length(X)<N!"))
      return;
//--- check
   if(!CAp::Assert(CApServ::IsFiniteVector(x,n),__FUNCTION__+": X contains infinite or NaN values!"))
      return;
//--- initialize
   state.m_n=n;
   state.m_m=m;
   state.m_algomode=1;
   state.m_hasf=true;
   state.m_hasfi=false;
   state.m_hasg=false;
//--- init 2
   LMPRepare(n,m,true,state);
//--- function call
   MinLMSetAccType(state,0);
//--- function call
   MinLMSetCond(state,0,0,0,0);
//--- function call
   MinLMSetXRep(state,false);
//--- function call
   MinLMSetStpMax(state,0);
//--- function call
   MinLMRestartFrom(state,x);
  }
//+------------------------------------------------------------------+
//| Prepare internal structures (except for RComm).                  |
//| Note: M must be zero for FGH mode, non-zero for V/VJ/FJ/FGJ mode.|
//+------------------------------------------------------------------+
static void CMinLM::LMPRepare(const int n,const int m,bool havegrad,
                              CMinLMState &state)
  {
//--- create a variable
   int i=0;
//--- check
   if(n<=0 || m<0)
      return;
//--- check
   if(havegrad)
      ArrayResizeAL(state.m_g,n);
//--- check
   if(m!=0)
     {
      //--- allocation
      state.m_j.Resize(m,n);
      ArrayResizeAL(state.m_fi,m);
      ArrayResizeAL(state.m_fibase,m);
      ArrayResizeAL(state.m_deltaf,m);
      ArrayResizeAL(state.m_fm1,m);
      ArrayResizeAL(state.m_fp1,m);
     }
   else
      state.m_h.Resize(n,n);
//--- allocation
   ArrayResizeAL(state.m_x,n);
   ArrayResizeAL(state.m_deltax,n);
   state.m_quadraticmodel.Resize(n,n);
   ArrayResizeAL(state.m_xbase,n);
   ArrayResizeAL(state.m_gbase,n);
   ArrayResizeAL(state.m_xdir,n);
   ArrayResizeAL(state.m_tmp0,n);
//--- prepare internal L-BFGS
   for(i=0;i<=n-1;i++)
      state.m_x[i]=0;
//--- function call
   CMinLBFGS::MinLBFGSCreate(n,MathMin(m_additers,n),state.m_x,state.m_internalstate);
//--- function call
   CMinLBFGS::MinLBFGSSetCond(state.m_internalstate,0.0,0.0,0.0,MathMin(m_additers,n));
//--- Prepare internal QP solver
   CMinQP::MinQPCreate(n,state.m_qpstate);
//--- function call
   CMinQP::MinQPSetAlgoCholesky(state.m_qpstate);
//--- Prepare boundary constraints
   ArrayResizeAL(state.m_bndl,n);
   ArrayResizeAL(state.m_bndu,n);
   ArrayResizeAL(state.m_havebndl,n);
   ArrayResizeAL(state.m_havebndu,n);
   for(i=0;i<=n-1;i++)
     {
      //--- change values
      state.m_bndl[i]=CInfOrNaN::NegativeInfinity();
      state.m_havebndl[i]=false;
      state.m_bndu[i]=CInfOrNaN::PositiveInfinity();
      state.m_havebndu[i]=false;
     }
//--- Prepare scaling matrix
   ArrayResizeAL(state.m_s,n);
   for(i=0;i<=n-1;i++)
      state.m_s[i]=1.0;
  }
//+------------------------------------------------------------------+
//| Clears request fileds (to be sure that we don't forgot to clear  |
//| something)                                                       |
//+------------------------------------------------------------------+
static void CMinLM::ClearRequestFields(CMinLMState &state)
  {
//--- change values
   state.m_needf=false;
   state.m_needfg=false;
   state.m_needfgh=false;
   state.m_needfij=false;
   state.m_needfi=false;
   state.m_xupdated=false;
  }
//+------------------------------------------------------------------+
//| Increases lambda, returns False when there is a danger of        |
//| overflow                                                         |
//+------------------------------------------------------------------+
static bool CMinLM::IncreaseLambda(double &lambdav,double &nu)
  {
//--- create variables
   bool   result;
   double lnlambda=0;
   double lnnu=0;
   double lnlambdaup=0;
   double lnmax=0;
//--- initialization
   result=false;
   lnlambda=MathLog(lambdav);
   lnlambdaup=MathLog(m_lambdaup);
   lnnu=MathLog(nu);
   lnmax=MathLog(CMath::m_maxrealnumber);
//--- check
   if(lnlambda+lnlambdaup+lnnu>0.25*lnmax)
     {
      //--- return result
      return(result);
     }
//--- check
   if(lnnu+MathLog(2)>lnmax)
      return(result);
//--- change values
   lambdav=lambdav*m_lambdaup*nu;
   nu=nu*2;
   result=true;
//--- return result
   return(result);
  }
//+------------------------------------------------------------------+
//| Decreases lambda, but leaves it unchanged when there is danger of|
//| underflow.                                                       |
//+------------------------------------------------------------------+
static void CMinLM::DecreaseLambda(double &lambdav,double &nu)
  {
//--- initialization
   nu=1;
//--- check
   if(MathLog(lambdav)+MathLog(m_lambdadown)<MathLog(CMath::m_minrealnumber))
      lambdav=CMath::m_minrealnumber;
   else
      lambdav=lambdav*m_lambdadown;
  }
//+------------------------------------------------------------------+
//| Returns norm of bounded scaled anti-gradient.                    |
//| Bounded antigradient is a vector obtained from anti-gradient by  |
//| zeroing components which point outwards:                         |
//|     result = norm(v)                                             |
//|     v[i]=0     if ((-g[i]<0)and(x[i]=bndl[i])) or                |
//|                   ((-g[i]>0)and(x[i]=bndu[i]))                   |
//|     v[i]=-g[i]*s[i] otherwise, where s[i] is a scale for I-th    |
//|     variable                                                     |
//| This function may be used to check a stopping criterion.         |
//+------------------------------------------------------------------+
static double CMinLM::BoundedScaledAntigradNorm(CMinLMState &state,
                                                double &x[],double &g[])
  {
//--- create variables
   double result=0;
   int    n=0;
   int    i=0;
   double v=0;
//--- initialization
   result=0;
   n=state.m_n;
   for(i=0;i<=n-1;i++)
     {
      v=-(g[i]*state.m_s[i]);
      //--- check
      if(state.m_havebndl[i])
        {
         //--- check
         if(x[i]<=state.m_bndl[i] && (double)(-g[i])<0.0)
            v=0;
        }
      //--- check
      if(state.m_havebndu[i])
        {
         //--- check
         if(x[i]>=state.m_bndu[i] && (double)(-g[i])>0.0)
            v=0;
        }
      result=result+CMath::Sqr(v);
     }
//--- return result
   return(MathSqrt(result));
  }
//+------------------------------------------------------------------+
//| NOTES:                                                           |
//| 1. Depending on function used to create state structure, this    |
//|    algorithm may accept Jacobian and/or Hessian and/or gradient. |
//|    According to the said above, there ase several versions of    |
//|    this function, which accept different sets of callbacks.      |
//|    This flexibility opens way to subtle errors - you may create  |
//|    state with MinLMCreateFGH() (optimization using Hessian), but |
//|    call function which does not accept Hessian. So when          |
//|    algorithm will request Hessian, there will be no callback to  |
//|    call. In this case exception will be thrown.                  |
//|    Be careful to avoid such errors because there is no way to    |
//|    find them at compile time - you can see them at runtime only. |
//+------------------------------------------------------------------+
static bool CMinLM::MinLMIteration(CMinLMState &state)
  {
//--- create variables
   int    n=0;
   int    m=0;
   bool   bflag;
   int    iflag=0;
   double v=0;
   double s=0;
   double t=0;
   int    i=0;
   int    k=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];
      iflag=state.m_rstate.ia[2];
      i=state.m_rstate.ia[3];
      k=state.m_rstate.ia[4];
      bflag=state.m_rstate.ba[0];
      v=state.m_rstate.ra[0];
      s=state.m_rstate.ra[1];
      t=state.m_rstate.ra[2];
     }
   else
     {
      //--- initialization
      n=-983;
      m=-989;
      iflag=-834;
      i=900;
      k=-287;
      bflag=false;
      v=214;
      s=-338;
      t=-686;
     }
//--- check
   if(state.m_rstate.stage==0)
     {
      //--- change value
      state.m_needf=false;
      //--- function call, return result
      return(Func_lbl_19(state,n,m,iflag,i,k,bflag,v,s,t));
     }
//--- check
   if(state.m_rstate.stage==1)
     {
      //--- change values
      state.m_needfi=false;
      v=0.0;
      for(i_=0;i_<=m-1;i_++)
         v+=state.m_fi[i_]*state.m_fi[i_];
      state.m_f=v;
      //--- function call, return result
      return(Func_lbl_19(state,n,m,iflag,i,k,bflag,v,s,t));
     }
//--- check
   if(state.m_rstate.stage==2)
     {
      //--- change value
      state.m_xupdated=false;
      //--- function call, return result
      return(Func_lbl_16(state,n,m,iflag,i,k,bflag,v,s,t));
     }
//--- check
   if(state.m_rstate.stage==3)
     {
      //--- change value
      state.m_repnfunc=state.m_repnfunc+1;
      //--- copy
      for(i_=0;i_<=m-1;i_++)
         state.m_fm1[i_]=state.m_fi[i_];
      for(i_=0;i_<=n-1;i_++)
         state.m_x[i_]=state.m_xbase[i_];
      state.m_x[k]=state.m_x[k]+state.m_s[k]*state.m_diffstep;
      //--- check
      if(state.m_havebndl[k])
         state.m_x[k]=MathMax(state.m_x[k],state.m_bndl[k]);
      //--- check
      if(state.m_havebndu[k])
         state.m_x[k]=MathMin(state.m_x[k],state.m_bndu[k]);
      state.m_xp1=state.m_x[k];
      //--- function call
      ClearRequestFields(state);
      state.m_needfi=true;
      state.m_rstate.stage=4;
      //--- Saving state
      Func_lbl_rcomm(state,n,m,iflag,i,k,bflag,v,s,t);
      //--- return result
      return(true);
     }
//--- check
   if(state.m_rstate.stage==4)
     {
      //--- change value
      state.m_repnfunc=state.m_repnfunc+1;
      //--- copy
      for(i_=0;i_<=m-1;i_++)
         state.m_fp1[i_]=state.m_fi[i_];
      v=state.m_xp1-state.m_xm1;
      //--- check
      if(v!=0.0)
        {
         v=1/v;
         for(i_=0;i_<=m-1;i_++)
            state.m_j[i_].Set(k,v*state.m_fp1[i_]);
         for(i_=0;i_<=m-1;i_++)
            state.m_j[i_].Set(k,state.m_j[i_][k]-v*state.m_fm1[i_]);
        }
      else
        {
         for(i=0;i<=m-1;i++)
            state.m_j[i].Set(k,0);
        }
      k=k+1;
      //--- function call, return result
      return(Func_lbl_28(state,n,m,iflag,i,k,bflag,v,s,t));
     }
//--- check
   if(state.m_rstate.stage==5)
     {
      //--- change values
      state.m_needfi=false;
      state.m_repnfunc=state.m_repnfunc+1;
      state.m_repnjac=state.m_repnjac+1;
      //--- New model
      state.m_modelage=0;
      //--- function call, return result
      return(Func_lbl_25(state,n,m,iflag,i,k,bflag,v,s,t));
     }
//--- check
   if(state.m_rstate.stage==6)
     {
      //--- change values
      state.m_needfij=false;
      state.m_repnfunc=state.m_repnfunc+1;
      state.m_repnjac=state.m_repnjac+1;
      //--- New model
      state.m_modelage=0;
      //--- function call, return result
      return(Func_lbl_25(state,n,m,iflag,i,k,bflag,v,s,t));
     }
//--- check
   if(state.m_rstate.stage==7)
     {
      //--- change values
      state.m_needfgh=false;
      state.m_repnfunc=state.m_repnfunc+1;
      state.m_repngrad=state.m_repngrad+1;
      state.m_repnhess=state.m_repnhess+1;
      //--- function call
      CAblas::RMatrixCopy(n,n,state.m_h,0,0,state.m_quadraticmodel,0,0);
      for(i_=0;i_<=n-1;i_++)
         state.m_gbase[i_]=state.m_g[i_];
      state.m_fbase=state.m_f;
      //--- set control variables
      bflag=true;
      state.m_modelage=0;
      //--- function call, return result
      return(Func_lbl_31(state,n,m,iflag,i,k,bflag,v,s,t));
     }
//--- check
   if(state.m_rstate.stage==8)
     {
      //--- change value
      state.m_xupdated=false;
      //--- return result
      return(false);
     }
//--- check
   if(state.m_rstate.stage==9)
     {
      //--- change value
      state.m_xupdated=false;
      //--- return result
      return(false);
     }
//--- check
   if(state.m_rstate.stage==10)
     {
      //--- change values
      state.m_needfi=false;
      v=0.0;
      for(i_=0;i_<=m-1;i_++)
         v+=state.m_fi[i_]*state.m_fi[i_];
      state.m_f=v;
      //--- copy
      for(i_=0;i_<=m-1;i_++)
         state.m_deltaf[i_]=state.m_fi[i_];
      for(i_=0;i_<=m-1;i_++)
         state.m_deltaf[i_]=state.m_deltaf[i_]-state.m_fibase[i_];
      state.m_deltafready=true;
      //--- function call, return result
      return(Func_lbl_48(state,n,m,iflag,i,k,bflag,v,s,t));
     }
//--- check
   if(state.m_rstate.stage==11)
     {
      //--- change value
      state.m_needf=false;
      //--- function call, return result
      return(Func_lbl_48(state,n,m,iflag,i,k,bflag,v,s,t));
     }
//--- check
   if(state.m_rstate.stage==12)
     {
      //--- change value
      state.m_xupdated=false;
      //--- return result
      return(false);
     }
//--- check
   if(state.m_rstate.stage==13)
     {
      //--- change value
      state.m_xupdated=false;
      //--- function call, return result
      return(Func_lbl_55(state,n,m,iflag,i,k,bflag,v,s,t));
     }
//--- check
   if(state.m_rstate.stage==14)
     {
      //--- change value
      state.m_xupdated=false;
      //--- return result
      return(false);
     }
//--- check
   if(state.m_rstate.stage==15)
     {
      //--- change value
      state.m_xupdated=false;
      //--- return result
      return(false);
     }
//--- Routine body
//--- prepare
   n=state.m_n;
   m=state.m_m;
   state.m_repiterationscount=0;
   state.m_repterminationtype=0;
   state.m_repnfunc=0;
   state.m_repnjac=0;
   state.m_repngrad=0;
   state.m_repnhess=0;
   state.m_repncholesky=0;
//--- check consistency of constraints
//--- set constraints
   for(i=0;i<=n-1;i++)
     {
      //--- check
      if(state.m_havebndl[i] && state.m_havebndu[i])
        {
         //--- check
         if(state.m_bndl[i]>state.m_bndu[i])
           {
            state.m_repterminationtype=-3;
            //--- return result
            return(false);
           }
        }
     }
//--- function call
   CMinQP::MinQPSetBC(state.m_qpstate,state.m_bndl,state.m_bndu);
//--- Initial report of current point
//--- Note 1: we rewrite State.X twice because
//--- user may accidentally change it after first call.
//--- Note 2: we set NeedF or NeedFI depending on what
//--- information about function we have.
   if(!state.m_xrep)
      return(Func_lbl_16(state,n,m,iflag,i,k,bflag,v,s,t));
   for(i_=0;i_<=n-1;i_++)
      state.m_x[i_]=state.m_xbase[i_];
//--- function call
   ClearRequestFields(state);
//--- check
   if(!state.m_hasf)
     {
      //--- check
      if(!CAp::Assert(state.m_hasfi,"MinLM: internal error 2!"))
         return(false);
      //--- change values
      state.m_needfi=true;
      state.m_rstate.stage=1;
      //--- Saving state
      Func_lbl_rcomm(state,n,m,iflag,i,k,bflag,v,s,t);
      //--- return result
      return(true);
     }
//--- change values
   state.m_needf=true;
   state.m_rstate.stage=0;
//--- Saving state
   Func_lbl_rcomm(state,n,m,iflag,i,k,bflag,v,s,t);
//--- return result
   return(true);
  }
//+------------------------------------------------------------------+
//| Auxiliary function for MinLMIteration. Is a product to get rid of|
//| the operator unconditional jump goto.                            |
//+------------------------------------------------------------------+
static void CMinLM::Func_lbl_rcomm(CMinLMState &state,int n,int m,int iflag,
                                   int i,int k,bool bflag,double v,
                                   double s,double t)
  {
//--- save
   state.m_rstate.ia[0]=n;
   state.m_rstate.ia[1]=m;
   state.m_rstate.ia[2]=iflag;
   state.m_rstate.ia[3]=i;
   state.m_rstate.ia[4]=k;
   state.m_rstate.ba[0]=bflag;
   state.m_rstate.ra[0]=v;
   state.m_rstate.ra[1]=s;
   state.m_rstate.ra[2]=t;
  }
//+------------------------------------------------------------------+
//| Auxiliary function for MinLMIteration. Is a product to get rid of|
//| the operator unconditional jump goto.                            |
//+------------------------------------------------------------------+
static bool CMinLM::Func_lbl_16(CMinLMState &state,int &n,int &m,int &iflag,
                                int &i,int &k,bool &bflag,double &v,
                                double &s,double &t)
  {
//--- Prepare control variables
   state.m_nu=1;
   state.m_lambdav=-CMath::m_maxrealnumber;
   state.m_modelage=state.m_maxmodelage+1;
   state.m_deltaxready=false;
   state.m_deltafready=false;
//--- Main cycle.
//--- We move through it until either:
//--- * one of the stopping conditions is met
//--- * we decide that stopping conditions are too stringent
//---   and break from cycle
   return(Func_lbl_20(state,n,m,iflag,i,k,bflag,v,s,t));
  }
//+------------------------------------------------------------------+
//| Auxiliary function for MinLMIteration. Is a product to get rid of|
//| the operator unconditional jump goto.                            |
//+------------------------------------------------------------------+
static bool CMinLM::Func_lbl_19(CMinLMState &state,int &n,int &m,int &iflag,
                                int &i,int &k,bool &bflag,double &v,
                                double &s,double &t)
  {
//--- change value
   state.m_repnfunc=state.m_repnfunc+1;
//--- copy
   for(int i_=0;i_<=n-1;i_++)
      state.m_x[i_]=state.m_xbase[i_];
//--- function call
   ClearRequestFields(state);
//--- change values
   state.m_xupdated=true;
   state.m_rstate.stage=2;
//--- Saving state
   Func_lbl_rcomm(state,n,m,iflag,i,k,bflag,v,s,t);
//--- return result
   return(true);
  }
//+------------------------------------------------------------------+
//| Auxiliary function for MinLMIteration. Is a product to get rid of|
//| the operator unconditional jump goto.                            |
//+------------------------------------------------------------------+
static bool CMinLM::Func_lbl_20(CMinLMState &state,int &n,int &m,int &iflag,
                                int &i,int &k,bool &bflag,double &v,
                                double &s,double &t)
  {
//--- First,we have to prepare quadratic model for our function.
//--- We use BFlag to ensure that model is prepared;
//--- if it is false at the end of this block,something went wrong.
//--- We may either calculate brand new model or update old one.
//--- Before this block we have:
//--- * State.XBase            - current position.
//--- * State.DeltaX           - if DeltaXReady is True
//--- * State.DeltaF           - if DeltaFReady is True
//--- After this block is over,we will have:
//--- * State.XBase            - base point (unchanged)
//--- * State.FBase            - F(XBase)
//--- * State.GBase            - linear term
//--- * State.QuadraticModel   - quadratic term
//--- * State.LambdaV          - current estimate for lambda
//--- We also clear DeltaXReady/DeltaFReady flags
//--- after initialization is done.
   bflag=false;
   if(!(state.m_algomode==0 || state.m_algomode==1))
      return(Func_lbl_22(state,n,m,iflag,i,k,bflag,v,s,t));
//--- Calculate f[] and Jacobian
   if(!(state.m_modelage>state.m_maxmodelage||!(state.m_deltaxready  &state.m_deltafready)))
      return(Func_lbl_24(state,n,m,iflag,i,k,bflag,v,s,t));
//--- Refresh model (using either finite differences or analytic Jacobian)
   if(state.m_algomode!=0)
     {
      //--- Obtain f[] and Jacobian
      for(int i_=0;i_<=n-1;i_++)
         state.m_x[i_]=state.m_xbase[i_];
      //--- function call
      ClearRequestFields(state);
      //--- change values
      state.m_needfij=true;
      state.m_rstate.stage=6;
      //--- Saving state
      Func_lbl_rcomm(state,n,m,iflag,i,k,bflag,v,s,t);
      //--- return result
      return(true);
     }
//--- Optimization using F values only.
//--- Use finite differences to estimate Jacobian.
   if(!CAp::Assert(state.m_hasfi,"MinLMIteration: internal error when estimating Jacobian (no f[])"))
      return(false);
   k=0;
//--- function call, return result
   return(Func_lbl_28(state,n,m,iflag,i,k,bflag,v,s,t));
  }
//+------------------------------------------------------------------+
//| Auxiliary function for MinLMIteration. Is a product to get rid of|
//| the operator unconditional jump goto.                            |
//+------------------------------------------------------------------+
static bool CMinLM::Func_lbl_21(CMinLMState &state,int &n,int &m,int &iflag,
                                int &i,int &k,bool &bflag,double &v,
                                double &s,double &t)
  {
//--- Lambda is too large,we have to break iterations.
   state.m_repterminationtype=7;
   if(!state.m_xrep)
      return(false);
   for(int i_=0;i_<=n-1;i_++)
      state.m_x[i_]=state.m_xbase[i_];
   state.m_f=state.m_fbase;
//--- function call
   ClearRequestFields(state);
//--- change values
   state.m_xupdated=true;
   state.m_rstate.stage=15;
//--- Saving state
   Func_lbl_rcomm(state,n,m,iflag,i,k,bflag,v,s,t);
//--- return result
   return(true);
  }
//+------------------------------------------------------------------+
//| Auxiliary function for MinLMIteration. Is a product to get rid of|
//| the operator unconditional jump goto.                            |
//+------------------------------------------------------------------+
static bool CMinLM::Func_lbl_22(CMinLMState &state,int &n,int &m,int &iflag,
                                int &i,int &k,bool &bflag,double &v,
                                double &s,double &t)
  {
//--- check
   if(state.m_algomode!=2)
      return(Func_lbl_31(state,n,m,iflag,i,k,bflag,v,s,t));
//--- check
   if(!CAp::Assert(!state.m_hasfi,"MinLMIteration: internal error (HasFI is True in Hessian-based mode)"))
      return(false);
//--- Obtain F,G,H
   for(int i_=0;i_<=n-1;i_++)
      state.m_x[i_]=state.m_xbase[i_];
//--- function call
   ClearRequestFields(state);
//--- change values
   state.m_needfgh=true;
   state.m_rstate.stage=7;
//--- Saving state
   Func_lbl_rcomm(state,n,m,iflag,i,k,bflag,v,s,t);
//--- return result
   return(true);
  }
//+------------------------------------------------------------------+
//| Auxiliary function for MinLMIteration. Is a product to get rid of|
//| the operator unconditional jump goto.                            |
//+------------------------------------------------------------------+
static bool CMinLM::Func_lbl_24(CMinLMState &state,int &n,int &m,int &iflag,
                                int &i,int &k,bool &bflag,double &v,
                                double &s,double &t)
  {
//--- State.J contains Jacobian or its current approximation;
//--- refresh it using secant updates:
//--- f(x0+dx)=f(x0) + J*dx,
//--- J_new=J_old + u*h'
//--- h=x_new-x_old
//--- u=(f_new - f_old - J_old*h)/(h'h)
//--- We can explicitly generate h and u,but it is
//--- preferential to do in-place calculations. Only
//--- I-th row of J_old is needed to calculate u[I],
//--- so we can update J row by row in one pass.
//--- NOTE: we expect that State.XBase contains new point,
//--- State.FBase contains old point,State.DeltaX and
//--- State.DeltaY contain updates from last step.
   if(!CAp::Assert(state.m_deltaxready && state.m_deltafready,"MinLMIteration: uninitialized DeltaX/DeltaF"))
      return(false);
   t=0.0;
   for(int i_=0;i_<=n-1;i_++)
      t+=state.m_deltax[i_]*state.m_deltax[i_];
//--- check
   if(!CAp::Assert(t!=0.0,"MinLM: internal error (T=0)"))
      return(false);
   for(i=0;i<=m-1;i++)
     {
      //--- change value
      v=0.0;
      for(int i_=0;i_<=n-1;i_++)
         v+=state.m_j[i][i_]*state.m_deltax[i_];
      v=(state.m_deltaf[i]-v)/t;
      for(int i_=0;i_<=n-1;i_++)
         state.m_j[i].Set(i_,state.m_j[i][i_]+v*state.m_deltax[i_]);
     }
   for(int i_=0;i_<=m-1;i_++)
      state.m_fi[i_]=state.m_fibase[i_];
   for(int i_=0;i_<=m-1;i_++)
      state.m_fi[i_]=state.m_fi[i_]+state.m_deltaf[i_];
//--- Increase model age
   state.m_modelage=state.m_modelage+1;
//--- function call, return result
   return(Func_lbl_25(state,n,m,iflag,i,k,bflag,v,s,t));
  }
//+------------------------------------------------------------------+
//| Auxiliary function for MinLMIteration. Is a product to get rid of|
//| the operator unconditional jump goto.                            |
//+------------------------------------------------------------------+
static bool CMinLM::Func_lbl_25(CMinLMState &state,int &n,int &m,int &iflag,
                                int &i,int &k,bool &bflag,double &v,
                                double &s,double &t)
  {
//--- Generate quadratic model:
//---     f(xbase+dx)=
//---                =(f0 + J*dx)'(f0 + J*dx)
//---                =f0^2 + dx'J'f0 + f0*J*dx + dx'J'J*dx
//---                =f0^2 + 2*f0*J*dx + dx'J'J*dx
//--- Note that we calculate 2*(J'J) instead of J'J because
//--- our quadratic model is based on Tailor decomposition,
//--- i.m_e. it has 0.5 before quadratic term.
   CAblas::RMatrixGemm(n,n,m,2.0,state.m_j,0,0,1,state.m_j,0,0,0,0.0,state.m_quadraticmodel,0,0);
   CAblas::RMatrixMVect(n,m,state.m_j,0,0,1,state.m_fi,0,state.m_gbase,0);
   for(int i_=0;i_<=n-1;i_++)
      state.m_gbase[i_]=2*state.m_gbase[i_];
//--- change value
   v=0.0;
   for(int i_=0;i_<=m-1;i_++)
      v+=state.m_fi[i_]*state.m_fi[i_];
   state.m_fbase=v;
//--- copy
   for(int i_=0;i_<=m-1;i_++)
      state.m_fibase[i_]=state.m_fi[i_];
//--- set control variables
   bflag=true;
//--- function call, return result
   return(Func_lbl_22(state,n,m,iflag,i,k,bflag,v,s,t));
  }
//+------------------------------------------------------------------+
//| Auxiliary function for MinLMIteration. Is a product to get rid of|
//| the operator unconditional jump goto.                            |
//+------------------------------------------------------------------+
static bool CMinLM::Func_lbl_28(CMinLMState &state,int &n,int &m,int &iflag,
                                int &i,int &k,bool &bflag,double &v,
                                double &s,double &t)
  {
//--- check
   if(k>n-1)
     {
      //--- Calculate F(XBase)
      for(int i_=0;i_<=n-1;i_++)
         state.m_x[i_]=state.m_xbase[i_];
      //--- function call
      ClearRequestFields(state);
      //--- change values
      state.m_needfi=true;
      state.m_rstate.stage=5;
      //--- Saving state
      Func_lbl_rcomm(state,n,m,iflag,i,k,bflag,v,s,t);
      //--- return result
      return(true);
     }
//--- We guard X[k] from leaving [BndL,BndU].
//--- In case BndL=BndU,we assume that derivative in this direction is zero.
   for(int i_=0;i_<=n-1;i_++)
      state.m_x[i_]=state.m_xbase[i_];
   state.m_x[k]=state.m_x[k]-state.m_s[k]*state.m_diffstep;
//--- check
   if(state.m_havebndl[k])
      state.m_x[k]=MathMax(state.m_x[k],state.m_bndl[k]);
//--- check
   if(state.m_havebndu[k])
      state.m_x[k]=MathMin(state.m_x[k],state.m_bndu[k]);
   state.m_xm1=state.m_x[k];
//--- function call
   ClearRequestFields(state);
//--- change values
   state.m_needfi=true;
   state.m_rstate.stage=3;
//--- Saving state
   Func_lbl_rcomm(state,n,m,iflag,i,k,bflag,v,s,t);
//--- return result
   return(true);
  }
//+------------------------------------------------------------------+
//| Auxiliary function for MinLMIteration. Is a product to get rid of|
//| the operator unconditional jump goto.                            |
//+------------------------------------------------------------------+
static bool CMinLM::Func_lbl_31(CMinLMState &state,int &n,int &m,int &iflag,
                                int &i,int &k,bool &bflag,double &v,
                                double &s,double &t)
  {
//--- check
   if(!CAp::Assert(bflag,"MinLM: internal integrity check failed!"))
      return(false);
//--- change values
   state.m_deltaxready=false;
   state.m_deltafready=false;
//--- If Lambda is not initialized,initialize it using quadratic model
   if(state.m_lambdav<0.0)
     {
      state.m_lambdav=0;
      for(i=0;i<=n-1;i++)
         state.m_lambdav=MathMax(state.m_lambdav,MathAbs(state.m_quadraticmodel[i][i])*CMath::Sqr(state.m_s[i]));
      state.m_lambdav=0.001*state.m_lambdav;
      //--- check
      if(state.m_lambdav==0.0)
         state.m_lambdav=1;
     }
//--- Test stopping conditions for function gradient
   if(BoundedScaledAntigradNorm(state,state.m_xbase,state.m_gbase)>state.m_epsg)
     {
      //--- Find value of Levenberg-Marquardt damping parameter which:
      //--- * leads to positive definite damped model
      //--- * within bounds specified by StpMax
      //--- * generates step which decreases function value
      //--- After this block IFlag is set to:
      //--- * -3,if constraints are infeasible
      //--- * -2,if model update is needed (either Lambda growth is too large
      //---       or step is too short,but we can't rely on model and stop iterations)
      //--- * -1,if model is fresh,Lambda have grown too large,termination is needed
      //--- *  0,if everything is OK,continue iterations
      //--- State.Nu can have any value on enter,but after exit it is set to 1.0
      iflag=-99;
      //--- function call, return result
      return(Func_lbl_39(state,n,m,iflag,i,k,bflag,v,s,t));
     }
//--- check
   if(state.m_modelage!=0)
     {
      //--- Model is not fresh,we should refresh it and test
      //--- conditions once more
      state.m_modelage=state.m_maxmodelage+1;
      //--- function call, return result
      return(Func_lbl_20(state,n,m,iflag,i,k,bflag,v,s,t));
     }
//--- Model is fresh,we can rely on it and terminate algorithm
   state.m_repterminationtype=4;
//--- check
   if(!state.m_xrep)
      return(false);
   for(int i_=0;i_<=n-1;i_++)
      state.m_x[i_]=state.m_xbase[i_];
   state.m_f=state.m_fbase;
//--- function call
   ClearRequestFields(state);
//--- change values
   state.m_xupdated=true;
   state.m_rstate.stage=8;
//--- Saving state
   Func_lbl_rcomm(state,n,m,iflag,i,k,bflag,v,s,t);
//--- return result
   return(true);
  }
//+------------------------------------------------------------------+
//| Auxiliary function for MinLMIteration. Is a product to get rid of|
//| the operator unconditional jump goto.                            |
//+------------------------------------------------------------------+
static bool CMinLM::Func_lbl_39(CMinLMState &state,int &n,int &m,int &iflag,
                                int &i,int &k,bool &bflag,double &v,
                                double &s,double &t)
  {
//--- Do we need model update?
   if(state.m_modelage>0 && state.m_nu>=m_suspiciousnu)
     {
      iflag=-2;
      //--- function call, return result
      return(Func_lbl_40(state,n,m,iflag,i,k,bflag,v,s,t));
     }
//--- Setup quadratic solver and solve quadratic programming problem.
//--- After problem is solved we'll try to bound step by StpMax
//--- (Lambda will be increased if step size is too large).
//--- We use BFlag variable to indicate that we have to increase Lambda.
//--- If it is False,we will try to increase Lambda and move to new iteration.
   bflag=true;
//--- function call
   CMinQP::MinQPSetStartingPointFast(state.m_qpstate,state.m_xbase);
//--- function call
   CMinQP::MinQPSetOriginFast(state.m_qpstate,state.m_xbase);
//--- function call
   CMinQP::MinQPSetLinearTermFast(state.m_qpstate,state.m_gbase);
//--- function call
   CMinQP::MinQPSetQuadraticTermFast(state.m_qpstate,state.m_quadraticmodel,true,0.0);
   for(i=0;i<=n-1;i++)
      state.m_tmp0[i]=state.m_quadraticmodel[i][i]+state.m_lambdav/CMath::Sqr(state.m_s[i]);
//--- function call
   CMinQP::MinQPRewriteDiagonal(state.m_qpstate,state.m_tmp0);
//--- function call
   CMinQP::MinQPOptimize(state.m_qpstate);
//--- function call
   CMinQP::MinQPResultsBuf(state.m_qpstate,state.m_xdir,state.m_qprep);
//--- check
   if(state.m_qprep.m_terminationtype>0)
     {
      //--- successful solution of QP problem
      for(int i_=0;i_<=n-1;i_++)
         state.m_xdir[i_]=state.m_xdir[i_]-state.m_xbase[i_];
      v=0.0;
      for(int i_=0;i_<=n-1;i_++)
         v+=state.m_xdir[i_]*state.m_xdir[i_];
      //--- check
      if(CMath::IsFinite(v))
        {
         v=MathSqrt(v);
         //--- check
         if((state.m_stpmax>0.0)&&(v>state.m_stpmax))
            bflag=false;
        }
      else
         bflag=false;
     }
   else
     {
      //--- Either problem is non-convex (increase LambdaV) or constraints are inconsistent
      if(!CAp::Assert(state.m_qprep.m_terminationtype==-3 || state.m_qprep.m_terminationtype==-5,"MinLM: unexpected completion code from QP solver"))
         return(false);
      //--- check
      if(state.m_qprep.m_terminationtype==-3)
        {
         iflag=-3;
         //--- function call, return result
         return(Func_lbl_40(state,n,m,iflag,i,k,bflag,v,s,t));
        }
      bflag=false;
     }
//--- check
   if(!bflag)
     {
      //--- Solution failed:
      //--- try to increase lambda to make matrix positive definite and continue.
      if(!IncreaseLambda(state.m_lambdav,state.m_nu))
        {
         iflag=-1;
         //--- function call, return result
         return(Func_lbl_40(state,n,m,iflag,i,k,bflag,v,s,t));
        }
      //--- function call, return result
      return(Func_lbl_39(state,n,m,iflag,i,k,bflag,v,s,t));
     }
//--- Step in State.XDir and it is bounded by StpMax.
//--- We should check stopping conditions on step size here.
//--- DeltaX,which is used for secant updates,is initialized here.
//--- This code is a bit tricky because sometimes XDir<>0,but
//--- it is so small that XDir+XBase==XBase (in finite precision
//--- arithmetics). So we set DeltaX to XBase,then
//--- add XDir,and then subtract XBase to get exact value of
//--- DeltaX.
//--- Step length is estimated using DeltaX.
//--- NOTE: stopping conditions are tested
//--- for fresh models only (ModelAge=0)
   for(int i_=0;i_<=n-1;i_++)
      state.m_deltax[i_]=state.m_xbase[i_];
   for(int i_=0;i_<=n-1;i_++)
      state.m_deltax[i_]=state.m_deltax[i_]+state.m_xdir[i_];
   for(int i_=0;i_<=n-1;i_++)
      state.m_deltax[i_]=state.m_deltax[i_]-state.m_xbase[i_];
   state.m_deltaxready=true;
//--- change value
   v=0.0;
   for(i=0;i<=n-1;i++)
      v=v+CMath::Sqr(state.m_deltax[i]/state.m_s[i]);
   v=MathSqrt(v);
//--- check
   if(v>state.m_epsx)
      return(Func_lbl_41(state,n,m,iflag,i,k,bflag,v,s,t));
//--- check
   if(state.m_modelage!=0)
     {
      //--- Step is suspiciously short,but model is not fresh
      //--- and we can't rely on it.
      iflag=-2;
      //--- function call, return result
      return(Func_lbl_40(state,n,m,iflag,i,k,bflag,v,s,t));
     }
//--- Step is too short,model is fresh and we can rely on it.
//--- Terminating.
   state.m_repterminationtype=2;
   if(!state.m_xrep)
      return(false);
//--- copy
   for(int i_=0;i_<=n-1;i_++)
      state.m_x[i_]=state.m_xbase[i_];
   state.m_f=state.m_fbase;
//--- function call
   ClearRequestFields(state);
//--- change values
   state.m_xupdated=true;
   state.m_rstate.stage=9;
//--- Saving state
   Func_lbl_rcomm(state,n,m,iflag,i,k,bflag,v,s,t);
//--- return result
   return(true);
  }
//+------------------------------------------------------------------+
//| Auxiliary function for MinLMIteration. Is a product to get rid of|
//| the operator unconditional jump goto.                            |
//+------------------------------------------------------------------+
static bool CMinLM::Func_lbl_40(CMinLMState &state,int &n,int &m,int &iflag,
                                int &i,int &k,bool &bflag,double &v,
                                double &s,double &t)
  {
   state.m_nu=1;
//--- check
   if(!CAp::Assert(iflag>=-3 && iflag<=0,"MinLM: internal integrity check failed!"))
      return(false);
//--- check
   if(iflag==-3)
     {
      state.m_repterminationtype=-3;
      //--- return result
      return(false);
     }
//--- check
   if(iflag==-2)
     {
      state.m_modelage=state.m_maxmodelage+1;
      //--- function call, return result
      return(Func_lbl_20(state,n,m,iflag,i,k,bflag,v,s,t));
     }
//--- check
   if(iflag==-1)
      return(Func_lbl_21(state,n,m,iflag,i,k,bflag,v,s,t));
//--- Levenberg-Marquardt step is ready.
//--- Compare predicted vs. actual decrease and decide what to do with lambda.
//--- NOTE: we expect that State.DeltaX contains direction of step,
//--- State.F contains function value at new point.
   if(!CAp::Assert(state.m_deltaxready,"MinLM: deltaX is not ready"))
      return(false);
   t=0;
   for(i=0;i<=n-1;i++)
     {
      //--- change values
      v=0.0;
      for(int i_=0;i_<=n-1;i_++)
         v+=state.m_quadraticmodel[i][i_]*state.m_deltax[i_];
      t=t+state.m_deltax[i]*state.m_gbase[i]+0.5*state.m_deltax[i]*v;
     }
//--- change values
   state.m_predicteddecrease=-t;
   state.m_actualdecrease=-(state.m_f-state.m_fbase);
//--- check
   if(state.m_predicteddecrease<=0.0)
      return(Func_lbl_21(state,n,m,iflag,i,k,bflag,v,s,t));
   v=state.m_actualdecrease/state.m_predicteddecrease;
//--- check
   if(v>=0.1)
      return(Func_lbl_49(state,n,m,iflag,i,k,bflag,v,s,t));
//--- check
   if(IncreaseLambda(state.m_lambdav,state.m_nu))
      return(Func_lbl_49(state,n,m,iflag,i,k,bflag,v,s,t));
//--- Lambda is too large,we have to break iterations.
   state.m_repterminationtype=7;
//--- check
   if(!state.m_xrep)
      return(false);
   for(int i_=0;i_<=n-1;i_++)
      state.m_x[i_]=state.m_xbase[i_];
   state.m_f=state.m_fbase;
//--- function call
   ClearRequestFields(state);
//--- change values
   state.m_xupdated=true;
   state.m_rstate.stage=12;
//--- Saving state
   Func_lbl_rcomm(state,n,m,iflag,i,k,bflag,v,s,t);
//--- return result
   return(true);
  }
//+------------------------------------------------------------------+
//| Auxiliary function for MinLMIteration. Is a product to get rid of|
//| the operator unconditional jump goto.                            |
//+------------------------------------------------------------------+
static bool CMinLM::Func_lbl_41(CMinLMState &state,int &n,int &m,int &iflag,
                                int &i,int &k,bool &bflag,double &v,
                                double &s,double &t)
  {
//--- Let's evaluate new step:
//--- a) if we have Fi vector,we evaluate it using rcomm,and
//---    then we manually calculate State.F as sum of squares of Fi[]
//--- b) if we have F value,we just evaluate it through rcomm interface
//--- We prefer (a) because we may need Fi vector for additional
//--- iterations
   if(!CAp::Assert(state.m_hasfi|state.m_hasf,"MinLM: internal error 2!"))
      return(false);
   for(int i_=0;i_<=n-1;i_++)
      state.m_x[i_]=state.m_xbase[i_];
   for(int i_=0;i_<=n-1;i_++)
      state.m_x[i_]=state.m_x[i_]+state.m_xdir[i_];
//--- function call
   ClearRequestFields(state);
//--- check
   if(!state.m_hasfi)
     {
      //--- change values
      state.m_needf=true;
      state.m_rstate.stage=11;
      //--- Saving state
      Func_lbl_rcomm(state,n,m,iflag,i,k,bflag,v,s,t);
      //--- return result
      return(true);
     }
//--- change values
   state.m_needfi=true;
   state.m_rstate.stage=10;
//--- Saving state
   Func_lbl_rcomm(state,n,m,iflag,i,k,bflag,v,s,t);
//--- return result
   return(true);
  }
//+------------------------------------------------------------------+
//| Auxiliary function for MinLMIteration. Is a product to get rid of|
//| the operator unconditional jump goto.                            |
//+------------------------------------------------------------------+
static bool CMinLM::Func_lbl_48(CMinLMState &state,int &n,int &m,int &iflag,
                                int &i,int &k,bool &bflag,double &v,
                                double &s,double &t)
  {
   state.m_repnfunc=state.m_repnfunc+1;
//--- check
   if(state.m_f>=state.m_fbase)
     {
      //--- Increase lambda and continue
      if(!IncreaseLambda(state.m_lambdav,state.m_nu))
        {
         iflag=-1;
         //--- function call, return result
         return(Func_lbl_40(state,n,m,iflag,i,k,bflag,v,s,t));
        }
      //--- function call, return result
      return(Func_lbl_39(state,n,m,iflag,i,k,bflag,v,s,t));
     }
//--- We've found our step!
   iflag=0;
//--- function call, return result
   return(Func_lbl_40(state,n,m,iflag,i,k,bflag,v,s,t));
  }
//+------------------------------------------------------------------+
//| Auxiliary function for MinLMIteration. Is a product to get rid of|
//| the operator unconditional jump goto.                            |
//+------------------------------------------------------------------+
static bool CMinLM::Func_lbl_49(CMinLMState &state,int &n,int &m,int &iflag,
                                int &i,int &k,bool &bflag,double &v,
                                double &s,double &t)
  {
//--- check
   if(v>0.5)
      DecreaseLambda(state.m_lambdav,state.m_nu);
//--- Accept step,report it and
//--- test stopping conditions on iterations count and function decrease.
//--- NOTE: we expect that State.DeltaX contains direction of step,
//--- State.F contains function value at new point.
//--- NOTE2: we should update XBase ONLY. In the beginning of the next
//--- iteration we expect that State.FIBase is NOT updated and
//--- contains old value of a function vector.
   for(int i_=0;i_<=n-1;i_++)
      state.m_xbase[i_]=state.m_xbase[i_]+state.m_deltax[i_];
//--- check
   if(!state.m_xrep)
      return(Func_lbl_55(state,n,m,iflag,i,k,bflag,v,s,t));
   for(int i_=0;i_<=n-1;i_++)
      state.m_x[i_]=state.m_xbase[i_];
//--- function call
   ClearRequestFields(state);
//--- change values
   state.m_xupdated=true;
   state.m_rstate.stage=13;
//--- Saving state
   Func_lbl_rcomm(state,n,m,iflag,i,k,bflag,v,s,t);
//--- return result
   return(true);
  }
//+------------------------------------------------------------------+
//| Auxiliary function for MinLMIteration. Is a product to get rid of|
//| the operator unconditional jump goto.                            |
//+------------------------------------------------------------------+
static bool CMinLM::Func_lbl_55(CMinLMState &state,int &n,int &m,int &iflag,
                                int &i,int &k,bool &bflag,double &v,
                                double &s,double &t)
  {
   state.m_repiterationscount=state.m_repiterationscount+1;
//--- check
   if(state.m_repiterationscount>=state.m_maxits&&state.m_maxits>0)
      state.m_repterminationtype=5;
//--- check
   if(state.m_modelage==0)
     {
      //--- check
      if(MathAbs(state.m_f-state.m_fbase)<=state.m_epsf*MathMax(1,MathMax(MathAbs(state.m_f),MathAbs(state.m_fbase))))
         state.m_repterminationtype=1;
     }
//--- check
   if(state.m_repterminationtype<=0)
     {
      state.m_modelage=state.m_modelage+1;
      //--- function call, return result
      return(Func_lbl_20(state,n,m,iflag,i,k,bflag,v,s,t));
     }
//--- check
   if(!state.m_xrep)
      return(false);
//--- Report: XBase contains new point,F contains function value at new point
   for(int i_=0;i_<=n-1;i_++)
      state.m_x[i_]=state.m_xbase[i_];
//--- function call
   ClearRequestFields(state);
//--- change values
   state.m_xupdated=true;
   state.m_rstate.stage=14;
//--- Saving state
   Func_lbl_rcomm(state,n,m,iflag,i,k,bflag,v,s,t);
//--- return result
   return(true);
  }
//+------------------------------------------------------------------+
//| Auxiliary class for CMinComp                                     |
//+------------------------------------------------------------------+
class CMinASAState
  {
public:
   //--- variables
   int               m_n;
   double            m_epsg;
   double            m_epsf;
   double            m_epsx;
   int               m_maxits;
   bool              m_xrep;
   double            m_stpmax;
   int               m_cgtype;
   int               m_k;
   int               m_nfev;
   int               m_mcstage;
   int               m_curalgo;
   int               m_acount;
   double            m_mu;
   double            m_finit;
   double            m_dginit;
   double            m_fold;
   double            m_stp;
   double            m_laststep;
   double            m_f;
   bool              m_needfg;
   bool              m_xupdated;
   RCommState        m_rstate;
   int               m_repiterationscount;
   int               m_repnfev;
   int               m_repterminationtype;
   int               m_debugrestartscount;
   CLinMinState      m_lstate;
   double            m_betahs;
   double            m_betady;
   //--- arrays
   double            m_bndl[];
   double            m_bndu[];
   double            m_ak[];
   double            m_xk[];
   double            m_dk[];
   double            m_an[];
   double            m_xn[];
   double            m_dn[];
   double            m_d[];
   double            m_work[];
   double            m_yk[];
   double            m_gc[];
   double            m_x[];
   double            m_g[];
   //--- constructor, destructor
                     CMinASAState(void);
                    ~CMinASAState(void);
   //--- copy
   void              Copy(CMinASAState &obj);
  };
//+------------------------------------------------------------------+
//| Constructor without parameters                                   |
//+------------------------------------------------------------------+
CMinASAState::CMinASAState(void)
  {

  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CMinASAState::~CMinASAState(void)
  {

  }
//+------------------------------------------------------------------+
//| Copy                                                             |
//+------------------------------------------------------------------+
void CMinASAState::Copy(CMinASAState &obj)
  {
//--- copy variables
   m_n=obj.m_n;
   m_epsg=obj.m_epsg;
   m_epsf=obj.m_epsf;
   m_epsx=obj.m_epsx;
   m_maxits=obj.m_maxits;
   m_xrep=obj.m_xrep;
   m_stpmax=obj.m_stpmax;
   m_cgtype=obj.m_cgtype;
   m_k=obj.m_k;
   m_nfev=obj.m_nfev;
   m_mcstage=obj.m_mcstage;
   m_curalgo=obj.m_curalgo;
   m_acount=obj.m_acount;
   m_mu=obj.m_mu;
   m_finit=obj.m_finit;
   m_dginit=obj.m_dginit;
   m_fold=obj.m_fold;
   m_stp=obj.m_stp;
   m_laststep=obj.m_laststep;
   m_f=obj.m_f;
   m_needfg=obj.m_needfg;
   m_xupdated=obj.m_xupdated;
   m_repiterationscount=obj.m_repiterationscount;
   m_repnfev=obj.m_repnfev;
   m_repterminationtype=obj.m_repterminationtype;
   m_debugrestartscount=obj.m_debugrestartscount;
   m_betahs=obj.m_betahs;
   m_betady=obj.m_betady;
   m_rstate.Copy(obj.m_rstate);
   m_lstate.Copy(obj.m_lstate);
//--- copy arrays
   ArrayCopy(m_bndl,obj.m_bndl);
   ArrayCopy(m_bndu,obj.m_bndu);
   ArrayCopy(m_ak,obj.m_ak);
   ArrayCopy(m_xk,obj.m_xk);
   ArrayCopy(m_dk,obj.m_dk);
   ArrayCopy(m_an,obj.m_an);
   ArrayCopy(m_xn,obj.m_xn);
   ArrayCopy(m_dn,obj.m_dn);
   ArrayCopy(m_d,obj.m_d);
   ArrayCopy(m_work,obj.m_work);
   ArrayCopy(m_yk,obj.m_yk);
   ArrayCopy(m_gc,obj.m_gc);
   ArrayCopy(m_x,obj.m_x);
   ArrayCopy(m_g,obj.m_g);
  }
//+------------------------------------------------------------------+
//| This class is a shell for class CMinASAState                     |
//+------------------------------------------------------------------+
class CMinASAStateShell
  {
private:
   CMinASAState      m_innerobj;
public:
   //--- constructors, destructor
                     CMinASAStateShell(void);
                     CMinASAStateShell(CMinASAState &obj);
                    ~CMinASAStateShell(void);
   //--- methods
   bool              GetNeedFG(void);
   void              SetNeedFG(const bool b);
   bool              GetXUpdated(void);
   void              SetXUpdated(const bool b);
   double            GetF(void);
   void              SetF(const double d);
   CMinASAState     *GetInnerObj(void);
  };
//+------------------------------------------------------------------+
//| Constructor without parameters                                   |
//+------------------------------------------------------------------+
CMinASAStateShell::CMinASAStateShell(void)
  {

  }
//+------------------------------------------------------------------+
//| Copy constructor                                                 |
//+------------------------------------------------------------------+
CMinASAStateShell::CMinASAStateShell(CMinASAState &obj)
  {
//--- copy
   m_innerobj.Copy(obj);
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CMinASAStateShell::~CMinASAStateShell(void)
  {

  }
//+------------------------------------------------------------------+
//| Returns the value of the variable needfg                         |
//+------------------------------------------------------------------+
bool CMinASAStateShell::GetNeedFG(void)
  {
//--- return result
   return(m_innerobj.m_needfg);
  }
//+------------------------------------------------------------------+
//| Changing the value of the variable needfg                        |
//+------------------------------------------------------------------+
void CMinASAStateShell::SetNeedFG(const bool b)
  {
//--- change value
   m_innerobj.m_needfg=b;
  }
//+------------------------------------------------------------------+
//| Returns the value of the variable xupdated                       |
//+------------------------------------------------------------------+
bool CMinASAStateShell::GetXUpdated(void)
  {
//--- return result
   return(m_innerobj.m_xupdated);
  }
//+------------------------------------------------------------------+
//| Changing the value of the variable xupdated                      |
//+------------------------------------------------------------------+
void CMinASAStateShell::SetXUpdated(const bool b)
  {
//--- change value
   m_innerobj.m_xupdated=b;
  }
//+------------------------------------------------------------------+
//| Returns the value of the variable f                              |
//+------------------------------------------------------------------+
double CMinASAStateShell::GetF(void)
  {
//--- return result
   return(m_innerobj.m_f);
  }
//+------------------------------------------------------------------+
//| Changing the value of the variable f                             |
//+------------------------------------------------------------------+
void CMinASAStateShell::SetF(const double d)
  {
//--- change value
   m_innerobj.m_f=d;
  }
//+------------------------------------------------------------------+
//| Return object of class                                           |
//+------------------------------------------------------------------+
CMinASAState *CMinASAStateShell::GetInnerObj(void)
  {
//--- return result
   return(GetPointer(m_innerobj));
  }
//+------------------------------------------------------------------+
//| Auxiliary class for CMinComp                                     |
//+------------------------------------------------------------------+
class CMinASAReport
  {
public:
   //--- variables
   int               m_iterationscount;
   int               m_nfev;
   int               m_terminationtype;
   int               m_activeconstraints;
   //--- constructor, destructor
                     CMinASAReport(void);
                    ~CMinASAReport(void);
   //--- copy
   void              Copy(CMinASAReport &obj);
  };
//+------------------------------------------------------------------+
//| Constructor without parameters                                   |
//+------------------------------------------------------------------+
CMinASAReport::CMinASAReport(void)
  {

  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CMinASAReport::~CMinASAReport(void)
  {

  }
//+------------------------------------------------------------------+
//| Copy                                                             |
//+------------------------------------------------------------------+
void CMinASAReport::Copy(CMinASAReport &obj)
  {
//--- copy variables
   m_iterationscount=obj.m_iterationscount;
   m_nfev=obj.m_nfev;
   m_terminationtype=obj.m_terminationtype;
   m_activeconstraints=obj.m_activeconstraints;
  }
//+------------------------------------------------------------------+
//| This class is a shell for class CMinASAReport                    |
//+------------------------------------------------------------------+
class CMinASAReportShell
  {
private:
   CMinASAReport     m_innerobj;
public:
   //--- constructors, destructor
                     CMinASAReportShell(void);
                     CMinASAReportShell(CMinASAReport &obj);
                    ~CMinASAReportShell(void);
   //--- methods
   int               GetIterationsCount(void);
   void              SetIterationsCount(const int i);
   int               GetNFev(void);
   void              SetNFev(const int i);
   int               GetTerminationType(void);
   void              SetTerminationType(const int i);
   int               GetActiveConstraints(void);
   void              SetActiveConstraints(const int i);
   CMinASAReport    *GetInnerObj(void);
  };
//+------------------------------------------------------------------+
//| Constructor without parameters                                   |
//+------------------------------------------------------------------+
CMinASAReportShell::CMinASAReportShell(void)
  {

  }
//+------------------------------------------------------------------+
//| Copy constructor                                                 |
//+------------------------------------------------------------------+
CMinASAReportShell::CMinASAReportShell(CMinASAReport &obj)
  {
//--- copy
   m_innerobj.Copy(obj);
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CMinASAReportShell::~CMinASAReportShell(void)
  {

  }
//+------------------------------------------------------------------+
//| Returns the value of the variable iterationscount                |
//+------------------------------------------------------------------+
int CMinASAReportShell::GetIterationsCount(void)
  {
//--- return result
   return(m_innerobj.m_iterationscount);
  }
//+------------------------------------------------------------------+
//| Changing the value of the variable iterationscount               |
//+------------------------------------------------------------------+
void CMinASAReportShell::SetIterationsCount(const int i)
  {
//--- change value
   m_innerobj.m_iterationscount=i;
  }
//+------------------------------------------------------------------+
//| Returns the value of the variable nfev                           |
//+------------------------------------------------------------------+
int CMinASAReportShell::GetNFev(void)
  {
//--- return result
   return(m_innerobj.m_nfev);
  }
//+------------------------------------------------------------------+
//| Changing the value of the variable nfev                          |
//+------------------------------------------------------------------+
void CMinASAReportShell::SetNFev(const int i)
  {
//--- change value
   m_innerobj.m_nfev=i;
  }
//+------------------------------------------------------------------+
//| Returns the value of the variable terminationtype                |
//+------------------------------------------------------------------+
int CMinASAReportShell::GetTerminationType(void)
  {
//--- return result
   return(m_innerobj.m_terminationtype);
  }
//+------------------------------------------------------------------+
//| Changing the value of the variable terminationtype               |
//+------------------------------------------------------------------+
void CMinASAReportShell::SetTerminationType(const int i)
  {
//--- change value
   m_innerobj.m_terminationtype=i;
  }
//+------------------------------------------------------------------+
//| Returns the value of the variable activeconstraints              |
//+------------------------------------------------------------------+
int CMinASAReportShell::GetActiveConstraints(void)
  {
//--- return result
   return(m_innerobj.m_activeconstraints);
  }
//+------------------------------------------------------------------+
//| Changing the value of the variable activeconstraints             |
//+------------------------------------------------------------------+
void CMinASAReportShell::SetActiveConstraints(const int i)
  {
//--- change value
   m_innerobj.m_activeconstraints=i;
  }
//+------------------------------------------------------------------+
//| Return object of class                                           |
//+------------------------------------------------------------------+
CMinASAReport *CMinASAReportShell::GetInnerObj(void)
  {
//--- return result
   return(GetPointer(m_innerobj));
  }
//+------------------------------------------------------------------+
//| Backward compatibility functions                                 |
//+------------------------------------------------------------------+
class CMinComp
  {
private:
   //--- private methods
   static double     ASABoundedAntigradNorm(CMinASAState &state);
   static double     ASAGINorm(CMinASAState &state);
   static double     ASAD1Norm(CMinASAState &state);
   static bool       ASAUIsEmpty(CMinASAState &state);
   static void       ClearRequestFields(CMinASAState &state);
   //--- auxiliary functions for MinASAIteration
   static void       Func_lbl_rcomm(CMinASAState &state,int n,int i,int mcinfo,int diffcnt,bool b,bool stepfound,double betak,double v,double vv);
   static bool       Func_lbl_15(CMinASAState &state,int &n,int &i,int &mcinfo,int &diffcnt,bool &b,bool &stepfound,double &betak,double &v,double &vv);
   static bool       Func_lbl_17(CMinASAState &state,int &n,int &i,int &mcinfo,int &diffcnt,bool &b,bool &stepfound,double &betak,double &v,double &vv);
   static bool       Func_lbl_19(CMinASAState &state,int &n,int &i,int &mcinfo,int &diffcnt,bool &b,bool &stepfound,double &betak,double &v,double &vv);
   static bool       Func_lbl_21(CMinASAState &state,int &n,int &i,int &mcinfo,int &diffcnt,bool &b,bool &stepfound,double &betak,double &v,double &vv);
   static bool       Func_lbl_24(CMinASAState &state,int &n,int &i,int &mcinfo,int &diffcnt,bool &b,bool &stepfound,double &betak,double &v,double &vv);
   static bool       Func_lbl_26(CMinASAState &state,int &n,int &i,int &mcinfo,int &diffcnt,bool &b,bool &stepfound,double &betak,double &v,double &vv);
   static bool       Func_lbl_27(CMinASAState &state,int &n,int &i,int &mcinfo,int &diffcnt,bool &b,bool &stepfound,double &betak,double &v,double &vv);
   static bool       Func_lbl_29(CMinASAState &state,int &n,int &i,int &mcinfo,int &diffcnt,bool &b,bool &stepfound,double &betak,double &v,double &vv);
   static bool       Func_lbl_31(CMinASAState &state,int &n,int &i,int &mcinfo,int &diffcnt,bool &b,bool &stepfound,double &betak,double &v,double &vv);
   static bool       Func_lbl_35(CMinASAState &state,int &n,int &i,int &mcinfo,int &diffcnt,bool &b,bool &stepfound,double &betak,double &v,double &vv);
   static bool       Func_lbl_39(CMinASAState &state,int &n,int &i,int &mcinfo,int &diffcnt,bool &b,bool &stepfound,double &betak,double &v,double &vv);
   static bool       Func_lbl_43(CMinASAState &state,int &n,int &i,int &mcinfo,int &diffcnt,bool &b,bool &stepfound,double &betak,double &v,double &vv);
   static bool       Func_lbl_49(CMinASAState &state,int &n,int &i,int &mcinfo,int &diffcnt,bool &b,bool &stepfound,double &betak,double &v,double &vv);
   static bool       Func_lbl_51(CMinASAState &state,int &n,int &i,int &mcinfo,int &diffcnt,bool &b,bool &stepfound,double &betak,double &v,double &vv);
   static bool       Func_lbl_52(CMinASAState &state,int &n,int &i,int &mcinfo,int &diffcnt,bool &b,bool &stepfound,double &betak,double &v,double &vv);
   static bool       Func_lbl_53(CMinASAState &state,int &n,int &i,int &mcinfo,int &diffcnt,bool &b,bool &stepfound,double &betak,double &v,double &vv);
   static bool       Func_lbl_55(CMinASAState &state,int &n,int &i,int &mcinfo,int &diffcnt,bool &b,bool &stepfound,double &betak,double &v,double &vv);
   static bool       Func_lbl_59(CMinASAState &state,int &n,int &i,int &mcinfo,int &diffcnt,bool &b,bool &stepfound,double &betak,double &v,double &vv);
   static bool       Func_lbl_63(CMinASAState &state,int &n,int &i,int &mcinfo,int &diffcnt,bool &b,bool &stepfound,double &betak,double &v,double &vv);
   static bool       Func_lbl_65(CMinASAState &state,int &n,int &i,int &mcinfo,int &diffcnt,bool &b,bool &stepfound,double &betak,double &v,double &vv);
public:
   //--- class constants
   static const int  m_n1;
   static const int  m_n2;
   static const double m_stpmin;
   static const double m_gtol;
   static const double m_gpaftol;
   static const double m_gpadecay;
   static const double m_asarho;
   //--- constructor, destructor
                     CMinComp(void);
                    ~CMinComp(void);
   //--- public methods
   static void       MinLBFGSSetDefaultPreconditioner(CMinLBFGSState &state);
   static void       MinLBFGSSetCholeskyPreconditioner(CMinLBFGSState &state,CMatrixDouble &p,const bool isupper);
   static void       MinBLEICSetBarrierWidth(CMinBLEICState &state,const double mu);
   static void       MinBLEICSetBarrierDecay(CMinBLEICState &state,const double mudecay);
   static void       MinASACreate(const int n,double &x[],double &bndl[],double &bndu[],CMinASAState &state);
   static void       MinASASetCond(CMinASAState &state,const double epsg,const double epsf,double epsx,const int maxits);
   static void       MinASASetXRep(CMinASAState &state,const bool needxrep);
   static void       MinASASetAlgorithm(CMinASAState &state,int algotype);
   static void       MinASASetStpMax(CMinASAState &state,const double stpmax);
   static void       MinASAResults(CMinASAState &state,double &x[],CMinASAReport &rep);
   static void       MinASAResultsBuf(CMinASAState &state,double &x[],CMinASAReport &rep);
   static void       MinASARestartFrom(CMinASAState &state,double &x[],double &bndl[],double &bndu[]);
   static bool       MinASAIteration(CMinASAState &state);
  };
//+------------------------------------------------------------------+
//| Initialize constants                                             |
//+------------------------------------------------------------------+
const int    CMinComp::m_n1=2;
const int    CMinComp::m_n2=2;
const double CMinComp::m_stpmin=1.0E-300;
const double CMinComp::m_gtol=0.3;
const double CMinComp::m_gpaftol=0.0001;
const double CMinComp::m_gpadecay=0.5;
const double CMinComp::m_asarho=0.5;
//+------------------------------------------------------------------+
//| Constructor without parameters                                   |
//+------------------------------------------------------------------+
CMinComp::CMinComp(void)
  {

  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CMinComp::~CMinComp(void)
  {

  }
//+------------------------------------------------------------------+
//| Obsolete function, use MinLBFGSSetPrecDefault() instead.         |
//+------------------------------------------------------------------+
static void CMinComp::MinLBFGSSetDefaultPreconditioner(CMinLBFGSState &state)
  {
//--- function call
   CMinLBFGS::MinLBFGSSetPrecDefault(state);
  }
//+------------------------------------------------------------------+
//| Obsolete function, use MinLBFGSSetCholeskyPreconditioner()       |
//| instead.                                                         |
//+------------------------------------------------------------------+
static void CMinComp::MinLBFGSSetCholeskyPreconditioner(CMinLBFGSState &state,
                                                        CMatrixDouble &p,
                                                        const bool isupper)
  {
//--- function call
   CMinLBFGS::MinLBFGSSetPrecCholesky(state,p,isupper);
  }
//+------------------------------------------------------------------+
//| This is obsolete function which was used by previous version of  |
//| the  BLEIC optimizer. It does nothing in the current version of  |
//| BLEIC.                                                           |
//+------------------------------------------------------------------+
static void CMinComp::MinBLEICSetBarrierWidth(CMinBLEICState &state,
                                              const double mu)
  {

  }
//+------------------------------------------------------------------+
//| This is obsolete function which was used by previous version of  |
//| the  BLEIC optimizer. It does nothing in the current version of  |
//| BLEIC.                                                           |
//+------------------------------------------------------------------+
static void CMinComp::MinBLEICSetBarrierDecay(CMinBLEICState &state,
                                              const double mudecay)
  {

  }
//+------------------------------------------------------------------+
//| Obsolete optimization algorithm.                                 |
//| Was replaced by MinBLEIC subpackage.                             |
//+------------------------------------------------------------------+
static void CMinComp::MinASACreate(const int n,double &x[],double &bndl[],
                                   double &bndu[],CMinASAState &state)
  {
//--- create a variable
   int i=0;
//--- check
   if(!CAp::Assert(n>=1,__FUNCTION__+": N too small!"))
      return;
//--- check
   if(!CAp::Assert(CAp::Len(x)>=n,__FUNCTION__+": Length(X)<N!"))
      return;
//--- check
   if(!CAp::Assert(CApServ::IsFiniteVector(x,n),__FUNCTION__+": X contains infinite or NaN values!"))
      return;
//--- check
   if(!CAp::Assert(CAp::Len(bndl)>=n,__FUNCTION__+": Length(BndL)<N!"))
      return;
//--- check
   if(!CAp::Assert(CApServ::IsFiniteVector(bndl,n),__FUNCTION__+": BndL contains infinite or NaN values!"))
      return;
//--- check
   if(!CAp::Assert(CAp::Len(bndu)>=n,__FUNCTION__+": Length(BndU)<N!"))
      return;
//--- check
   if(!CAp::Assert(CApServ::IsFiniteVector(bndu,n),__FUNCTION__+": BndU contains infinite or NaN values!"))
      return;
   for(i=0;i<=n-1;i++)
     {
      //--- check
      if(!CAp::Assert((double)(bndl[i])<=(double)(bndu[i]),__FUNCTION__+": inconsistent bounds!"))
         return;
      //--- check
      if(!CAp::Assert((double)(bndl[i])<=x[i],__FUNCTION__+": infeasible X!"))
         return;
      //--- check
      if(!CAp::Assert(x[i]<=(double)(bndu[i]),__FUNCTION__+": infeasible X!"))
         return;
     }
//--- Initialize
   state.m_n=n;
   MinASASetCond(state,0,0,0,0);
   MinASASetXRep(state,false);
   MinASASetStpMax(state,0);
   MinASASetAlgorithm(state,-1);
//--- allocation
   ArrayResizeAL(state.m_bndl,n);
   ArrayResizeAL(state.m_bndu,n);
   ArrayResizeAL(state.m_ak,n);
   ArrayResizeAL(state.m_xk,n);
   ArrayResizeAL(state.m_dk,n);
   ArrayResizeAL(state.m_an,n);
   ArrayResizeAL(state.m_xn,n);
   ArrayResizeAL(state.m_dn,n);
   ArrayResizeAL(state.m_x,n);
   ArrayResizeAL(state.m_d,n);
   ArrayResizeAL(state.m_g,n);
   ArrayResizeAL(state.m_gc,n);
   ArrayResizeAL(state.m_work,n);
   ArrayResizeAL(state.m_yk,n);
//--- function call
   MinASARestartFrom(state,x,bndl,bndu);
  }
//+------------------------------------------------------------------+
//| Obsolete optimization algorithm.                                 |
//| Was replaced by MinBLEIC subpackage.                             |
//+------------------------------------------------------------------+
static void CMinComp::MinASASetCond(CMinASAState &state,const double epsg,
                                    const double epsf,double epsx,
                                    const int maxits)
  {
//--- check
   if(!CAp::Assert(CMath::IsFinite(epsg),__FUNCTION__+": EpsG is not finite number!"))
      return;
//--- check
   if(!CAp::Assert(epsg>=0.0,__FUNCTION__+": negative EpsG!"))
      return;
//--- check
   if(!CAp::Assert(CMath::IsFinite(epsf),__FUNCTION__+": EpsF is not finite number!"))
      return;
//--- check
   if(!CAp::Assert(epsf>=0.0,__FUNCTION__+": negative EpsF!"))
      return;
//--- check
   if(!CAp::Assert(CMath::IsFinite(epsx),__FUNCTION__+": EpsX is not finite number!"))
      return;
//--- check
   if(!CAp::Assert(epsx>=0.0,__FUNCTION__+": negative EpsX!"))
      return;
//--- check
   if(!CAp::Assert(maxits>=0,__FUNCTION__+": negative MaxIts!"))
      return;
//--- check
   if(((epsg==0.0 && epsf==0.0) && epsx==0.0) && maxits==0)
      epsx=1.0E-6;
//--- change values
   state.m_epsg=epsg;
   state.m_epsf=epsf;
   state.m_epsx=epsx;
   state.m_maxits=maxits;
  }
//+------------------------------------------------------------------+
//| Obsolete optimization algorithm.                                 |
//| Was replaced by MinBLEIC subpackage.                             |
//+------------------------------------------------------------------+
static void CMinComp::MinASASetXRep(CMinASAState &state,const bool needxrep)
  {
//--- change value
   state.m_xrep=needxrep;
  }
//+------------------------------------------------------------------+
//| Obsolete optimization algorithm.                                 |
//| Was replaced by MinBLEIC subpackage.                             |
//+------------------------------------------------------------------+
static void CMinComp::MinASASetAlgorithm(CMinASAState &state,int algotype)
  {
//--- check
   if(!CAp::Assert(algotype>=-1 && algotype<=1,__FUNCTION__+": incorrect AlgoType!"))
      return;
//--- check
   if(algotype==-1)
      algotype=1;
//--- change value
   state.m_cgtype=algotype;
  }
//+------------------------------------------------------------------+
//| Obsolete optimization algorithm.                                 |
//| Was replaced by MinBLEIC subpackage.                             |
//+------------------------------------------------------------------+
static void CMinComp::MinASASetStpMax(CMinASAState &state,const double stpmax)
  {
//--- check
   if(!CAp::Assert(CMath::IsFinite(stpmax),__FUNCTION__+": StpMax is not finite!"))
      return;
//--- check
   if(!CAp::Assert(stpmax>=0.0,__FUNCTION__+": StpMax<0!"))
      return;
//--- change value
   state.m_stpmax=stpmax;
  }
//+------------------------------------------------------------------+
//| Obsolete optimization algorithm.                                 |
//| Was replaced by MinBLEIC subpackage.                             |
//+------------------------------------------------------------------+
static void CMinComp::MinASAResults(CMinASAState &state,double &x[],CMinASAReport &rep)
  {
//--- reset memory
   ArrayResizeAL(x,0);
//--- function call
   MinASAResultsBuf(state,x,rep);
  }
//+------------------------------------------------------------------+
//| Obsolete optimization algorithm.                                 |
//| Was replaced by MinBLEIC subpackage.                             |
//+------------------------------------------------------------------+
static void CMinComp::MinASAResultsBuf(CMinASAState &state,double &x[],
                                       CMinASAReport &rep)
  {
//--- create variables
   int i=0;
   int i_=0;
//--- check
   if(CAp::Len(x)<state.m_n)
      ArrayResizeAL(x,state.m_n);
//--- copy
   for(i_=0;i_<=state.m_n-1;i_++)
      x[i_]=state.m_x[i_];
//--- change values
   rep.m_iterationscount=state.m_repiterationscount;
   rep.m_nfev=state.m_repnfev;
   rep.m_terminationtype=state.m_repterminationtype;
   rep.m_activeconstraints=0;
   for(i=0;i<=state.m_n-1;i++)
     {
      //--- check
      if(state.m_ak[i]==0.0)
         rep.m_activeconstraints=rep.m_activeconstraints+1;
     }
  }
//+------------------------------------------------------------------+
//| Obsolete optimization algorithm.                                 |
//| Was replaced by MinBLEIC subpackage.                             |
//+------------------------------------------------------------------+
static void CMinComp::MinASARestartFrom(CMinASAState &state,double &x[],double &bndl[],double &bndu[])
  {
//--- create a variable
   int i_=0;
//--- check
   if(!CAp::Assert(CAp::Len(x)>=state.m_n,__FUNCTION__+": Length(X)<N!"))
      return;
//--- check
   if(!CAp::Assert(CApServ::IsFiniteVector(x,state.m_n),__FUNCTION__+": X contains infinite or NaN values!"))
      return;
//--- check
   if(!CAp::Assert(CAp::Len(bndl)>=state.m_n,__FUNCTION__+": Length(BndL)<N!"))
      return;
//--- check
   if(!CAp::Assert(CApServ::IsFiniteVector(bndl,state.m_n),__FUNCTION__+": BndL contains infinite or NaN values!"))
      return;
//--- check
   if(!CAp::Assert(CAp::Len(bndu)>=state.m_n,__FUNCTION__+": Length(BndU)<N!"))
      return;
//--- check
   if(!CAp::Assert(CApServ::IsFiniteVector(bndu,state.m_n),__FUNCTION__+": BndU contains infinite or NaN values!"))
      return;
//--- copy
   for(i_=0;i_<=state.m_n-1;i_++)
      state.m_x[i_]=x[i_];
   for(i_=0;i_<=state.m_n-1;i_++)
      state.m_bndl[i_]=bndl[i_];
   for(i_=0;i_<=state.m_n-1;i_++)
      state.m_bndu[i_]=bndu[i_];
   state.m_laststep=0;
//--- allocation
   ArrayResizeAL(state.m_rstate.ia,4);
   ArrayResizeAL(state.m_rstate.ba,2);
   ArrayResizeAL(state.m_rstate.ra,3);
   state.m_rstate.stage=-1;
//--- function call
   ClearRequestFields(state);
  }
//+------------------------------------------------------------------+
//| Returns norm of bounded anti-gradient.                           |
//| Bounded antigradient is a vector obtained from anti-gradient by  |
//| zeroing components which point outwards:                         |
//|     result = norm(v)                                             |
//|     v[i]=0     if ((-g[i]<0)and(x[i]=bndl[i])) or                |
//|                   ((-g[i]>0)and(x[i]=bndu[i]))                   |
//|     v[i]=-g[i] otherwise                                         |
//| This function may be used to check a stopping criterion.         |
//+------------------------------------------------------------------+
static double CMinComp::ASABoundedAntigradNorm(CMinASAState &state)
  {
//--- create variables
   double result=0;
   int    i=0;
   double v=0;
//--- initialization
   result=0;
   for(i=0;i<=state.m_n-1;i++)
     {
      v=-state.m_g[i];
      //--- check
      if(state.m_x[i]==state.m_bndl[i] && -state.m_g[i]<0.0)
         v=0;
      //--- check
      if(state.m_x[i]==state.m_bndu[i] && -state.m_g[i]>0.0)
         v=0;
      result=result+CMath::Sqr(v);
     }
//--- return result
   return(MathSqrt(result));
  }
//+------------------------------------------------------------------+
//| Returns norm of GI(x).                                           |
//| GI(x) is a gradient vector whose components associated with      |
//| active constraints are zeroed. It differs from bounded           |
//| anti-gradient because components of GI(x) are zeroed             |
//| independently of sign(g[i]), and anti-gradient's components are  |
//| zeroed with respect to both constraint and sign.                 |
//+------------------------------------------------------------------+
static double CMinComp::ASAGINorm(CMinASAState &state)
  {
//--- create variables
   double result=0;
   int    i=0;
//--- initialization
   result=0;
   for(i=0;i<=state.m_n-1;i++)
     {
      //--- check
      if(state.m_x[i]!=state.m_bndl[i] && state.m_x[i]!=state.m_bndu[i])
         result=result+CMath::Sqr(state.m_g[i]);
     }
//--- return result
   return(MathSqrt(result));
  }
//+------------------------------------------------------------------+
//| Returns norm(D1(State.X))                                        |
//| For a meaning of D1 see 'NEW ACTIVE SET ALGORITHM FOR BOX        |
//| CONSTRAINED OPTIMIZATION' by WILLIAM W. HAGER AND HONGCHAO ZHANG.|
//+------------------------------------------------------------------+
static double CMinComp::ASAD1Norm(CMinASAState &state)
  {
//--- create variables
   double result=0;
   int    i=0;
//--- initialization
   result=0;
   for(i=0;i<=state.m_n-1;i++)
      result=result+CMath::Sqr(CApServ::BoundVal(state.m_x[i]-state.m_g[i],state.m_bndl[i],state.m_bndu[i])-state.m_x[i]);
//--- return result
   return(MathSqrt(result));
  }
//+------------------------------------------------------------------+
//| Returns True, if U set is empty.                                 |
//| * State.X is used as point,                                      |
//| * State.G - as gradient,                                         |
//| * D is calculated within function (because State.D may have      |
//|   different meaning depending on current optimization algorithm) |
//| For a meaning of U see 'NEW ACTIVE SET ALGORITHM FOR BOX         |
//| CONSTRAINED OPTIMIZATION' by WILLIAM W. HAGER AND HONGCHAO ZHANG.|
//+------------------------------------------------------------------+
static bool CMinComp::ASAUIsEmpty(CMinASAState &state)
  {
//--- create variables
   int    i=0;
   double d=0;
   double d2=0;
   double d32=0;
//--- initialization
   d=ASAD1Norm(state);
   d2=MathSqrt(d);
   d32=d*d2;
   for(i=0;i<=state.m_n-1;i++)
     {
      //--- check
      if(MathAbs(state.m_g[i])>=d2 && MathMin(state.m_x[i]-state.m_bndl[i],state.m_bndu[i]-state.m_x[i])>=d32)
         return(false);
     }
//--- return result
   return(true);
  }
//+------------------------------------------------------------------+
//| Clears request fileds (to be sure that we don't forgot to clear  |
//| something)                                                       |
//+------------------------------------------------------------------+
static void CMinComp::ClearRequestFields(CMinASAState &state)
  {
//--- change values
   state.m_needfg=false;
   state.m_xupdated=false;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
static bool CMinComp::MinASAIteration(CMinASAState &state)
  {
//--- create variables
   int    n=0;
   int    i=0;
   double betak=0;
   double v=0;
   double vv=0;
   int    mcinfo=0;
   bool   b;
   bool   stepfound;
   int    diffcnt=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];
      i=state.m_rstate.ia[1];
      mcinfo=state.m_rstate.ia[2];
      diffcnt=state.m_rstate.ia[3];
      b=state.m_rstate.ba[0];
      stepfound=state.m_rstate.ba[1];
      betak=state.m_rstate.ra[0];
      v=state.m_rstate.ra[1];
      vv=state.m_rstate.ra[2];
     }
   else
     {
      //--- initialization
      n=-983;
      i=-989;
      mcinfo=-834;
      diffcnt=900;
      b=true;
      stepfound=false;
      betak=214;
      v=-338;
      vv=-686;
     }
//--- check
   if(state.m_rstate.stage==0)
     {
      //--- change value
      state.m_needfg=false;
      //--- check
      if(!state.m_xrep)
         return(Func_lbl_15(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv));
      //--- progress report
      ClearRequestFields(state);
      state.m_xupdated=true;
      state.m_rstate.stage=1;
      //--- Saving state
      Func_lbl_rcomm(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv);
      //--- return result
      return(true);
     }
//--- check
   if(state.m_rstate.stage==1)
     {
      //--- change value
      state.m_xupdated=false;
      //--- function call, return result
      return(Func_lbl_15(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv));
     }
//--- check
   if(state.m_rstate.stage==2)
     {
      //--- change values
      state.m_needfg=false;
      state.m_repnfev=state.m_repnfev+1;
      stepfound=state.m_f<=state.m_finit+m_gpaftol*state.m_dginit;
      //--- function call, return result
      return(Func_lbl_24(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv));
     }
//--- check
   if(state.m_rstate.stage==3)
     {
      //--- change values
      state.m_needfg=false;
      state.m_repnfev=state.m_repnfev+1;
      //--- check
      if(state.m_stp<=m_stpmin)
        {
         for(i_=0;i_<=n-1;i_++)
            state.m_xn[i_]=state.m_x[i_];
         //--- function call, return result
         return(Func_lbl_26(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv));
        }
      //--- check
      if(state.m_f<=state.m_finit+state.m_stp*m_gpaftol*state.m_dginit)
        {
         //--- copy
         for(i_=0;i_<=n-1;i_++)
            state.m_xn[i_]=state.m_x[i_];
         //--- function call, return result
         return(Func_lbl_26(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv));
        }
      //--- change value
      state.m_stp=state.m_stp*m_gpadecay;
      //--- function call, return result
      return(Func_lbl_27(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv));
     }
//--- check
   if(state.m_rstate.stage==4)
     {
      //--- change value
      state.m_xupdated=false;
      //--- function call, return result
      return(Func_lbl_29(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv));
     }
//--- check
   if(state.m_rstate.stage==5)
     {
      //--- change value
      state.m_xupdated=false;
      //--- return result
      return(false);
     }
//--- check
   if(state.m_rstate.stage==6)
     {
      //--- change value
      state.m_xupdated=false;
      //--- return result
      return(false);
     }
//--- check
   if(state.m_rstate.stage==7)
     {
      //--- change value
      state.m_xupdated=false;
      //--- return result
      return(false);
     }
//--- check
   if(state.m_rstate.stage==8)
     {
      //--- change value
      state.m_xupdated=false;
      //--- return result
      return(false);
     }
//--- check
   if(state.m_rstate.stage==9)
     {
      //--- change value
      state.m_needfg=false;
      //--- postprocess data: zero components of G corresponding to
      //--- the active constraints
      for(i=0;i<=n-1;i++)
        {
         //--- check
         if(state.m_x[i]==state.m_bndl[i] || state.m_x[i]==state.m_bndu[i])
            state.m_gc[i]=0;
         else
            state.m_gc[i]=state.m_g[i];
        }
      CLinMin::MCSrch(n,state.m_xn,state.m_f,state.m_gc,state.m_d,state.m_stp,state.m_stpmax,m_gtol,mcinfo,state.m_nfev,state.m_work,state.m_lstate,state.m_mcstage);
      //--- function call, return result
      return(Func_lbl_51(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv));
     }
//--- check
   if(state.m_rstate.stage==10)
     {
      //--- change value
      state.m_xupdated=false;
      //--- function call, return result
      return(Func_lbl_53(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv));
     }
//--- check
   if(state.m_rstate.stage==11)
     {
      //--- change value
      state.m_xupdated=false;
      //--- return result
      return(false);
     }
//--- check
   if(state.m_rstate.stage==12)
     {
      //--- change value
      state.m_xupdated=false;
      //--- return result
      return(false);
     }
//--- check
   if(state.m_rstate.stage==13)
     {
      //--- change value
      state.m_xupdated=false;
      //--- return result
      return(false);
     }
//--- check
   if(state.m_rstate.stage==14)
     {
      //--- change value
      state.m_xupdated=false;
      //--- return result
      return(false);
     }
//--- Routine body
//--- Prepare
   n=state.m_n;
   state.m_repterminationtype=0;
   state.m_repiterationscount=0;
   state.m_repnfev=0;
   state.m_debugrestartscount=0;
   state.m_cgtype=1;
//--- copy
   for(i_=0;i_<=n-1;i_++)
      state.m_xk[i_]=state.m_x[i_];
   for(i=0;i<=n-1;i++)
     {
      //--- check
      if(state.m_xk[i]==state.m_bndl[i] || state.m_xk[i]==state.m_bndu[i])
         state.m_ak[i]=0;
      else
         state.m_ak[i]=1;
     }
//--- change values
   state.m_mu=0.1;
   state.m_curalgo=0;
//--- Calculate F/G,initialize algorithm
   ClearRequestFields(state);
//--- change values
   state.m_needfg=true;
   state.m_rstate.stage=0;
//--- Saving state
   Func_lbl_rcomm(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv);
//--- return result
   return(true);
  }
//+------------------------------------------------------------------+
//| Auxiliary function for MinASAIteration. Is a product to get rid  |
//| of the operator unconditional jump goto.                         |
//+------------------------------------------------------------------+
static void CMinComp::Func_lbl_rcomm(CMinASAState &state,int n,int i,
                                     int mcinfo,int diffcnt,bool b,
                                     bool stepfound,double betak,
                                     double v,double vv)
  {
//--- save
   state.m_rstate.ia[0]=n;
   state.m_rstate.ia[1]=i;
   state.m_rstate.ia[2]=mcinfo;
   state.m_rstate.ia[3]=diffcnt;
   state.m_rstate.ba[0]=b;
   state.m_rstate.ba[1]=stepfound;
   state.m_rstate.ra[0]=betak;
   state.m_rstate.ra[1]=v;
   state.m_rstate.ra[2]=vv;
  }
//+------------------------------------------------------------------+
//| Auxiliary function for MinASAIteration. Is a product to get rid  |
//| of the operator unconditional jump goto.                         |
//+------------------------------------------------------------------+
static bool CMinComp::Func_lbl_15(CMinASAState &state,int &n,int &i,
                                  int &mcinfo,int &diffcnt,bool &b,
                                  bool &stepfound,double &betak,
                                  double &v,double &vv)
  {
//--- check
   if(ASABoundedAntigradNorm(state)<=state.m_epsg)
     {
      state.m_repterminationtype=4;
      //--- return result
      return(false);
     }
   state.m_repnfev=state.m_repnfev+1;
//--- Main cycle
//--- At the beginning of new iteration:
//--- * CurAlgo stores current algorithm selector
//--- * State.XK,State.F and State.G store current X/F/G
//--- * State.AK stores current set of active constraints
   return(Func_lbl_17(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv));
  }
//+------------------------------------------------------------------+
//| Auxiliary function for MinASAIteration. Is a product to get rid  |
//| of the operator unconditional jump goto.                         |
//+------------------------------------------------------------------+
static bool CMinComp::Func_lbl_17(CMinASAState &state,int &n,int &i,
                                  int &mcinfo,int &diffcnt,bool &b,
                                  bool &stepfound,double &betak,
                                  double &v,double &vv)
  {
//--- GPA algorithm
   if(state.m_curalgo!=0)
      return(Func_lbl_19(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv));
//--- change values
   state.m_k=0;
   state.m_acount=0;
//--- function call, return result
   return(Func_lbl_21(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv));
  }
//+------------------------------------------------------------------+
//| Auxiliary function for MinASAIteration. Is a product to get rid  |
//| of the operator unconditional jump goto.                         |
//+------------------------------------------------------------------+
static bool CMinComp::Func_lbl_19(CMinASAState &state,int &n,int &i,
                                  int &mcinfo,int &diffcnt,bool &b,
                                  bool &stepfound,double &betak,
                                  double &v,double &vv)
  {
//--- CG algorithm
   if(state.m_curalgo!=1)
      return(Func_lbl_17(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv));
//--- first,check that there are non-active constraints.
//--- move to GPA algorithm,if all constraints are active
   b=true;
   for(i=0;i<=n-1;i++)
     {
      //--- check
      if(state.m_ak[i]!=0.0)
        {
         b=false;
         break;
        }
     }
//--- check
   if(b)
     {
      state.m_curalgo=0;
      //--- function call, return result
      return(Func_lbl_17(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv));
     }
//--- CG iterations
   state.m_fold=state.m_f;
   for(int i_=0;i_<=n-1;i_++)
      state.m_xk[i_]=state.m_x[i_];
   for(i=0;i<=n-1;i++)
     {
      //--- change values
      state.m_dk[i]=-(state.m_g[i]*state.m_ak[i]);
      state.m_gc[i]=state.m_g[i]*state.m_ak[i];
     }
//--- function call, return result
   return(Func_lbl_49(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv));
  }
//+------------------------------------------------------------------+
//| Auxiliary function for MinASAIteration. Is a product to get rid  |
//| of the operator unconditional jump goto.                         |
//+------------------------------------------------------------------+
static bool CMinComp::Func_lbl_21(CMinASAState &state,int &n,int &i,
                                  int &mcinfo,int &diffcnt,bool &b,
                                  bool &stepfound,double &betak,
                                  double &v,double &vv)
  {
//--- Determine Dk=proj(xk - gk)-xk
   for(i=0;i<=n-1;i++)
      state.m_d[i]=CApServ::BoundVal(state.m_xk[i]-state.m_g[i],state.m_bndl[i],state.m_bndu[i])-state.m_xk[i];
//--- Armijo line search.
//--- * exact search with alpha=1 is tried first,
//---   'exact' means that we evaluate f() EXACTLY at
//---   bound(x-g,bndl,bndu),without intermediate floating
//---   point operations.
//--- * alpha<1 are tried if explicit search wasn't successful
//--- Result is placed into XN.
//--- Two types of search are needed because we can't
//--- just use second type with alpha=1 because in finite
//--- precision arithmetics (x1-x0)+x0 may differ from x1.
//--- So while x1 is correctly bounded (it lie EXACTLY on
//--- boundary,if it is active),(x1-x0)+x0 may be
//--- not bounded.
   v=0.0;
   for(int i_=0;i_<=n-1;i_++)
      v+=state.m_d[i_]*state.m_g[i_];
//--- change values
   state.m_dginit=v;
   state.m_finit=state.m_f;
//--- check
   if(!(ASAD1Norm(state)<=state.m_stpmax || state.m_stpmax==0.0))
     {
      stepfound=false;
      //--- function call, return result
      return(Func_lbl_24(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv));
     }
//--- Try alpha=1 step first
   for(i=0;i<=n-1;i++)
      state.m_x[i]=CApServ::BoundVal(state.m_xk[i]-state.m_g[i],state.m_bndl[i],state.m_bndu[i]);
//--- function call
   ClearRequestFields(state);
//--- change values
   state.m_needfg=true;
   state.m_rstate.stage=2;
//--- Saving state
   Func_lbl_rcomm(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv);
//--- return result
   return(true);
  }
//+------------------------------------------------------------------+
//| Auxiliary function for MinASAIteration. Is a product to get rid  |
//| of the operator unconditional jump goto.                         |
//+------------------------------------------------------------------+
static bool CMinComp::Func_lbl_24(CMinASAState &state,int &n,int &i,
                                  int &mcinfo,int &diffcnt,bool &b,
                                  bool &stepfound,double &betak,
                                  double &v,double &vv)
  {
//--- check
   if(!stepfound)
     {
      //--- alpha=1 is too large,try smaller values
      state.m_stp=1;
      //--- function call
      CLinMin::LinMinNormalized(state.m_d,state.m_stp,n);
      //--- change values
      state.m_dginit=state.m_dginit/state.m_stp;
      state.m_stp=m_gpadecay*state.m_stp;
      //--- check
      if(state.m_stpmax>0.0)
         state.m_stp=MathMin(state.m_stp,state.m_stpmax);
      //--- function call, return result
      return(Func_lbl_27(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv));
     }
//--- we are at the boundary(ies)
   for(int i_=0;i_<=n-1;i_++)
      state.m_xn[i_]=state.m_x[i_];
   state.m_stp=1;
//--- function call, return result
   return(Func_lbl_26(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv));
  }
//+------------------------------------------------------------------+
//| Auxiliary function for MinASAIteration. Is a product to get rid  |
//| of the operator unconditional jump goto.                         |
//+------------------------------------------------------------------+
static bool CMinComp::Func_lbl_26(CMinASAState &state,int &n,int &i,
                                  int &mcinfo,int &diffcnt,bool &b,
                                  bool &stepfound,double &betak,
                                  double &v,double &vv)
  {
   state.m_repiterationscount=state.m_repiterationscount+1;
//--- check
   if(!state.m_xrep)
      return(Func_lbl_29(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv));
//--- progress report
   ClearRequestFields(state);
//--- change values
   state.m_xupdated=true;
   state.m_rstate.stage=4;
//--- Saving state
   Func_lbl_rcomm(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv);
//--- return result
   return(true);
  }
//+------------------------------------------------------------------+
//| Auxiliary function for MinASAIteration. Is a product to get rid  |
//| of the operator unconditional jump goto.                         |
//+------------------------------------------------------------------+
static bool CMinComp::Func_lbl_27(CMinASAState &state,int &n,int &i,
                                  int &mcinfo,int &diffcnt,bool &b,
                                  bool &stepfound,double &betak,
                                  double &v,double &vv)
  {
   v=state.m_stp;
//--- copy
   for(int i_=0;i_<=n-1;i_++)
      state.m_x[i_]=state.m_xk[i_];
   for(int i_=0;i_<=n-1;i_++)
      state.m_x[i_]=state.m_x[i_]+v*state.m_d[i_];
   ClearRequestFields(state);
//--- change values
   state.m_needfg=true;
   state.m_rstate.stage=3;
//--- Saving state
   Func_lbl_rcomm(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv);
//--- return result
   return(true);
  }
//+------------------------------------------------------------------+
//| Auxiliary function for MinASAIteration. Is a product to get rid  |
//| of the operator unconditional jump goto.                         |
//+------------------------------------------------------------------+
static bool CMinComp::Func_lbl_29(CMinASAState &state,int &n,int &i,
                                  int &mcinfo,int &diffcnt,bool &b,
                                  bool &stepfound,double &betak,
                                  double &v,double &vv)
  {
//--- Calculate new set of active constraints.
//--- Reset counter if active set was changed.
//--- Prepare for the new iteration
   for(i=0;i<=n-1;i++)
     {
      //--- check
      if(state.m_xn[i]==state.m_bndl[i] || state.m_xn[i]==state.m_bndu[i])
         state.m_an[i]=0;
      else
         state.m_an[i]=1;
     }
   for(i=0;i<=n-1;i++)
     {
      //--- check
      if(state.m_ak[i]!=state.m_an[i])
        {
         state.m_acount=-1;
         break;
        }
     }
   state.m_acount=state.m_acount+1;
//--- copy
   for(int i_=0;i_<=n-1;i_++)
      state.m_xk[i_]=state.m_xn[i_];
   for(int i_=0;i_<=n-1;i_++)
      state.m_ak[i_]=state.m_an[i_];
//--- Stopping conditions
   if(!(state.m_repiterationscount>=state.m_maxits&&state.m_maxits>0))
      return(Func_lbl_31(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv));
//--- Too many iterations
   state.m_repterminationtype=5;
//--- check
   if(!state.m_xrep)
      return(false);
//--- function call
   ClearRequestFields(state);
//--- change values
   state.m_xupdated=true;
   state.m_rstate.stage=5;
//--- Saving state
   Func_lbl_rcomm(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv);
//--- return result
   return(true);
  }
//+------------------------------------------------------------------+
//| Auxiliary function for MinASAIteration. Is a product to get rid  |
//| of the operator unconditional jump goto.                         |
//+------------------------------------------------------------------+
static bool CMinComp::Func_lbl_31(CMinASAState &state,int &n,int &i,
                                  int &mcinfo,int &diffcnt,bool &b,
                                  bool &stepfound,double &betak,
                                  double &v,double &vv)
  {
//--- check
   if(ASABoundedAntigradNorm(state)>state.m_epsg)
      return(Func_lbl_35(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv));
//--- Gradient is small enough
   state.m_repterminationtype=4;
//--- check
   if(!state.m_xrep)
      return(false);
//--- function call
   ClearRequestFields(state);
//--- change values
   state.m_xupdated=true;
   state.m_rstate.stage=6;
//--- Saving state
   Func_lbl_rcomm(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv);
//--- return result
   return(true);
  }
//+------------------------------------------------------------------+
//| Auxiliary function for MinASAIteration. Is a product to get rid  |
//| of the operator unconditional jump goto.                         |
//+------------------------------------------------------------------+
static bool CMinComp::Func_lbl_35(CMinASAState &state,int &n,int &i,
                                  int &mcinfo,int &diffcnt,bool &b,
                                  bool &stepfound,double &betak,
                                  double &v,double &vv)
  {
//--- change value
   v=0.0;
   for(int i_=0;i_<=n-1;i_++)
      v+=state.m_d[i_]*state.m_d[i_];
//--- check
   if(MathSqrt(v)*state.m_stp>state.m_epsx)
      return(Func_lbl_39(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv));
//--- Step size is too small,no further improvement is
//--- possible
   state.m_repterminationtype=2;
//--- check
   if(!state.m_xrep)
      return(false);
//--- function call
   ClearRequestFields(state);
//--- change values
   state.m_xupdated=true;
   state.m_rstate.stage=7;
//--- Saving state
   Func_lbl_rcomm(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv);
//--- return result
   return(true);
  }
//+------------------------------------------------------------------+
//| Auxiliary function for MinASAIteration. Is a product to get rid  |
//| of the operator unconditional jump goto.                         |
//+------------------------------------------------------------------+
static bool CMinComp::Func_lbl_39(CMinASAState &state,int &n,int &i,
                                  int &mcinfo,int &diffcnt,bool &b,
                                  bool &stepfound,double &betak,
                                  double &v,double &vv)
  {
//--- check
   if(state.m_finit-state.m_f>state.m_epsf*MathMax(MathAbs(state.m_finit),MathMax(MathAbs(state.m_f),1.0)))
      return(Func_lbl_43(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv));
//--- F(k+1)-F(k) is small enough
   state.m_repterminationtype=1;
//--- check
   if(!state.m_xrep)
      return(false);
   ClearRequestFields(state);
//--- change values
   state.m_xupdated=true;
   state.m_rstate.stage=8;
//--- Saving state
   Func_lbl_rcomm(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv);
//--- return result
   return(true);
  }
//+------------------------------------------------------------------+
//| Auxiliary function for MinASAIteration. Is a product to get rid  |
//| of the operator unconditional jump goto.                         |
//+------------------------------------------------------------------+
static bool CMinComp::Func_lbl_43(CMinASAState &state,int &n,int &i,
                                  int &mcinfo,int &diffcnt,bool &b,
                                  bool &stepfound,double &betak,
                                  double &v,double &vv)
  {
//--- Decide - should we switch algorithm or not
   if(ASAUIsEmpty(state))
     {
      //--- check
      if(ASAGINorm(state)>=state.m_mu*ASAD1Norm(state))
        {
         state.m_curalgo=1;
         //--- function call, return result
         return(Func_lbl_19(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv));
        }
      else
         state.m_mu=state.m_mu*m_asarho;
     }
   else
     {
      //--- check
      if(state.m_acount==m_n1)
        {
         //--- check
         if(ASAGINorm(state)>=state.m_mu*ASAD1Norm(state))
           {
            state.m_curalgo=1;
            //--- function call, return result
            return(Func_lbl_19(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv));
           }
        }
     }
//--- Next iteration
   state.m_k=state.m_k+1;
//--- function call, return result
   return(Func_lbl_21(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv));
  }
//+------------------------------------------------------------------+
//| Auxiliary function for MinASAIteration. Is a product to get rid  |
//| of the operator unconditional jump goto.                         |
//+------------------------------------------------------------------+
static bool CMinComp::Func_lbl_49(CMinASAState &state,int &n,int &i,
                                  int &mcinfo,int &diffcnt,bool &b,
                                  bool &stepfound,double &betak,
                                  double &v,double &vv)
  {
//--- Store G[k] for later calculation of Y[k]
   for(i=0;i<=n-1;i++)
      state.m_yk[i]=-state.m_gc[i];
//--- Make a CG step in direction given by DK[]:
//--- * calculate step. Step projection into feasible set
//---   is used. It has several benefits: a) step may be
//---   found with usual line search,b) multiple constraints
//---   may be activated with one step,c) activated constraints
//---   are detected in a natural way - just compare x[i] with
//---   bounds
//--- * update active set,set B to True,if there
//---   were changes in the set.
   for(int i_=0;i_<=n-1;i_++)
      state.m_d[i_]=state.m_dk[i_];
   for(int i_=0;i_<=n-1;i_++)
      state.m_xn[i_]=state.m_xk[i_];
//--- change values
   state.m_mcstage=0;
   state.m_stp=1;
//--- function call
   CLinMin::LinMinNormalized(state.m_d,state.m_stp,n);
//--- check
   if(state.m_laststep!=0.0)
      state.m_stp=state.m_laststep;
//--- function call
   CLinMin::MCSrch(n,state.m_xn,state.m_f,state.m_gc,state.m_d,state.m_stp,state.m_stpmax,m_gtol,mcinfo,state.m_nfev,state.m_work,state.m_lstate,state.m_mcstage);
//--- function call, return result
   return(Func_lbl_51(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv));
  }
//+------------------------------------------------------------------+
//| Auxiliary function for MinASAIteration. Is a product to get rid  |
//| of the operator unconditional jump goto.                         |
//+------------------------------------------------------------------+
static bool CMinComp::Func_lbl_51(CMinASAState &state,int &n,int &i,
                                  int &mcinfo,int &diffcnt,bool &b,
                                  bool &stepfound,double &betak,
                                  double &v,double &vv)
  {
//--- check
   if(state.m_mcstage==0)
      return(Func_lbl_52(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv));
//--- preprocess data: bound State.XN so it belongs to the
//--- feasible set and store it in the State.X
   for(i=0;i<=n-1;i++)
      state.m_x[i]=CApServ::BoundVal(state.m_xn[i],state.m_bndl[i],state.m_bndu[i]);
//--- RComm
   ClearRequestFields(state);
//--- change values
   state.m_needfg=true;
   state.m_rstate.stage=9;
//--- Saving state
   Func_lbl_rcomm(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv);
//--- return result
   return(true);
  }
//+------------------------------------------------------------------+
//| Auxiliary function for MinASAIteration. Is a product to get rid  |
//| of the operator unconditional jump goto.                         |
//+------------------------------------------------------------------+
static bool CMinComp::Func_lbl_52(CMinASAState &state,int &n,int &i,
                                  int &mcinfo,int &diffcnt,bool &b,
                                  bool &stepfound,double &betak,
                                  double &v,double &vv)
  {
   diffcnt=0;
   for(i=0;i<=n-1;i++)
     {
      //--- XN contains unprojected result,project it,
      //--- save copy to X (will be used for progress reporting)
      state.m_xn[i]=CApServ::BoundVal(state.m_xn[i],state.m_bndl[i],state.m_bndu[i]);
      //--- update active set
      if(state.m_xn[i]==state.m_bndl[i] || state.m_xn[i]==state.m_bndu[i])
         state.m_an[i]=0;
      else
         state.m_an[i]=1;
      //--- check
      if(state.m_an[i]!=state.m_ak[i])
         diffcnt=diffcnt+1;
      state.m_ak[i]=state.m_an[i];
     }
   for(int i_=0;i_<=n-1;i_++)
      state.m_xk[i_]=state.m_xn[i_];
//--- change values
   state.m_repnfev=state.m_repnfev+state.m_nfev;
   state.m_repiterationscount=state.m_repiterationscount+1;
//--- check
   if(!state.m_xrep)
      return(Func_lbl_53(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv));
//--- progress report
   ClearRequestFields(state);
//--- change values
   state.m_xupdated=true;
   state.m_rstate.stage=10;
//--- Saving state
   Func_lbl_rcomm(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv);
//--- return result
   return(true);
  }
//+------------------------------------------------------------------+
//| Auxiliary function for MinASAIteration. Is a product to get rid  |
//| of the operator unconditional jump goto.                         |
//+------------------------------------------------------------------+
static bool CMinComp::Func_lbl_53(CMinASAState &state,int &n,int &i,
                                  int &mcinfo,int &diffcnt,bool &b,
                                  bool &stepfound,double &betak,
                                  double &v,double &vv)
  {
//--- Update info about step length
   v=0.0;
   for(int i_=0;i_<=n-1;i_++)
      v+=state.m_d[i_]*state.m_d[i_];
   state.m_laststep=MathSqrt(v)*state.m_stp;
//--- Check stopping conditions.
   if(ASABoundedAntigradNorm(state)>state.m_epsg)
      return(Func_lbl_55(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv));
//--- Gradient is small enough
   state.m_repterminationtype=4;
//--- check
   if(!state.m_xrep)
      return(false);
   ClearRequestFields(state);
//--- change values
   state.m_xupdated=true;
   state.m_rstate.stage=11;
//--- Saving state
   Func_lbl_rcomm(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv);
//--- return result
   return(true);
  }
//+------------------------------------------------------------------+
//| Auxiliary function for MinASAIteration. Is a product to get rid  |
//| of the operator unconditional jump goto.                         |
//+------------------------------------------------------------------+
static bool CMinComp::Func_lbl_55(CMinASAState &state,int &n,int &i,
                                  int &mcinfo,int &diffcnt,bool &b,
                                  bool &stepfound,double &betak,
                                  double &v,double &vv)
  {
//--- check
   if(!(state.m_repiterationscount>=state.m_maxits && state.m_maxits>0))
      return(Func_lbl_59(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv));
//--- Too many iterations
   state.m_repterminationtype=5;
//--- check
   if(!state.m_xrep)
      return(false);
   ClearRequestFields(state);
//--- change values
   state.m_xupdated=true;
   state.m_rstate.stage=12;
//--- Saving state
   Func_lbl_rcomm(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv);
//--- return result
   return(true);
  }
//+------------------------------------------------------------------+
//| Auxiliary function for MinASAIteration. Is a product to get rid  |
//| of the operator unconditional jump goto.                         |
//+------------------------------------------------------------------+
static bool CMinComp::Func_lbl_59(CMinASAState &state,int &n,int &i,
                                  int &mcinfo,int &diffcnt,bool &b,
                                  bool &stepfound,double &betak,
                                  double &v,double &vv)
  {
//--- check
   if(!(ASAGINorm(state)>=state.m_mu*ASAD1Norm(state) && diffcnt==0))
      return(Func_lbl_63(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv));
//--- These conditions (EpsF/EpsX) are explicitly or implicitly
//--- related to the current step size and influenced
//--- by changes in the active constraints.
//--- For these reasons they are checked only when we don't
//--- want to 'unstick' at the end of the iteration and there
//--- were no changes in the active set.
//--- NOTE: consition |G|>=Mu*|D1| must be exactly opposite
//--- to the condition used to switch back to GPA. At least
//--- one inequality must be strict,otherwise infinite cycle
//--- may occur when |G|=Mu*|D1| (we DON'T test stopping
//--- conditions and we DON'T switch to GPA,so we cycle
//--- indefinitely).
   if(state.m_fold-state.m_f>state.m_epsf*MathMax(MathAbs(state.m_fold),MathMax(MathAbs(state.m_f),1.0)))
      return(Func_lbl_65(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv));
//--- F(k+1)-F(k) is small enough
   state.m_repterminationtype=1;
   if(!state.m_xrep)
      return(false);
//--- function call
   ClearRequestFields(state);
//--- change values
   state.m_xupdated=true;
   state.m_rstate.stage=13;
//--- Saving state
   Func_lbl_rcomm(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv);
//--- return result
   return(true);
  }
//+------------------------------------------------------------------+
//| Auxiliary function for MinASAIteration. Is a product to get rid  |
//| of the operator unconditional jump goto.                         |
//+------------------------------------------------------------------+
static bool CMinComp::Func_lbl_63(CMinASAState &state,int &n,int &i,
                                  int &mcinfo,int &diffcnt,bool &b,
                                  bool &stepfound,double &betak,
                                  double &v,double &vv)
  {
//--- Check conditions for switching
   if(ASAGINorm(state)<state.m_mu*ASAD1Norm(state))
     {
      state.m_curalgo=0;
      //--- function call, return result
      return(Func_lbl_17(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv));
     }
//--- check
   if(diffcnt>0)
     {
      //--- check
      if(ASAUIsEmpty(state) || diffcnt>=m_n2)
         state.m_curalgo=1;
      else
         state.m_curalgo=0;
      //--- function call, return result
      return(Func_lbl_17(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv));
     }
//--- Calculate D(k+1)
//--- Line search may result in:
//--- * maximum feasible step being taken (already processed)
//--- * point satisfying Wolfe conditions
//--- * some kind of error (CG is restarted by assigning 0.0 to Beta)
   if(mcinfo==1)
     {
      //--- Standard Wolfe conditions are satisfied:
      //--- * calculate Y[K] and BetaK
      for(int i_=0;i_<=n-1;i_++)
         state.m_yk[i_]=state.m_yk[i_]+state.m_gc[i_];
      //--- change value
      vv=0.0;
      for(int i_=0;i_<=n-1;i_++)
         vv+=state.m_yk[i_]*state.m_dk[i_];
      //--- change value
      v=0.0;
      for(int i_=0;i_<=n-1;i_++)
         v+=state.m_gc[i_]*state.m_gc[i_];
      state.m_betady=v/vv;
      //--- change value
      v=0.0;
      for(int i_=0;i_<=n-1;i_++)
         v+=state.m_gc[i_]*state.m_yk[i_];
      state.m_betahs=v/vv;
      //--- check
      if(state.m_cgtype==0)
         betak=state.m_betady;
      //--- check
      if(state.m_cgtype==1)
         betak=MathMax(0,MathMin(state.m_betady,state.m_betahs));
     }
   else
     {
      //--- Something is wrong (may be function is too wild or too flat).
      //--- We'll set BetaK=0,which will restart CG algorithm.
      //--- We can stop later (during normal checks) if stopping conditions are met.
      betak=0;
      state.m_debugrestartscount=state.m_debugrestartscount+1;
     }
//--- change values
   for(int i_=0;i_<=n-1;i_++)
      state.m_dn[i_]=-state.m_gc[i_];
   for(int i_=0;i_<=n-1;i_++)
      state.m_dn[i_]=state.m_dn[i_]+betak*state.m_dk[i_];
   for(int i_=0;i_<=n-1;i_++)
      state.m_dk[i_]=state.m_dn[i_];
//--- update other information
   state.m_fold=state.m_f;
   state.m_k=state.m_k+1;
//--- function call, return result
   return(Func_lbl_49(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv));
  }
//+------------------------------------------------------------------+
//| Auxiliary function for MinASAIteration. Is a product to get rid  |
//| of the operator unconditional jump goto.                         |
//+------------------------------------------------------------------+
static bool CMinComp::Func_lbl_65(CMinASAState &state,int &n,int &i,
                                  int &mcinfo,int &diffcnt,bool &b,
                                  bool &stepfound,double &betak,
                                  double &v,double &vv)
  {
//--- check
   if(state.m_laststep>state.m_epsx)
      return(Func_lbl_63(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv));
//--- X(k+1)-X(k) is small enough
   state.m_repterminationtype=2;
//--- check
   if(!state.m_xrep)
      return(false);
//--- function call
   ClearRequestFields(state);
//--- change values
   state.m_xupdated=true;
   state.m_rstate.stage=14;
//--- Saving state
   Func_lbl_rcomm(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv);
//--- return result
   return(true);
  }
//+------------------------------------------------------------------+
