diff --git a/CMakeLists.txt b/CMakeLists.txt
index 425011ea84c460cedcc586a08ebf00e9293193c9..64791f22f30f8767c64260ccdcdb2496f5a56c27 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -21,6 +21,8 @@ option(ENABLE_ANN "Enable ANN to compute Approximate Nearest Neighbors" ON)
 option(ENABLE_APP_BUNDLE "Create .app bundle on Mac when installing" ON)
 option(ENABLE_BAMG "Enable Bamg mesh generator" ON)
 option(ENABLE_BFGS "Enable BFGS" ON)
+option(ENABLE_RTREE "Enable RTREE" ON)
+option(ENABLE_Voro3D "Enable Voro3D" ON)
 option(ENABLE_BLAS_LAPACK "Use BLAS and Lapack for linear algebra" ON)
 option(ENABLE_BLOSSOM "Enable Blossom algo (based on MATCH and concorde97)" ON)
 option(ENABLE_CGNS "Enable CGNS mesh export" OFF)
@@ -89,7 +91,7 @@ set(GMSH_API
     Geo/SOrientedBoundingBox.h Geo/CellComplex.h Geo/ChainComplex.h Geo/Cell.h
     Geo/Homology.h Geo/partitionEdge.h Geo/CGNSOptions.h Geo/gmshLevelset.h
   Mesh/meshGEdge.h Mesh/meshGFace.h Mesh/meshGFaceOptimize.h Mesh/meshPartition.h
-    Mesh/meshGFaceDelaunayInsertion.h Mesh/Levy3D.h Mesh/meshPartitionOptions.h
+    Mesh/meshGFaceDelaunayInsertion.h Mesh/simple3D.h Mesh/meshPartitionOptions.h Mesh/Voronoi3D.h Mesh/Levy3D.h Mesh/periodical.h
   Numeric/mathEvaluator.h
   Solver/dofManager.h Solver/femTerm.h Solver/laplaceTerm.h Solver/elasticityTerm.h
     Solver/crossConfTerm.h Solver/orthogonalTerm.h
@@ -483,6 +485,18 @@ if(ENABLE_BFGS)
   set_config_option(HAVE_BFGS "Bfgs")
 endif(ENABLE_BFGS)
 
+if(ENABLE_RTREE)
+  add_subdirectory(contrib/rtree)
+  include_directories(contrib/rtree)
+  set_config_option(HAVE_RTREE "RTree")
+endif(ENABLE_RTREE)
+
+if(ENABLE_Voro3D)
+  add_subdirectory(contrib/voro++)
+  include_directories(contrib/voro++/src)
+  set_config_option(HAVE_Voro3D "Voro3D")
+endif(ENABLE_Voro3D)
+
 if(ENABLE_DINTEGRATION)
   add_subdirectory(contrib/DiscreteIntegration)
   include_directories(contrib/DiscreteIntegration)
diff --git a/Geo/GFaceCompound.cpp b/Geo/GFaceCompound.cpp
index 5664d096810bb142e83d9b91ef93f22dc5919022..eb7b2468b7707edd9cfcfb17c5862d76b5d03f83 100644
--- a/Geo/GFaceCompound.cpp
+++ b/Geo/GFaceCompound.cpp
@@ -1873,6 +1873,9 @@ void GFaceCompound::buildOct() const
 bool GFaceCompound::checkTopology() const
 {
   if (_mapping == RBF) return true; 
+
+  //fixme tristan
+  //return true;
 	
   bool correctTopo = true;
   if(allNodes.empty()) buildAllNodes();
diff --git a/Mesh/CMakeLists.txt b/Mesh/CMakeLists.txt
index 456bd68f7ffdf390904c1fd8beb59864028687d5..81d880f5e2f4bf5ab49f8799db2ce8b8a660038e 100644
--- a/Mesh/CMakeLists.txt
+++ b/Mesh/CMakeLists.txt
@@ -31,7 +31,10 @@ CenterlineField.cpp
     multiscalePartition.cpp
     QuadTriUtils.cpp
       QuadTriExtruded2D.cpp QuadTriExtruded3D.cpp QuadTriTransfinite3D.cpp
+    simple3D.cpp
+    Voronoi3D.cpp
     Levy3D.cpp
+    periodical.cpp
 )
 
 file(GLOB HDR RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.h) 
diff --git a/Mesh/Levy3D.cpp b/Mesh/Levy3D.cpp
index 6f320bf9b2c7be65f21c9ebd98ad4b5a4ff36900..784545cddbfb28aaafe8c040849622a7ad1e04b5 100755
--- a/Mesh/Levy3D.cpp
+++ b/Mesh/Levy3D.cpp
@@ -12,18 +12,175 @@
 
 #include "Levy3D.h"
 #include "polynomialBasis.h"
-#include "GaussIntegration.h"
 #include "GModel.h"
 #include "MElement.h"
 #include "MElementOctree.h"
 #include "meshGRegion.h"
-#include "ap.h"
-#include "alglibinternal.h"
-#include "alglibmisc.h" 
-#include "linalg.h"
-#include "optimization.h"
+#include "Voronoi3D.h"
+#include "time.h"
+#include <algorithm>
+
+/*********definitions*********/
+
+class Wrap{
+ private:
+  int p;
+  int dimension;
+  int iteration;
+  int max_iteration;
+  int offset;
+  double initial_energy;
+  MElementOctree* octree;
+  std::vector<SPoint3> bank;
+  std::vector<int> movability;
+ public:
+  Wrap();
+  ~Wrap();
+  int get_p();
+  int get_dimension();
+  int get_iteration();
+  int get_max_iteration();
+  int get_offset();
+  double get_initial_energy();
+  MElementOctree* get_octree();
+  SPoint3 get_bank(int);
+  int get_movability(int);
+  int get_size();
+  void set_p(int);
+  void set_dimension(int);
+  void set_iteration(int);
+  void set_max_iteration(int);
+  void set_offset(int);
+  void set_initial_energy(double);
+  void set_octree(MElementOctree*);
+  void set_bank(SPoint3,int);
+  void set_movability(int,int);
+  void resize(int);
+};
+
+class LpCVT{
+ private:
+  std::vector<VoronoiElement> clipped;
+  fullMatrix<double> gauss_points;
+  fullMatrix<double> gauss_weights;
+  int gauss_num;
+ public:
+  LpCVT();
+  ~LpCVT();
+  void verification(std::vector<SPoint3>&,std::vector<int>&,int,int);
+  void eval(std::vector<SPoint3>&,std::vector<int>&,int,std::vector<SVector3>&,double&,int);
+  void compute_parameters(int);
+  double get_size(double,double,double);
+  Tensor get_tensor(double,double,double);
+  double drho_dx(double,double,double,int);
+  double drho_dy(double,double,double,int);
+  double drho_dz(double,double,double,int);
+  double h_to_rho(double,int);
+  void swap();
+  void get_gauss();
+  double F(VoronoiElement,int);
+  SVector3 simple(VoronoiElement,int);
+  SVector3 dF_dC1(VoronoiElement,int);
+  SVector3 dF_dC2(VoronoiElement,int);
+  SVector3 dF_dC3(VoronoiElement,int);
+  double f(SPoint3,SPoint3,Tensor,int);
+  double df_dx(SPoint3,SPoint3,Tensor,int);
+  double df_dy(SPoint3,SPoint3,Tensor,int);
+  double df_dz(SPoint3,SPoint3,Tensor,int);
+  SVector3 bisectors3(SVector3,SPoint3,SPoint3,SPoint3,SPoint3,SPoint3);
+  SVector3 bisectors2(SVector3,SPoint3,SPoint3,SPoint3,SPoint3,SVector3);
+  SVector3 bisectors1(SVector3,SPoint3,SPoint3,SPoint3,SVector3,SVector3);
+  void clear();
+};
+
+/*********functions*********/
 
-void call_back(const alglib::real_1d_array&,double&,alglib::real_1d_array&,void*);
+bool inside_domain(MElementOctree* octree,double x,double y,double z){
+  MElement* element;
+  element = (MElement*)octree->find(x,y,z,3,true);
+  if(element!=NULL) return 1;
+  else return 0;
+}
+
+void call_back(const alglib::real_1d_array& x,double& func,alglib::real_1d_array& grad,void* ptr){
+  int i;
+  int p;
+  int dimension;
+  int iteration;
+  int max_iteration;
+  int offset;
+  int size;
+  int error1;
+  int error2;
+  bool flag;
+  double initial_energy;
+  double energy;
+  LpCVT obj;
+  Wrap* w;
+  MElementOctree* octree;
+  std::vector<SPoint3> bank;
+  std::vector<int> movability;
+  std::vector<SVector3> gradients;
+  
+  w = static_cast<Wrap*>(ptr);
+  p = w->get_p();
+  dimension = w->get_dimension();
+  iteration = w->get_iteration();
+  max_iteration = w->get_max_iteration();
+  offset = w->get_offset();
+  size = w->get_size();
+  initial_energy = w->get_initial_energy();
+  octree = w->get_octree();
+  error1 = 0;
+  error2 = 0;
+  
+  bank.resize(size);
+  movability.resize(size);
+  for(i=0;i<size;i++){
+    bank[i] = w->get_bank(i);
+    movability[i] = w->get_movability(i);
+  }
+	
+  for(i=0;i<dimension/3;i++){
+    bank[i+offset] = SPoint3(x[i],x[i+(dimension/3)],x[i+(2*dimension/3)]);
+	flag = inside_domain(octree,x[i],x[i+(dimension/3)],x[i+(2*dimension/3)]);
+	if(!flag){
+	  error1 = 1;
+	  printf("Vertices outside domain.\n");
+	}
+  }
+	
+  if(iteration>max_iteration){
+    error2 = 1;
+	printf("Maximum number of iterations reached.\n");
+  }
+	
+  if(!error1 && !error2){
+    gradients.resize(dimension/3);
+    obj.get_gauss();
+    obj.eval(bank,movability,offset,gradients,energy,p);
+    func = energy;
+    for(i=0;i<dimension/3;i++){
+      grad[i] = gradients[i].x();
+	  grad[i+(dimension/3)] = gradients[i].y();
+	  grad[i+(2*dimension/3)] = gradients[i].z();
+    }
+  }
+  else{
+    func = 1000000000.0;
+	for(i=0;i<dimension;i++){
+	  grad[i] = 0.0;
+	}
+  }
+	
+  if(initial_energy>0.0 && !error1 && !error2){
+    printf("%d %.9f\n",iteration,100.0*(initial_energy-energy)/initial_energy);
+	w->set_iteration(iteration+1);
+  }
+  else if(!error1 && !error2){
+    w->set_initial_energy(energy);
+  }
+}
 
 /*********class VoronoiVertex*********/
 
@@ -110,92 +267,92 @@ void VoronoiVertex::set_rho(double new_rho){
   rho = new_rho;
 }
 
-/*********class Metric*********/
+/*********class Tensor*********/
 
-Metric::Metric(){
-  m11 = 1.0;
-  m12 = 0.0;
-  m13 = 0.0;
-  m21 = 0.0;
-  m22 = 1.0;
-  m23 = 0.0;
-  m31 = 0.0;
-  m32 = 0.0;
-  m33 = 1.0;	
+Tensor::Tensor(){
+  t11 = 1.0;
+  t12 = 0.0;
+  t13 = 0.0;
+  t21 = 0.0;
+  t22 = 1.0;
+  t23 = 0.0;
+  t31 = 0.0;
+  t32 = 0.0;
+  t33 = 1.0;	
 }
 
-Metric::~Metric(){}
+Tensor::~Tensor(){}
 
-void Metric::set_m11(double new_m11){
-  m11 = new_m11;
+void Tensor::set_t11(double new_t11){
+  t11 = new_t11;
 }
 
-void Metric::set_m12(double new_m12){
-  m12 = new_m12;
+void Tensor::set_t12(double new_t12){
+  t12 = new_t12;
 }
 
-void Metric::set_m13(double new_m13){
-  m13 = new_m13;
+void Tensor::set_t13(double new_t13){
+  t13 = new_t13;
 }
 
-void Metric::set_m21(double new_m21){
-  m21 = new_m21;
+void Tensor::set_t21(double new_t21){
+  t21 = new_t21;
 }
 
-void Metric::set_m22(double new_m22){
-  m22 = new_m22;
+void Tensor::set_t22(double new_t22){
+  t22 = new_t22;
 }
 
-void Metric::set_m23(double new_m23){
-  m23 = new_m23;
+void Tensor::set_t23(double new_t23){
+  t23 = new_t23;
 }
 
-void Metric::set_m31(double new_m31){
-  m31 = new_m31;
+void Tensor::set_t31(double new_t31){
+  t31 = new_t31;
 }
 
-void Metric::set_m32(double new_m32){
-  m32 = new_m32;
+void Tensor::set_t32(double new_t32){
+  t32 = new_t32;
 }
 
-void Metric::set_m33(double new_m33){
-  m33 = new_m33;
+void Tensor::set_t33(double new_t33){
+  t33 = new_t33;
 }
 
-double Metric::get_m11(){
-  return m11;
+double Tensor::get_t11(){
+  return t11;
 }
 
-double Metric::get_m12(){
-  return m12;
+double Tensor::get_t12(){
+  return t12;
 }
 
-double Metric::get_m13(){
-  return m13;
+double Tensor::get_t13(){
+  return t13;
 }
 
-double Metric::get_m21(){
-  return m21;
+double Tensor::get_t21(){
+  return t21;
 }
 
-double Metric::get_m22(){
-  return m22;
+double Tensor::get_t22(){
+  return t22;
 }
 
-double Metric::get_m23(){
-  return m23;
+double Tensor::get_t23(){
+  return t23;
 }
 
-double Metric::get_m31(){
-  return m31;
+double Tensor::get_t31(){
+  return t31;
 }
 
-double Metric::get_m32(){
-  return m32;
+double Tensor::get_t32(){
+  return t32;
 }
 
-double Metric::get_m33(){
-  return m33;
+double Tensor::get_t33(){
+  return t33;
 }
 
 /*********class VoronoiElement*********/
@@ -236,8 +393,8 @@ double VoronoiElement::get_drho_dz(){
   return drho_dz;
 }
 
-Metric VoronoiElement::get_metric(){
-  return m;
+Tensor VoronoiElement::get_tensor(){
+  return t;
 }
 
 void VoronoiElement::set_v1(VoronoiVertex new_v1){
@@ -256,8 +413,8 @@ void VoronoiElement::set_v4(VoronoiVertex new_v4){
   v4 = new_v4;
 }
 
-void VoronoiElement::set_metric(Metric new_m){
-  m = new_m;
+void VoronoiElement::set_tensor(Tensor new_t){
+  t = new_t;
 }
 
 double VoronoiElement::get_rho(double u,double v,double w){
@@ -271,7 +428,7 @@ double VoronoiElement::get_rho(double u,double v,double w){
   rho2 = v2.get_rho();
   rho3 = v3.get_rho();
   rho4 = v4.get_rho();
-  rho = T(u,v,w,rho1,rho2,rho3,rho4); //A CORRIGER POUR 2D
+  rho = T(u,v,w,rho1,rho2,rho3,rho4);
   return rho;
 }
 
@@ -333,15 +490,15 @@ void VoronoiElement::deriv_rho(){
   t31 = z2-z1;
   t32 = z3-z1;
   t33 = z4-z1;
-  jacobian2 = t11*(t22*t33-t23*t32) - t12*(t12*t33-t13*t32) + t13*(t12*t23-t13*t22);
+  jacobian2 = t11*(t22*t33-t23*t32) - t12*(t21*t33-t31*t23) + t13*(t21*t32-t31*t22);
   b11 = t22*t33-t32*t23;
-  b12 = t13*t32-t12*t33;
-  b13 = t12*t23-t13*t22;
-  b21 = t31*t23-t21*t33;
+  b12 = t31*t23-t21*t33;
+  b13 = t21*t32-t31*t22;
+  b21 = t13*t32-t12*t33;
   b22 = t11*t33-t13*t31;
-  b23 = t21*t13-t23*t11;
-  b31 = t21*t32-t31*t22;
-  b32 = t12*t31-t32*t11;
+  b23 = t12*t31-t32*t11;
+  b31 = t12*t23-t13*t22;
+  b32 = t21*t13-t23*t11;
   b33 = t11*t22-t12*t21;
   du_dx = b11/jacobian2;
   dv_dx = b12/jacobian2;
@@ -404,12 +561,6 @@ double VoronoiElement::T(double u,double v,double w,double val1,double val2,doub
   return val;
 }
 
-double VoronoiElement::h_to_rho(double h,int p){
-  double rho;
-  rho = pow_int(1.0/h,p+3);
-  return rho;
-}
-
 void VoronoiElement::swap(){
   VoronoiVertex v;
   compute_jacobian();
@@ -420,61 +571,379 @@ void VoronoiElement::swap(){
   }
 }
 
+double VoronoiElement::get_quality(){
+  int i;
+  double quality;
+  double min_l,max_l;
+  double l[6];
+	
+  l[0] = v1.get_point().distance(v2.get_point());
+  l[1] = v1.get_point().distance(v3.get_point());
+  l[2] = v1.get_point().distance(v4.get_point());
+  l[3] = v2.get_point().distance(v3.get_point());
+  l[4] = v2.get_point().distance(v4.get_point());
+  l[5] = v3.get_point().distance(v4.get_point());
+	
+  min_l = 1000000.0;
+  max_l = -1000000.0;
+	
+  for(i=0;i<6;i++){
+    min_l = std::min(min_l,l[i]);
+	max_l = std::max(max_l,l[i]);
+  }
+	
+  quality = min_l/max_l;
+  return quality;
+}
+
+/*********class Wrap*********/
+
+Wrap::Wrap(){
+  iteration = 0;
+  initial_energy = -1000000.0;
+}
+
+Wrap::~Wrap(){}
+
+int Wrap::get_p(){
+  return p;
+}
+
+int Wrap::get_dimension(){
+  return dimension;
+}
+
+int Wrap::get_iteration(){
+  return iteration;
+}
+
+int Wrap::get_max_iteration(){
+  return max_iteration;
+}
+
+int Wrap::get_offset(){
+  return offset;
+}
+
+double Wrap::get_initial_energy(){
+  return initial_energy;
+}
+
+MElementOctree* Wrap::get_octree(){
+  return octree;
+}
+
+SPoint3 Wrap::get_bank(int index){
+  return bank[index];
+}
+
+int Wrap::get_movability(int index){
+  return movability[index];
+}
+
+int Wrap::get_size(){
+  return bank.size();
+}
+
+void Wrap::set_p(int new_p){
+  p = new_p;
+}
+
+void Wrap::set_dimension(int new_dimension){
+  dimension = new_dimension;
+}
+
+void Wrap::set_iteration(int new_iteration){
+  iteration = new_iteration;
+}
+
+void Wrap::set_max_iteration(int new_max_iteration){
+  max_iteration = new_max_iteration;
+}
+
+void Wrap::set_offset(int new_offset){
+  offset = new_offset;
+}
+
+void Wrap::set_initial_energy(double new_initial_energy){
+  initial_energy = new_initial_energy;
+}
+
+void Wrap::set_octree(MElementOctree* new_octree){
+  octree = new_octree;
+}
+
+void Wrap::set_bank(SPoint3 point,int index){
+  bank[index] = point;
+}
+
+void Wrap::set_movability(int flag,int index){
+  movability[index] = flag;
+}
+
+void Wrap::resize(int size){
+  bank.resize(size);
+  movability.resize(size);
+}
+
 /*********class LpCVT*********/
 
 LpCVT::LpCVT(){}
 
 LpCVT::~LpCVT(){}
 
-void LpCVT::swap(){
-  std::list<VoronoiElement>::iterator it;
-  for(it=clipped.begin();it!=clipped.end();it++){
-	it->swap();		
+void LpCVT::verification(std::vector<SPoint3>& bank,std::vector<int>& movability,int offset,int p){
+  int index;
+  double energy;
+  double up,down;
+  double left,right;
+  double front,back;
+  double e;
+  std::vector<SVector3> gradients;
+ 
+  gradients.resize(bank.size()-offset);
+  e = 0.0001;
+  srand(time(NULL));
+  index = rand()%(bank.size()-offset) + offset;
+	
+  bank[index] = SPoint3(bank[index].x()+e,bank[index].y(),bank[index].z());
+  eval(bank,movability,offset,gradients,right,p);
+  bank[index] = SPoint3(bank[index].x()-e,bank[index].y(),bank[index].z());
+	
+  bank[index] = SPoint3(bank[index].x()-e,bank[index].y(),bank[index].z());
+  eval(bank,movability,offset,gradients,left,p);
+  bank[index] = SPoint3(bank[index].x()+e,bank[index].y(),bank[index].z());
+	
+  bank[index] = SPoint3(bank[index].x(),bank[index].y()+e,bank[index].z());
+  eval(bank,movability,offset,gradients,up,p);
+  bank[index] = SPoint3(bank[index].x(),bank[index].y()-e,bank[index].z());
+	
+  bank[index] = SPoint3(bank[index].x(),bank[index].y()-e,bank[index].z());
+  eval(bank,movability,offset,gradients,down,p);
+  bank[index] = SPoint3(bank[index].x(),bank[index].y()+e,bank[index].z());
+	
+  bank[index] = SPoint3(bank[index].x(),bank[index].y(),bank[index].z()+e);
+  eval(bank,movability,offset,gradients,front,p);
+  bank[index] = SPoint3(bank[index].x(),bank[index].y(),bank[index].z()-e);
+	
+  bank[index] = SPoint3(bank[index].x(),bank[index].y(),bank[index].z()-e);
+  eval(bank,movability,offset,gradients,back,p);
+  bank[index] = SPoint3(bank[index].x(),bank[index].y(),bank[index].z()+e);
+	
+  eval(bank,movability,offset,gradients,energy,p);
+
+  printf("...%f  %f  %f\n",gradients[index-offset].x(),gradients[index-offset].y(),gradients[index-offset].z());
+  printf("...%f  %f  %f\n",(right-left)/(2.0*e),(up-down)/(2.0*e),(front-back)/(2.0*e));
+}
+
+void LpCVT::eval(std::vector<SPoint3>& bank,std::vector<int>& movability,int offset,std::vector<SVector3>& gradients,double& energy,int p){
+  int i;
+  int index;
+  int index1,index2,index3;
+  int index4,index5,index6;
+  int index7,index8,index9;
+  double e;
+  SVector3 grad1,grad2,grad3;
+  clip approx;
+	
+  for(i=0;i<gradients.size();i++){
+    gradients[i] = SVector3(0.0,0.0,0.0);
+  }
+  energy = 0.0;
+  e = 0.000001;
+	
+  clipped.clear();
+  approx.execute(bank,clipped);
+  swap();
+  compute_parameters(p);
+	
+  for(i=0;i<clipped.size();i++){
+	if(clipped[i].get_quality()<e) continue;
+    energy = energy + F(clipped[i],p);
+	grad1 = dF_dC1(clipped[i],p);
+	grad2 = dF_dC2(clipped[i],p);
+	grad3 = dF_dC3(clipped[i],p);
+	index = clipped[i].get_v1().get_index1();
+	index1 = clipped[i].get_v2().get_index2();
+	index2 = clipped[i].get_v2().get_index3();
+	index3 = clipped[i].get_v2().get_index4();
+	index4 = clipped[i].get_v3().get_index2();
+	index5 = clipped[i].get_v3().get_index3();
+	index6 = clipped[i].get_v3().get_index4();
+	index7 = clipped[i].get_v4().get_index2();
+	index8 = clipped[i].get_v4().get_index3();
+	index9 = clipped[i].get_v4().get_index4();
+	if(movability[index]==1){
+	  gradients[index-offset] = gradients[index-offset] + simple(clipped[i],p);
+	  if(index1>0 && index2>0 && index3>0)
+	    gradients[index-offset] = gradients[index-offset] + bisectors3(grad1,clipped[i].get_v2().get_point(),bank[index],bank[index1],bank[index2],bank[index3]);
+	  if(index4>0 && index5>0 && index6>0)
+        gradients[index-offset] = gradients[index-offset] + bisectors3(grad2,clipped[i].get_v3().get_point(),bank[index],bank[index4],bank[index5],bank[index6]);
+	  if(index7>0 && index8>0 && index9>0)
+	    gradients[index-offset] = gradients[index-offset] + bisectors3(grad3,clipped[i].get_v4().get_point(),bank[index],bank[index7],bank[index8],bank[index9]);
+	}
+	if(index1>0 && index2>0 && index3>0){
+	  if(movability[index1]==1){
+	    gradients[index1-offset] = gradients[index1-offset] + bisectors3(grad1,clipped[i].get_v2().get_point(),bank[index1],bank[index],bank[index2],bank[index3]);
+	  }
+	  if(movability[index2]==1){
+	    gradients[index2-offset] = gradients[index2-offset] + bisectors3(grad1,clipped[i].get_v2().get_point(),bank[index2],bank[index],bank[index1],bank[index3]);
+	  }
+	  if(movability[index3]==1){
+	    gradients[index3-offset] = gradients[index3-offset] + bisectors3(grad1,clipped[i].get_v2().get_point(),bank[index3],bank[index],bank[index1],bank[index2]);
+	  }
+	}
+	if(index4>0 && index5>0 && index6>0){
+	  if(movability[index4]==1){
+	    gradients[index4-offset] = gradients[index4-offset] + bisectors3(grad2,clipped[i].get_v3().get_point(),bank[index4],bank[index],bank[index5],bank[index6]);
+	  }
+	  if(movability[index5]==1){
+	    gradients[index5-offset] = gradients[index5-offset] + bisectors3(grad2,clipped[i].get_v3().get_point(),bank[index5],bank[index],bank[index4],bank[index6]);
+	  }
+	  if(movability[index6]==1){
+	    gradients[index6-offset] = gradients[index6-offset] + bisectors3(grad2,clipped[i].get_v3().get_point(),bank[index6],bank[index],bank[index4],bank[index5]);
+	  }
+	}
+	if(index7>0 && index8>0 && index9>0){
+	  if(movability[index7]==1){
+	    gradients[index7-offset] = gradients[index7-offset] + bisectors3(grad3,clipped[i].get_v4().get_point(),bank[index7],bank[index],bank[index8],bank[index9]);
+	  }
+	  if(movability[index8]==1){
+	    gradients[index8-offset] = gradients[index8-offset] + bisectors3(grad3,clipped[i].get_v4().get_point(),bank[index8],bank[index],bank[index7],bank[index9]);
+	  }
+	  if(movability[index9]==1){
+	    gradients[index9-offset] = gradients[index9-offset] + bisectors3(grad3,clipped[i].get_v4().get_point(),bank[index9],bank[index],bank[index7],bank[index8]);
+	  }
+	}
   }
 }
 
 void LpCVT::compute_parameters(int p){
+  int i;
   double h1,h2,h3,h4;
   double rho1,rho2,rho3,rho4;
-  Metric m;
+  Tensor t;
   VoronoiVertex v1,v2,v3,v4;
-  std::list<VoronoiElement>::iterator it;
-		
-  for(it=clipped.begin();it!=clipped.end();it++){
-	v1 = it->get_v1();
-	v2 = it->get_v2();
-	v3 = it->get_v3();
-	v4 = it->get_v4(); 
-	h1 = 0.0000001;
-	h2 = 0.0000001;
-	h3 = 0.0000001;
-	h4 = 0.0000001;
-	rho1 = it->h_to_rho(h1,p);
-	rho2 = it->h_to_rho(h2,p);
-	rho3 = it->h_to_rho(h3,p);
-	rho4 = it->h_to_rho(h4,p);
+	
+  for(i=0;i<clipped.size();i++){
+    v1 = clipped[i].get_v1();
+	v2 = clipped[i].get_v2();
+	v3 = clipped[i].get_v3();
+	v4 = clipped[i].get_v4(); 
+	h1 = get_size(clipped[i].get_v1().get_point().x(),clipped[i].get_v1().get_point().y(),clipped[i].get_v1().get_point().z());
+	h2 = get_size(clipped[i].get_v2().get_point().x(),clipped[i].get_v2().get_point().y(),clipped[i].get_v2().get_point().z());
+	h3 = get_size(clipped[i].get_v3().get_point().x(),clipped[i].get_v3().get_point().y(),clipped[i].get_v3().get_point().z());
+	h4 = get_size(clipped[i].get_v4().get_point().x(),clipped[i].get_v4().get_point().y(),clipped[i].get_v4().get_point().z());
+	rho1 = h_to_rho(h1,p);
+	rho2 = h_to_rho(h2,p);
+	rho3 = h_to_rho(h3,p);
+	rho4 = h_to_rho(h4,p);
 	v1.set_rho(rho1);
 	v2.set_rho(rho2);
 	v3.set_rho(rho3);
 	v4.set_rho(rho4);
-	it->set_v1(v1);
-	it->set_v2(v2);
-	it->set_v3(v3);
-	it->set_v4(v4);
-	m = Metric();
-	m.set_m11(1.0);
-	m.set_m12(0.0);
-	m.set_m13(0.0);
-	m.set_m21(0.0);
-	m.set_m22(1.0);
-	m.set_m23(0.0);
-	m.set_m31(0.0);
-	m.set_m32(0.0);
-	m.set_m33(1.0);
-	it->set_metric(m);
-	it->compute_jacobian();
-	it->deriv_rho();
-  }		
+	clipped[i].set_v1(v1);
+	clipped[i].set_v2(v2);
+	clipped[i].set_v3(v3);
+	clipped[i].set_v4(v4);
+	t = get_tensor(clipped[i].get_v1().get_point().x(),clipped[i].get_v1().get_point().y(),clipped[i].get_v1().get_point().z());
+	clipped[i].set_tensor(t);
+	clipped[i].compute_jacobian();
+	clipped[i].deriv_rho();
+  }
+}
+
+double LpCVT::get_size(double x,double y,double z){
+  return 0.25;
+}
+
+Tensor LpCVT::get_tensor(double x,double y,double z){
+  double angle;
+  Tensor t;
+
+  angle = atan2(z,x);
+  t = Tensor();
+	
+  t.set_t11(1.0);
+  t.set_t12(0.0);
+  t.set_t13(0.0);
+  
+  t.set_t21(0.0);
+  t.set_t22(1.0);
+  t.set_t23(0.0);
+  
+  t.set_t31(0.0);
+  t.set_t32(0.0);
+  t.set_t33(1.0);
+	
+  return t;
+}
+
+double LpCVT::drho_dx(double x,double y,double z,int p){
+  double e;
+  double less2;
+  double less1;
+  double plus1;
+  double plus2;
+  double val;
+
+  e = 0.000001;
+  less2 = h_to_rho(get_size(x-2.0*e,y,z),p);
+  less1 = h_to_rho(get_size(x-e,y,z),p);
+  plus1 = h_to_rho(get_size(x+e,y,z),p);
+  plus2 = h_to_rho(get_size(x+2.0*e,y,z),p);
+	
+  val = (less2 - 8.0*less1 + 8.0*plus1 - plus2)/(12.0*e);
+  return val;
+}
+
+double LpCVT::drho_dy(double x,double y,double z,int p){
+  double e;
+  double less2;
+  double less1;
+  double plus1;
+  double plus2;
+  double val;
+	
+  e = 0.000001;
+  less2 = h_to_rho(get_size(x,y-2.0*e,z),p);
+  less1 = h_to_rho(get_size(x,y-e,z),p);
+  plus1 = h_to_rho(get_size(x,y+e,z),p);
+  plus2 = h_to_rho(get_size(x,y+2.0*e,z),p);
+	
+  val = (less2 - 8.0*less1 + 8.0*plus1 - plus2)/(12.0*e);
+  return val;
+}
+
+double LpCVT::drho_dz(double x,double y,double z,int p){
+  double e;
+  double less2;
+  double less1;
+  double plus1;
+  double plus2;
+  double val;
+	
+  e = 0.000001;
+  less2 = h_to_rho(get_size(x,y,z-2.0*e),p);
+  less1 = h_to_rho(get_size(x,y,z-e),p);
+  plus1 = h_to_rho(get_size(x,y,z+e),p);
+  plus2 = h_to_rho(get_size(x,y,z+2.0*e),p);
+	
+  val = (less2 - 8.0*less1 + 8.0*plus1 - plus2)/(12.0*e);
+  return val;	
+}
+
+double LpCVT::h_to_rho(double h,int p){
+  double rho;
+  rho = pow_int(1.0/h,p+3);
+  return rho;
+}
+
+void LpCVT::swap(){
+  int i;	
+  for(i=0;i<clipped.size();i++){
+    clipped[i].swap();		
+  }
 }
 
 void LpCVT::get_gauss(){
@@ -493,7 +962,7 @@ double LpCVT::F(VoronoiElement element,int p){
   double rho;
   SPoint3 point,generator,C1,C2,C3;
   VoronoiVertex v1,v2,v3,v4;
-  Metric m;
+  Tensor t;
 	
   v1 = element.get_v1();
   v2 = element.get_v2();
@@ -504,7 +973,7 @@ double LpCVT::F(VoronoiElement element,int p){
   C2 = v3.get_point();
   C3 = v4.get_point();
   energy = 0.0;
-  m = element.get_metric();
+  t = element.get_tensor();
 	
   for(i=0;i<gauss_num;i++){
     u = gauss_points(i,0);
@@ -516,7 +985,7 @@ double LpCVT::F(VoronoiElement element,int p){
 	point = SPoint3(x,y,z);
 	weight = gauss_weights(i,0);
 	rho = element.get_rho(u,v,w);
-	energy = energy + weight*rho*f(generator,point,m,p);
+	energy = energy + weight*rho*f(generator,point,t,p);
   }
   energy = element.get_jacobian()*energy;
   return energy;
@@ -532,7 +1001,7 @@ SVector3 LpCVT::simple(VoronoiElement element,int p){
   double jacobian;
   SPoint3 point,generator,C1,C2,C3;
   VoronoiVertex v1,v2,v3,v4;
-  Metric m;
+  Tensor t;
 	
   v1 = element.get_v1();
   v2 = element.get_v2();
@@ -546,7 +1015,7 @@ SVector3 LpCVT::simple(VoronoiElement element,int p){
   comp_y = 0.0;
   comp_z = 0.0;
   jacobian = element.get_jacobian();
-  m = element.get_metric();
+  t = element.get_tensor();
 	
   for(i=0;i<gauss_num;i++){
     u = gauss_points(i,0);
@@ -558,9 +1027,9 @@ SVector3 LpCVT::simple(VoronoiElement element,int p){
 	point = SPoint3(x,y,z);
 	weight = gauss_weights(i,0);
 	rho = element.get_rho(u,v,w);
-	comp_x = comp_x + weight*rho*df_dx(generator,point,m,p);
-	comp_y = comp_y + weight*rho*df_dy(generator,point,m,p);
-	comp_z = comp_z + weight*rho*df_dz(generator,point,m,p);
+	comp_x = comp_x + weight*rho*df_dx(generator,point,t,p);
+	comp_y = comp_y + weight*rho*df_dy(generator,point,t,p);
+	comp_z = comp_z + weight*rho*df_dz(generator,point,t,p);
   }
   comp_x = jacobian*comp_x;
   comp_y = jacobian*comp_y;
@@ -581,7 +1050,7 @@ SVector3 LpCVT::dF_dC1(VoronoiElement element,int p){
   double gx,gy,gz;
   SPoint3 point,generator,C1,C2,C3;
   VoronoiVertex v1,v2,v3,v4;
-  Metric m;
+  Tensor t;
 	
   v1 = element.get_v1();
   v2 = element.get_v2();
@@ -595,7 +1064,7 @@ SVector3 LpCVT::dF_dC1(VoronoiElement element,int p){
   comp_y = 0.0;
   comp_z = 0.0;
   jacobian = element.get_jacobian();
-  m = element.get_metric();
+  t = element.get_tensor();
   gx = generator.x();
   gy = generator.y();
   gz = generator.z();
@@ -613,14 +1082,14 @@ SVector3 LpCVT::dF_dC1(VoronoiElement element,int p){
 	drho_dx = element.get_drho_dx();
 	drho_dy = element.get_drho_dy();
 	drho_dz = element.get_drho_dz();
-	distance = f(point,generator,m,p);
-	comp_x = comp_x + weight*rho*df_dx(point,generator,m,p)*u*jacobian;
+	distance = f(point,generator,t,p);
+	comp_x = comp_x + weight*rho*df_dx(point,generator,t,p)*u*jacobian;
 	comp_x = comp_x + weight*rho*distance*((C2.y()-gy)*(C3.z()-gz) - (C3.y()-gy)*(C2.z()-gz));
 	comp_x = comp_x + weight*drho_dx*u*distance*jacobian;
-	comp_y = comp_y + weight*rho*df_dy(point,generator,m,p)*u*jacobian;
+	comp_y = comp_y + weight*rho*df_dy(point,generator,t,p)*u*jacobian;
 	comp_y = comp_y + weight*rho*distance*((C2.z()-gz)*(C3.x()-gx) - (C2.x()-gx)*(C3.z()-gz));
 	comp_y = comp_y + weight*drho_dy*u*distance*jacobian;
-	comp_z = comp_z + weight*rho*df_dz(point,generator,m,p)*u*jacobian;
+	comp_z = comp_z + weight*rho*df_dz(point,generator,t,p)*u*jacobian;
 	comp_z = comp_z + weight*rho*distance*((C2.x()-gx)*(C3.y()-gy) - (C3.x()-gx)*(C2.y()-gy));
 	comp_z = comp_z + weight*drho_dz*u*distance*jacobian;
   }		
@@ -640,7 +1109,7 @@ SVector3 LpCVT::dF_dC2(VoronoiElement element,int p){
   double gx,gy,gz;
   SPoint3 point,generator,C1,C2,C3;
   VoronoiVertex v1,v2,v3,v4;
-  Metric m;
+  Tensor t;
 	
   v1 = element.get_v1();
   v2 = element.get_v2();
@@ -654,7 +1123,7 @@ SVector3 LpCVT::dF_dC2(VoronoiElement element,int p){
   comp_y = 0.0;
   comp_z = 0.0;
   jacobian = element.get_jacobian();
-  m = element.get_metric();
+  t = element.get_tensor();
   gx = generator.x();
   gy = generator.y();
   gz = generator.z();
@@ -672,14 +1141,14 @@ SVector3 LpCVT::dF_dC2(VoronoiElement element,int p){
 	drho_dx = element.get_drho_dx();
 	drho_dy = element.get_drho_dy();
 	drho_dz = element.get_drho_dz();
-	distance = f(point,generator,m,p);
-	comp_x = comp_x + weight*rho*df_dx(point,generator,m,p)*v*jacobian;
+	distance = f(point,generator,t,p);
+	comp_x = comp_x + weight*rho*df_dx(point,generator,t,p)*v*jacobian;
 	comp_x = comp_x + weight*rho*distance*((C1.z()-gz)*(C3.y()-gy) - (C1.y()-gy)*(C3.z()-gz));
 	comp_x = comp_x + weight*drho_dx*v*distance*jacobian;
-	comp_y = comp_y + weight*rho*df_dy(point,generator,m,p)*v*jacobian;
+	comp_y = comp_y + weight*rho*df_dy(point,generator,t,p)*v*jacobian;
 	comp_y = comp_y + weight*rho*distance*((C1.x()-gx)*(C3.z()-gz) - (C3.x()-gx)*(C1.z()-gz));
 	comp_y = comp_y + weight*drho_dy*v*distance*jacobian;
-	comp_z = comp_z + weight*rho*df_dz(point,generator,m,p)*v*jacobian;
+	comp_z = comp_z + weight*rho*df_dz(point,generator,t,p)*v*jacobian;
 	comp_z = comp_z + weight*rho*distance*((C3.x()-gx)*(C1.y()-gy) - (C1.x()-gx)*(C3.y()-gy));
 	comp_z = comp_z + weight*drho_dz*v*distance*jacobian;
   }		
@@ -699,7 +1168,7 @@ SVector3 LpCVT::dF_dC3(VoronoiElement element,int p){
   double gx,gy,gz;
   SPoint3 point,generator,C1,C2,C3;
   VoronoiVertex v1,v2,v3,v4;
-  Metric m;
+  Tensor t;
 	
   v1 = element.get_v1();
   v2 = element.get_v2();
@@ -713,7 +1182,7 @@ SVector3 LpCVT::dF_dC3(VoronoiElement element,int p){
   comp_y = 0.0;
   comp_z = 0.0;
   jacobian = element.get_jacobian();
-  m = element.get_metric();
+  t = element.get_tensor();
   gx = generator.x();
   gy = generator.y();
   gz = generator.z();
@@ -731,26 +1200,26 @@ SVector3 LpCVT::dF_dC3(VoronoiElement element,int p){
 	drho_dx = element.get_drho_dx();
 	drho_dy = element.get_drho_dy();
 	drho_dz = element.get_drho_dz();
-	distance = f(point,generator,m,p);
-	comp_x = comp_x + weight*rho*df_dx(point,generator,m,p)*w*jacobian;
+	distance = f(point,generator,t,p);
+	comp_x = comp_x + weight*rho*df_dx(point,generator,t,p)*w*jacobian;
 	comp_x = comp_x + weight*rho*distance*((C1.y()-gy)*(C2.z()-gz) - (C2.y()-gy)*(C1.z()-gz));
 	comp_x = comp_x + weight*drho_dx*w*distance*jacobian;
-	comp_y = comp_y + weight*rho*df_dy(point,generator,m,p)*w*jacobian;
+	comp_y = comp_y + weight*rho*df_dy(point,generator,t,p)*w*jacobian;
 	comp_y = comp_y + weight*rho*distance*((C2.x()-gx)*(C1.z()-gz) - (C1.x()-gx)*(C2.z()-gz));
 	comp_y = comp_y + weight*drho_dy*w*distance*jacobian;
-	comp_z = comp_z + weight*rho*df_dz(point,generator,m,p)*w*jacobian;
+	comp_z = comp_z + weight*rho*df_dz(point,generator,t,p)*w*jacobian;
 	comp_z = comp_z + weight*rho*distance*((C1.x()-gx)*(C2.y()-gy) - (C2.x()-gx)*(C1.y()-gy));
 	comp_z = comp_z + weight*drho_dz*w*distance*jacobian;
   }		
   return SVector3(comp_x,comp_y,comp_z);
 }
 
-double LpCVT::f(SPoint3 p1,SPoint3 p2,Metric m,int p){
+double LpCVT::f(SPoint3 p1,SPoint3 p2,Tensor t,int p){
   double x1,y1,z1;
   double x2,y2,z2;
-  double m11,m12,m13;
-  double m21,m22,m23;
-  double m31,m32,m33;
+  double t11,t12,t13;
+  double t21,t22,t23;
+  double t31,t32,t33;
   double val1,val2,val3;
   double val;
 	
@@ -760,28 +1229,28 @@ double LpCVT::f(SPoint3 p1,SPoint3 p2,Metric m,int p){
   x2 = p2.x();
   y2 = p2.y();
   z2 = p2.z();
-  m11 = m.get_m11();
-  m12 = m.get_m12();
-  m13 = m.get_m13();
-  m21 = m.get_m21();
-  m22 = m.get_m22();
-  m23 = m.get_m23();
-  m31 = m.get_m31();
-  m32 = m.get_m32();
-  m33 = m.get_m33();	
-  val1 = m11*x1 + m12*y1 + m13*z1 - m11*x2 - m12*y2 - m13*z2; //A AMELIORER POUR 2D ET 3D ?
-  val2 = m21*x1 + m22*y1 + m23*z1 - m21*x2 - m22*y2 - m23*z2;
-  val3 = m31*x1 + m32*y1 + m33*z1 - m31*x2 - m32*y2 - m33*z2;
+  t11 = t.get_t11();
+  t12 = t.get_t12();
+  t13 = t.get_t13();
+  t21 = t.get_t21();
+  t22 = t.get_t22();
+  t23 = t.get_t23();
+  t31 = t.get_t31();
+  t32 = t.get_t32();
+  t33 = t.get_t33();	
+  val1 = t11*x1 + t12*y1 + t13*z1 - t11*x2 - t12*y2 - t13*z2;
+  val2 = t21*x1 + t22*y1 + t23*z1 - t21*x2 - t22*y2 - t23*z2;
+  val3 = t31*x1 + t32*y1 + t33*z1 - t31*x2 - t32*y2 - t33*z2;
   val = pow_int(val1,p) + pow_int(val2,p) + pow_int(val3,p);
   return val;
 }
 
-double LpCVT::df_dx(SPoint3 p1,SPoint3 p2,Metric m,int p){
+double LpCVT::df_dx(SPoint3 p1,SPoint3 p2,Tensor t,int p){
   double x1,y1,z1;
   double x2,y2,z2;
-  double m11,m12,m13;
-  double m21,m22,m23;
-  double m31,m32,m33;
+  double t11,t12,t13;
+  double t21,t22,t23;
+  double t31,t32,t33;
   double val1,val2,val3;
   double val;
 	
@@ -791,28 +1260,28 @@ double LpCVT::df_dx(SPoint3 p1,SPoint3 p2,Metric m,int p){
   x2 = p2.x();
   y2 = p2.y();
   z2 = p2.z();
-  m11 = m.get_m11();
-  m12 = m.get_m12();
-  m13 = m.get_m13();
-  m21 = m.get_m21();
-  m22 = m.get_m22();
-  m23 = m.get_m23();
-  m31 = m.get_m31();
-  m32 = m.get_m32();
-  m33 = m.get_m33();	
-  val1 = m11*x1 + m12*y1 + m13*z1 - m11*x2 - m12*y2 - m13*z2;
-  val2 = m21*x1 + m22*y1 + m23*z1 - m21*x2 - m22*y2 - m23*z2;
-  val3 = m31*x1 + m32*y1 + m33*z1 - m31*x2 - m32*y2 - m33*z2;
-  val = ((double)p)*pow_int(val1,p-1)*m11 + ((double)p)*pow_int(val2,p-1)*m21 + ((double)p)*pow_int(val3,p-1)*m31;
+  t11 = t.get_t11();
+  t12 = t.get_t12();
+  t13 = t.get_t13();
+  t21 = t.get_t21();
+  t22 = t.get_t22();
+  t23 = t.get_t23();
+  t31 = t.get_t31();
+  t32 = t.get_t32();
+  t33 = t.get_t33();	
+  val1 = t11*x1 + t12*y1 + t13*z1 - t11*x2 - t12*y2 - t13*z2;
+  val2 = t21*x1 + t22*y1 + t23*z1 - t21*x2 - t22*y2 - t23*z2;
+  val3 = t31*x1 + t32*y1 + t33*z1 - t31*x2 - t32*y2 - t33*z2;
+  val = ((double)p)*pow_int(val1,p-1)*t11 + ((double)p)*pow_int(val2,p-1)*t21 + ((double)p)*pow_int(val3,p-1)*t31;
   return val;
 }
 
-double LpCVT::df_dy(SPoint3 p1,SPoint3 p2,Metric m,int p){
+double LpCVT::df_dy(SPoint3 p1,SPoint3 p2,Tensor t,int p){
   double x1,y1,z1;
   double x2,y2,z2;
-  double m11,m12,m13;
-  double m21,m22,m23;
-  double m31,m32,m33;
+  double t11,t12,t13;
+  double t21,t22,t23;
+  double t31,t32,t33;
   double val1,val2,val3;
   double val;
 	
@@ -822,28 +1291,28 @@ double LpCVT::df_dy(SPoint3 p1,SPoint3 p2,Metric m,int p){
   x2 = p2.x();
   y2 = p2.y();
   z2 = p2.z();
-  m11 = m.get_m11();
-  m12 = m.get_m12();
-  m13 = m.get_m13();
-  m21 = m.get_m21();
-  m22 = m.get_m22();
-  m23 = m.get_m23();
-  m31 = m.get_m31();
-  m32 = m.get_m32();
-  m33 = m.get_m33();	
-  val1 = m11*x1 + m12*y1 + m13*z1 - m11*x2 - m12*y2 - m13*z2;
-  val2 = m21*x1 + m22*y1 + m23*z1 - m21*x2 - m22*y2 - m23*z2;
-  val3 = m31*x1 + m32*y1 + m33*z1 - m31*x2 - m32*y2 - m33*z2;
-  val = ((double)p)*pow_int(val1,p-1)*m12 + ((double)p)*pow_int(val2,p-1)*m22 + ((double)p)*pow_int(val3,p-1)*m32;
+  t11 = t.get_t11();
+  t12 = t.get_t12();
+  t13 = t.get_t13();
+  t21 = t.get_t21();
+  t22 = t.get_t22();
+  t23 = t.get_t23();
+  t31 = t.get_t31();
+  t32 = t.get_t32();
+  t33 = t.get_t33();	
+  val1 = t11*x1 + t12*y1 + t13*z1 - t11*x2 - t12*y2 - t13*z2;
+  val2 = t21*x1 + t22*y1 + t23*z1 - t21*x2 - t22*y2 - t23*z2;
+  val3 = t31*x1 + t32*y1 + t33*z1 - t31*x2 - t32*y2 - t33*z2;
+  val = ((double)p)*pow_int(val1,p-1)*t12 + ((double)p)*pow_int(val2,p-1)*t22 + ((double)p)*pow_int(val3,p-1)*t32;
   return val;
 }
 
-double LpCVT::df_dz(SPoint3 p1,SPoint3 p2,Metric m,int p){
+double LpCVT::df_dz(SPoint3 p1,SPoint3 p2,Tensor t,int p){
   double x1,y1,z1;
   double x2,y2,z2;
-  double m11,m12,m13;
-  double m21,m22,m23;
-  double m31,m32,m33;
+  double t11,t12,t13;
+  double t21,t22,t23;
+  double t31,t32,t33;
   double val1,val2,val3;
   double val;
 	
@@ -853,19 +1322,19 @@ double LpCVT::df_dz(SPoint3 p1,SPoint3 p2,Metric m,int p){
   x2 = p2.x();
   y2 = p2.y();
   z2 = p2.z();
-  m11 = m.get_m11();
-  m12 = m.get_m12();
-  m13 = m.get_m13();
-  m21 = m.get_m21();
-  m22 = m.get_m22();
-  m23 = m.get_m23();
-  m31 = m.get_m31();
-  m32 = m.get_m32();
-  m33 = m.get_m33();	
-  val1 = m11*x1 + m12*y1 + m13*z1 - m11*x2 - m12*y2 - m13*z2;
-  val2 = m21*x1 + m22*y1 + m23*z1 - m21*x2 - m22*y2 - m23*z2;
-  val3 = m31*x1 + m32*y1 + m33*z1 - m31*x2 - m32*y2 - m33*z2;
-  val = ((double)p)*pow_int(val1,p-1)*m13 + ((double)p)*pow_int(val2,p-1)*m23 + ((double)p)*pow_int(val3,p-1)*m33;
+  t11 = t.get_t11();
+  t12 = t.get_t12();
+  t13 = t.get_t13();
+  t21 = t.get_t21();
+  t22 = t.get_t22();
+  t23 = t.get_t23();
+  t31 = t.get_t31();
+  t32 = t.get_t32();
+  t33 = t.get_t33();	
+  val1 = t11*x1 + t12*y1 + t13*z1 - t11*x2 - t12*y2 - t13*z2;
+  val2 = t21*x1 + t22*y1 + t23*z1 - t21*x2 - t22*y2 - t23*z2;
+  val3 = t31*x1 + t32*y1 + t33*z1 - t31*x2 - t32*y2 - t33*z2;
+  val = ((double)p)*pow_int(val1,p-1)*t13 + ((double)p)*pow_int(val2,p-1)*t23 + ((double)p)*pow_int(val3,p-1)*t33;
   return val;
 }
 
@@ -997,134 +1466,171 @@ void LpSmoother::improve_model(){
 
 void LpSmoother::improve_region(GRegion* gr){
   int i;
-  int j;
+  int offset;
   double epsg;
   double epsf;
   double epsx;
+  double factor;
+  SPoint3 point;
   MVertex* vertex;
+  MVertex *v1,*v2,*v3,*v4;
   MElement* element;
   MElementOctree* octree;
   deMeshGRegion deleter;
-  double initial_conditions[2];
-  std::set<MVertex*> all_vertices;
-  std::vector<MVertex*> interior_vertices;
+  Wrap w;
+  std::set<MVertex*> movable2;
+  std::set<MVertex*> unmovable2;
   std::set<MVertex*>::iterator it;
+  std::vector<MVertex*> movable;
+  std::vector<MVertex*> unmovable;
+  std::vector<SPoint3> bank;
+  std::vector<int> movability;
   alglib::ae_int_t maxits;
   alglib::minlbfgsstate state;
   alglib::minlbfgsreport rep;
   alglib::real_1d_array x;
+  alglib::real_1d_array alglib_scales;
+
+  octree = new MElementOctree(gr->model());	
 	
   for(i=0;i<gr->getNumMeshElements();i++){
     element = gr->getMeshElement(i);
-	for(j=0;j<element->getNumVertices();j++){
-	  vertex = element->getVertex(j);
-	  all_vertices.insert(vertex);
+	v1 = element->getVertex(0);
+	v2 = element->getVertex(1);
+	v3 = element->getVertex(2);
+	v4 = element->getVertex(3);
+	if(v1->onWhat()->dim()<3 || v2->onWhat()->dim()<3 || v3->onWhat()->dim()<3 || v4->onWhat()->dim()<3){
+	  unmovable2.insert(v1);
+	  unmovable2.insert(v2);
+	  unmovable2.insert(v3);
+	  unmovable2.insert(v4);
 	}
+  }	
+
+  for(i=0;i<gr->getNumMeshElements();i++){
+    element = gr->getMeshElement(i);
+	v1 = element->getVertex(0);
+	v2 = element->getVertex(1);
+	v3 = element->getVertex(2);
+	v4 = element->getVertex(3);
+	if(unmovable2.find(v1)==unmovable2.end()){
+	  movable2.insert(v1);
+	}
+	if(unmovable2.find(v2)==unmovable2.end()){
+	  movable2.insert(v2);
+	}
+	if(unmovable2.find(v3)==unmovable2.end()){
+	  movable2.insert(v3);
+	}
+	if(unmovable2.find(v4)==unmovable2.end()){
+      movable2.insert(v4);
+	}
+  }		
+
+  for(it=unmovable2.begin();it!=unmovable2.end();it++){
+    unmovable.push_back(*it);
+  }
+
+  for(it=movable2.begin();it!=movable2.end();it++){
+    movable.push_back(*it);
+  }
+
+  offset = unmovable.size();
+		
+  for(i=0;i<unmovable.size();i++){
+	point = SPoint3(unmovable[i]->x(),unmovable[i]->y(),unmovable[i]->z());
+	bank.push_back(point);
+	movability.push_back(0);
   }
 	
-  octree = new MElementOctree(gr->model());
+  for(i=0;i<movable.size();i++){
+    point = SPoint3(movable[i]->x(),movable[i]->y(),movable[i]->z());
+	bank.push_back(point);
+	movability.push_back(1);
+  }	
+
+  w = Wrap();
+  w.set_p(norm);
+  w.set_dimension(3*(bank.size()-offset));
+  w.set_iteration(0);
+  w.set_max_iteration(2*max_iter);
+  w.set_offset(offset);
+  w.set_initial_energy(-1000000.0);
+  w.set_octree(octree);
+  w.resize(bank.size());
+  for(i=0;i<bank.size();i++) w.set_bank(bank[i],i);
+  for(i=0;i<bank.size();i++) w.set_movability(movability[i],i);
+
+  //LpCVT obj;
+  //obj.get_gauss();
+  //obj.verification(bank,movability,offset,6);
 	
   epsg = 0;
   epsf = 0;
   epsx = 0;
   maxits = max_iter;
   
-  initial_conditions[0] = 12.0;
-  initial_conditions[1] = 37.0;
-  x.setcontent(2,initial_conditions);
-	
-  minlbfgscreate(2,1,x,state);
-  minlbfgssetcond(state,epsg,epsf,epsx,maxits);
-  minlbfgsoptimize(state,call_back,NULL,NULL);
-  minlbfgsresults(state,x,rep);
-  printf("%f %f\n",x[0],x[1]);
-	
-  for(it=all_vertices.begin();it!=all_vertices.end();it++){
-	if((*it)->onWhat()->dim()==3){
-	  interior_vertices.push_back(*it);
-	}
+  double initial_conditions[3*(bank.size()-offset)];
+  double scales[3*(bank.size()-offset)];
+  factor = 2.0;
+  for(i=0;i<(bank.size()-offset);i++){
+    initial_conditions[i] = bank[i+offset].x();
+	initial_conditions[i+(bank.size()-offset)] = bank[i+offset].y();
+	initial_conditions[i+2*(bank.size()-offset)] = bank[i+offset].z();
+	scales[i] = factor*get_size(bank[i+offset].x(),bank[i+offset].y(),bank[i+offset].z());
+	scales[i+(bank.size()-offset)] = factor*get_size(bank[i+offset].x(),bank[i+offset].y(),bank[i+offset].z());
+	scales[i+2*(bank.size()-offset)] = factor*get_size(bank[i+offset].x(),bank[i+offset].y(),bank[i+offset].z());
+  }
+  x.setcontent(3*(bank.size()-offset),initial_conditions);
+  alglib_scales.setcontent(3*(bank.size()-offset),scales);
+
+  if((bank.size()-offset)>1){	
+    minlbfgscreate(3*(bank.size()-offset),4,x,state);
+	minlbfgssetscale(state,alglib_scales);
+	minlbfgssetprecscale(state);
+    minlbfgssetcond(state,epsg,epsf,epsx,maxits);
+    minlbfgsoptimize(state,call_back,NULL,&w);
+    minlbfgsresults(state,x,rep);
   }
-  printf("%d\n", (int) interior_vertices.size());
-	
-  deleter(gr);
-  //std::vector<GRegion*> regions;
-  //regions.push_back(gr);
-  //meshGRegion mesher(regions);
-  //mesher(gr);
-	
-  delete octree;
-}
-
-/*********class Wrap*********/
-
-Wrap::Wrap(){
-  iteration = 0;
-  initial_energy = -1.0;
-}
-
-Wrap::~Wrap(){}
-
-int Wrap::get_p(){
-  return p;
-}
-
-int Wrap::get_dimension(){
-  return dimension;
-}
-
-int Wrap::get_iteration(){
-  return iteration;
-}
-
-int Wrap::get_max_iteration(){
-  return max_iteration;
-}
-
-double Wrap::get_initial_energy(){
-  return initial_energy;
-}
-
-MElementOctree* Wrap::get_octree(){
-  return octree;
-}
-
-void Wrap::set_p(int new_p){
-  p = new_p;
-}
 
-void Wrap::set_dimension(int new_dimension){
-  dimension = new_dimension;
-}
+  for(i=0;i<(bank.size()-offset);i++){
+    vertex = new MVertex(x[i],x[i+(bank.size()-offset)],x[i+2*(bank.size()-offset)],gr,0);
+	interior_vertices.push_back(vertex);
+  }
 
-void Wrap::set_iteration(int new_iteration){
-  iteration = new_iteration;
+  for(i=0;i<unmovable.size();i++){
+    if(unmovable[i]->onWhat()->dim()==3){
+	  vertex = new MVertex(unmovable[i]->x(),unmovable[i]->y(),unmovable[i]->z(),gr,0);
+	  interior_vertices.push_back(vertex);
+	}
+  }	
+		
+  deleter(gr);
+  std::vector<GRegion*> regions;
+  regions.push_back(gr);
+  meshGRegion mesher(regions); //?
+  mesher(gr); //?
+  MeshDelaunayVolume(regions);
+  
+  for(i=0;i<interior_vertices.size();i++) delete interior_vertices[i];
+  interior_vertices.clear();
+  delete octree;
 }
 
-void Wrap::set_max_iteration(int new_max_iteration){
-  max_iteration = new_max_iteration;
+double LpSmoother::get_size(double x,double y,double z){
+  return 0.25;
 }
 
-void Wrap::set_initial_energy(double new_initial_energy){
-  initial_energy = new_initial_energy;
+int LpSmoother::get_nbr_interior_vertices(){
+  return interior_vertices.size();
 }
-
-void Wrap::set_octree(MElementOctree* new_octree){
-  octree = new_octree;
+ 
+MVertex* LpSmoother::get_interior_vertex(int i){
+  return interior_vertices[i];
 }
 
-/*********functions*********/
+/*********static declarations*********/
 
-bool inside_domain(MElementOctree* octree,double x,double y,double z){
-  MElement* element;
-  element = (MElement*)octree->find(x,y,z,3,true);
-  if(element!=NULL) return 1;
-  else return 0;
-}
-
-void call_back(const alglib::real_1d_array& x,double& func,alglib::real_1d_array& grad,void* ptr){
-  func = pow_int(3.0-x[0],2) + pow_int(4.0-x[1],2);
-  grad[0] = -2.0*(3.0-x[0]);
-  grad[1] = -2.0*(4.0-x[1]);
-}
+std::vector<MVertex*> LpSmoother::interior_vertices;
 
 #endif
diff --git a/Mesh/Levy3D.h b/Mesh/Levy3D.h
index 1d8c950bcae8e4f51e146e54e55c3b9dc6d87ad9..6513de97c9a0ca81b9ab570950df15d0dc543051 100755
--- a/Mesh/Levy3D.h
+++ b/Mesh/Levy3D.h
@@ -10,9 +10,12 @@
 #include <list>
 #include "fullMatrix.h"
 #include "GRegion.h"
-class MElementOctree;
-
-/*********class VoronoiVertex*********/
+#include "MElementOctree.h"
+#include "ap.h"
+#include "alglibinternal.h"
+#include "alglibmisc.h"
+#include "linalg.h"
+#include "optimization.h"
 
 class VoronoiVertex{
  private:
@@ -48,36 +51,32 @@ class VoronoiVertex{
   void set_rho(double);
 };
 
-/*********class Metric*********/
-
-class Metric{
+class Tensor{
  private:
-  double m11,m12,m13,m21,m22,m23,m31,m32,m33;
+  double t11,t12,t13,t21,t22,t23,t31,t32,t33;
  public:
-  Metric();
-  ~Metric();
-  void set_m11(double);
-  void set_m12(double);
-  void set_m13(double);
-  void set_m21(double);
-  void set_m22(double);
-  void set_m23(double);
-  void set_m31(double);
-  void set_m32(double);
-  void set_m33(double);
-  double get_m11();	
-  double get_m12();	
-  double get_m13();	
-  double get_m21();
-  double get_m22();
-  double get_m23();
-  double get_m31();
-  double get_m32();
-  double get_m33();
+  Tensor();
+  ~Tensor();
+  void set_t11(double);
+  void set_t12(double);
+  void set_t13(double);
+  void set_t21(double);
+  void set_t22(double);
+  void set_t23(double);
+  void set_t31(double);
+  void set_t32(double);
+  void set_t33(double);
+  double get_t11();	
+  double get_t12();	
+  double get_t13();	
+  double get_t21();
+  double get_t22();
+  double get_t23();
+  double get_t31();
+  double get_t32();
+  double get_t33();
 };
 
-/*********class VoronoiElement*********/
-
 class VoronoiElement{
  private:
   VoronoiVertex v1;
@@ -88,7 +87,7 @@ class VoronoiElement{
   double drho_dx;
   double drho_dy;
   double drho_dz;
-  Metric m;
+  Tensor t;
  public:
   VoronoiElement();
   ~VoronoiElement();
@@ -100,89 +99,31 @@ class VoronoiElement{
   double get_drho_dx();
   double get_drho_dy();
   double get_drho_dz();
-  Metric get_metric();
+  Tensor get_tensor();
   void set_v1(VoronoiVertex);
   void set_v2(VoronoiVertex);
   void set_v3(VoronoiVertex);
   void set_v4(VoronoiVertex);
-  void set_metric(Metric);
+  void set_tensor(Tensor);
   double get_rho(double,double,double);
   void deriv_rho();
   void compute_jacobian();
   double T(double,double,double,double,double,double,double);
-  double h_to_rho(double,int);
-  void swap();
-};
-
-/*********class LpCVT*********/
-
-class LpCVT{
- private:
-  std::list<VoronoiElement> clipped;
-  fullMatrix<double> gauss_points;
-  fullMatrix<double> gauss_weights;
-  int gauss_num;
- public:
-  LpCVT();
-  ~LpCVT();
   void swap();
-  void compute_parameters(int);
-  void get_gauss();
-  double F(VoronoiElement,int);
-  SVector3 simple(VoronoiElement,int);
-  SVector3 dF_dC1(VoronoiElement,int);
-  SVector3 dF_dC2(VoronoiElement,int);
-  SVector3 dF_dC3(VoronoiElement,int);
-  double f(SPoint3,SPoint3,Metric,int);
-  double df_dx(SPoint3,SPoint3,Metric,int);
-  double df_dy(SPoint3,SPoint3,Metric,int);
-  double df_dz(SPoint3,SPoint3,Metric,int);
-  SVector3 bisectors3(SVector3,SPoint3,SPoint3,SPoint3,SPoint3,SPoint3);
-  SVector3 bisectors2(SVector3,SPoint3,SPoint3,SPoint3,SPoint3,SVector3);
-  SVector3 bisectors1(SVector3,SPoint3,SPoint3,SPoint3,SVector3,SVector3);
-  void clear();
+  double get_quality();
 };
 
-/*********class LpSmoother*********/
-
 class LpSmoother{
  private:
   int max_iter;
   int norm;
+  static std::vector<MVertex*> interior_vertices;
  public:
   LpSmoother(int,int);
   ~LpSmoother();
   void improve_model();
   void improve_region(GRegion*);
-};
-
-/*********class Wrap*********/
-
-class Wrap{
- private:
-  int p;
-  int dimension;
-  int iteration;
-  int max_iteration;
-  double initial_energy;
-  MElementOctree* octree;
- public:
-  Wrap();
-  ~Wrap();
-  int get_p();
-  int get_dimension();
-  int get_iteration();
-  int get_max_iteration();
-  double get_initial_energy();
-  MElementOctree* get_octree();
-  void set_p(int);
-  void set_dimension(int);
-  void set_iteration(int);
-  void set_max_iteration(int);
-  void set_initial_energy(double);
-  void set_octree(MElementOctree*);
-};
-
-/*********functions*********/
-
-bool inside_domain(MElementOctree*,double,double,double);
+  double get_size(double,double,double);
+  static int get_nbr_interior_vertices();
+  static MVertex* get_interior_vertex(int);
+};
\ No newline at end of file
diff --git a/Mesh/meshGFaceLloyd.cpp b/Mesh/meshGFaceLloyd.cpp
index 21419e66224507da7d508bff76bda325005bb37a..a02a7709113e4878a54b0bdb26b5aecd30b032e2 100644
--- a/Mesh/meshGFaceLloyd.cpp
+++ b/Mesh/meshGFaceLloyd.cpp
@@ -7,38 +7,144 @@
 //   Tristan Carrier
 
 #include <set>
-#include <fstream>
 #include "meshGFaceLloyd.h"
 #include "DivideAndConquer.h"
-#include "GModel.h"
 #include "GFace.h"
 #include "MElement.h"
 #include "MVertex.h"
 #include "MTriangle.h"
 #include "Context.h"
 #include "meshGFace.h"
-#include "meshGFaceOptimize.h"
 #include "BackgroundMesh.h" 
-#include "polynomialBasis.h"
-#include "MElementOctree.h"
-
-#if defined(HAVE_BFGS)
-
+#include <fstream>
 #include "ap.h"
 #include "alglibinternal.h"
 #include "alglibmisc.h"
 #include "linalg.h"
 #include "optimization.h"
+#include "polynomialBasis.h"
+#include "MElementOctree.h"
+#include "GModel.h"
+#include "meshGFaceOptimize.h"
+#include <algorithm>
 
-bool domain_search(MElementOctree* octree,double x,double y){
-  MElement* element;
-	
-  element = (MElement*)octree->find(x,y,0.0,2,true);
-  if(element!=NULL) return 1;
-  else return 0;
-}
+/****************definitions****************/
+
+class metric{
+ private :
+  double a,b,c,d;
+ public :
+  metric(double,double,double,double);
+  metric();
+  ~metric();
+  void set_a(double);	
+  void set_b(double);	
+  void set_c(double);	
+  void set_d(double);	
+  double get_a();	
+  double get_b();	
+  double get_c();	
+  double get_d();
+};
+
+class voronoi_vertex{
+ private :
+  SPoint2 point;
+  int index1;
+  int index2;
+  int index3;
+  SVector3 normal;
+  bool duplicate;
+  double rho;
+ public :
+  voronoi_vertex(SPoint2);
+  voronoi_vertex();
+  ~voronoi_vertex();
+  SPoint2 get_point();
+  int get_index1();
+  int get_index2();
+  int get_index3();
+  SVector3 get_normal();
+  bool get_duplicate();
+  double get_rho();
+  void set_point(SPoint2);
+  void set_index1(int);
+  void set_index2(int);
+  void set_index3(int);
+  void set_normal(SVector3);
+  void set_duplicate(bool);
+  void set_rho(double);
+};
+
+class voronoi_element{
+ private :
+  voronoi_vertex v1;
+  voronoi_vertex v2;
+  voronoi_vertex v3;
+  double drho_dx;
+  double drho_dy;
+  metric m;
+ public :
+  voronoi_element(voronoi_vertex,voronoi_vertex,voronoi_vertex);
+  voronoi_element();
+  ~voronoi_element();
+  voronoi_vertex get_v1();
+  voronoi_vertex get_v2();
+  voronoi_vertex get_v3();
+  double get_rho(double,double);
+  double get_drho_dx();
+  double get_drho_dy();
+  metric get_metric();
+  void set_v1(voronoi_vertex);
+  void set_v2(voronoi_vertex);
+  void set_v3(voronoi_vertex);
+  void set_metric(metric);
+  void deriv_rho(int);
+  double compute_rho(double,int);
+  double get_quality();
+};
 
+class voronoi_cell{
+ private :
+  std::vector<voronoi_vertex> vertices;
+ public :
+  voronoi_cell();
+  ~voronoi_cell();
+  int get_number_vertices();
+  voronoi_vertex get_vertex(int);
+  void add_vertex(voronoi_vertex);
+  void clear();
+};
 
+class segment{
+ private :
+  int index1;
+  int index2;
+  int reference;
+ public :
+  segment(int,int,int);
+  segment();
+  ~segment();
+  int get_index1();
+  int get_index2();
+  int get_reference();
+  void set_index1(int);
+  void set_index2(int);
+  void set_reference(int);
+  bool equal(int,int);
+};
+
+class segment_list{
+ private :
+  std::vector<segment> segments;
+ public :
+  segment_list();
+  ~segment_list();
+  int get_number_segments();
+  segment get_segment(int);
+  bool add_segment(int,int,int);
+  bool add_segment(segment);
+};
 
 class wrapper{
  private :
@@ -71,10 +177,76 @@ class wrapper{
   void set_octree(MElementOctree*);
 };
 
+class lpcvt{
+ private :
+  std::list<voronoi_element> clipped;
+  std::queue<int> fifo;
+  std::vector<segment_list> borders;
+  std::vector<double> angles;
+  std::vector<voronoi_cell> temp;
+  fullMatrix<double> gauss_points;
+  fullMatrix<double> gauss_weights;
+  int gauss_num;
+ public :
+  lpcvt();
+  ~lpcvt();
+  double angle(SPoint2,SPoint2,SPoint2);
+  SVector3 normal(SPoint2,SPoint2);
+  SPoint2 mid(SPoint2,SPoint2);
+  bool same_side(SPoint2,SPoint2,SPoint2,SPoint2);
+  bool interior(DocRecord&,GFace*,int);
+  bool interior(DocRecord&,segment,segment,double,SPoint2);
+  bool invisible(DocRecord&,GFace*,int);
+  bool real(DocRecord&,int,int,int);
+  double triangle_area(SPoint2,SPoint2,SPoint2);
+  bool sliver(SPoint2,SPoint2,SPoint2);
+  SPoint2 intersection(DocRecord&,segment,segment,SPoint2,SPoint2,bool&,SVector3&,segment&);
+  SPoint2 intersection(SPoint2,SPoint2,SPoint2,SPoint2,bool&);
+  SPoint2 convert(DocRecord&,int);
+  SPoint2 circumcircle(DocRecord&,int,int,int);
+  SPoint2 seed(DocRecord&,GFace*);
+  void step1(DocRecord&,GFace*);
+  void step2(DocRecord&,GFace*);
+  void step3(DocRecord&,GFace*);
+  void step4(DocRecord&,GFace*);
+  void step5(DocRecord&,GFace*);
+  void clip_cells(DocRecord&,GFace*);
+  void clear();
+  double total_area();
+  void print_voronoi1();
+  void print_voronoi2();
+  void print_delaunay(DocRecord&);
+  void print_segment(SPoint2,SPoint2,std::ofstream&);
+	
+  void compute_parameters(GFace*,int);
+  double get_ratio(GFace*,SPoint2);
+  void write(DocRecord&,GFace*,int);
+  void eval(DocRecord&,std::vector<SVector3>&,double&,int);
+  void swap();
+  void get_gauss();
+  double F(voronoi_element,int);
+  SVector3 simple(voronoi_element,int);
+  SVector3 dF_dC1(voronoi_element,int);
+  SVector3 dF_dC2(voronoi_element,int);
+  double f(SPoint2,SPoint2,metric,int);
+  double df_dx(SPoint2,SPoint2,metric,int);
+  double df_dy(SPoint2,SPoint2,metric,int);
+  double Tx(double,double,SPoint2,SPoint2,SPoint2);
+  double Ty(double,double,SPoint2,SPoint2,SPoint2);
+  double J(SPoint2,SPoint2,SPoint2);
+  SVector3 inner_dFdx0(SVector3,SPoint2,SPoint2,SPoint2,SPoint2);
+  SVector3 boundary_dFdx0(SVector3,SPoint2,SPoint2,SPoint2,SVector3);
+};
 
+/****************functions****************/
 
-/****************fonction callback****************/
-/*************************************************/
+bool domain_search(MElementOctree* octree,double x,double y){
+  MElement* element;
+	
+  element = (MElement*)octree->find(x,y,0.0,2,true);
+  if(element!=NULL) return 1;
+  else return 0;
+}
 
 void callback(const alglib::real_1d_array& x,double& func,alglib::real_1d_array& grad,void* ptr){
   int i;
@@ -102,7 +274,7 @@ void callback(const alglib::real_1d_array& x,double& func,alglib::real_1d_array&
   lpcvt obj;
   std::vector<SVector3> gradients;
   	
-  w = static_cast<wrapper*>(ptr);	
+  w = static_cast<wrapper*>(ptr);
   p = w->get_p();
   dimension = w->get_dimension();
   gf = w->get_face();
@@ -134,7 +306,7 @@ void callback(const alglib::real_1d_array& x,double& func,alglib::real_1d_array&
   if(iteration>=max){
     error2 = 1;
   }
-	
+
   if(!error1 && !error2){
     pointer->Voronoi();
 	pointer->build_edges();
@@ -164,22 +336,20 @@ void callback(const alglib::real_1d_array& x,double& func,alglib::real_1d_array&
   if(error1){
     printf("Vertices outside domain.\n");
   }
-	
   if(error2){
-    printf("Oscillations.\n");
-  }
-	
+    printf("Maximum number of iterations reached.\n");
+  }	
   if(error3){
     printf("Boundary intersection.\n");
   }	
 	
-  if(start>0.0){
+  if(start>0.0 && !error1 && !error2 && !error3){
     printf("%d %.3f\n",iteration,100.0*(start-energy)/start);
+	w->set_iteration(iteration+1);
   }
   else if(!error1 && !error2 && !error3){
     w->set_start(energy);
   }
-  w->set_iteration(iteration+1);
   
   for(i=0;i<num;i++){
     if(obj.interior(*pointer,gf,i)){
@@ -190,7 +360,6 @@ void callback(const alglib::real_1d_array& x,double& func,alglib::real_1d_array&
   }	
 }
 
-
 /****************class smoothing****************/
 
 smoothing::smoothing(int param1,int param2){
@@ -256,12 +425,17 @@ void smoothing::optimize_face(GFace* gf){
   double epsg;
   double epsf;
   double epsx;
+  double varx,vary;
+  double ratio;
+  double factor;
   lpcvt obj;
-  std::vector<double> initial_conditions(2*triangulator.numPoints);
+  double initial_conditions[2*triangulator.numPoints];
+  double variables_scales[2*triangulator.numPoints];
   alglib::ae_int_t maxits;
   alglib::minlbfgsstate state;
   alglib::minlbfgsreport rep;
   alglib::real_1d_array x;
+  alglib::real_1d_array scales;
   wrapper w;
   MElementOctree* octree;
   
@@ -278,16 +452,23 @@ void smoothing::optimize_face(GFace* gf){
 	}
   }
 
+  factor = 2.0;
   index = 0;
   for(int i=0;i<triangulator.numPoints;i++){
 	if(obj.interior(triangulator,gf,i)){
-	  initial_conditions[index] = triangulator.points[i].where.h;
-	  initial_conditions[index+num_interior] = triangulator.points[i].where.v;
+	  varx = triangulator.points[i].where.h;
+	  vary = triangulator.points[i].where.v;
+	  initial_conditions[index] = varx;
+	  initial_conditions[index+num_interior] = vary;
+	  ratio = obj.get_ratio(gf,SPoint2(varx,vary));
+	  variables_scales[index] = factor*backgroundMesh::current()->operator()(varx,vary,0.0)*ratio;
+	  variables_scales[index+num_interior] = factor*backgroundMesh::current()->operator()(varx,vary,0.0)*ratio;
 	  index++;
 	}
   }
 	
-  x.setcontent(2*num_interior, &initial_conditions[0]);
+  x.setcontent(2*num_interior,initial_conditions);
+  scales.setcontent(2*num_interior,variables_scales);
 
   octree = backgroundMesh::current()->get_octree();	
 	
@@ -300,6 +481,8 @@ void smoothing::optimize_face(GFace* gf){
 
   if(num_interior>1){
     minlbfgscreate(2*num_interior,4,x,state);
+	minlbfgssetscale(state,scales);
+	minlbfgssetprecscale(state);
     minlbfgssetcond(state,epsg,epsf,epsx,maxits);
     minlbfgsoptimize(state,callback,NULL,&w);
     minlbfgsresults(state,x,rep);
@@ -364,15 +547,13 @@ void smoothing::optimize_model(){
   for(it=model->firstFace();it!=model->lastFace();it++)
   {
     gf = *it;
-	if(gf->getNumMeshElements()>0 && gf->geomType()==GEntity::CompoundSurface){
+	if(gf->getNumMeshElements()>0 /*&& gf->geomType()==GEntity::CompoundSurface*/){
 	  optimize_face(gf);
-	  recombineIntoQuads(gf,1,1);
+	  //recombineIntoQuads(gf,1,1);
 	}
   }
 }
 
-
-
 /****************class lpcvt****************/
 
 lpcvt::lpcvt(){}
@@ -971,7 +1152,7 @@ double lpcvt::total_area(){
   double total;
   SPoint2 p1,p2,p3;
   voronoi_vertex v1,v2,v3;
-  std::vector<voronoi_element>::iterator it;
+  std::list<voronoi_element>::iterator it;
   total = 0.0;
   for(it=clipped.begin();it!=clipped.end();it++){
     v1 = it->get_v1();
@@ -988,7 +1169,7 @@ double lpcvt::total_area(){
 void lpcvt::print_voronoi1(){
   SPoint2 p1,p2,p3;
   voronoi_vertex v1,v2,v3;
-  std::vector<voronoi_element>::iterator it;
+  std::list<voronoi_element>::iterator it;
   std::ofstream file("voronoi1.pos");
   file << "View \"test\" {\n";
   for(it=clipped.begin();it!=clipped.end();it++){
@@ -1066,7 +1247,7 @@ void lpcvt::compute_parameters(GFace* gf,int p){
   SPoint2 p1,p2,p3;
   voronoi_vertex v1,v2,v3;
   metric m;
-  std::vector<voronoi_element>::iterator it;
+  std::list<voronoi_element>::iterator it;
 	
   k = 1.0;	
   for(it=clipped.begin();it!=clipped.end();it++){
@@ -1084,10 +1265,10 @@ void lpcvt::compute_parameters(GFace* gf,int p){
 	rho1 = it->compute_rho(h1,p);
 	rho2 = it->compute_rho(h2,p);
 	rho3 = it->compute_rho(h3,p);
-	angle = -backgroundMesh::current()->getAngle(p1.x(),p1.y(),0.0);
+	angle = backgroundMesh::current()->getAngle(p1.x(),p1.y(),0.0);
 	cosinus = cos(angle);
 	sinus = sin(angle);
-	m = metric(cosinus,-sinus,sinus,cosinus);
+	m = metric(cosinus,sinus,-sinus,cosinus);
 	v1.set_rho(rho1);
 	v2.set_rho(rho2);
 	v3.set_rho(rho3);
@@ -1137,20 +1318,23 @@ void lpcvt::eval(DocRecord& triangulator,std::vector<SVector3>& gradients,double
   int index1;
   int index2;
   int index3;
+  double e;
   SPoint2 generator;
   SPoint2 C1,C2;
   SPoint2 p1,p2,p3;
   SVector3 grad1,grad2;
   SVector3 normal;
   voronoi_vertex v1,v2,v3;
-  std::vector<voronoi_element>::iterator it;
+  std::list<voronoi_element>::iterator it;
 	
   for(i=0;i<gradients.size();i++){
     gradients[i] = SVector3(0.0,0.0,0.0);
   }
   energy = 0.0;
+  e = 0.000001;
 	
   for(it=clipped.begin();it!=clipped.end();it++){
+	if(it->get_quality()<e) continue;
     v1 = it->get_v1();
 	v2 = it->get_v2();
 	v3 = it->get_v3();
@@ -1207,7 +1391,7 @@ void lpcvt::eval(DocRecord& triangulator,std::vector<SVector3>& gradients,double
 
 void lpcvt::swap(){
   voronoi_vertex vertex;
-  std::vector<voronoi_element>::iterator it;
+  std::list<voronoi_element>::iterator it;
   for(it=clipped.begin();it!=clipped.end();it++){
 	if(J(it->get_v1().get_point(),it->get_v2().get_point(),it->get_v3().get_point())<0.0){
       vertex = it->get_v3();
@@ -1423,8 +1607,8 @@ double lpcvt::f(SPoint2 p1,SPoint2 p2,metric m,int p){
   b = m.get_b();
   c = m.get_c();
   d = m.get_d();
-  val1 = a*x1 + b*y1 - a*x2 - b*y2;
-  val2 = c*x1 + d*y1 - c*x2 - d*y2;
+  val1 = a*(x1-x2) + b*(y1-y2);
+  val2 = c*(x1-x2) + d*(y1-y2);
   val = pow_int(val1,p) + pow_int(val2,p);
   return val;
 }
@@ -1450,8 +1634,8 @@ double lpcvt::df_dx(SPoint2 p1,SPoint2 p2,metric m,int p){
   b = m.get_b();
   c = m.get_c();
   d = m.get_d();
-  val1 = a*x1 + b*y1 - a*x2 - b*y2;
-  val2 = c*x1 + d*y1 - c*x2 - d*y2;
+  val1 = a*(x1-x2) + b*(y1-y2);
+  val2 = c*(x1-x2) + d*(y1-y2);
   val = ((double)p)*pow_int(val1,p-1)*a + ((double)p)*pow_int(val2,p-1)*c;
   return val;
 }
@@ -1477,8 +1661,8 @@ double lpcvt::df_dy(SPoint2 p1,SPoint2 p2,metric m,int p){
   b = m.get_b();
   c = m.get_c();
   d = m.get_d();
-  val1 = a*x1 + b*y1 - a*x2 - b*y2;
-  val2 = c*x1 + d*y1 - c*x2 - d*y2;
+  val1 = a*(x1-x2) + b*(y1-y2);
+  val2 = c*(x1-x2) + d*(y1-y2);
   val = ((double)p)*pow_int(val1,p-1)*b + ((double)p)*pow_int(val2,p-1)*d;
   return val;
 }
@@ -1544,8 +1728,6 @@ SVector3 lpcvt::boundary_dFdx0(SVector3 dFdC,SPoint2 C,SPoint2 x0,SPoint2 x1,SVe
   return SVector3(_val(0,0),_val(0,1),0.0);	
 }
 
-
-
 /****************class metric****************/
 
 metric::metric(double new_a,double new_b,double new_c,double new_d){
@@ -1591,8 +1773,6 @@ double metric::get_d(){
   return d;
 }
 
-
-
 /****************class voronoi_vertex****************/
 
 voronoi_vertex::voronoi_vertex(SPoint2 new_point){
@@ -1664,8 +1844,6 @@ void voronoi_vertex::set_rho(double new_rho){
   rho = new_rho;
 }
 
-
-
 /****************class voronoi_element****************/
 
 voronoi_element::voronoi_element(voronoi_vertex new_v1,voronoi_vertex new_v2,voronoi_vertex new_v3){
@@ -1773,11 +1951,35 @@ void voronoi_element::deriv_rho(int p){
 
 double voronoi_element::compute_rho(double h,int p){
   double rho;
-  rho = pow_int(1.0/h,p+1);
+  rho = pow_int(1.0/h,p+2);
   return rho;
 }
 
-
+double voronoi_element::get_quality(){
+  double x1,y1;
+  double x2,y2;
+  double x3,y3;
+  double quality;
+  double l1,l2,l3;
+  double min_l,max_l;
+	
+  x1 = v1.get_point().x();
+  y1 = v1.get_point().y();
+  x2 = v2.get_point().x();
+  y2 = v2.get_point().y();
+  x3 = v3.get_point().x();
+  y3 = v3.get_point().y();
+	
+  l1 = sqrt(pow_int(x2-x1,2) + pow_int(y2-y1,2));
+  l2 = sqrt(pow_int(x3-x1,2) + pow_int(y3-y1,2));
+  l3 = sqrt(pow_int(x3-x2,2) + pow_int(y3-y2,2));
+	
+  min_l = std::min(std::min(l1,l2),l3);
+  max_l = std::max(std::max(l1,l2),l3);
+	
+  quality = min_l/max_l;
+  return quality;
+}
 
 /****************class voronoi_cell****************/
 
@@ -1801,8 +2003,6 @@ void voronoi_cell::clear(){
   vertices.clear();
 }
 
-
-
 /****************class segment****************/
 
 segment::segment(int new_index1,int new_index2,int new_reference){
@@ -1849,8 +2049,6 @@ bool segment::equal(int index3,int index4){
   else return 0;
 }
 
-
-
 /****************class list_segment****************/
 
 segment_list::segment_list(){}
@@ -1878,13 +2076,11 @@ bool segment_list::add_segment(segment s){
   return add_segment(s.get_index1(),s.get_index2(),s.get_reference());
 }
 
-
-
 /****************class wrapper****************/
 
 wrapper::wrapper(){
   iteration = 0;
-  start = -100.0;
+  start = -1000000.0;
 }
 
 wrapper::~wrapper(){}
@@ -1952,5 +2148,3 @@ MElementOctree* wrapper::get_octree(){
 void wrapper::set_octree(MElementOctree* new_octree){
   octree = new_octree;
 }
-
-#endif
diff --git a/Mesh/meshGFaceLloyd.h b/Mesh/meshGFaceLloyd.h
index f64160fa76cc9d6c99ed21654a8df0096be93288..318b592fb8798e50f7019c8e8573697fead4b411 100644
--- a/Mesh/meshGFaceLloyd.h
+++ b/Mesh/meshGFaceLloyd.h
@@ -5,23 +5,17 @@
 
 #ifndef _MESH_GFACE_LLOYD_H_
 #define _MESH_GFACE_LLOYD_H_
-
-#include "GmshConfig.h"
-
-#if defined(HAVE_BFGS)
-
 #include "fullMatrix.h"
 #include "DivideAndConquer.h"
 #include <queue>
+#include "ap.h"
+#include "alglibinternal.h"
+#include "alglibmisc.h"
+#include "linalg.h"
+#include "optimization.h"
+#include "MElementOctree.h"
 
 class GFace;
-class voronoi_vertex;
-class voronoi_element;
-class voronoi_cell;  
-class segment;
-class segment_list;
-class metric;
-
 
 class smoothing{
   int ITER_MAX;
@@ -32,182 +26,4 @@ class smoothing{
   void optimize_model();
 };
 
-class lpcvt{
- private :
-  std::vector<voronoi_element> clipped;
-  std::queue<int> fifo;
-  std::vector<segment_list> borders;
-  std::vector<double> angles;
-  std::vector<voronoi_cell> temp;
-  fullMatrix<double> gauss_points;
-  fullMatrix<double> gauss_weights;
-  int gauss_num;
- public :
-  lpcvt();
-  ~lpcvt();
-  double angle(SPoint2,SPoint2,SPoint2);
-  SVector3 normal(SPoint2,SPoint2);
-  SPoint2 mid(SPoint2,SPoint2);
-  bool same_side(SPoint2,SPoint2,SPoint2,SPoint2);
-  bool interior(DocRecord&,GFace*,int);
-  bool interior(DocRecord&,segment,segment,double,SPoint2);
-  bool invisible(DocRecord&,GFace*,int);
-  bool real(DocRecord&,int,int,int);
-  double triangle_area(SPoint2,SPoint2,SPoint2);
-  bool sliver(SPoint2,SPoint2,SPoint2);
-  SPoint2 intersection(DocRecord&,segment,segment,SPoint2,SPoint2,bool&,SVector3&,segment&);
-  SPoint2 intersection(SPoint2,SPoint2,SPoint2,SPoint2,bool&);
-  SPoint2 convert(DocRecord&,int);
-  SPoint2 circumcircle(DocRecord&,int,int,int);
-  SPoint2 seed(DocRecord&,GFace*);
-  void step1(DocRecord&,GFace*);
-  void step2(DocRecord&,GFace*);
-  void step3(DocRecord&,GFace*);
-  void step4(DocRecord&,GFace*);
-  void step5(DocRecord&,GFace*);
-  void clip_cells(DocRecord&,GFace*);
-  void clear();
-  double total_area();
-  void print_voronoi1();
-  void print_voronoi2();
-  void print_delaunay(DocRecord&);
-  void print_segment(SPoint2,SPoint2,std::ofstream&);
-
-  void compute_parameters(GFace*,int);
-  double get_ratio(GFace*,SPoint2);
-  void write(DocRecord&,GFace*,int);
-  void eval(DocRecord&,std::vector<SVector3>&,double&,int);
-  void swap();
-  void get_gauss();
-  double F(voronoi_element,int);
-  SVector3 simple(voronoi_element,int);
-  SVector3 dF_dC1(voronoi_element,int);
-  SVector3 dF_dC2(voronoi_element,int);
-  double f(SPoint2,SPoint2,metric,int);
-  double df_dx(SPoint2,SPoint2,metric,int);
-  double df_dy(SPoint2,SPoint2,metric,int);
-  double Tx(double,double,SPoint2,SPoint2,SPoint2);
-  double Ty(double,double,SPoint2,SPoint2,SPoint2);
-  double J(SPoint2,SPoint2,SPoint2);
-  SVector3 inner_dFdx0(SVector3,SPoint2,SPoint2,SPoint2,SPoint2);
-  SVector3 boundary_dFdx0(SVector3,SPoint2,SPoint2,SPoint2,SVector3);
-};
-
-class metric{
- private :
-  double a,b,c,d;
- public :
-  metric(double,double,double,double);
-  metric();
-  ~metric();
-  void set_a(double);	
-  void set_b(double);	
-  void set_c(double);	
-  void set_d(double);	
-  double get_a();	
-  double get_b();	
-  double get_c();	
-  double get_d();
-};
-
-class voronoi_vertex{
- private :
-  SPoint2 point;
-  int index1;
-  int index2;
-  int index3;
-  SVector3 normal;
-  bool duplicate;
-  double rho;
- public :
-  voronoi_vertex(SPoint2);
-  voronoi_vertex();
-  ~voronoi_vertex();
-  SPoint2 get_point();
-  int get_index1();
-  int get_index2();
-  int get_index3();
-  SVector3 get_normal();
-  bool get_duplicate();
-  double get_rho();
-  void set_point(SPoint2);
-  void set_index1(int);
-  void set_index2(int);
-  void set_index3(int);
-  void set_normal(SVector3);
-  void set_duplicate(bool);
-  void set_rho(double);
-};
-
-class voronoi_element{
- private :
-  voronoi_vertex v1;
-  voronoi_vertex v2;
-  voronoi_vertex v3;
-  double drho_dx;
-  double drho_dy;
-  metric m;
- public :
-  voronoi_element(voronoi_vertex,voronoi_vertex,voronoi_vertex);
-  voronoi_element();
-  ~voronoi_element();
-  voronoi_vertex get_v1();
-  voronoi_vertex get_v2();
-  voronoi_vertex get_v3();
-  double get_rho(double,double);
-  double get_drho_dx();
-  double get_drho_dy();
-  metric get_metric();
-  void set_v1(voronoi_vertex);
-  void set_v2(voronoi_vertex);
-  void set_v3(voronoi_vertex);
-  void set_metric(metric);
-  void deriv_rho(int);
-  double compute_rho(double,int);
-};
-
-class voronoi_cell{
- private :
-  std::vector<voronoi_vertex> vertices;
- public :
-  voronoi_cell();
-  ~voronoi_cell();
-  int get_number_vertices();
-  voronoi_vertex get_vertex(int);
-  void add_vertex(voronoi_vertex);
-  void clear();
-};
-
-class segment{
- private :
-  int index1;
-  int index2;
-  int reference;
- public :
-  segment(int,int,int);
-  segment();
-  ~segment();
-  int get_index1();
-  int get_index2();
-  int get_reference();
-  void set_index1(int);
-  void set_index2(int);
-  void set_reference(int);
-  bool equal(int,int);
-};
-
-class segment_list{
- private :
-  std::vector<segment> segments;
- public :
-  segment_list();
-  ~segment_list();
-  int get_number_segments();
-  segment get_segment(int);
-  bool add_segment(int,int,int);
-  bool add_segment(segment);
-};
-
-#endif
-
-#endif
+#endif
\ No newline at end of file
diff --git a/Mesh/meshGRegion.cpp b/Mesh/meshGRegion.cpp
index a1f339fcb22db6671c6a93dee03e020c11e1b8dc..171dd9c7c49e93af8b740e4cc2f3de17eaaaf141 100644
--- a/Mesh/meshGRegion.cpp
+++ b/Mesh/meshGRegion.cpp
@@ -22,6 +22,8 @@
 #include "Context.h"
 #include "GFaceCompound.h"
 #include "meshGRegionMMG3D.h"
+#include "simple3D.h"
+#include "Levy3D.h"
 
 #if defined(HAVE_ANN)
 #include "ANN/ANN.h"
@@ -277,7 +279,7 @@ void buildTetgenStructure(GRegion *gr, tetgenio &in, std::vector<MVertex*> &numb
 
   in.mesh_dim = 3;
   in.firstnumber = 1;
-  in.numberofpoints = allBoundingVertices.size();
+  in.numberofpoints = allBoundingVertices.size() + Filler::get_nbr_new_vertices() + LpSmoother::get_nbr_interior_vertices();
   in.pointlist = new REAL[in.numberofpoints * 3];
   in.pointmarkerlist = NULL;
 
@@ -292,6 +294,24 @@ void buildTetgenStructure(GRegion *gr, tetgenio &in, std::vector<MVertex*> &numb
     ++itv;
   }
   
+  for(int i=0;i<Filler::get_nbr_new_vertices();i++){
+    MVertex* v;
+	v = Filler::get_new_vertex(i);
+	in.pointlist[(I - 1) * 3 + 0] = v->x();
+	in.pointlist[(I - 1) * 3 + 1] = v->y();
+	in.pointlist[(I - 1) * 3 + 2] = v->z();
+	I++;
+  }
+	
+  for(int i=0;i<LpSmoother::get_nbr_interior_vertices();i++){
+    MVertex* v;
+	v = LpSmoother::get_interior_vertex(i);
+	in.pointlist[(I - 1) * 3 + 0] = v->x();
+	in.pointlist[(I - 1) * 3 + 1] = v->y();
+	in.pointlist[(I - 1) * 3 + 2] = v->z();
+	I++;
+  }	
+	
   int nbFace = 0;
   std::list<GFace*> faces = gr->faces();
   std::list<GFace*>::iterator it = faces.begin();
@@ -578,7 +598,7 @@ void MeshDelaunayVolume(std::vector<GRegion*> &regions)
  else if(CTX::instance()->mesh.algo3d == ALGO_3D_MMG3D)
    refineMeshMMG(gr);
  else
-   insertVerticesInRegion(gr);
+   if(Filler::get_nbr_new_vertices()==0 && LpSmoother::get_nbr_interior_vertices()==0) insertVerticesInRegion(gr);
 #endif
 }
 
diff --git a/Numeric/DivideAndConquer.cpp b/Numeric/DivideAndConquer.cpp
index 7ba924e10aff64906035f5f71b9c3574640bd44f..0fb8ed5c9c5206cb17092a138ffd9a9a7a626db7 100644
--- a/Numeric/DivideAndConquer.cpp
+++ b/Numeric/DivideAndConquer.cpp
@@ -864,6 +864,7 @@ void DocRecord::setPoints(fullMatrix<double> *p)
   }
 } 
 
+
 void DocRecord::recur_tag_triangles(int iTriangle, std::set<int>& taggedTriangles,
                                     std::map<std::pair<void*, void*>,
                                     std::pair<int,int> > &edgesToTriangles)
@@ -930,8 +931,7 @@ std::set<int> DocRecord::tagInterior(double x, double y)
   return taggedTriangles;
 }
 
-void DocRecord::concave(double x,double y,GFace* gf)
-{
+void DocRecord::concave(double x,double y,GFace* gf){
   int i;
   int index1;
   int index2;
@@ -976,8 +976,7 @@ void DocRecord::concave(double x,double y,GFace* gf)
   }
 }
 
-bool DocRecord::contain(int index1,int index2,int index3)
-{
+bool DocRecord::contain(int index1,int index2,int index3){
   int i;
   void* dataA;
   void* dataB;
@@ -996,23 +995,20 @@ bool DocRecord::contain(int index1,int index2,int index3)
   return 0;
 }
 
-void DocRecord::add(int index1,int index2)
-{
+void DocRecord::add(int index1,int index2){
   void* data;
   data = points[index2].data;
   points[index1].vicinity.push_back(data);
 }
 
-void DocRecord::initialize()
-{
+void DocRecord::initialize(){
   int i;
   for(i = 0; i < numPoints; i++){
     points[i].flag = 0;
   }
 }
 
-bool DocRecord::remove_point(int index)
-{
+bool DocRecord::remove_point(int index){
   if(points[index].flag == 0){
     points[index].flag = 1;
     return 1;
@@ -1020,8 +1016,7 @@ bool DocRecord::remove_point(int index)
   else return 0;
 }
 
-void DocRecord::remove_all()
-{
+void DocRecord::remove_all(){
   int i;
   int index;
   int numPoints2;
@@ -1049,8 +1044,7 @@ void DocRecord::remove_all()
   numPoints = numPoints2;
 }
 
-void DocRecord::add_point(double x,double y,GFace*face)
-{
+void DocRecord::add_point(double x,double y,GFace*face){
   PointRecord point;
   point.where.h = x;
   point.where.v = y; 
@@ -1059,8 +1053,7 @@ void DocRecord::add_point(double x,double y,GFace*face)
   numPoints = numPoints + 1;
 }
 
-void DocRecord::build_edges()
-{
+void DocRecord::build_edges(){
   int i;
   int j;
   int num;
@@ -1079,13 +1072,11 @@ void DocRecord::build_edges()
   }
 }
 
-void DocRecord::clear_edges()
-{
+void DocRecord::clear_edges(){
   mesh_edges.clear();
 }
 
-bool DocRecord::delaunay_conformity(GFace* gf)
-{
+bool DocRecord::delaunay_conformity(GFace* gf){
   int i;
   bool flag;
   GEdge* edge;
@@ -1107,5 +1098,6 @@ bool DocRecord::delaunay_conformity(GFace* gf)
       if(!flag) return false;
     }
   }
-  return true;
+  return 1;
 }
+	
\ No newline at end of file
diff --git a/contrib/lbfgs/CMakeLists.txt b/contrib/lbfgs/CMakeLists.txt
index 5c8988732e6f4ce56151bf1f7d1657a5f009dd6c..8e9c4e89b7b496943dc104efcff97e057b50a374 100644
--- a/contrib/lbfgs/CMakeLists.txt
+++ b/contrib/lbfgs/CMakeLists.txt
@@ -4,6 +4,7 @@ set(SRC
   alglibmisc.cpp
   linalg.cpp
   optimization.cpp
+  solvers.cpp
 )
 
 file(GLOB_RECURSE HDR RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.h)
diff --git a/contrib/lbfgs/alglibinternal.cpp b/contrib/lbfgs/alglibinternal.cpp
index 4d0ddef2a50b7d96d3a3cddbbb8df2d84b5c0ee3..e8a508ef9a5a134c73065c09e7f70cc83542a427 100755
--- a/contrib/lbfgs/alglibinternal.cpp
+++ b/contrib/lbfgs/alglibinternal.cpp
@@ -46,6 +46,10 @@ namespace alglib
 /////////////////////////////////////////////////////////////////////////
 namespace alglib_impl
 {
+
+
+
+
 static void tsort_tagsortfastirec(/* Real    */ ae_vector* a,
      /* Integer */ ae_vector* b,
      /* Real    */ ae_vector* bufa,
@@ -83,8 +87,6 @@ static void tsort_tagsortfastrec(/* Real    */ ae_vector* a,
 
 
 
-
-
 static void hsschur_internalauxschur(ae_bool wantt,
      ae_bool wantz,
      ae_int_t n,
@@ -140,7 +142,6 @@ static double xblas_xfastpow(double r, ae_int_t n, ae_state *_state);
 
 static double linmin_ftol = 0.001;
 static double linmin_xtol = 100*ae_machineepsilon;
-static double linmin_gtol = 0.3;
 static ae_int_t linmin_maxfev = 20;
 static double linmin_stpmin = 1.0E-50;
 static double linmin_defstpmax = 1.0E+50;
@@ -161,6 +162,8 @@ static void linmin_mcstep(double* stx,
      ae_state *_state);
 
 
+
+
 static ae_int_t ftbase_ftbaseplanentrysize = 8;
 static ae_int_t ftbase_ftbasecffttask = 0;
 static ae_int_t ftbase_ftbaserfhttask = 1;
@@ -248,2060 +251,2616 @@ static void ftbase_reffht(/* Real    */ ae_vector* a,
 
 
 
-/*************************************************************************
-This function sorts array of real keys by ascending.
+ae_int_t getrdfserializationcode(ae_state *_state)
+{
+    ae_int_t result;
 
-Its results are:
-* sorted array A
-* permutation tables P1, P2
 
-Algorithm outputs permutation tables using two formats:
-* as usual permutation of [0..N-1]. If P1[i]=j, then sorted A[i]  contains
-  value which was moved there from J-th position.
-* as a sequence of pairwise permutations. Sorted A[] may  be  obtained  by
-  swaping A[i] and A[P2[i]] for all i from 0 to N-1.
-  
-INPUT PARAMETERS:
-    A       -   unsorted array
-    N       -   array size
+    result = 1;
+    return result;
+}
 
-OUPUT PARAMETERS:
-    A       -   sorted array
-    P1, P2  -   permutation tables, array[N]
-    
-NOTES:
-    this function assumes that A[] is finite; it doesn't checks that
-    condition. All other conditions (size of input arrays, etc.) are not
-    checked too.
 
-  -- ALGLIB --
-     Copyright 14.05.2008 by Bochkanov Sergey
-*************************************************************************/
-void tagsort(/* Real    */ ae_vector* a,
-     ae_int_t n,
-     /* Integer */ ae_vector* p1,
-     /* Integer */ ae_vector* p2,
-     ae_state *_state)
+ae_int_t getkdtreeserializationcode(ae_state *_state)
 {
-    ae_frame _frame_block;
-    ae_int_t i;
-    ae_vector pv;
-    ae_vector vp;
-    ae_vector bufa;
-    ae_vector bufb;
-    ae_int_t lv;
-    ae_int_t lp;
-    ae_int_t rv;
-    ae_int_t rp;
+    ae_int_t result;
 
-    ae_frame_make(_state, &_frame_block);
-    ae_vector_clear(p1);
-    ae_vector_clear(p2);
-    ae_vector_init(&pv, 0, DT_INT, _state, ae_true);
-    ae_vector_init(&vp, 0, DT_INT, _state, ae_true);
-    ae_vector_init(&bufa, 0, DT_REAL, _state, ae_true);
-    ae_vector_init(&bufb, 0, DT_INT, _state, ae_true);
 
-    
-    /*
-     * Special cases
-     */
-    if( n<=0 )
-    {
-        ae_frame_leave(_state);
-        return;
-    }
-    if( n==1 )
-    {
-        ae_vector_set_length(p1, 0+1, _state);
-        ae_vector_set_length(p2, 0+1, _state);
-        p1->ptr.p_int[0] = 0;
-        p2->ptr.p_int[0] = 0;
-        ae_frame_leave(_state);
-        return;
-    }
-    
-    /*
-     * General case, N>1: prepare permutations table P1
-     */
-    ae_vector_set_length(p1, n-1+1, _state);
-    for(i=0; i<=n-1; i++)
-    {
-        p1->ptr.p_int[i] = i;
-    }
-    
-    /*
-     * General case, N>1: sort, update P1
-     */
-    ae_vector_set_length(&bufa, n, _state);
-    ae_vector_set_length(&bufb, n, _state);
-    tagsortfasti(a, p1, &bufa, &bufb, n, _state);
-    
-    /*
-     * General case, N>1: fill permutations table P2
-     *
-     * To fill P2 we maintain two arrays:
-     * * PV, Position(Value). PV[i] contains position of I-th key at the moment
-     * * VP, Value(Position). VP[i] contains key which has position I at the moment
-     *
-     * At each step we making permutation of two items:
-     *   Left, which is given by position/value pair LP/LV
-     *   and Right, which is given by RP/RV
-     * and updating PV[] and VP[] correspondingly.
-     */
-    ae_vector_set_length(&pv, n-1+1, _state);
-    ae_vector_set_length(&vp, n-1+1, _state);
-    ae_vector_set_length(p2, n-1+1, _state);
-    for(i=0; i<=n-1; i++)
-    {
-        pv.ptr.p_int[i] = i;
-        vp.ptr.p_int[i] = i;
-    }
-    for(i=0; i<=n-1; i++)
-    {
-        
-        /*
-         * calculate LP, LV, RP, RV
-         */
-        lp = i;
-        lv = vp.ptr.p_int[lp];
-        rv = p1->ptr.p_int[i];
-        rp = pv.ptr.p_int[rv];
-        
-        /*
-         * Fill P2
-         */
-        p2->ptr.p_int[i] = rp;
-        
-        /*
-         * update PV and VP
-         */
-        vp.ptr.p_int[lp] = rv;
-        vp.ptr.p_int[rp] = lv;
-        pv.ptr.p_int[lv] = rp;
-        pv.ptr.p_int[rv] = lp;
-    }
-    ae_frame_leave(_state);
+    result = 2;
+    return result;
 }
 
 
-/*************************************************************************
-Same as TagSort, but optimized for real keys and integer labels.
+ae_int_t getmlpserializationcode(ae_state *_state)
+{
+    ae_int_t result;
 
-A is sorted, and same permutations are applied to B.
 
-NOTES:
-1.  this function assumes that A[] is finite; it doesn't checks that
-    condition. All other conditions (size of input arrays, etc.) are not
-    checked too.
-2.  this function uses two buffers, BufA and BufB, each is N elements large.
-    They may be preallocated (which will save some time) or not, in which
-    case function will automatically allocate memory.
+    result = 3;
+    return result;
+}
+
+
+
+
+/*************************************************************************
+This  function  generates  1-dimensional  general  interpolation task with
+moderate Lipshitz constant (close to 1.0)
+
+If N=1 then suborutine generates only one point at the middle of [A,B]
 
   -- ALGLIB --
-     Copyright 11.12.2008 by Bochkanov Sergey
+     Copyright 02.12.2009 by Bochkanov Sergey
 *************************************************************************/
-void tagsortfasti(/* Real    */ ae_vector* a,
-     /* Integer */ ae_vector* b,
-     /* Real    */ ae_vector* bufa,
-     /* Integer */ ae_vector* bufb,
+void taskgenint1d(double a,
+     double b,
      ae_int_t n,
+     /* Real    */ ae_vector* x,
+     /* Real    */ ae_vector* y,
      ae_state *_state)
 {
     ae_int_t i;
-    ae_int_t j;
-    ae_bool isascending;
-    ae_bool isdescending;
-    double tmpr;
-    ae_int_t tmpi;
+    double h;
 
+    ae_vector_clear(x);
+    ae_vector_clear(y);
 
-    
-    /*
-     * Special case
-     */
-    if( n<=1 )
-    {
-        return;
-    }
-    
-    /*
-     * Test for already sorted set
-     */
-    isascending = ae_true;
-    isdescending = ae_true;
-    for(i=1; i<=n-1; i++)
-    {
-        isascending = isascending&&a->ptr.p_double[i]>=a->ptr.p_double[i-1];
-        isdescending = isdescending&&a->ptr.p_double[i]<=a->ptr.p_double[i-1];
-    }
-    if( isascending )
-    {
-        return;
-    }
-    if( isdescending )
+    ae_assert(n>=1, "TaskGenInterpolationEqdist1D: N<1!", _state);
+    ae_vector_set_length(x, n, _state);
+    ae_vector_set_length(y, n, _state);
+    if( n>1 )
     {
-        for(i=0; i<=n-1; i++)
+        x->ptr.p_double[0] = a;
+        y->ptr.p_double[0] = 2*ae_randomreal(_state)-1;
+        h = (b-a)/(n-1);
+        for(i=1; i<=n-1; i++)
         {
-            j = n-1-i;
-            if( j<=i )
+            if( i!=n-1 )
             {
-                break;
+                x->ptr.p_double[i] = a+(i+0.2*(2*ae_randomreal(_state)-1))*h;
             }
-            tmpr = a->ptr.p_double[i];
-            a->ptr.p_double[i] = a->ptr.p_double[j];
-            a->ptr.p_double[j] = tmpr;
-            tmpi = b->ptr.p_int[i];
-            b->ptr.p_int[i] = b->ptr.p_int[j];
-            b->ptr.p_int[j] = tmpi;
+            else
+            {
+                x->ptr.p_double[i] = b;
+            }
+            y->ptr.p_double[i] = y->ptr.p_double[i-1]+(2*ae_randomreal(_state)-1)*(x->ptr.p_double[i]-x->ptr.p_double[i-1]);
         }
-        return;
-    }
-    
-    /*
-     * General case
-     */
-    if( bufa->cnt<n )
-    {
-        ae_vector_set_length(bufa, n, _state);
     }
-    if( bufb->cnt<n )
+    else
     {
-        ae_vector_set_length(bufb, n, _state);
+        x->ptr.p_double[0] = 0.5*(a+b);
+        y->ptr.p_double[0] = 2*ae_randomreal(_state)-1;
     }
-    tsort_tagsortfastirec(a, b, bufa, bufb, 0, n-1, _state);
 }
 
 
 /*************************************************************************
-Same as TagSort, but optimized for real keys and real labels.
-
-A is sorted, and same permutations are applied to B.
+This function generates  1-dimensional equidistant interpolation task with
+moderate Lipshitz constant (close to 1.0)
 
-NOTES:
-1.  this function assumes that A[] is finite; it doesn't checks that
-    condition. All other conditions (size of input arrays, etc.) are not
-    checked too.
-2.  this function uses two buffers, BufA and BufB, each is N elements large.
-    They may be preallocated (which will save some time) or not, in which
-    case function will automatically allocate memory.
+If N=1 then suborutine generates only one point at the middle of [A,B]
 
   -- ALGLIB --
-     Copyright 11.12.2008 by Bochkanov Sergey
+     Copyright 02.12.2009 by Bochkanov Sergey
 *************************************************************************/
-void tagsortfastr(/* Real    */ ae_vector* a,
-     /* Real    */ ae_vector* b,
-     /* Real    */ ae_vector* bufa,
-     /* Real    */ ae_vector* bufb,
+void taskgenint1dequidist(double a,
+     double b,
      ae_int_t n,
+     /* Real    */ ae_vector* x,
+     /* Real    */ ae_vector* y,
      ae_state *_state)
 {
     ae_int_t i;
-    ae_int_t j;
-    ae_bool isascending;
-    ae_bool isdescending;
-    double tmpr;
+    double h;
 
+    ae_vector_clear(x);
+    ae_vector_clear(y);
 
-    
-    /*
-     * Special case
-     */
-    if( n<=1 )
-    {
-        return;
-    }
-    
-    /*
-     * Test for already sorted set
-     */
-    isascending = ae_true;
-    isdescending = ae_true;
-    for(i=1; i<=n-1; i++)
-    {
-        isascending = isascending&&a->ptr.p_double[i]>=a->ptr.p_double[i-1];
-        isdescending = isdescending&&a->ptr.p_double[i]<=a->ptr.p_double[i-1];
-    }
-    if( isascending )
-    {
-        return;
-    }
-    if( isdescending )
+    ae_assert(n>=1, "TaskGenInterpolationEqdist1D: N<1!", _state);
+    ae_vector_set_length(x, n, _state);
+    ae_vector_set_length(y, n, _state);
+    if( n>1 )
     {
-        for(i=0; i<=n-1; i++)
+        x->ptr.p_double[0] = a;
+        y->ptr.p_double[0] = 2*ae_randomreal(_state)-1;
+        h = (b-a)/(n-1);
+        for(i=1; i<=n-1; i++)
         {
-            j = n-1-i;
-            if( j<=i )
-            {
-                break;
-            }
-            tmpr = a->ptr.p_double[i];
-            a->ptr.p_double[i] = a->ptr.p_double[j];
-            a->ptr.p_double[j] = tmpr;
-            tmpr = b->ptr.p_double[i];
-            b->ptr.p_double[i] = b->ptr.p_double[j];
-            b->ptr.p_double[j] = tmpr;
+            x->ptr.p_double[i] = a+i*h;
+            y->ptr.p_double[i] = y->ptr.p_double[i-1]+(2*ae_randomreal(_state)-1)*h;
         }
-        return;
-    }
-    
-    /*
-     * General case
-     */
-    if( bufa->cnt<n )
-    {
-        ae_vector_set_length(bufa, n, _state);
     }
-    if( bufb->cnt<n )
+    else
     {
-        ae_vector_set_length(bufb, n, _state);
+        x->ptr.p_double[0] = 0.5*(a+b);
+        y->ptr.p_double[0] = 2*ae_randomreal(_state)-1;
     }
-    tsort_tagsortfastrrec(a, b, bufa, bufb, 0, n-1, _state);
 }
 
 
 /*************************************************************************
-Same as TagSort, but optimized for real keys without labels.
-
-A is sorted, and that's all.
+This function generates  1-dimensional Chebyshev-1 interpolation task with
+moderate Lipshitz constant (close to 1.0)
 
-NOTES:
-1.  this function assumes that A[] is finite; it doesn't checks that
-    condition. All other conditions (size of input arrays, etc.) are not
-    checked too.
-2.  this function uses buffer, BufA, which is N elements large. It may be
-    preallocated (which will save some time) or not, in which case
-    function will automatically allocate memory.
+If N=1 then suborutine generates only one point at the middle of [A,B]
 
   -- ALGLIB --
-     Copyright 11.12.2008 by Bochkanov Sergey
+     Copyright 02.12.2009 by Bochkanov Sergey
 *************************************************************************/
-void tagsortfast(/* Real    */ ae_vector* a,
-     /* Real    */ ae_vector* bufa,
+void taskgenint1dcheb1(double a,
+     double b,
      ae_int_t n,
+     /* Real    */ ae_vector* x,
+     /* Real    */ ae_vector* y,
      ae_state *_state)
 {
     ae_int_t i;
-    ae_int_t j;
-    ae_bool isascending;
-    ae_bool isdescending;
-    double tmpr;
 
+    ae_vector_clear(x);
+    ae_vector_clear(y);
 
-    
-    /*
-     * Special case
-     */
-    if( n<=1 )
-    {
-        return;
-    }
-    
-    /*
-     * Test for already sorted set
-     */
-    isascending = ae_true;
-    isdescending = ae_true;
-    for(i=1; i<=n-1; i++)
-    {
-        isascending = isascending&&a->ptr.p_double[i]>=a->ptr.p_double[i-1];
-        isdescending = isdescending&&a->ptr.p_double[i]<=a->ptr.p_double[i-1];
-    }
-    if( isascending )
-    {
-        return;
-    }
-    if( isdescending )
+    ae_assert(n>=1, "TaskGenInterpolation1DCheb1: N<1!", _state);
+    ae_vector_set_length(x, n, _state);
+    ae_vector_set_length(y, n, _state);
+    if( n>1 )
     {
         for(i=0; i<=n-1; i++)
         {
-            j = n-1-i;
-            if( j<=i )
+            x->ptr.p_double[i] = 0.5*(b+a)+0.5*(b-a)*ae_cos(ae_pi*(2*i+1)/(2*n), _state);
+            if( i==0 )
             {
-                break;
+                y->ptr.p_double[i] = 2*ae_randomreal(_state)-1;
+            }
+            else
+            {
+                y->ptr.p_double[i] = y->ptr.p_double[i-1]+(2*ae_randomreal(_state)-1)*(x->ptr.p_double[i]-x->ptr.p_double[i-1]);
             }
-            tmpr = a->ptr.p_double[i];
-            a->ptr.p_double[i] = a->ptr.p_double[j];
-            a->ptr.p_double[j] = tmpr;
         }
-        return;
     }
-    
-    /*
-     * General case
-     */
-    if( bufa->cnt<n )
+    else
     {
-        ae_vector_set_length(bufa, n, _state);
+        x->ptr.p_double[0] = 0.5*(a+b);
+        y->ptr.p_double[0] = 2*ae_randomreal(_state)-1;
     }
-    tsort_tagsortfastrec(a, bufa, 0, n-1, _state);
 }
 
 
 /*************************************************************************
-Heap operations: adds element to the heap
+This function generates  1-dimensional Chebyshev-2 interpolation task with
+moderate Lipshitz constant (close to 1.0)
 
-PARAMETERS:
-    A       -   heap itself, must be at least array[0..N]
-    B       -   array of integer tags, which are updated according to
-                permutations in the heap
-    N       -   size of the heap (without new element).
-                updated on output
-    VA      -   value of the element being added
-    VB      -   value of the tag
+If N=1 then suborutine generates only one point at the middle of [A,B]
 
   -- ALGLIB --
-     Copyright 28.02.2010 by Bochkanov Sergey
+     Copyright 02.12.2009 by Bochkanov Sergey
 *************************************************************************/
-void tagheappushi(/* Real    */ ae_vector* a,
-     /* Integer */ ae_vector* b,
-     ae_int_t* n,
-     double va,
-     ae_int_t vb,
+void taskgenint1dcheb2(double a,
+     double b,
+     ae_int_t n,
+     /* Real    */ ae_vector* x,
+     /* Real    */ ae_vector* y,
      ae_state *_state)
 {
-    ae_int_t j;
-    ae_int_t k;
-    double v;
+    ae_int_t i;
 
+    ae_vector_clear(x);
+    ae_vector_clear(y);
 
-    if( *n<0 )
-    {
-        return;
-    }
-    
-    /*
-     * N=0 is a special case
-     */
-    if( *n==0 )
-    {
-        a->ptr.p_double[0] = va;
-        b->ptr.p_int[0] = vb;
-        *n = *n+1;
-        return;
-    }
-    
-    /*
-     * add current point to the heap
-     * (add to the bottom, then move up)
-     *
-     * we don't write point to the heap
-     * until its final position is determined
-     * (it allow us to reduce number of array access operations)
-     */
-    j = *n;
-    *n = *n+1;
-    while(j>0)
+    ae_assert(n>=1, "TaskGenInterpolation1DCheb2: N<1!", _state);
+    ae_vector_set_length(x, n, _state);
+    ae_vector_set_length(y, n, _state);
+    if( n>1 )
     {
-        k = (j-1)/2;
-        v = a->ptr.p_double[k];
-        if( ae_fp_less(v,va) )
-        {
-            
-            /*
-             * swap with higher element
-             */
-            a->ptr.p_double[j] = v;
-            b->ptr.p_int[j] = b->ptr.p_int[k];
-            j = k;
-        }
-        else
+        for(i=0; i<=n-1; i++)
         {
-            
-            /*
-             * element in its place. terminate.
-             */
-            break;
+            x->ptr.p_double[i] = 0.5*(b+a)+0.5*(b-a)*ae_cos(ae_pi*i/(n-1), _state);
+            if( i==0 )
+            {
+                y->ptr.p_double[i] = 2*ae_randomreal(_state)-1;
+            }
+            else
+            {
+                y->ptr.p_double[i] = y->ptr.p_double[i-1]+(2*ae_randomreal(_state)-1)*(x->ptr.p_double[i]-x->ptr.p_double[i-1]);
+            }
         }
     }
-    a->ptr.p_double[j] = va;
-    b->ptr.p_int[j] = vb;
+    else
+    {
+        x->ptr.p_double[0] = 0.5*(a+b);
+        y->ptr.p_double[0] = 2*ae_randomreal(_state)-1;
+    }
 }
 
 
 /*************************************************************************
-Heap operations: replaces top element with new element
-(which is moved down)
+This function checks that all values from X[] are distinct. It does more
+than just usual floating point comparison:
+* first, it calculates max(X) and min(X)
+* second, it maps X[] from [min,max] to [1,2]
+* only at this stage actual comparison is done
 
-PARAMETERS:
-    A       -   heap itself, must be at least array[0..N-1]
-    B       -   array of integer tags, which are updated according to
-                permutations in the heap
-    N       -   size of the heap
-    VA      -   value of the element which replaces top element
-    VB      -   value of the tag
+The meaning of such check is to ensure that all values are "distinct enough"
+and will not cause interpolation subroutine to fail.
+
+NOTE:
+    X[] must be sorted by ascending (subroutine ASSERT's it)
 
   -- ALGLIB --
-     Copyright 28.02.2010 by Bochkanov Sergey
+     Copyright 02.12.2009 by Bochkanov Sergey
 *************************************************************************/
-void tagheapreplacetopi(/* Real    */ ae_vector* a,
-     /* Integer */ ae_vector* b,
+ae_bool aredistinct(/* Real    */ ae_vector* x,
      ae_int_t n,
-     double va,
-     ae_int_t vb,
      ae_state *_state)
 {
-    ae_int_t j;
-    ae_int_t k1;
-    ae_int_t k2;
-    double v;
-    double v1;
-    double v2;
+    double a;
+    double b;
+    ae_int_t i;
+    ae_bool nonsorted;
+    ae_bool result;
 
 
-    if( n<1 )
+    ae_assert(n>=1, "APSERVAreDistinct: internal error (N<1)", _state);
+    if( n==1 )
     {
-        return;
+        
+        /*
+         * everything is alright, it is up to caller to decide whether it
+         * can interpolate something with just one point
+         */
+        result = ae_true;
+        return result;
     }
-    
-    /*
-     * N=1 is a special case
-     */
-    if( n==1 )
+    a = x->ptr.p_double[0];
+    b = x->ptr.p_double[0];
+    nonsorted = ae_false;
+    for(i=1; i<=n-1; i++)
     {
-        a->ptr.p_double[0] = va;
-        b->ptr.p_int[0] = vb;
-        return;
+        a = ae_minreal(a, x->ptr.p_double[i], _state);
+        b = ae_maxreal(b, x->ptr.p_double[i], _state);
+        nonsorted = nonsorted||ae_fp_greater_eq(x->ptr.p_double[i-1],x->ptr.p_double[i]);
     }
-    
-    /*
-     * move down through heap:
-     * * J  -   current element
-     * * K1 -   first child (always exists)
-     * * K2 -   second child (may not exists)
-     *
-     * we don't write point to the heap
-     * until its final position is determined
-     * (it allow us to reduce number of array access operations)
-     */
-    j = 0;
-    k1 = 1;
-    k2 = 2;
-    while(k1<n)
+    ae_assert(!nonsorted, "APSERVAreDistinct: internal error (not sorted)", _state);
+    for(i=1; i<=n-1; i++)
     {
-        if( k2>=n )
-        {
-            
-            /*
-             * only one child.
-             *
-             * swap and terminate (because this child
-             * have no siblings due to heap structure)
-             */
-            v = a->ptr.p_double[k1];
-            if( ae_fp_greater(v,va) )
-            {
-                a->ptr.p_double[j] = v;
-                b->ptr.p_int[j] = b->ptr.p_int[k1];
-                j = k1;
-            }
-            break;
-        }
-        else
+        if( ae_fp_eq((x->ptr.p_double[i]-a)/(b-a)+1,(x->ptr.p_double[i-1]-a)/(b-a)+1) )
         {
-            
-            /*
-             * two childs
-             */
-            v1 = a->ptr.p_double[k1];
-            v2 = a->ptr.p_double[k2];
-            if( ae_fp_greater(v1,v2) )
-            {
-                if( ae_fp_less(va,v1) )
-                {
-                    a->ptr.p_double[j] = v1;
-                    b->ptr.p_int[j] = b->ptr.p_int[k1];
-                    j = k1;
-                }
-                else
-                {
-                    break;
-                }
-            }
-            else
-            {
-                if( ae_fp_less(va,v2) )
-                {
-                    a->ptr.p_double[j] = v2;
-                    b->ptr.p_int[j] = b->ptr.p_int[k2];
-                    j = k2;
-                }
-                else
-                {
-                    break;
-                }
-            }
-            k1 = 2*j+1;
-            k2 = 2*j+2;
+            result = ae_false;
+            return result;
         }
     }
-    a->ptr.p_double[j] = va;
-    b->ptr.p_int[j] = vb;
+    result = ae_true;
+    return result;
 }
 
 
 /*************************************************************************
-Heap operations: pops top element from the heap
+If Length(X)<N, resizes X
 
-PARAMETERS:
-    A       -   heap itself, must be at least array[0..N-1]
-    B       -   array of integer tags, which are updated according to
-                permutations in the heap
-    N       -   size of the heap, N>=1
+  -- ALGLIB --
+     Copyright 20.03.2009 by Bochkanov Sergey
+*************************************************************************/
+void bvectorsetlengthatleast(/* Boolean */ ae_vector* x,
+     ae_int_t n,
+     ae_state *_state)
+{
+
+
+    if( x->cnt<n )
+    {
+        ae_vector_set_length(x, n, _state);
+    }
+}
 
-On output top element is moved to A[N-1], B[N-1], heap is reordered, N is
-decreased by 1.
+
+/*************************************************************************
+If Length(X)<N, resizes X
 
   -- ALGLIB --
-     Copyright 28.02.2010 by Bochkanov Sergey
+     Copyright 20.03.2009 by Bochkanov Sergey
 *************************************************************************/
-void tagheappopi(/* Real    */ ae_vector* a,
-     /* Integer */ ae_vector* b,
-     ae_int_t* n,
+void ivectorsetlengthatleast(/* Integer */ ae_vector* x,
+     ae_int_t n,
      ae_state *_state)
 {
-    double va;
-    ae_int_t vb;
 
 
-    if( *n<1 )
+    if( x->cnt<n )
     {
-        return;
+        ae_vector_set_length(x, n, _state);
     }
-    
-    /*
-     * N=1 is a special case
-     */
-    if( *n==1 )
+}
+
+
+/*************************************************************************
+If Length(X)<N, resizes X
+
+  -- ALGLIB --
+     Copyright 20.03.2009 by Bochkanov Sergey
+*************************************************************************/
+void rvectorsetlengthatleast(/* Real    */ ae_vector* x,
+     ae_int_t n,
+     ae_state *_state)
+{
+
+
+    if( x->cnt<n )
     {
-        *n = 0;
-        return;
+        ae_vector_set_length(x, n, _state);
     }
-    
-    /*
-     * swap top element and last element,
-     * then reorder heap
-     */
-    va = a->ptr.p_double[*n-1];
-    vb = b->ptr.p_int[*n-1];
-    a->ptr.p_double[*n-1] = a->ptr.p_double[0];
-    b->ptr.p_int[*n-1] = b->ptr.p_int[0];
-    *n = *n-1;
-    tagheapreplacetopi(a, b, *n, va, vb, _state);
 }
 
 
 /*************************************************************************
-Internal TagSortFastI: sorts A[I1...I2] (both bounds are included),
-applies same permutations to B.
+If Cols(X)<N or Rows(X)<M, resizes X
 
   -- ALGLIB --
-     Copyright 06.09.2010 by Bochkanov Sergey
+     Copyright 20.03.2009 by Bochkanov Sergey
 *************************************************************************/
-static void tsort_tagsortfastirec(/* Real    */ ae_vector* a,
-     /* Integer */ ae_vector* b,
-     /* Real    */ ae_vector* bufa,
-     /* Integer */ ae_vector* bufb,
-     ae_int_t i1,
-     ae_int_t i2,
+void rmatrixsetlengthatleast(/* Real    */ ae_matrix* x,
+     ae_int_t m,
+     ae_int_t n,
      ae_state *_state)
 {
-    ae_int_t i;
-    ae_int_t j;
-    ae_int_t k;
-    ae_int_t cntless;
-    ae_int_t cnteq;
-    ae_int_t cntgreater;
-    double tmpr;
-    ae_int_t tmpi;
-    double v0;
-    double v1;
-    double v2;
-    double vp;
 
 
-    
-    /*
-     * Fast exit
-     */
-    if( i2<=i1 )
+    if( x->rows<m||x->cols<n )
     {
-        return;
+        ae_matrix_set_length(x, m, n, _state);
     }
-    
-    /*
-     * Non-recursive sort for small arrays
-     */
-    if( i2-i1<=16 )
+}
+
+
+/*************************************************************************
+Resizes X and:
+* preserves old contents of X
+* fills new elements by zeros
+
+  -- ALGLIB --
+     Copyright 20.03.2009 by Bochkanov Sergey
+*************************************************************************/
+void rmatrixresize(/* Real    */ ae_matrix* x,
+     ae_int_t m,
+     ae_int_t n,
+     ae_state *_state)
+{
+    ae_frame _frame_block;
+    ae_matrix oldx;
+    ae_int_t i;
+    ae_int_t j;
+    ae_int_t m2;
+    ae_int_t n2;
+
+    ae_frame_make(_state, &_frame_block);
+    ae_matrix_init(&oldx, 0, 0, DT_REAL, _state, ae_true);
+
+    m2 = x->rows;
+    n2 = x->cols;
+    ae_swap_matrices(x, &oldx);
+    ae_matrix_set_length(x, m, n, _state);
+    for(i=0; i<=m-1; i++)
     {
-        for(j=i1+1; j<=i2; j++)
+        for(j=0; j<=n-1; j++)
         {
-            
-            /*
-             * Search elements [I1..J-1] for place to insert Jth element.
-             *
-             * This code stops immediately if we can leave A[J] at J-th position
-             * (all elements have same value of A[J] larger than any of them)
-             */
-            tmpr = a->ptr.p_double[j];
-            tmpi = j;
-            for(k=j-1; k>=i1; k--)
+            if( i<m2&&j<n2 )
             {
-                if( a->ptr.p_double[k]<=tmpr )
-                {
-                    break;
-                }
-                tmpi = k;
+                x->ptr.pp_double[i][j] = oldx.ptr.pp_double[i][j];
             }
-            k = tmpi;
-            
-            /*
-             * Insert Jth element into Kth position
-             */
-            if( k!=j )
+            else
             {
-                tmpr = a->ptr.p_double[j];
-                tmpi = b->ptr.p_int[j];
-                for(i=j-1; i>=k; i--)
-                {
-                    a->ptr.p_double[i+1] = a->ptr.p_double[i];
-                    b->ptr.p_int[i+1] = b->ptr.p_int[i];
-                }
-                a->ptr.p_double[k] = tmpr;
-                b->ptr.p_int[k] = tmpi;
+                x->ptr.pp_double[i][j] = 0.0;
             }
         }
-        return;
-    }
-    
-    /*
-     * Quicksort: choose pivot
-     * Here we assume that I2-I1>=2
-     */
-    v0 = a->ptr.p_double[i1];
-    v1 = a->ptr.p_double[i1+(i2-i1)/2];
-    v2 = a->ptr.p_double[i2];
-    if( v0>v1 )
-    {
-        tmpr = v1;
-        v1 = v0;
-        v0 = tmpr;
     }
-    if( v1>v2 )
+    ae_frame_leave(_state);
+}
+
+
+/*************************************************************************
+This function checks that all values from X[] are finite
+
+  -- ALGLIB --
+     Copyright 18.06.2010 by Bochkanov Sergey
+*************************************************************************/
+ae_bool isfinitevector(/* Real    */ ae_vector* x,
+     ae_int_t n,
+     ae_state *_state)
+{
+    ae_int_t i;
+    ae_bool result;
+
+
+    ae_assert(n>=0, "APSERVIsFiniteVector: internal error (N<0)", _state);
+    for(i=0; i<=n-1; i++)
     {
-        tmpr = v2;
-        v2 = v1;
-        v1 = tmpr;
+        if( !ae_isfinite(x->ptr.p_double[i], _state) )
+        {
+            result = ae_false;
+            return result;
+        }
     }
-    if( v0>v1 )
+    result = ae_true;
+    return result;
+}
+
+
+/*************************************************************************
+This function checks that all values from X[] are finite
+
+  -- ALGLIB --
+     Copyright 18.06.2010 by Bochkanov Sergey
+*************************************************************************/
+ae_bool isfinitecvector(/* Complex */ ae_vector* z,
+     ae_int_t n,
+     ae_state *_state)
+{
+    ae_int_t i;
+    ae_bool result;
+
+
+    ae_assert(n>=0, "APSERVIsFiniteCVector: internal error (N<0)", _state);
+    for(i=0; i<=n-1; i++)
     {
-        tmpr = v1;
-        v1 = v0;
-        v0 = tmpr;
+        if( !ae_isfinite(z->ptr.p_complex[i].x, _state)||!ae_isfinite(z->ptr.p_complex[i].y, _state) )
+        {
+            result = ae_false;
+            return result;
+        }
     }
-    vp = v1;
-    
-    /*
-     * now pass through A/B and:
-     * * move elements that are LESS than VP to the left of A/B
-     * * move elements that are EQUAL to VP to the right of BufA/BufB (in the reverse order)
-     * * move elements that are GREATER than VP to the left of BufA/BufB (in the normal order
-     * * move elements from the tail of BufA/BufB to the middle of A/B (restoring normal order)
-     * * move elements from the left of BufA/BufB to the end of A/B
-     */
-    cntless = 0;
-    cnteq = 0;
-    cntgreater = 0;
-    for(i=i1; i<=i2; i++)
+    result = ae_true;
+    return result;
+}
+
+
+/*************************************************************************
+This function checks that all values from X[0..M-1,0..N-1] are finite
+
+  -- ALGLIB --
+     Copyright 18.06.2010 by Bochkanov Sergey
+*************************************************************************/
+ae_bool apservisfinitematrix(/* Real    */ ae_matrix* x,
+     ae_int_t m,
+     ae_int_t n,
+     ae_state *_state)
+{
+    ae_int_t i;
+    ae_int_t j;
+    ae_bool result;
+
+
+    ae_assert(n>=0, "APSERVIsFiniteMatrix: internal error (N<0)", _state);
+    ae_assert(m>=0, "APSERVIsFiniteMatrix: internal error (M<0)", _state);
+    for(i=0; i<=m-1; i++)
     {
-        v0 = a->ptr.p_double[i];
-        if( v0<vp )
+        for(j=0; j<=n-1; j++)
         {
-            
-            /*
-             * LESS
-             */
-            k = i1+cntless;
-            if( i!=k )
+            if( !ae_isfinite(x->ptr.pp_double[i][j], _state) )
             {
-                a->ptr.p_double[k] = v0;
-                b->ptr.p_int[k] = b->ptr.p_int[i];
+                result = ae_false;
+                return result;
             }
-            cntless = cntless+1;
-            continue;
-        }
-        if( v0==vp )
-        {
-            
-            /*
-             * EQUAL
-             */
-            k = i2-cnteq;
-            bufa->ptr.p_double[k] = v0;
-            bufb->ptr.p_int[k] = b->ptr.p_int[i];
-            cnteq = cnteq+1;
-            continue;
         }
-        
-        /*
-         * GREATER
-         */
-        k = i1+cntgreater;
-        bufa->ptr.p_double[k] = v0;
-        bufb->ptr.p_int[k] = b->ptr.p_int[i];
-        cntgreater = cntgreater+1;
-    }
-    for(i=0; i<=cnteq-1; i++)
-    {
-        j = i1+cntless+cnteq-1-i;
-        k = i2+i-(cnteq-1);
-        a->ptr.p_double[j] = bufa->ptr.p_double[k];
-        b->ptr.p_int[j] = bufb->ptr.p_int[k];
-    }
-    for(i=0; i<=cntgreater-1; i++)
-    {
-        j = i1+cntless+cnteq+i;
-        k = i1+i;
-        a->ptr.p_double[j] = bufa->ptr.p_double[k];
-        b->ptr.p_int[j] = bufb->ptr.p_int[k];
     }
-    
-    /*
-     * Sort left and right parts of the array (ignoring middle part)
-     */
-    tsort_tagsortfastirec(a, b, bufa, bufb, i1, i1+cntless-1, _state);
-    tsort_tagsortfastirec(a, b, bufa, bufb, i1+cntless+cnteq, i2, _state);
+    result = ae_true;
+    return result;
 }
 
 
 /*************************************************************************
-Internal TagSortFastR: sorts A[I1...I2] (both bounds are included),
-applies same permutations to B.
+This function checks that all values from X[0..M-1,0..N-1] are finite
 
   -- ALGLIB --
-     Copyright 06.09.2010 by Bochkanov Sergey
+     Copyright 18.06.2010 by Bochkanov Sergey
 *************************************************************************/
-static void tsort_tagsortfastrrec(/* Real    */ ae_vector* a,
-     /* Real    */ ae_vector* b,
-     /* Real    */ ae_vector* bufa,
-     /* Real    */ ae_vector* bufb,
-     ae_int_t i1,
-     ae_int_t i2,
+ae_bool apservisfinitecmatrix(/* Complex */ ae_matrix* x,
+     ae_int_t m,
+     ae_int_t n,
      ae_state *_state)
 {
     ae_int_t i;
     ae_int_t j;
-    ae_int_t k;
-    double tmpr;
-    double tmpr2;
-    ae_int_t tmpi;
-    ae_int_t cntless;
-    ae_int_t cnteq;
-    ae_int_t cntgreater;
-    double v0;
-    double v1;
-    double v2;
-    double vp;
+    ae_bool result;
 
 
-    
-    /*
-     * Fast exit
-     */
-    if( i2<=i1 )
-    {
-        return;
-    }
-    
-    /*
-     * Non-recursive sort for small arrays
-     */
-    if( i2-i1<=16 )
+    ae_assert(n>=0, "APSERVIsFiniteCMatrix: internal error (N<0)", _state);
+    ae_assert(m>=0, "APSERVIsFiniteCMatrix: internal error (M<0)", _state);
+    for(i=0; i<=m-1; i++)
     {
-        for(j=i1+1; j<=i2; j++)
+        for(j=0; j<=n-1; j++)
         {
-            
-            /*
-             * Search elements [I1..J-1] for place to insert Jth element.
-             *
-             * This code stops immediatly if we can leave A[J] at J-th position
-             * (all elements have same value of A[J] larger than any of them)
-             */
-            tmpr = a->ptr.p_double[j];
-            tmpi = j;
-            for(k=j-1; k>=i1; k--)
+            if( !ae_isfinite(x->ptr.pp_complex[i][j].x, _state)||!ae_isfinite(x->ptr.pp_complex[i][j].y, _state) )
             {
-                if( a->ptr.p_double[k]<=tmpr )
-                {
-                    break;
-                }
-                tmpi = k;
+                result = ae_false;
+                return result;
             }
-            k = tmpi;
-            
-            /*
-             * Insert Jth element into Kth position
-             */
-            if( k!=j )
+        }
+    }
+    result = ae_true;
+    return result;
+}
+
+
+/*************************************************************************
+This function checks that all values from upper/lower triangle of
+X[0..N-1,0..N-1] are finite
+
+  -- ALGLIB --
+     Copyright 18.06.2010 by Bochkanov Sergey
+*************************************************************************/
+ae_bool isfinitertrmatrix(/* Real    */ ae_matrix* x,
+     ae_int_t n,
+     ae_bool isupper,
+     ae_state *_state)
+{
+    ae_int_t i;
+    ae_int_t j1;
+    ae_int_t j2;
+    ae_int_t j;
+    ae_bool result;
+
+
+    ae_assert(n>=0, "APSERVIsFiniteRTRMatrix: internal error (N<0)", _state);
+    for(i=0; i<=n-1; i++)
+    {
+        if( isupper )
+        {
+            j1 = i;
+            j2 = n-1;
+        }
+        else
+        {
+            j1 = 0;
+            j2 = i;
+        }
+        for(j=j1; j<=j2; j++)
+        {
+            if( !ae_isfinite(x->ptr.pp_double[i][j], _state) )
+            {
+                result = ae_false;
+                return result;
+            }
+        }
+    }
+    result = ae_true;
+    return result;
+}
+
+
+/*************************************************************************
+This function checks that all values from upper/lower triangle of
+X[0..N-1,0..N-1] are finite
+
+  -- ALGLIB --
+     Copyright 18.06.2010 by Bochkanov Sergey
+*************************************************************************/
+ae_bool apservisfinitectrmatrix(/* Complex */ ae_matrix* x,
+     ae_int_t n,
+     ae_bool isupper,
+     ae_state *_state)
+{
+    ae_int_t i;
+    ae_int_t j1;
+    ae_int_t j2;
+    ae_int_t j;
+    ae_bool result;
+
+
+    ae_assert(n>=0, "APSERVIsFiniteCTRMatrix: internal error (N<0)", _state);
+    for(i=0; i<=n-1; i++)
+    {
+        if( isupper )
+        {
+            j1 = i;
+            j2 = n-1;
+        }
+        else
+        {
+            j1 = 0;
+            j2 = i;
+        }
+        for(j=j1; j<=j2; j++)
+        {
+            if( !ae_isfinite(x->ptr.pp_complex[i][j].x, _state)||!ae_isfinite(x->ptr.pp_complex[i][j].y, _state) )
+            {
+                result = ae_false;
+                return result;
+            }
+        }
+    }
+    result = ae_true;
+    return result;
+}
+
+
+/*************************************************************************
+This function checks that all values from X[0..M-1,0..N-1] are  finite  or
+NaN's.
+
+  -- ALGLIB --
+     Copyright 18.06.2010 by Bochkanov Sergey
+*************************************************************************/
+ae_bool apservisfiniteornanmatrix(/* Real    */ ae_matrix* x,
+     ae_int_t m,
+     ae_int_t n,
+     ae_state *_state)
+{
+    ae_int_t i;
+    ae_int_t j;
+    ae_bool result;
+
+
+    ae_assert(n>=0, "APSERVIsFiniteOrNaNMatrix: internal error (N<0)", _state);
+    ae_assert(m>=0, "APSERVIsFiniteOrNaNMatrix: internal error (M<0)", _state);
+    for(i=0; i<=m-1; i++)
+    {
+        for(j=0; j<=n-1; j++)
+        {
+            if( !(ae_isfinite(x->ptr.pp_double[i][j], _state)||ae_isnan(x->ptr.pp_double[i][j], _state)) )
+            {
+                result = ae_false;
+                return result;
+            }
+        }
+    }
+    result = ae_true;
+    return result;
+}
+
+
+/*************************************************************************
+Safe sqrt(x^2+y^2)
+
+  -- ALGLIB --
+     Copyright by Bochkanov Sergey
+*************************************************************************/
+double safepythag2(double x, double y, ae_state *_state)
+{
+    double w;
+    double xabs;
+    double yabs;
+    double z;
+    double result;
+
+
+    xabs = ae_fabs(x, _state);
+    yabs = ae_fabs(y, _state);
+    w = ae_maxreal(xabs, yabs, _state);
+    z = ae_minreal(xabs, yabs, _state);
+    if( ae_fp_eq(z,0) )
+    {
+        result = w;
+    }
+    else
+    {
+        result = w*ae_sqrt(1+ae_sqr(z/w, _state), _state);
+    }
+    return result;
+}
+
+
+/*************************************************************************
+Safe sqrt(x^2+y^2)
+
+  -- ALGLIB --
+     Copyright by Bochkanov Sergey
+*************************************************************************/
+double safepythag3(double x, double y, double z, ae_state *_state)
+{
+    double w;
+    double result;
+
+
+    w = ae_maxreal(ae_fabs(x, _state), ae_maxreal(ae_fabs(y, _state), ae_fabs(z, _state), _state), _state);
+    if( ae_fp_eq(w,0) )
+    {
+        result = 0;
+        return result;
+    }
+    x = x/w;
+    y = y/w;
+    z = z/w;
+    result = w*ae_sqrt(ae_sqr(x, _state)+ae_sqr(y, _state)+ae_sqr(z, _state), _state);
+    return result;
+}
+
+
+/*************************************************************************
+Safe division.
+
+This function attempts to calculate R=X/Y without overflow.
+
+It returns:
+* +1, if abs(X/Y)>=MaxRealNumber or undefined - overflow-like situation
+      (no overlfow is generated, R is either NAN, PosINF, NegINF)
+*  0, if MinRealNumber<abs(X/Y)<MaxRealNumber or X=0, Y<>0
+      (R contains result, may be zero)
+* -1, if 0<abs(X/Y)<MinRealNumber - underflow-like situation
+      (R contains zero; it corresponds to underflow)
+
+No overflow is generated in any case.
+
+  -- ALGLIB --
+     Copyright by Bochkanov Sergey
+*************************************************************************/
+ae_int_t saferdiv(double x, double y, double* r, ae_state *_state)
+{
+    ae_int_t result;
+
+    *r = 0;
+
+    
+    /*
+     * Two special cases:
+     * * Y=0
+     * * X=0 and Y<>0
+     */
+    if( ae_fp_eq(y,0) )
+    {
+        result = 1;
+        if( ae_fp_eq(x,0) )
+        {
+            *r = _state->v_nan;
+        }
+        if( ae_fp_greater(x,0) )
+        {
+            *r = _state->v_posinf;
+        }
+        if( ae_fp_less(x,0) )
+        {
+            *r = _state->v_neginf;
+        }
+        return result;
+    }
+    if( ae_fp_eq(x,0) )
+    {
+        *r = 0;
+        result = 0;
+        return result;
+    }
+    
+    /*
+     * make Y>0
+     */
+    if( ae_fp_less(y,0) )
+    {
+        x = -x;
+        y = -y;
+    }
+    
+    /*
+     *
+     */
+    if( ae_fp_greater_eq(y,1) )
+    {
+        *r = x/y;
+        if( ae_fp_less_eq(ae_fabs(*r, _state),ae_minrealnumber) )
+        {
+            result = -1;
+            *r = 0;
+        }
+        else
+        {
+            result = 0;
+        }
+    }
+    else
+    {
+        if( ae_fp_greater_eq(ae_fabs(x, _state),ae_maxrealnumber*y) )
+        {
+            if( ae_fp_greater(x,0) )
             {
-                tmpr = a->ptr.p_double[j];
-                tmpr2 = b->ptr.p_double[j];
-                for(i=j-1; i>=k; i--)
-                {
-                    a->ptr.p_double[i+1] = a->ptr.p_double[i];
-                    b->ptr.p_double[i+1] = b->ptr.p_double[i];
-                }
-                a->ptr.p_double[k] = tmpr;
-                b->ptr.p_double[k] = tmpr2;
+                *r = _state->v_posinf;
+            }
+            else
+            {
+                *r = _state->v_neginf;
             }
+            result = 1;
+        }
+        else
+        {
+            *r = x/y;
+            result = 0;
+        }
+    }
+    return result;
+}
+
+
+/*************************************************************************
+This function calculates "safe" min(X/Y,V) for positive finite X, Y, V.
+No overflow is generated in any case.
+
+  -- ALGLIB --
+     Copyright by Bochkanov Sergey
+*************************************************************************/
+double safeminposrv(double x, double y, double v, ae_state *_state)
+{
+    double r;
+    double result;
+
+
+    if( ae_fp_greater_eq(y,1) )
+    {
+        
+        /*
+         * Y>=1, we can safely divide by Y
+         */
+        r = x/y;
+        result = v;
+        if( ae_fp_greater(v,r) )
+        {
+            result = r;
+        }
+        else
+        {
+            result = v;
+        }
+    }
+    else
+    {
+        
+        /*
+         * Y<1, we can safely multiply by Y
+         */
+        if( ae_fp_less(x,v*y) )
+        {
+            result = x/y;
+        }
+        else
+        {
+            result = v;
         }
+    }
+    return result;
+}
+
+
+/*************************************************************************
+This function makes periodic mapping of X to [A,B].
+
+It accepts X, A, B (A>B). It returns T which lies in  [A,B] and integer K,
+such that X = T + K*(B-A).
+
+NOTES:
+* K is represented as real value, although actually it is integer
+* T is guaranteed to be in [A,B]
+* T replaces X
+
+  -- ALGLIB --
+     Copyright by Bochkanov Sergey
+*************************************************************************/
+void apperiodicmap(double* x,
+     double a,
+     double b,
+     double* k,
+     ae_state *_state)
+{
+
+    *k = 0;
+
+    ae_assert(ae_fp_less(a,b), "APPeriodicMap: internal error!", _state);
+    *k = ae_ifloor((*x-a)/(b-a), _state);
+    *x = *x-*k*(b-a);
+    while(ae_fp_less(*x,a))
+    {
+        *x = *x+(b-a);
+        *k = *k-1;
+    }
+    while(ae_fp_greater(*x,b))
+    {
+        *x = *x-(b-a);
+        *k = *k+1;
+    }
+    *x = ae_maxreal(*x, a, _state);
+    *x = ae_minreal(*x, b, _state);
+}
+
+
+/*************************************************************************
+'bounds' value: maps X to [B1,B2]
+
+  -- ALGLIB --
+     Copyright 20.03.2009 by Bochkanov Sergey
+*************************************************************************/
+double boundval(double x, double b1, double b2, ae_state *_state)
+{
+    double result;
+
+
+    if( ae_fp_less_eq(x,b1) )
+    {
+        result = b1;
+        return result;
+    }
+    if( ae_fp_greater_eq(x,b2) )
+    {
+        result = b2;
+        return result;
+    }
+    result = x;
+    return result;
+}
+
+
+/*************************************************************************
+Allocation of serializer: complex value
+*************************************************************************/
+void alloccomplex(ae_serializer* s, ae_complex v, ae_state *_state)
+{
+
+
+    ae_serializer_alloc_entry(s);
+    ae_serializer_alloc_entry(s);
+}
+
+
+/*************************************************************************
+Serialization: complex value
+*************************************************************************/
+void serializecomplex(ae_serializer* s, ae_complex v, ae_state *_state)
+{
+
+
+    ae_serializer_serialize_double(s, v.x, _state);
+    ae_serializer_serialize_double(s, v.y, _state);
+}
+
+
+/*************************************************************************
+Unserialization: complex value
+*************************************************************************/
+ae_complex unserializecomplex(ae_serializer* s, ae_state *_state)
+{
+    ae_complex result;
+
+
+    ae_serializer_unserialize_double(s, &result.x, _state);
+    ae_serializer_unserialize_double(s, &result.y, _state);
+    return result;
+}
+
+
+/*************************************************************************
+Allocation of serializer: real array
+*************************************************************************/
+void allocrealarray(ae_serializer* s,
+     /* Real    */ ae_vector* v,
+     ae_int_t n,
+     ae_state *_state)
+{
+    ae_int_t i;
+
+
+    if( n<0 )
+    {
+        n = v->cnt;
+    }
+    ae_serializer_alloc_entry(s);
+    for(i=0; i<=n-1; i++)
+    {
+        ae_serializer_alloc_entry(s);
+    }
+}
+
+
+/*************************************************************************
+Serialization: complex value
+*************************************************************************/
+void serializerealarray(ae_serializer* s,
+     /* Real    */ ae_vector* v,
+     ae_int_t n,
+     ae_state *_state)
+{
+    ae_int_t i;
+
+
+    if( n<0 )
+    {
+        n = v->cnt;
+    }
+    ae_serializer_serialize_int(s, n, _state);
+    for(i=0; i<=n-1; i++)
+    {
+        ae_serializer_serialize_double(s, v->ptr.p_double[i], _state);
+    }
+}
+
+
+/*************************************************************************
+Unserialization: complex value
+*************************************************************************/
+void unserializerealarray(ae_serializer* s,
+     /* Real    */ ae_vector* v,
+     ae_state *_state)
+{
+    ae_int_t n;
+    ae_int_t i;
+    double t;
+
+    ae_vector_clear(v);
+
+    ae_serializer_unserialize_int(s, &n, _state);
+    if( n==0 )
+    {
+        return;
+    }
+    ae_vector_set_length(v, n, _state);
+    for(i=0; i<=n-1; i++)
+    {
+        ae_serializer_unserialize_double(s, &t, _state);
+        v->ptr.p_double[i] = t;
+    }
+}
+
+
+/*************************************************************************
+Allocation of serializer: Integer array
+*************************************************************************/
+void allocintegerarray(ae_serializer* s,
+     /* Integer */ ae_vector* v,
+     ae_int_t n,
+     ae_state *_state)
+{
+    ae_int_t i;
+
+
+    if( n<0 )
+    {
+        n = v->cnt;
+    }
+    ae_serializer_alloc_entry(s);
+    for(i=0; i<=n-1; i++)
+    {
+        ae_serializer_alloc_entry(s);
+    }
+}
+
+
+/*************************************************************************
+Serialization: Integer array
+*************************************************************************/
+void serializeintegerarray(ae_serializer* s,
+     /* Integer */ ae_vector* v,
+     ae_int_t n,
+     ae_state *_state)
+{
+    ae_int_t i;
+
+
+    if( n<0 )
+    {
+        n = v->cnt;
+    }
+    ae_serializer_serialize_int(s, n, _state);
+    for(i=0; i<=n-1; i++)
+    {
+        ae_serializer_serialize_int(s, v->ptr.p_int[i], _state);
+    }
+}
+
+
+/*************************************************************************
+Unserialization: complex value
+*************************************************************************/
+void unserializeintegerarray(ae_serializer* s,
+     /* Integer */ ae_vector* v,
+     ae_state *_state)
+{
+    ae_int_t n;
+    ae_int_t i;
+    ae_int_t t;
+
+    ae_vector_clear(v);
+
+    ae_serializer_unserialize_int(s, &n, _state);
+    if( n==0 )
+    {
         return;
     }
-    
-    /*
-     * Quicksort: choose pivot
-     * Here we assume that I2-I1>=16
-     */
-    v0 = a->ptr.p_double[i1];
-    v1 = a->ptr.p_double[i1+(i2-i1)/2];
-    v2 = a->ptr.p_double[i2];
-    if( v0>v1 )
+    ae_vector_set_length(v, n, _state);
+    for(i=0; i<=n-1; i++)
     {
-        tmpr = v1;
-        v1 = v0;
-        v0 = tmpr;
+        ae_serializer_unserialize_int(s, &t, _state);
+        v->ptr.p_int[i] = t;
     }
-    if( v1>v2 )
+}
+
+
+/*************************************************************************
+Allocation of serializer: real matrix
+*************************************************************************/
+void allocrealmatrix(ae_serializer* s,
+     /* Real    */ ae_matrix* v,
+     ae_int_t n0,
+     ae_int_t n1,
+     ae_state *_state)
+{
+    ae_int_t i;
+    ae_int_t j;
+
+
+    if( n0<0 )
     {
-        tmpr = v2;
-        v2 = v1;
-        v1 = tmpr;
+        n0 = v->rows;
     }
-    if( v0>v1 )
+    if( n1<0 )
     {
-        tmpr = v1;
-        v1 = v0;
-        v0 = tmpr;
+        n1 = v->cols;
     }
-    vp = v1;
-    
-    /*
-     * now pass through A/B and:
-     * * move elements that are LESS than VP to the left of A/B
-     * * move elements that are EQUAL to VP to the right of BufA/BufB (in the reverse order)
-     * * move elements that are GREATER than VP to the left of BufA/BufB (in the normal order
-     * * move elements from the tail of BufA/BufB to the middle of A/B (restoring normal order)
-     * * move elements from the left of BufA/BufB to the end of A/B
-     */
-    cntless = 0;
-    cnteq = 0;
-    cntgreater = 0;
-    for(i=i1; i<=i2; i++)
+    ae_serializer_alloc_entry(s);
+    ae_serializer_alloc_entry(s);
+    for(i=0; i<=n0-1; i++)
     {
-        v0 = a->ptr.p_double[i];
-        if( v0<vp )
+        for(j=0; j<=n1-1; j++)
         {
-            
-            /*
-             * LESS
-             */
-            k = i1+cntless;
-            if( i!=k )
-            {
-                a->ptr.p_double[k] = v0;
-                b->ptr.p_double[k] = b->ptr.p_double[i];
-            }
-            cntless = cntless+1;
-            continue;
+            ae_serializer_alloc_entry(s);
         }
-        if( v0==vp )
+    }
+}
+
+
+/*************************************************************************
+Serialization: complex value
+*************************************************************************/
+void serializerealmatrix(ae_serializer* s,
+     /* Real    */ ae_matrix* v,
+     ae_int_t n0,
+     ae_int_t n1,
+     ae_state *_state)
+{
+    ae_int_t i;
+    ae_int_t j;
+
+
+    if( n0<0 )
+    {
+        n0 = v->rows;
+    }
+    if( n1<0 )
+    {
+        n1 = v->cols;
+    }
+    ae_serializer_serialize_int(s, n0, _state);
+    ae_serializer_serialize_int(s, n1, _state);
+    for(i=0; i<=n0-1; i++)
+    {
+        for(j=0; j<=n1-1; j++)
         {
-            
-            /*
-             * EQUAL
-             */
-            k = i2-cnteq;
-            bufa->ptr.p_double[k] = v0;
-            bufb->ptr.p_double[k] = b->ptr.p_double[i];
-            cnteq = cnteq+1;
-            continue;
+            ae_serializer_serialize_double(s, v->ptr.pp_double[i][j], _state);
         }
-        
-        /*
-         * GREATER
-         */
-        k = i1+cntgreater;
-        bufa->ptr.p_double[k] = v0;
-        bufb->ptr.p_double[k] = b->ptr.p_double[i];
-        cntgreater = cntgreater+1;
     }
-    for(i=0; i<=cnteq-1; i++)
+}
+
+
+/*************************************************************************
+Unserialization: complex value
+*************************************************************************/
+void unserializerealmatrix(ae_serializer* s,
+     /* Real    */ ae_matrix* v,
+     ae_state *_state)
+{
+    ae_int_t i;
+    ae_int_t j;
+    ae_int_t n0;
+    ae_int_t n1;
+    double t;
+
+    ae_matrix_clear(v);
+
+    ae_serializer_unserialize_int(s, &n0, _state);
+    ae_serializer_unserialize_int(s, &n1, _state);
+    if( n0==0||n1==0 )
     {
-        j = i1+cntless+cnteq-1-i;
-        k = i2+i-(cnteq-1);
-        a->ptr.p_double[j] = bufa->ptr.p_double[k];
-        b->ptr.p_double[j] = bufb->ptr.p_double[k];
+        return;
     }
-    for(i=0; i<=cntgreater-1; i++)
+    ae_matrix_set_length(v, n0, n1, _state);
+    for(i=0; i<=n0-1; i++)
     {
-        j = i1+cntless+cnteq+i;
-        k = i1+i;
-        a->ptr.p_double[j] = bufa->ptr.p_double[k];
-        b->ptr.p_double[j] = bufb->ptr.p_double[k];
+        for(j=0; j<=n1-1; j++)
+        {
+            ae_serializer_unserialize_double(s, &t, _state);
+            v->ptr.pp_double[i][j] = t;
+        }
+    }
+}
+
+
+/*************************************************************************
+Copy integer array
+*************************************************************************/
+void copyintegerarray(/* Integer */ ae_vector* src,
+     /* Integer */ ae_vector* dst,
+     ae_state *_state)
+{
+    ae_int_t i;
+
+    ae_vector_clear(dst);
+
+    if( src->cnt>0 )
+    {
+        ae_vector_set_length(dst, src->cnt, _state);
+        for(i=0; i<=src->cnt-1; i++)
+        {
+            dst->ptr.p_int[i] = src->ptr.p_int[i];
+        }
+    }
+}
+
+
+/*************************************************************************
+Copy real array
+*************************************************************************/
+void copyrealarray(/* Real    */ ae_vector* src,
+     /* Real    */ ae_vector* dst,
+     ae_state *_state)
+{
+    ae_int_t i;
+
+    ae_vector_clear(dst);
+
+    if( src->cnt>0 )
+    {
+        ae_vector_set_length(dst, src->cnt, _state);
+        for(i=0; i<=src->cnt-1; i++)
+        {
+            dst->ptr.p_double[i] = src->ptr.p_double[i];
+        }
+    }
+}
+
+
+/*************************************************************************
+Copy real matrix
+*************************************************************************/
+void copyrealmatrix(/* Real    */ ae_matrix* src,
+     /* Real    */ ae_matrix* dst,
+     ae_state *_state)
+{
+    ae_int_t i;
+    ae_int_t j;
+
+    ae_matrix_clear(dst);
+
+    if( src->rows>0&&src->cols>0 )
+    {
+        ae_matrix_set_length(dst, src->rows, src->cols, _state);
+        for(i=0; i<=src->rows-1; i++)
+        {
+            for(j=0; j<=src->cols-1; j++)
+            {
+                dst->ptr.pp_double[i][j] = src->ptr.pp_double[i][j];
+            }
+        }
+    }
+}
+
+
+/*************************************************************************
+This function searches integer array. Elements in this array are actually
+records, each NRec elements wide. Each record has unique header - NHeader
+integer values, which identify it. Records are lexicographically sorted by
+header.
+
+Records are identified by their index, not offset (offset = NRec*index).
+
+This function searches A (records with indices [I0,I1)) for a record with
+header B. It returns index of this record (not offset!), or -1 on failure.
+
+  -- ALGLIB --
+     Copyright 28.03.2011 by Bochkanov Sergey
+*************************************************************************/
+ae_int_t recsearch(/* Integer */ ae_vector* a,
+     ae_int_t nrec,
+     ae_int_t nheader,
+     ae_int_t i0,
+     ae_int_t i1,
+     /* Integer */ ae_vector* b,
+     ae_state *_state)
+{
+    ae_int_t mididx;
+    ae_int_t cflag;
+    ae_int_t k;
+    ae_int_t offs;
+    ae_int_t result;
+
+
+    result = -1;
+    for(;;)
+    {
+        if( i0>=i1 )
+        {
+            break;
+        }
+        mididx = (i0+i1)/2;
+        offs = nrec*mididx;
+        cflag = 0;
+        for(k=0; k<=nheader-1; k++)
+        {
+            if( a->ptr.p_int[offs+k]<b->ptr.p_int[k] )
+            {
+                cflag = -1;
+                break;
+            }
+            if( a->ptr.p_int[offs+k]>b->ptr.p_int[k] )
+            {
+                cflag = 1;
+                break;
+            }
+        }
+        if( cflag==0 )
+        {
+            result = mididx;
+            return result;
+        }
+        if( cflag<0 )
+        {
+            i0 = mididx+1;
+        }
+        else
+        {
+            i1 = mididx;
+        }
     }
+    return result;
+}
+
+
+ae_bool _apbuffers_init(apbuffers* p, ae_state *_state, ae_bool make_automatic)
+{
+    if( !ae_vector_init(&p->ia0, 0, DT_INT, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init(&p->ia1, 0, DT_INT, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init(&p->ia2, 0, DT_INT, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init(&p->ia3, 0, DT_INT, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init(&p->ra0, 0, DT_REAL, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init(&p->ra1, 0, DT_REAL, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init(&p->ra2, 0, DT_REAL, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init(&p->ra3, 0, DT_REAL, _state, make_automatic) )
+        return ae_false;
+    return ae_true;
+}
+
+
+ae_bool _apbuffers_init_copy(apbuffers* dst, apbuffers* src, ae_state *_state, ae_bool make_automatic)
+{
+    if( !ae_vector_init_copy(&dst->ia0, &src->ia0, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init_copy(&dst->ia1, &src->ia1, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init_copy(&dst->ia2, &src->ia2, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init_copy(&dst->ia3, &src->ia3, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init_copy(&dst->ra0, &src->ra0, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init_copy(&dst->ra1, &src->ra1, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init_copy(&dst->ra2, &src->ra2, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init_copy(&dst->ra3, &src->ra3, _state, make_automatic) )
+        return ae_false;
+    return ae_true;
+}
+
+
+void _apbuffers_clear(apbuffers* p)
+{
+    ae_vector_clear(&p->ia0);
+    ae_vector_clear(&p->ia1);
+    ae_vector_clear(&p->ia2);
+    ae_vector_clear(&p->ia3);
+    ae_vector_clear(&p->ra0);
+    ae_vector_clear(&p->ra1);
+    ae_vector_clear(&p->ra2);
+    ae_vector_clear(&p->ra3);
+}
+
+
+
+
+/*************************************************************************
+This function sorts array of real keys by ascending.
+
+Its results are:
+* sorted array A
+* permutation tables P1, P2
+
+Algorithm outputs permutation tables using two formats:
+* as usual permutation of [0..N-1]. If P1[i]=j, then sorted A[i]  contains
+  value which was moved there from J-th position.
+* as a sequence of pairwise permutations. Sorted A[] may  be  obtained  by
+  swaping A[i] and A[P2[i]] for all i from 0 to N-1.
+  
+INPUT PARAMETERS:
+    A       -   unsorted array
+    N       -   array size
+
+OUPUT PARAMETERS:
+    A       -   sorted array
+    P1, P2  -   permutation tables, array[N]
     
-    /*
-     * Sort left and right parts of the array (ignoring middle part)
-     */
-    tsort_tagsortfastrrec(a, b, bufa, bufb, i1, i1+cntless-1, _state);
-    tsort_tagsortfastrrec(a, b, bufa, bufb, i1+cntless+cnteq, i2, _state);
+NOTES:
+    this function assumes that A[] is finite; it doesn't checks that
+    condition. All other conditions (size of input arrays, etc.) are not
+    checked too.
+
+  -- ALGLIB --
+     Copyright 14.05.2008 by Bochkanov Sergey
+*************************************************************************/
+void tagsort(/* Real    */ ae_vector* a,
+     ae_int_t n,
+     /* Integer */ ae_vector* p1,
+     /* Integer */ ae_vector* p2,
+     ae_state *_state)
+{
+    ae_frame _frame_block;
+    apbuffers buf;
+
+    ae_frame_make(_state, &_frame_block);
+    ae_vector_clear(p1);
+    ae_vector_clear(p2);
+    _apbuffers_init(&buf, _state, ae_true);
+
+    tagsortbuf(a, n, p1, p2, &buf, _state);
+    ae_frame_leave(_state);
 }
 
 
 /*************************************************************************
-Internal TagSortFastI: sorts A[I1...I2] (both bounds are included),
-applies same permutations to B.
+Buffered variant of TagSort, which accepts preallocated output arrays as
+well as special structure for buffered allocations. If arrays are too
+short, they are reallocated. If they are large enough, no memory
+allocation is done.
+
+It is intended to be used in the performance-critical parts of code, where
+additional allocations can lead to severe performance degradation
 
   -- ALGLIB --
-     Copyright 06.09.2010 by Bochkanov Sergey
+     Copyright 14.05.2008 by Bochkanov Sergey
 *************************************************************************/
-static void tsort_tagsortfastrec(/* Real    */ ae_vector* a,
-     /* Real    */ ae_vector* bufa,
-     ae_int_t i1,
-     ae_int_t i2,
+void tagsortbuf(/* Real    */ ae_vector* a,
+     ae_int_t n,
+     /* Integer */ ae_vector* p1,
+     /* Integer */ ae_vector* p2,
+     apbuffers* buf,
      ae_state *_state)
 {
-    ae_int_t cntless;
-    ae_int_t cnteq;
-    ae_int_t cntgreater;
     ae_int_t i;
-    ae_int_t j;
-    ae_int_t k;
-    double tmpr;
-    ae_int_t tmpi;
-    double v0;
-    double v1;
-    double v2;
-    double vp;
+    ae_int_t lv;
+    ae_int_t lp;
+    ae_int_t rv;
+    ae_int_t rp;
 
 
     
     /*
-     * Fast exit
+     * Special cases
      */
-    if( i2<=i1 )
+    if( n<=0 )
     {
         return;
     }
-    
-    /*
-     * Non-recursive sort for small arrays
-     */
-    if( i2-i1<=16 )
+    if( n==1 )
     {
-        for(j=i1+1; j<=i2; j++)
-        {
-            
-            /*
-             * Search elements [I1..J-1] for place to insert Jth element.
-             *
-             * This code stops immediatly if we can leave A[J] at J-th position
-             * (all elements have same value of A[J] larger than any of them)
-             */
-            tmpr = a->ptr.p_double[j];
-            tmpi = j;
-            for(k=j-1; k>=i1; k--)
-            {
-                if( a->ptr.p_double[k]<=tmpr )
-                {
-                    break;
-                }
-                tmpi = k;
-            }
-            k = tmpi;
-            
-            /*
-             * Insert Jth element into Kth position
-             */
-            if( k!=j )
-            {
-                tmpr = a->ptr.p_double[j];
-                for(i=j-1; i>=k; i--)
-                {
-                    a->ptr.p_double[i+1] = a->ptr.p_double[i];
-                }
-                a->ptr.p_double[k] = tmpr;
-            }
-        }
+        ivectorsetlengthatleast(p1, 1, _state);
+        ivectorsetlengthatleast(p2, 1, _state);
+        p1->ptr.p_int[0] = 0;
+        p2->ptr.p_int[0] = 0;
         return;
     }
     
     /*
-     * Quicksort: choose pivot
-     * Here we assume that I2-I1>=16
+     * General case, N>1: prepare permutations table P1
      */
-    v0 = a->ptr.p_double[i1];
-    v1 = a->ptr.p_double[i1+(i2-i1)/2];
-    v2 = a->ptr.p_double[i2];
-    if( v0>v1 )
-    {
-        tmpr = v1;
-        v1 = v0;
-        v0 = tmpr;
-    }
-    if( v1>v2 )
-    {
-        tmpr = v2;
-        v2 = v1;
-        v1 = tmpr;
-    }
-    if( v0>v1 )
+    ivectorsetlengthatleast(p1, n, _state);
+    for(i=0; i<=n-1; i++)
     {
-        tmpr = v1;
-        v1 = v0;
-        v0 = tmpr;
+        p1->ptr.p_int[i] = i;
     }
-    vp = v1;
     
     /*
-     * now pass through A/B and:
-     * * move elements that are LESS than VP to the left of A/B
-     * * move elements that are EQUAL to VP to the right of BufA/BufB (in the reverse order)
-     * * move elements that are GREATER than VP to the left of BufA/BufB (in the normal order
-     * * move elements from the tail of BufA/BufB to the middle of A/B (restoring normal order)
-     * * move elements from the left of BufA/BufB to the end of A/B
+     * General case, N>1: sort, update P1
      */
-    cntless = 0;
-    cnteq = 0;
-    cntgreater = 0;
-    for(i=i1; i<=i2; i++)
+    rvectorsetlengthatleast(&buf->ra0, n, _state);
+    ivectorsetlengthatleast(&buf->ia0, n, _state);
+    tagsortfasti(a, p1, &buf->ra0, &buf->ia0, n, _state);
+    
+    /*
+     * General case, N>1: fill permutations table P2
+     *
+     * To fill P2 we maintain two arrays:
+     * * PV (Buf.IA0), Position(Value). PV[i] contains position of I-th key at the moment
+     * * VP (Buf.IA1), Value(Position). VP[i] contains key which has position I at the moment
+     *
+     * At each step we making permutation of two items:
+     *   Left, which is given by position/value pair LP/LV
+     *   and Right, which is given by RP/RV
+     * and updating PV[] and VP[] correspondingly.
+     */
+    ivectorsetlengthatleast(&buf->ia0, n, _state);
+    ivectorsetlengthatleast(&buf->ia1, n, _state);
+    ivectorsetlengthatleast(p2, n, _state);
+    for(i=0; i<=n-1; i++)
+    {
+        buf->ia0.ptr.p_int[i] = i;
+        buf->ia1.ptr.p_int[i] = i;
+    }
+    for(i=0; i<=n-1; i++)
     {
-        v0 = a->ptr.p_double[i];
-        if( v0<vp )
-        {
-            
-            /*
-             * LESS
-             */
-            k = i1+cntless;
-            if( i!=k )
-            {
-                a->ptr.p_double[k] = v0;
-            }
-            cntless = cntless+1;
-            continue;
-        }
-        if( v0==vp )
-        {
-            
-            /*
-             * EQUAL
-             */
-            k = i2-cnteq;
-            bufa->ptr.p_double[k] = v0;
-            cnteq = cnteq+1;
-            continue;
-        }
         
         /*
-         * GREATER
+         * calculate LP, LV, RP, RV
          */
-        k = i1+cntgreater;
-        bufa->ptr.p_double[k] = v0;
-        cntgreater = cntgreater+1;
-    }
-    for(i=0; i<=cnteq-1; i++)
-    {
-        j = i1+cntless+cnteq-1-i;
-        k = i2+i-(cnteq-1);
-        a->ptr.p_double[j] = bufa->ptr.p_double[k];
-    }
-    for(i=0; i<=cntgreater-1; i++)
-    {
-        j = i1+cntless+cnteq+i;
-        k = i1+i;
-        a->ptr.p_double[j] = bufa->ptr.p_double[k];
+        lp = i;
+        lv = buf->ia1.ptr.p_int[lp];
+        rv = p1->ptr.p_int[i];
+        rp = buf->ia0.ptr.p_int[rv];
+        
+        /*
+         * Fill P2
+         */
+        p2->ptr.p_int[i] = rp;
+        
+        /*
+         * update PV and VP
+         */
+        buf->ia1.ptr.p_int[lp] = rv;
+        buf->ia1.ptr.p_int[rp] = lv;
+        buf->ia0.ptr.p_int[lv] = rp;
+        buf->ia0.ptr.p_int[rv] = lp;
     }
-    
-    /*
-     * Sort left and right parts of the array (ignoring middle part)
-     */
-    tsort_tagsortfastrec(a, bufa, i1, i1+cntless-1, _state);
-    tsort_tagsortfastrec(a, bufa, i1+cntless+cnteq, i2, _state);
 }
 
 
-
-
 /*************************************************************************
-This  function  generates  1-dimensional  general  interpolation task with
-moderate Lipshitz constant (close to 1.0)
+Same as TagSort, but optimized for real keys and integer labels.
 
-If N=1 then suborutine generates only one point at the middle of [A,B]
+A is sorted, and same permutations are applied to B.
+
+NOTES:
+1.  this function assumes that A[] is finite; it doesn't checks that
+    condition. All other conditions (size of input arrays, etc.) are not
+    checked too.
+2.  this function uses two buffers, BufA and BufB, each is N elements large.
+    They may be preallocated (which will save some time) or not, in which
+    case function will automatically allocate memory.
 
   -- ALGLIB --
-     Copyright 02.12.2009 by Bochkanov Sergey
+     Copyright 11.12.2008 by Bochkanov Sergey
 *************************************************************************/
-void taskgenint1d(double a,
-     double b,
+void tagsortfasti(/* Real    */ ae_vector* a,
+     /* Integer */ ae_vector* b,
+     /* Real    */ ae_vector* bufa,
+     /* Integer */ ae_vector* bufb,
      ae_int_t n,
-     /* Real    */ ae_vector* x,
-     /* Real    */ ae_vector* y,
      ae_state *_state)
 {
     ae_int_t i;
-    double h;
+    ae_int_t j;
+    ae_bool isascending;
+    ae_bool isdescending;
+    double tmpr;
+    ae_int_t tmpi;
 
-    ae_vector_clear(x);
-    ae_vector_clear(y);
 
-    ae_assert(n>=1, "TaskGenInterpolationEqdist1D: N<1!", _state);
-    ae_vector_set_length(x, n, _state);
-    ae_vector_set_length(y, n, _state);
-    if( n>1 )
+    
+    /*
+     * Special case
+     */
+    if( n<=1 )
     {
-        x->ptr.p_double[0] = a;
-        y->ptr.p_double[0] = 2*ae_randomreal(_state)-1;
-        h = (b-a)/(n-1);
-        for(i=1; i<=n-1; i++)
+        return;
+    }
+    
+    /*
+     * Test for already sorted set
+     */
+    isascending = ae_true;
+    isdescending = ae_true;
+    for(i=1; i<=n-1; i++)
+    {
+        isascending = isascending&&a->ptr.p_double[i]>=a->ptr.p_double[i-1];
+        isdescending = isdescending&&a->ptr.p_double[i]<=a->ptr.p_double[i-1];
+    }
+    if( isascending )
+    {
+        return;
+    }
+    if( isdescending )
+    {
+        for(i=0; i<=n-1; i++)
         {
-            if( i!=n-1 )
-            {
-                x->ptr.p_double[i] = a+(i+0.2*(2*ae_randomreal(_state)-1))*h;
-            }
-            else
+            j = n-1-i;
+            if( j<=i )
             {
-                x->ptr.p_double[i] = b;
+                break;
             }
-            y->ptr.p_double[i] = y->ptr.p_double[i-1]+(2*ae_randomreal(_state)-1)*(x->ptr.p_double[i]-x->ptr.p_double[i-1]);
+            tmpr = a->ptr.p_double[i];
+            a->ptr.p_double[i] = a->ptr.p_double[j];
+            a->ptr.p_double[j] = tmpr;
+            tmpi = b->ptr.p_int[i];
+            b->ptr.p_int[i] = b->ptr.p_int[j];
+            b->ptr.p_int[j] = tmpi;
         }
+        return;
     }
-    else
+    
+    /*
+     * General case
+     */
+    if( bufa->cnt<n )
     {
-        x->ptr.p_double[0] = 0.5*(a+b);
-        y->ptr.p_double[0] = 2*ae_randomreal(_state)-1;
+        ae_vector_set_length(bufa, n, _state);
+    }
+    if( bufb->cnt<n )
+    {
+        ae_vector_set_length(bufb, n, _state);
     }
+    tsort_tagsortfastirec(a, b, bufa, bufb, 0, n-1, _state);
 }
 
 
 /*************************************************************************
-This function generates  1-dimensional equidistant interpolation task with
-moderate Lipshitz constant (close to 1.0)
+Same as TagSort, but optimized for real keys and real labels.
 
-If N=1 then suborutine generates only one point at the middle of [A,B]
+A is sorted, and same permutations are applied to B.
+
+NOTES:
+1.  this function assumes that A[] is finite; it doesn't checks that
+    condition. All other conditions (size of input arrays, etc.) are not
+    checked too.
+2.  this function uses two buffers, BufA and BufB, each is N elements large.
+    They may be preallocated (which will save some time) or not, in which
+    case function will automatically allocate memory.
 
   -- ALGLIB --
-     Copyright 02.12.2009 by Bochkanov Sergey
+     Copyright 11.12.2008 by Bochkanov Sergey
 *************************************************************************/
-void taskgenint1dequidist(double a,
-     double b,
+void tagsortfastr(/* Real    */ ae_vector* a,
+     /* Real    */ ae_vector* b,
+     /* Real    */ ae_vector* bufa,
+     /* Real    */ ae_vector* bufb,
      ae_int_t n,
-     /* Real    */ ae_vector* x,
-     /* Real    */ ae_vector* y,
      ae_state *_state)
 {
     ae_int_t i;
-    double h;
+    ae_int_t j;
+    ae_bool isascending;
+    ae_bool isdescending;
+    double tmpr;
 
-    ae_vector_clear(x);
-    ae_vector_clear(y);
 
-    ae_assert(n>=1, "TaskGenInterpolationEqdist1D: N<1!", _state);
-    ae_vector_set_length(x, n, _state);
-    ae_vector_set_length(y, n, _state);
-    if( n>1 )
+    
+    /*
+     * Special case
+     */
+    if( n<=1 )
     {
-        x->ptr.p_double[0] = a;
-        y->ptr.p_double[0] = 2*ae_randomreal(_state)-1;
-        h = (b-a)/(n-1);
-        for(i=1; i<=n-1; i++)
-        {
-            x->ptr.p_double[i] = a+i*h;
-            y->ptr.p_double[i] = y->ptr.p_double[i-1]+(2*ae_randomreal(_state)-1)*h;
-        }
+        return;
     }
-    else
+    
+    /*
+     * Test for already sorted set
+     */
+    isascending = ae_true;
+    isdescending = ae_true;
+    for(i=1; i<=n-1; i++)
     {
-        x->ptr.p_double[0] = 0.5*(a+b);
-        y->ptr.p_double[0] = 2*ae_randomreal(_state)-1;
+        isascending = isascending&&a->ptr.p_double[i]>=a->ptr.p_double[i-1];
+        isdescending = isdescending&&a->ptr.p_double[i]<=a->ptr.p_double[i-1];
     }
-}
-
-
-/*************************************************************************
-This function generates  1-dimensional Chebyshev-1 interpolation task with
-moderate Lipshitz constant (close to 1.0)
-
-If N=1 then suborutine generates only one point at the middle of [A,B]
-
-  -- ALGLIB --
-     Copyright 02.12.2009 by Bochkanov Sergey
-*************************************************************************/
-void taskgenint1dcheb1(double a,
-     double b,
-     ae_int_t n,
-     /* Real    */ ae_vector* x,
-     /* Real    */ ae_vector* y,
-     ae_state *_state)
-{
-    ae_int_t i;
-
-    ae_vector_clear(x);
-    ae_vector_clear(y);
-
-    ae_assert(n>=1, "TaskGenInterpolation1DCheb1: N<1!", _state);
-    ae_vector_set_length(x, n, _state);
-    ae_vector_set_length(y, n, _state);
-    if( n>1 )
+    if( isascending )
+    {
+        return;
+    }
+    if( isdescending )
     {
         for(i=0; i<=n-1; i++)
         {
-            x->ptr.p_double[i] = 0.5*(b+a)+0.5*(b-a)*ae_cos(ae_pi*(2*i+1)/(2*n), _state);
-            if( i==0 )
-            {
-                y->ptr.p_double[i] = 2*ae_randomreal(_state)-1;
-            }
-            else
+            j = n-1-i;
+            if( j<=i )
             {
-                y->ptr.p_double[i] = y->ptr.p_double[i-1]+(2*ae_randomreal(_state)-1)*(x->ptr.p_double[i]-x->ptr.p_double[i-1]);
+                break;
             }
+            tmpr = a->ptr.p_double[i];
+            a->ptr.p_double[i] = a->ptr.p_double[j];
+            a->ptr.p_double[j] = tmpr;
+            tmpr = b->ptr.p_double[i];
+            b->ptr.p_double[i] = b->ptr.p_double[j];
+            b->ptr.p_double[j] = tmpr;
         }
+        return;
     }
-    else
+    
+    /*
+     * General case
+     */
+    if( bufa->cnt<n )
     {
-        x->ptr.p_double[0] = 0.5*(a+b);
-        y->ptr.p_double[0] = 2*ae_randomreal(_state)-1;
+        ae_vector_set_length(bufa, n, _state);
+    }
+    if( bufb->cnt<n )
+    {
+        ae_vector_set_length(bufb, n, _state);
     }
+    tsort_tagsortfastrrec(a, b, bufa, bufb, 0, n-1, _state);
 }
 
 
 /*************************************************************************
-This function generates  1-dimensional Chebyshev-2 interpolation task with
-moderate Lipshitz constant (close to 1.0)
+Same as TagSort, but optimized for real keys without labels.
 
-If N=1 then suborutine generates only one point at the middle of [A,B]
+A is sorted, and that's all.
+
+NOTES:
+1.  this function assumes that A[] is finite; it doesn't checks that
+    condition. All other conditions (size of input arrays, etc.) are not
+    checked too.
+2.  this function uses buffer, BufA, which is N elements large. It may be
+    preallocated (which will save some time) or not, in which case
+    function will automatically allocate memory.
 
   -- ALGLIB --
-     Copyright 02.12.2009 by Bochkanov Sergey
+     Copyright 11.12.2008 by Bochkanov Sergey
 *************************************************************************/
-void taskgenint1dcheb2(double a,
-     double b,
+void tagsortfast(/* Real    */ ae_vector* a,
+     /* Real    */ ae_vector* bufa,
      ae_int_t n,
-     /* Real    */ ae_vector* x,
-     /* Real    */ ae_vector* y,
      ae_state *_state)
 {
     ae_int_t i;
+    ae_int_t j;
+    ae_bool isascending;
+    ae_bool isdescending;
+    double tmpr;
 
-    ae_vector_clear(x);
-    ae_vector_clear(y);
 
-    ae_assert(n>=1, "TaskGenInterpolation1DCheb2: N<1!", _state);
-    ae_vector_set_length(x, n, _state);
-    ae_vector_set_length(y, n, _state);
-    if( n>1 )
+    
+    /*
+     * Special case
+     */
+    if( n<=1 )
+    {
+        return;
+    }
+    
+    /*
+     * Test for already sorted set
+     */
+    isascending = ae_true;
+    isdescending = ae_true;
+    for(i=1; i<=n-1; i++)
+    {
+        isascending = isascending&&a->ptr.p_double[i]>=a->ptr.p_double[i-1];
+        isdescending = isdescending&&a->ptr.p_double[i]<=a->ptr.p_double[i-1];
+    }
+    if( isascending )
+    {
+        return;
+    }
+    if( isdescending )
     {
         for(i=0; i<=n-1; i++)
         {
-            x->ptr.p_double[i] = 0.5*(b+a)+0.5*(b-a)*ae_cos(ae_pi*i/(n-1), _state);
-            if( i==0 )
-            {
-                y->ptr.p_double[i] = 2*ae_randomreal(_state)-1;
-            }
-            else
+            j = n-1-i;
+            if( j<=i )
             {
-                y->ptr.p_double[i] = y->ptr.p_double[i-1]+(2*ae_randomreal(_state)-1)*(x->ptr.p_double[i]-x->ptr.p_double[i-1]);
+                break;
             }
+            tmpr = a->ptr.p_double[i];
+            a->ptr.p_double[i] = a->ptr.p_double[j];
+            a->ptr.p_double[j] = tmpr;
         }
+        return;
     }
-    else
+    
+    /*
+     * General case
+     */
+    if( bufa->cnt<n )
     {
-        x->ptr.p_double[0] = 0.5*(a+b);
-        y->ptr.p_double[0] = 2*ae_randomreal(_state)-1;
+        ae_vector_set_length(bufa, n, _state);
     }
+    tsort_tagsortfastrec(a, bufa, 0, n-1, _state);
 }
 
 
 /*************************************************************************
-This function checks that all values from X[] are distinct. It does more
-than just usual floating point comparison:
-* first, it calculates max(X) and min(X)
-* second, it maps X[] from [min,max] to [1,2]
-* only at this stage actual comparison is done
-
-The meaning of such check is to ensure that all values are "distinct enough"
-and will not cause interpolation subroutine to fail.
+Heap operations: adds element to the heap
 
-NOTE:
-    X[] must be sorted by ascending (subroutine ASSERT's it)
+PARAMETERS:
+    A       -   heap itself, must be at least array[0..N]
+    B       -   array of integer tags, which are updated according to
+                permutations in the heap
+    N       -   size of the heap (without new element).
+                updated on output
+    VA      -   value of the element being added
+    VB      -   value of the tag
 
   -- ALGLIB --
-     Copyright 02.12.2009 by Bochkanov Sergey
+     Copyright 28.02.2010 by Bochkanov Sergey
 *************************************************************************/
-ae_bool aredistinct(/* Real    */ ae_vector* x,
-     ae_int_t n,
+void tagheappushi(/* Real    */ ae_vector* a,
+     /* Integer */ ae_vector* b,
+     ae_int_t* n,
+     double va,
+     ae_int_t vb,
      ae_state *_state)
 {
-    double a;
-    double b;
-    ae_int_t i;
-    ae_bool nonsorted;
-    ae_bool result;
+    ae_int_t j;
+    ae_int_t k;
+    double v;
 
 
-    ae_assert(n>=1, "APSERVAreDistinct: internal error (N<1)", _state);
-    if( n==1 )
+    if( *n<0 )
     {
-        
-        /*
-         * everything is alright, it is up to caller to decide whether it
-         * can interpolate something with just one point
-         */
-        result = ae_true;
-        return result;
+        return;
     }
-    a = x->ptr.p_double[0];
-    b = x->ptr.p_double[0];
-    nonsorted = ae_false;
-    for(i=1; i<=n-1; i++)
+    
+    /*
+     * N=0 is a special case
+     */
+    if( *n==0 )
     {
-        a = ae_minreal(a, x->ptr.p_double[i], _state);
-        b = ae_maxreal(b, x->ptr.p_double[i], _state);
-        nonsorted = nonsorted||ae_fp_greater_eq(x->ptr.p_double[i-1],x->ptr.p_double[i]);
+        a->ptr.p_double[0] = va;
+        b->ptr.p_int[0] = vb;
+        *n = *n+1;
+        return;
     }
-    ae_assert(!nonsorted, "APSERVAreDistinct: internal error (not sorted)", _state);
-    for(i=1; i<=n-1; i++)
+    
+    /*
+     * add current point to the heap
+     * (add to the bottom, then move up)
+     *
+     * we don't write point to the heap
+     * until its final position is determined
+     * (it allow us to reduce number of array access operations)
+     */
+    j = *n;
+    *n = *n+1;
+    while(j>0)
     {
-        if( ae_fp_eq((x->ptr.p_double[i]-a)/(b-a)+1,(x->ptr.p_double[i-1]-a)/(b-a)+1) )
+        k = (j-1)/2;
+        v = a->ptr.p_double[k];
+        if( ae_fp_less(v,va) )
         {
-            result = ae_false;
-            return result;
+            
+            /*
+             * swap with higher element
+             */
+            a->ptr.p_double[j] = v;
+            b->ptr.p_int[j] = b->ptr.p_int[k];
+            j = k;
+        }
+        else
+        {
+            
+            /*
+             * element in its place. terminate.
+             */
+            break;
         }
     }
-    result = ae_true;
-    return result;
+    a->ptr.p_double[j] = va;
+    b->ptr.p_int[j] = vb;
 }
 
 
 /*************************************************************************
-If Length(X)<N, resizes X
+Heap operations: replaces top element with new element
+(which is moved down)
+
+PARAMETERS:
+    A       -   heap itself, must be at least array[0..N-1]
+    B       -   array of integer tags, which are updated according to
+                permutations in the heap
+    N       -   size of the heap
+    VA      -   value of the element which replaces top element
+    VB      -   value of the tag
 
   -- ALGLIB --
-     Copyright 20.03.2009 by Bochkanov Sergey
+     Copyright 28.02.2010 by Bochkanov Sergey
 *************************************************************************/
-void bvectorsetlengthatleast(/* Boolean */ ae_vector* x,
+void tagheapreplacetopi(/* Real    */ ae_vector* a,
+     /* Integer */ ae_vector* b,
      ae_int_t n,
+     double va,
+     ae_int_t vb,
      ae_state *_state)
 {
+    ae_int_t j;
+    ae_int_t k1;
+    ae_int_t k2;
+    double v;
+    double v1;
+    double v2;
 
 
-    if( x->cnt<n )
+    if( n<1 )
     {
-        ae_vector_set_length(x, n, _state);
+        return;
+    }
+    
+    /*
+     * N=1 is a special case
+     */
+    if( n==1 )
+    {
+        a->ptr.p_double[0] = va;
+        b->ptr.p_int[0] = vb;
+        return;
+    }
+    
+    /*
+     * move down through heap:
+     * * J  -   current element
+     * * K1 -   first child (always exists)
+     * * K2 -   second child (may not exists)
+     *
+     * we don't write point to the heap
+     * until its final position is determined
+     * (it allow us to reduce number of array access operations)
+     */
+    j = 0;
+    k1 = 1;
+    k2 = 2;
+    while(k1<n)
+    {
+        if( k2>=n )
+        {
+            
+            /*
+             * only one child.
+             *
+             * swap and terminate (because this child
+             * have no siblings due to heap structure)
+             */
+            v = a->ptr.p_double[k1];
+            if( ae_fp_greater(v,va) )
+            {
+                a->ptr.p_double[j] = v;
+                b->ptr.p_int[j] = b->ptr.p_int[k1];
+                j = k1;
+            }
+            break;
+        }
+        else
+        {
+            
+            /*
+             * two childs
+             */
+            v1 = a->ptr.p_double[k1];
+            v2 = a->ptr.p_double[k2];
+            if( ae_fp_greater(v1,v2) )
+            {
+                if( ae_fp_less(va,v1) )
+                {
+                    a->ptr.p_double[j] = v1;
+                    b->ptr.p_int[j] = b->ptr.p_int[k1];
+                    j = k1;
+                }
+                else
+                {
+                    break;
+                }
+            }
+            else
+            {
+                if( ae_fp_less(va,v2) )
+                {
+                    a->ptr.p_double[j] = v2;
+                    b->ptr.p_int[j] = b->ptr.p_int[k2];
+                    j = k2;
+                }
+                else
+                {
+                    break;
+                }
+            }
+            k1 = 2*j+1;
+            k2 = 2*j+2;
+        }
     }
+    a->ptr.p_double[j] = va;
+    b->ptr.p_int[j] = vb;
 }
 
 
 /*************************************************************************
-If Length(X)<N, resizes X
-
-  -- ALGLIB --
-     Copyright 20.03.2009 by Bochkanov Sergey
-*************************************************************************/
-void rvectorsetlengthatleast(/* Real    */ ae_vector* x,
-     ae_int_t n,
-     ae_state *_state)
-{
-
-
-    if( x->cnt<n )
-    {
-        ae_vector_set_length(x, n, _state);
-    }
-}
+Heap operations: pops top element from the heap
 
+PARAMETERS:
+    A       -   heap itself, must be at least array[0..N-1]
+    B       -   array of integer tags, which are updated according to
+                permutations in the heap
+    N       -   size of the heap, N>=1
 
-/*************************************************************************
-If Cols(X)<N or Rows(X)<M, resizes X
+On output top element is moved to A[N-1], B[N-1], heap is reordered, N is
+decreased by 1.
 
   -- ALGLIB --
-     Copyright 20.03.2009 by Bochkanov Sergey
+     Copyright 28.02.2010 by Bochkanov Sergey
 *************************************************************************/
-void rmatrixsetlengthatleast(/* Real    */ ae_matrix* x,
-     ae_int_t m,
-     ae_int_t n,
+void tagheappopi(/* Real    */ ae_vector* a,
+     /* Integer */ ae_vector* b,
+     ae_int_t* n,
      ae_state *_state)
 {
+    double va;
+    ae_int_t vb;
 
 
-    if( x->rows<m||x->cols<n )
+    if( *n<1 )
     {
-        ae_matrix_set_length(x, m, n, _state);
+        return;
     }
-}
-
-
-/*************************************************************************
-This function checks that all values from X[] are finite
-
-  -- ALGLIB --
-     Copyright 18.06.2010 by Bochkanov Sergey
-*************************************************************************/
-ae_bool isfinitevector(/* Real    */ ae_vector* x,
-     ae_int_t n,
-     ae_state *_state)
-{
-    ae_int_t i;
-    ae_bool result;
-
-
-    ae_assert(n>=0, "APSERVIsFiniteVector: internal error (N<0)", _state);
-    for(i=0; i<=n-1; i++)
+    
+    /*
+     * N=1 is a special case
+     */
+    if( *n==1 )
     {
-        if( !ae_isfinite(x->ptr.p_double[i], _state) )
-        {
-            result = ae_false;
-            return result;
-        }
+        *n = 0;
+        return;
     }
-    result = ae_true;
-    return result;
+    
+    /*
+     * swap top element and last element,
+     * then reorder heap
+     */
+    va = a->ptr.p_double[*n-1];
+    vb = b->ptr.p_int[*n-1];
+    a->ptr.p_double[*n-1] = a->ptr.p_double[0];
+    b->ptr.p_int[*n-1] = b->ptr.p_int[0];
+    *n = *n-1;
+    tagheapreplacetopi(a, b, *n, va, vb, _state);
 }
 
 
 /*************************************************************************
-This function checks that all values from X[] are finite
+Internal TagSortFastI: sorts A[I1...I2] (both bounds are included),
+applies same permutations to B.
 
   -- ALGLIB --
-     Copyright 18.06.2010 by Bochkanov Sergey
+     Copyright 06.09.2010 by Bochkanov Sergey
 *************************************************************************/
-ae_bool isfinitecvector(/* Complex */ ae_vector* z,
-     ae_int_t n,
+static void tsort_tagsortfastirec(/* Real    */ ae_vector* a,
+     /* Integer */ ae_vector* b,
+     /* Real    */ ae_vector* bufa,
+     /* Integer */ ae_vector* bufb,
+     ae_int_t i1,
+     ae_int_t i2,
      ae_state *_state)
 {
     ae_int_t i;
-    ae_bool result;
+    ae_int_t j;
+    ae_int_t k;
+    ae_int_t cntless;
+    ae_int_t cnteq;
+    ae_int_t cntgreater;
+    double tmpr;
+    ae_int_t tmpi;
+    double v0;
+    double v1;
+    double v2;
+    double vp;
 
 
-    ae_assert(n>=0, "APSERVIsFiniteCVector: internal error (N<0)", _state);
-    for(i=0; i<=n-1; i++)
+    
+    /*
+     * Fast exit
+     */
+    if( i2<=i1 )
     {
-        if( !ae_isfinite(z->ptr.p_complex[i].x, _state)||!ae_isfinite(z->ptr.p_complex[i].y, _state) )
-        {
-            result = ae_false;
-            return result;
-        }
+        return;
     }
-    result = ae_true;
-    return result;
-}
-
-
-/*************************************************************************
-This function checks that all values from X[0..M-1,0..N-1] are finite
-
-  -- ALGLIB --
-     Copyright 18.06.2010 by Bochkanov Sergey
-*************************************************************************/
-ae_bool apservisfinitematrix(/* Real    */ ae_matrix* x,
-     ae_int_t m,
-     ae_int_t n,
-     ae_state *_state)
-{
-    ae_int_t i;
-    ae_int_t j;
-    ae_bool result;
-
-
-    ae_assert(n>=0, "APSERVIsFiniteMatrix: internal error (N<0)", _state);
-    ae_assert(m>=0, "APSERVIsFiniteMatrix: internal error (M<0)", _state);
-    for(i=0; i<=m-1; i++)
+    
+    /*
+     * Non-recursive sort for small arrays
+     */
+    if( i2-i1<=16 )
     {
-        for(j=0; j<=n-1; j++)
+        for(j=i1+1; j<=i2; j++)
         {
-            if( !ae_isfinite(x->ptr.pp_double[i][j], _state) )
+            
+            /*
+             * Search elements [I1..J-1] for place to insert Jth element.
+             *
+             * This code stops immediately if we can leave A[J] at J-th position
+             * (all elements have same value of A[J] larger than any of them)
+             */
+            tmpr = a->ptr.p_double[j];
+            tmpi = j;
+            for(k=j-1; k>=i1; k--)
             {
-                result = ae_false;
-                return result;
+                if( a->ptr.p_double[k]<=tmpr )
+                {
+                    break;
+                }
+                tmpi = k;
+            }
+            k = tmpi;
+            
+            /*
+             * Insert Jth element into Kth position
+             */
+            if( k!=j )
+            {
+                tmpr = a->ptr.p_double[j];
+                tmpi = b->ptr.p_int[j];
+                for(i=j-1; i>=k; i--)
+                {
+                    a->ptr.p_double[i+1] = a->ptr.p_double[i];
+                    b->ptr.p_int[i+1] = b->ptr.p_int[i];
+                }
+                a->ptr.p_double[k] = tmpr;
+                b->ptr.p_int[k] = tmpi;
             }
         }
+        return;
     }
-    result = ae_true;
-    return result;
-}
-
-
-/*************************************************************************
-This function checks that all values from X[0..M-1,0..N-1] are finite
-
-  -- ALGLIB --
-     Copyright 18.06.2010 by Bochkanov Sergey
-*************************************************************************/
-ae_bool apservisfinitecmatrix(/* Complex */ ae_matrix* x,
-     ae_int_t m,
-     ae_int_t n,
-     ae_state *_state)
-{
-    ae_int_t i;
-    ae_int_t j;
-    ae_bool result;
-
-
-    ae_assert(n>=0, "APSERVIsFiniteCMatrix: internal error (N<0)", _state);
-    ae_assert(m>=0, "APSERVIsFiniteCMatrix: internal error (M<0)", _state);
-    for(i=0; i<=m-1; i++)
+    
+    /*
+     * Quicksort: choose pivot
+     * Here we assume that I2-I1>=2
+     */
+    v0 = a->ptr.p_double[i1];
+    v1 = a->ptr.p_double[i1+(i2-i1)/2];
+    v2 = a->ptr.p_double[i2];
+    if( v0>v1 )
+    {
+        tmpr = v1;
+        v1 = v0;
+        v0 = tmpr;
+    }
+    if( v1>v2 )
+    {
+        tmpr = v2;
+        v2 = v1;
+        v1 = tmpr;
+    }
+    if( v0>v1 )
+    {
+        tmpr = v1;
+        v1 = v0;
+        v0 = tmpr;
+    }
+    vp = v1;
+    
+    /*
+     * now pass through A/B and:
+     * * move elements that are LESS than VP to the left of A/B
+     * * move elements that are EQUAL to VP to the right of BufA/BufB (in the reverse order)
+     * * move elements that are GREATER than VP to the left of BufA/BufB (in the normal order
+     * * move elements from the tail of BufA/BufB to the middle of A/B (restoring normal order)
+     * * move elements from the left of BufA/BufB to the end of A/B
+     */
+    cntless = 0;
+    cnteq = 0;
+    cntgreater = 0;
+    for(i=i1; i<=i2; i++)
     {
-        for(j=0; j<=n-1; j++)
+        v0 = a->ptr.p_double[i];
+        if( v0<vp )
         {
-            if( !ae_isfinite(x->ptr.pp_complex[i][j].x, _state)||!ae_isfinite(x->ptr.pp_complex[i][j].y, _state) )
+            
+            /*
+             * LESS
+             */
+            k = i1+cntless;
+            if( i!=k )
             {
-                result = ae_false;
-                return result;
+                a->ptr.p_double[k] = v0;
+                b->ptr.p_int[k] = b->ptr.p_int[i];
             }
+            cntless = cntless+1;
+            continue;
         }
-    }
-    result = ae_true;
-    return result;
-}
-
-
-/*************************************************************************
-This function checks that all values from upper/lower triangle of
-X[0..N-1,0..N-1] are finite
-
-  -- ALGLIB --
-     Copyright 18.06.2010 by Bochkanov Sergey
-*************************************************************************/
-ae_bool isfinitertrmatrix(/* Real    */ ae_matrix* x,
-     ae_int_t n,
-     ae_bool isupper,
-     ae_state *_state)
-{
-    ae_int_t i;
-    ae_int_t j1;
-    ae_int_t j2;
-    ae_int_t j;
-    ae_bool result;
-
-
-    ae_assert(n>=0, "APSERVIsFiniteRTRMatrix: internal error (N<0)", _state);
-    for(i=0; i<=n-1; i++)
-    {
-        if( isupper )
-        {
-            j1 = i;
-            j2 = n-1;
-        }
-        else
-        {
-            j1 = 0;
-            j2 = i;
-        }
-        for(j=j1; j<=j2; j++)
+        if( v0==vp )
         {
-            if( !ae_isfinite(x->ptr.pp_double[i][j], _state) )
-            {
-                result = ae_false;
-                return result;
-            }
+            
+            /*
+             * EQUAL
+             */
+            k = i2-cnteq;
+            bufa->ptr.p_double[k] = v0;
+            bufb->ptr.p_int[k] = b->ptr.p_int[i];
+            cnteq = cnteq+1;
+            continue;
         }
+        
+        /*
+         * GREATER
+         */
+        k = i1+cntgreater;
+        bufa->ptr.p_double[k] = v0;
+        bufb->ptr.p_int[k] = b->ptr.p_int[i];
+        cntgreater = cntgreater+1;
     }
-    result = ae_true;
-    return result;
+    for(i=0; i<=cnteq-1; i++)
+    {
+        j = i1+cntless+cnteq-1-i;
+        k = i2+i-(cnteq-1);
+        a->ptr.p_double[j] = bufa->ptr.p_double[k];
+        b->ptr.p_int[j] = bufb->ptr.p_int[k];
+    }
+    for(i=0; i<=cntgreater-1; i++)
+    {
+        j = i1+cntless+cnteq+i;
+        k = i1+i;
+        a->ptr.p_double[j] = bufa->ptr.p_double[k];
+        b->ptr.p_int[j] = bufb->ptr.p_int[k];
+    }
+    
+    /*
+     * Sort left and right parts of the array (ignoring middle part)
+     */
+    tsort_tagsortfastirec(a, b, bufa, bufb, i1, i1+cntless-1, _state);
+    tsort_tagsortfastirec(a, b, bufa, bufb, i1+cntless+cnteq, i2, _state);
 }
 
 
 /*************************************************************************
-This function checks that all values from upper/lower triangle of
-X[0..N-1,0..N-1] are finite
+Internal TagSortFastR: sorts A[I1...I2] (both bounds are included),
+applies same permutations to B.
 
   -- ALGLIB --
-     Copyright 18.06.2010 by Bochkanov Sergey
+     Copyright 06.09.2010 by Bochkanov Sergey
 *************************************************************************/
-ae_bool apservisfinitectrmatrix(/* Complex */ ae_matrix* x,
-     ae_int_t n,
-     ae_bool isupper,
+static void tsort_tagsortfastrrec(/* Real    */ ae_vector* a,
+     /* Real    */ ae_vector* b,
+     /* Real    */ ae_vector* bufa,
+     /* Real    */ ae_vector* bufb,
+     ae_int_t i1,
+     ae_int_t i2,
      ae_state *_state)
 {
     ae_int_t i;
-    ae_int_t j1;
-    ae_int_t j2;
     ae_int_t j;
-    ae_bool result;
+    ae_int_t k;
+    double tmpr;
+    double tmpr2;
+    ae_int_t tmpi;
+    ae_int_t cntless;
+    ae_int_t cnteq;
+    ae_int_t cntgreater;
+    double v0;
+    double v1;
+    double v2;
+    double vp;
 
 
-    ae_assert(n>=0, "APSERVIsFiniteCTRMatrix: internal error (N<0)", _state);
-    for(i=0; i<=n-1; i++)
+    
+    /*
+     * Fast exit
+     */
+    if( i2<=i1 )
     {
-        if( isupper )
-        {
-            j1 = i;
-            j2 = n-1;
-        }
-        else
-        {
-            j1 = 0;
-            j2 = i;
-        }
-        for(j=j1; j<=j2; j++)
+        return;
+    }
+    
+    /*
+     * Non-recursive sort for small arrays
+     */
+    if( i2-i1<=16 )
+    {
+        for(j=i1+1; j<=i2; j++)
         {
-            if( !ae_isfinite(x->ptr.pp_complex[i][j].x, _state)||!ae_isfinite(x->ptr.pp_complex[i][j].y, _state) )
+            
+            /*
+             * Search elements [I1..J-1] for place to insert Jth element.
+             *
+             * This code stops immediatly if we can leave A[J] at J-th position
+             * (all elements have same value of A[J] larger than any of them)
+             */
+            tmpr = a->ptr.p_double[j];
+            tmpi = j;
+            for(k=j-1; k>=i1; k--)
             {
-                result = ae_false;
-                return result;
+                if( a->ptr.p_double[k]<=tmpr )
+                {
+                    break;
+                }
+                tmpi = k;
+            }
+            k = tmpi;
+            
+            /*
+             * Insert Jth element into Kth position
+             */
+            if( k!=j )
+            {
+                tmpr = a->ptr.p_double[j];
+                tmpr2 = b->ptr.p_double[j];
+                for(i=j-1; i>=k; i--)
+                {
+                    a->ptr.p_double[i+1] = a->ptr.p_double[i];
+                    b->ptr.p_double[i+1] = b->ptr.p_double[i];
+                }
+                a->ptr.p_double[k] = tmpr;
+                b->ptr.p_double[k] = tmpr2;
             }
         }
+        return;
     }
-    result = ae_true;
-    return result;
-}
-
-
-/*************************************************************************
-This function checks that all values from X[0..M-1,0..N-1] are  finite  or
-NaN's.
-
-  -- ALGLIB --
-     Copyright 18.06.2010 by Bochkanov Sergey
-*************************************************************************/
-ae_bool apservisfiniteornanmatrix(/* Real    */ ae_matrix* x,
-     ae_int_t m,
-     ae_int_t n,
-     ae_state *_state)
-{
-    ae_int_t i;
-    ae_int_t j;
-    ae_bool result;
-
-
-    ae_assert(n>=0, "APSERVIsFiniteOrNaNMatrix: internal error (N<0)", _state);
-    ae_assert(m>=0, "APSERVIsFiniteOrNaNMatrix: internal error (M<0)", _state);
-    for(i=0; i<=m-1; i++)
+    
+    /*
+     * Quicksort: choose pivot
+     * Here we assume that I2-I1>=16
+     */
+    v0 = a->ptr.p_double[i1];
+    v1 = a->ptr.p_double[i1+(i2-i1)/2];
+    v2 = a->ptr.p_double[i2];
+    if( v0>v1 )
+    {
+        tmpr = v1;
+        v1 = v0;
+        v0 = tmpr;
+    }
+    if( v1>v2 )
+    {
+        tmpr = v2;
+        v2 = v1;
+        v1 = tmpr;
+    }
+    if( v0>v1 )
+    {
+        tmpr = v1;
+        v1 = v0;
+        v0 = tmpr;
+    }
+    vp = v1;
+    
+    /*
+     * now pass through A/B and:
+     * * move elements that are LESS than VP to the left of A/B
+     * * move elements that are EQUAL to VP to the right of BufA/BufB (in the reverse order)
+     * * move elements that are GREATER than VP to the left of BufA/BufB (in the normal order
+     * * move elements from the tail of BufA/BufB to the middle of A/B (restoring normal order)
+     * * move elements from the left of BufA/BufB to the end of A/B
+     */
+    cntless = 0;
+    cnteq = 0;
+    cntgreater = 0;
+    for(i=i1; i<=i2; i++)
     {
-        for(j=0; j<=n-1; j++)
+        v0 = a->ptr.p_double[i];
+        if( v0<vp )
         {
-            if( !(ae_isfinite(x->ptr.pp_double[i][j], _state)||ae_isnan(x->ptr.pp_double[i][j], _state)) )
+            
+            /*
+             * LESS
+             */
+            k = i1+cntless;
+            if( i!=k )
             {
-                result = ae_false;
-                return result;
+                a->ptr.p_double[k] = v0;
+                b->ptr.p_double[k] = b->ptr.p_double[i];
             }
+            cntless = cntless+1;
+            continue;
+        }
+        if( v0==vp )
+        {
+            
+            /*
+             * EQUAL
+             */
+            k = i2-cnteq;
+            bufa->ptr.p_double[k] = v0;
+            bufb->ptr.p_double[k] = b->ptr.p_double[i];
+            cnteq = cnteq+1;
+            continue;
         }
+        
+        /*
+         * GREATER
+         */
+        k = i1+cntgreater;
+        bufa->ptr.p_double[k] = v0;
+        bufb->ptr.p_double[k] = b->ptr.p_double[i];
+        cntgreater = cntgreater+1;
     }
-    result = ae_true;
-    return result;
-}
-
-
-/*************************************************************************
-Safe sqrt(x^2+y^2)
-
-  -- ALGLIB --
-     Copyright by Bochkanov Sergey
-*************************************************************************/
-double safepythag2(double x, double y, ae_state *_state)
-{
-    double w;
-    double xabs;
-    double yabs;
-    double z;
-    double result;
-
-
-    xabs = ae_fabs(x, _state);
-    yabs = ae_fabs(y, _state);
-    w = ae_maxreal(xabs, yabs, _state);
-    z = ae_minreal(xabs, yabs, _state);
-    if( ae_fp_eq(z,0) )
+    for(i=0; i<=cnteq-1; i++)
     {
-        result = w;
+        j = i1+cntless+cnteq-1-i;
+        k = i2+i-(cnteq-1);
+        a->ptr.p_double[j] = bufa->ptr.p_double[k];
+        b->ptr.p_double[j] = bufb->ptr.p_double[k];
     }
-    else
+    for(i=0; i<=cntgreater-1; i++)
     {
-        result = w*ae_sqrt(1+ae_sqr(z/w, _state), _state);
+        j = i1+cntless+cnteq+i;
+        k = i1+i;
+        a->ptr.p_double[j] = bufa->ptr.p_double[k];
+        b->ptr.p_double[j] = bufb->ptr.p_double[k];
     }
-    return result;
+    
+    /*
+     * Sort left and right parts of the array (ignoring middle part)
+     */
+    tsort_tagsortfastrrec(a, b, bufa, bufb, i1, i1+cntless-1, _state);
+    tsort_tagsortfastrrec(a, b, bufa, bufb, i1+cntless+cnteq, i2, _state);
 }
 
 
 /*************************************************************************
-Safe sqrt(x^2+y^2)
+Internal TagSortFastI: sorts A[I1...I2] (both bounds are included),
+applies same permutations to B.
 
   -- ALGLIB --
-     Copyright by Bochkanov Sergey
+     Copyright 06.09.2010 by Bochkanov Sergey
 *************************************************************************/
-double safepythag3(double x, double y, double z, ae_state *_state)
+static void tsort_tagsortfastrec(/* Real    */ ae_vector* a,
+     /* Real    */ ae_vector* bufa,
+     ae_int_t i1,
+     ae_int_t i2,
+     ae_state *_state)
 {
-    double w;
-    double result;
+    ae_int_t cntless;
+    ae_int_t cnteq;
+    ae_int_t cntgreater;
+    ae_int_t i;
+    ae_int_t j;
+    ae_int_t k;
+    double tmpr;
+    ae_int_t tmpi;
+    double v0;
+    double v1;
+    double v2;
+    double vp;
 
 
-    w = ae_maxreal(ae_fabs(x, _state), ae_maxreal(ae_fabs(y, _state), ae_fabs(z, _state), _state), _state);
-    if( ae_fp_eq(w,0) )
+    
+    /*
+     * Fast exit
+     */
+    if( i2<=i1 )
     {
-        result = 0;
-        return result;
+        return;
     }
-    x = x/w;
-    y = y/w;
-    z = z/w;
-    result = w*ae_sqrt(ae_sqr(x, _state)+ae_sqr(y, _state)+ae_sqr(z, _state), _state);
-    return result;
-}
-
-
-/*************************************************************************
-Safe division.
-
-This function attempts to calculate R=X/Y without overflow.
-
-It returns:
-* +1, if abs(X/Y)>=MaxRealNumber or undefined - overflow-like situation
-      (no overlfow is generated, R is either NAN, PosINF, NegINF)
-*  0, if MinRealNumber<abs(X/Y)<MaxRealNumber or X=0, Y<>0
-      (R contains result, may be zero)
-* -1, if 0<abs(X/Y)<MinRealNumber - underflow-like situation
-      (R contains zero; it corresponds to underflow)
-
-No overflow is generated in any case.
-
-  -- ALGLIB --
-     Copyright by Bochkanov Sergey
-*************************************************************************/
-ae_int_t saferdiv(double x, double y, double* r, ae_state *_state)
-{
-    ae_int_t result;
-
-    *r = 0;
-
     
     /*
-     * Two special cases:
-     * * Y=0
-     * * X=0 and Y<>0
+     * Non-recursive sort for small arrays
      */
-    if( ae_fp_eq(y,0) )
+    if( i2-i1<=16 )
     {
-        result = 1;
-        if( ae_fp_eq(x,0) )
-        {
-            *r = _state->v_nan;
-        }
-        if( ae_fp_greater(x,0) )
-        {
-            *r = _state->v_posinf;
-        }
-        if( ae_fp_less(x,0) )
+        for(j=i1+1; j<=i2; j++)
         {
-            *r = _state->v_neginf;
+            
+            /*
+             * Search elements [I1..J-1] for place to insert Jth element.
+             *
+             * This code stops immediatly if we can leave A[J] at J-th position
+             * (all elements have same value of A[J] larger than any of them)
+             */
+            tmpr = a->ptr.p_double[j];
+            tmpi = j;
+            for(k=j-1; k>=i1; k--)
+            {
+                if( a->ptr.p_double[k]<=tmpr )
+                {
+                    break;
+                }
+                tmpi = k;
+            }
+            k = tmpi;
+            
+            /*
+             * Insert Jth element into Kth position
+             */
+            if( k!=j )
+            {
+                tmpr = a->ptr.p_double[j];
+                for(i=j-1; i>=k; i--)
+                {
+                    a->ptr.p_double[i+1] = a->ptr.p_double[i];
+                }
+                a->ptr.p_double[k] = tmpr;
+            }
         }
-        return result;
-    }
-    if( ae_fp_eq(x,0) )
-    {
-        *r = 0;
-        result = 0;
-        return result;
+        return;
     }
     
     /*
-     * make Y>0
+     * Quicksort: choose pivot
+     * Here we assume that I2-I1>=16
      */
-    if( ae_fp_less(y,0) )
+    v0 = a->ptr.p_double[i1];
+    v1 = a->ptr.p_double[i1+(i2-i1)/2];
+    v2 = a->ptr.p_double[i2];
+    if( v0>v1 )
     {
-        x = -x;
-        y = -y;
+        tmpr = v1;
+        v1 = v0;
+        v0 = tmpr;
     }
-    
-    /*
-     *
-     */
-    if( ae_fp_greater_eq(y,1) )
+    if( v1>v2 )
     {
-        *r = x/y;
-        if( ae_fp_less_eq(ae_fabs(*r, _state),ae_minrealnumber) )
-        {
-            result = -1;
-            *r = 0;
-        }
-        else
-        {
-            result = 0;
-        }
+        tmpr = v2;
+        v2 = v1;
+        v1 = tmpr;
+    }
+    if( v0>v1 )
+    {
+        tmpr = v1;
+        v1 = v0;
+        v0 = tmpr;
     }
-    else
+    vp = v1;
+    
+    /*
+     * now pass through A/B and:
+     * * move elements that are LESS than VP to the left of A/B
+     * * move elements that are EQUAL to VP to the right of BufA/BufB (in the reverse order)
+     * * move elements that are GREATER than VP to the left of BufA/BufB (in the normal order
+     * * move elements from the tail of BufA/BufB to the middle of A/B (restoring normal order)
+     * * move elements from the left of BufA/BufB to the end of A/B
+     */
+    cntless = 0;
+    cnteq = 0;
+    cntgreater = 0;
+    for(i=i1; i<=i2; i++)
     {
-        if( ae_fp_greater_eq(ae_fabs(x, _state),ae_maxrealnumber*y) )
+        v0 = a->ptr.p_double[i];
+        if( v0<vp )
         {
-            if( ae_fp_greater(x,0) )
-            {
-                *r = _state->v_posinf;
-            }
-            else
+            
+            /*
+             * LESS
+             */
+            k = i1+cntless;
+            if( i!=k )
             {
-                *r = _state->v_neginf;
+                a->ptr.p_double[k] = v0;
             }
-            result = 1;
-        }
-        else
-        {
-            *r = x/y;
-            result = 0;
-        }
-    }
-    return result;
-}
-
-
-/*************************************************************************
-This function calculates "safe" min(X/Y,V) for positive finite X, Y, V.
-No overflow is generated in any case.
-
-  -- ALGLIB --
-     Copyright by Bochkanov Sergey
-*************************************************************************/
-double safeminposrv(double x, double y, double v, ae_state *_state)
-{
-    double r;
-    double result;
-
-
-    if( ae_fp_greater_eq(y,1) )
-    {
-        
-        /*
-         * Y>=1, we can safely divide by Y
-         */
-        r = x/y;
-        result = v;
-        if( ae_fp_greater(v,r) )
-        {
-            result = r;
+            cntless = cntless+1;
+            continue;
         }
-        else
+        if( v0==vp )
         {
-            result = v;
+            
+            /*
+             * EQUAL
+             */
+            k = i2-cnteq;
+            bufa->ptr.p_double[k] = v0;
+            cnteq = cnteq+1;
+            continue;
         }
-    }
-    else
-    {
         
         /*
-         * Y<1, we can safely multiply by Y
+         * GREATER
          */
-        if( ae_fp_less(x,v*y) )
-        {
-            result = x/y;
-        }
-        else
-        {
-            result = v;
-        }
-    }
-    return result;
-}
-
-
-/*************************************************************************
-This function makes periodic mapping of X to [A,B].
-
-It accepts X, A, B (A>B). It returns T which lies in  [A,B] and integer K,
-such that X = T + K*(B-A).
-
-NOTES:
-* K is represented as real value, although actually it is integer
-* T is guaranteed to be in [A,B]
-* T replaces X
-
-  -- ALGLIB --
-     Copyright by Bochkanov Sergey
-*************************************************************************/
-void apperiodicmap(double* x,
-     double a,
-     double b,
-     double* k,
-     ae_state *_state)
-{
-
-    *k = 0;
-
-    ae_assert(ae_fp_less(a,b), "APPeriodicMap: internal error!", _state);
-    *k = ae_ifloor((*x-a)/(b-a), _state);
-    *x = *x-*k*(b-a);
-    while(ae_fp_less(*x,a))
-    {
-        *x = *x+(b-a);
-        *k = *k-1;
-    }
-    while(ae_fp_greater(*x,b))
-    {
-        *x = *x-(b-a);
-        *k = *k+1;
+        k = i1+cntgreater;
+        bufa->ptr.p_double[k] = v0;
+        cntgreater = cntgreater+1;
     }
-    *x = ae_maxreal(*x, a, _state);
-    *x = ae_minreal(*x, b, _state);
-}
-
-
-/*************************************************************************
-'bounds' value: maps X to [B1,B2]
-
-  -- ALGLIB --
-     Copyright 20.03.2009 by Bochkanov Sergey
-*************************************************************************/
-double boundval(double x, double b1, double b2, ae_state *_state)
-{
-    double result;
-
-
-    if( ae_fp_less_eq(x,b1) )
+    for(i=0; i<=cnteq-1; i++)
     {
-        result = b1;
-        return result;
+        j = i1+cntless+cnteq-1-i;
+        k = i2+i-(cnteq-1);
+        a->ptr.p_double[j] = bufa->ptr.p_double[k];
     }
-    if( ae_fp_greater_eq(x,b2) )
+    for(i=0; i<=cntgreater-1; i++)
     {
-        result = b2;
-        return result;
+        j = i1+cntless+cnteq+i;
+        k = i1+i;
+        a->ptr.p_double[j] = bufa->ptr.p_double[k];
     }
-    result = x;
-    return result;
-}
-
-
-ae_bool _apbuffers_init(apbuffers* p, ae_state *_state, ae_bool make_automatic)
-{
-    if( !ae_vector_init(&p->ia1, 0, DT_INT, _state, make_automatic) )
-        return ae_false;
-    if( !ae_vector_init(&p->ia2, 0, DT_INT, _state, make_automatic) )
-        return ae_false;
-    if( !ae_vector_init(&p->ra1, 0, DT_REAL, _state, make_automatic) )
-        return ae_false;
-    if( !ae_vector_init(&p->ra2, 0, DT_REAL, _state, make_automatic) )
-        return ae_false;
-    return ae_true;
-}
-
-
-ae_bool _apbuffers_init_copy(apbuffers* dst, apbuffers* src, ae_state *_state, ae_bool make_automatic)
-{
-    if( !ae_vector_init_copy(&dst->ia1, &src->ia1, _state, make_automatic) )
-        return ae_false;
-    if( !ae_vector_init_copy(&dst->ia2, &src->ia2, _state, make_automatic) )
-        return ae_false;
-    if( !ae_vector_init_copy(&dst->ra1, &src->ra1, _state, make_automatic) )
-        return ae_false;
-    if( !ae_vector_init_copy(&dst->ra2, &src->ra2, _state, make_automatic) )
-        return ae_false;
-    return ae_true;
-}
-
-
-void _apbuffers_clear(apbuffers* p)
-{
-    ae_vector_clear(&p->ia1);
-    ae_vector_clear(&p->ia2);
-    ae_vector_clear(&p->ra1);
-    ae_vector_clear(&p->ra2);
+    
+    /*
+     * Sort left and right parts of the array (ignoring middle part)
+     */
+    tsort_tagsortfastrec(a, bufa, i1, i1+cntless-1, _state);
+    tsort_tagsortfastrec(a, bufa, i1+cntless+cnteq, i2, _state);
 }
 
 
@@ -7911,6 +8470,22 @@ IF  NO  STEP  CAN BE FOUND  WHICH  SATISFIES  BOTH  CONDITIONS,  THEN  THE
 ALGORITHM  USUALLY STOPS  WHEN  ROUNDING ERRORS  PREVENT FURTHER PROGRESS.
 IN THIS CASE STP ONLY SATISFIES THE SUFFICIENT DECREASE CONDITION.
 
+
+:::::::::::::IMPORTANT NOTES:::::::::::::
+
+NOTE 1:
+
+This routine  guarantees that it will stop at the last point where function
+value was calculated. It won't make several additional function evaluations
+after finding good point. So if you store function evaluations requested by
+this routine, you can be sure that last one is the point where we've stopped.
+
+NOTE 2:
+
+when 0<StpMax<StpMin, algorithm will terminate with INFO=5 and Stp=0.0
+:::::::::::::::::::::::::::::::::::::::::
+
+
 PARAMETERS DESCRIPRION
 
 STAGE IS ZERO ON FIRST CALL, ZERO ON FINAL EXIT
@@ -7978,6 +8553,7 @@ void mcsrch(ae_int_t n,
      /* Real    */ ae_vector* s,
      double* stp,
      double stpmax,
+     double gtol,
      ae_int_t* info,
      ae_int_t* nfev,
      /* Real    */ ae_vector* wa,
@@ -8034,7 +8610,13 @@ void mcsrch(ae_int_t n,
             /*
              *     CHECK THE INPUT PARAMETERS FOR ERRORS.
              */
-            if( ((((((n<=0||ae_fp_less_eq(*stp,0))||ae_fp_less(linmin_ftol,0))||ae_fp_less(linmin_gtol,zero))||ae_fp_less(linmin_xtol,zero))||ae_fp_less(linmin_stpmin,zero))||ae_fp_less(stpmax,linmin_stpmin))||linmin_maxfev<=0 )
+            if( ae_fp_less(stpmax,linmin_stpmin)&&ae_fp_greater(stpmax,0) )
+            {
+                *info = 5;
+                *stp = 0.0;
+                return;
+            }
+            if( ((((((n<=0||ae_fp_less_eq(*stp,0))||ae_fp_less(linmin_ftol,0))||ae_fp_less(gtol,zero))||ae_fp_less(linmin_xtol,zero))||ae_fp_less(linmin_stpmin,zero))||ae_fp_less(stpmax,linmin_stpmin))||linmin_maxfev<=0 )
             {
                 *stage = 0;
                 return;
@@ -8179,7 +8761,7 @@ void mcsrch(ae_int_t n,
             {
                 *info = 2;
             }
-            if( ae_fp_less_eq(*f,state->ftest1)&&ae_fp_less_eq(ae_fabs(state->dg, _state),-linmin_gtol*state->dginit) )
+            if( ae_fp_less_eq(*f,state->ftest1)&&ae_fp_less_eq(ae_fabs(state->dg, _state),-gtol*state->dginit) )
             {
                 *info = 1;
             }
@@ -8197,7 +8779,7 @@ void mcsrch(ae_int_t n,
              *        IN THE FIRST STAGE WE SEEK A STEP FOR WHICH THE MODIFIED
              *        FUNCTION HAS A NONPOSITIVE VALUE AND NONNEGATIVE DERIVATIVE.
              */
-            if( (state->stage1&&ae_fp_less_eq(*f,state->ftest1))&&ae_fp_greater_eq(state->dg,ae_minreal(linmin_ftol, linmin_gtol, _state)*state->dginit) )
+            if( (state->stage1&&ae_fp_less_eq(*f,state->ftest1))&&ae_fp_greater_eq(state->dg,ae_minreal(linmin_ftol, gtol, _state)*state->dginit) )
             {
                 state->stage1 = ae_false;
             }
@@ -8960,6 +9542,62 @@ void _armijostate_clear(armijostate* p)
 
 
 
+/*************************************************************************
+This subroutine is used to prepare threshold value which will be used for
+trimming of the target function (see comments on TrimFunction() for more
+information).
+
+This function accepts only one parameter: function value at the starting
+point. It returns threshold which will be used for trimming.
+
+  -- ALGLIB --
+     Copyright 10.05.2011 by Bochkanov Sergey
+*************************************************************************/
+void trimprepare(double f, double* threshold, ae_state *_state)
+{
+
+    *threshold = 0;
+
+    *threshold = 10*(ae_fabs(f, _state)+1);
+}
+
+
+/*************************************************************************
+This subroutine is used to "trim" target function, i.e. to do following
+transformation:
+
+                   { {F,G}          if F<Threshold
+    {F_tr, G_tr} = {
+                   { {Threshold, 0} if F>=Threshold
+                   
+Such transformation allows us to  solve  problems  with  singularities  by
+redefining function in such way that it becomes bounded from above.
+
+  -- ALGLIB --
+     Copyright 10.05.2011 by Bochkanov Sergey
+*************************************************************************/
+void trimfunction(double* f,
+     /* Real    */ ae_vector* g,
+     ae_int_t n,
+     double threshold,
+     ae_state *_state)
+{
+    ae_int_t i;
+
+
+    if( ae_fp_greater_eq(*f,threshold) )
+    {
+        *f = threshold;
+        for(i=0; i<=n-1; i++)
+        {
+            g->ptr.p_double[i] = 0.0;
+        }
+    }
+}
+
+
+
+
 /*************************************************************************
 This subroutine generates FFT plan - a decomposition of a N-length FFT to
 the more simpler operations. Plan consists of the root entry and the child
diff --git a/contrib/lbfgs/alglibinternal.h b/contrib/lbfgs/alglibinternal.h
index ee81f195c0dbc235b1abdbae288370ae7fd134e6..d017f8e3e2d102970a2505670e9d81e3be25b88f 100755
--- a/contrib/lbfgs/alglibinternal.h
+++ b/contrib/lbfgs/alglibinternal.h
@@ -30,10 +30,14 @@ namespace alglib_impl
 {
 typedef struct
 {
+    ae_vector ia0;
     ae_vector ia1;
     ae_vector ia2;
+    ae_vector ia3;
+    ae_vector ra0;
     ae_vector ra1;
     ae_vector ra2;
+    ae_vector ra3;
 } apbuffers;
 typedef struct
 {
@@ -107,43 +111,9 @@ namespace alglib
 /////////////////////////////////////////////////////////////////////////
 namespace alglib_impl
 {
-void tagsort(/* Real    */ ae_vector* a,
-     ae_int_t n,
-     /* Integer */ ae_vector* p1,
-     /* Integer */ ae_vector* p2,
-     ae_state *_state);
-void tagsortfasti(/* Real    */ ae_vector* a,
-     /* Integer */ ae_vector* b,
-     /* Real    */ ae_vector* bufa,
-     /* Integer */ ae_vector* bufb,
-     ae_int_t n,
-     ae_state *_state);
-void tagsortfastr(/* Real    */ ae_vector* a,
-     /* Real    */ ae_vector* b,
-     /* Real    */ ae_vector* bufa,
-     /* Real    */ ae_vector* bufb,
-     ae_int_t n,
-     ae_state *_state);
-void tagsortfast(/* Real    */ ae_vector* a,
-     /* Real    */ ae_vector* bufa,
-     ae_int_t n,
-     ae_state *_state);
-void tagheappushi(/* Real    */ ae_vector* a,
-     /* Integer */ ae_vector* b,
-     ae_int_t* n,
-     double va,
-     ae_int_t vb,
-     ae_state *_state);
-void tagheapreplacetopi(/* Real    */ ae_vector* a,
-     /* Integer */ ae_vector* b,
-     ae_int_t n,
-     double va,
-     ae_int_t vb,
-     ae_state *_state);
-void tagheappopi(/* Real    */ ae_vector* a,
-     /* Integer */ ae_vector* b,
-     ae_int_t* n,
-     ae_state *_state);
+ae_int_t getrdfserializationcode(ae_state *_state);
+ae_int_t getkdtreeserializationcode(ae_state *_state);
+ae_int_t getmlpserializationcode(ae_state *_state);
 void taskgenint1d(double a,
      double b,
      ae_int_t n,
@@ -174,6 +144,9 @@ ae_bool aredistinct(/* Real    */ ae_vector* x,
 void bvectorsetlengthatleast(/* Boolean */ ae_vector* x,
      ae_int_t n,
      ae_state *_state);
+void ivectorsetlengthatleast(/* Integer */ ae_vector* x,
+     ae_int_t n,
+     ae_state *_state);
 void rvectorsetlengthatleast(/* Real    */ ae_vector* x,
      ae_int_t n,
      ae_state *_state);
@@ -181,6 +154,10 @@ void rmatrixsetlengthatleast(/* Real    */ ae_matrix* x,
      ae_int_t m,
      ae_int_t n,
      ae_state *_state);
+void rmatrixresize(/* Real    */ ae_matrix* x,
+     ae_int_t m,
+     ae_int_t n,
+     ae_state *_state);
 ae_bool isfinitevector(/* Real    */ ae_vector* x,
      ae_int_t n,
      ae_state *_state);
@@ -217,9 +194,106 @@ void apperiodicmap(double* x,
      double* k,
      ae_state *_state);
 double boundval(double x, double b1, double b2, ae_state *_state);
+void alloccomplex(ae_serializer* s, ae_complex v, ae_state *_state);
+void serializecomplex(ae_serializer* s, ae_complex v, ae_state *_state);
+ae_complex unserializecomplex(ae_serializer* s, ae_state *_state);
+void allocrealarray(ae_serializer* s,
+     /* Real    */ ae_vector* v,
+     ae_int_t n,
+     ae_state *_state);
+void serializerealarray(ae_serializer* s,
+     /* Real    */ ae_vector* v,
+     ae_int_t n,
+     ae_state *_state);
+void unserializerealarray(ae_serializer* s,
+     /* Real    */ ae_vector* v,
+     ae_state *_state);
+void allocintegerarray(ae_serializer* s,
+     /* Integer */ ae_vector* v,
+     ae_int_t n,
+     ae_state *_state);
+void serializeintegerarray(ae_serializer* s,
+     /* Integer */ ae_vector* v,
+     ae_int_t n,
+     ae_state *_state);
+void unserializeintegerarray(ae_serializer* s,
+     /* Integer */ ae_vector* v,
+     ae_state *_state);
+void allocrealmatrix(ae_serializer* s,
+     /* Real    */ ae_matrix* v,
+     ae_int_t n0,
+     ae_int_t n1,
+     ae_state *_state);
+void serializerealmatrix(ae_serializer* s,
+     /* Real    */ ae_matrix* v,
+     ae_int_t n0,
+     ae_int_t n1,
+     ae_state *_state);
+void unserializerealmatrix(ae_serializer* s,
+     /* Real    */ ae_matrix* v,
+     ae_state *_state);
+void copyintegerarray(/* Integer */ ae_vector* src,
+     /* Integer */ ae_vector* dst,
+     ae_state *_state);
+void copyrealarray(/* Real    */ ae_vector* src,
+     /* Real    */ ae_vector* dst,
+     ae_state *_state);
+void copyrealmatrix(/* Real    */ ae_matrix* src,
+     /* Real    */ ae_matrix* dst,
+     ae_state *_state);
+ae_int_t recsearch(/* Integer */ ae_vector* a,
+     ae_int_t nrec,
+     ae_int_t nheader,
+     ae_int_t i0,
+     ae_int_t i1,
+     /* Integer */ ae_vector* b,
+     ae_state *_state);
 ae_bool _apbuffers_init(apbuffers* p, ae_state *_state, ae_bool make_automatic);
 ae_bool _apbuffers_init_copy(apbuffers* dst, apbuffers* src, ae_state *_state, ae_bool make_automatic);
 void _apbuffers_clear(apbuffers* p);
+void tagsort(/* Real    */ ae_vector* a,
+     ae_int_t n,
+     /* Integer */ ae_vector* p1,
+     /* Integer */ ae_vector* p2,
+     ae_state *_state);
+void tagsortbuf(/* Real    */ ae_vector* a,
+     ae_int_t n,
+     /* Integer */ ae_vector* p1,
+     /* Integer */ ae_vector* p2,
+     apbuffers* buf,
+     ae_state *_state);
+void tagsortfasti(/* Real    */ ae_vector* a,
+     /* Integer */ ae_vector* b,
+     /* Real    */ ae_vector* bufa,
+     /* Integer */ ae_vector* bufb,
+     ae_int_t n,
+     ae_state *_state);
+void tagsortfastr(/* Real    */ ae_vector* a,
+     /* Real    */ ae_vector* b,
+     /* Real    */ ae_vector* bufa,
+     /* Real    */ ae_vector* bufb,
+     ae_int_t n,
+     ae_state *_state);
+void tagsortfast(/* Real    */ ae_vector* a,
+     /* Real    */ ae_vector* bufa,
+     ae_int_t n,
+     ae_state *_state);
+void tagheappushi(/* Real    */ ae_vector* a,
+     /* Integer */ ae_vector* b,
+     ae_int_t* n,
+     double va,
+     ae_int_t vb,
+     ae_state *_state);
+void tagheapreplacetopi(/* Real    */ ae_vector* a,
+     /* Integer */ ae_vector* b,
+     ae_int_t n,
+     double va,
+     ae_int_t vb,
+     ae_state *_state);
+void tagheappopi(/* Real    */ ae_vector* a,
+     /* Integer */ ae_vector* b,
+     ae_int_t* n,
+     ae_state *_state);
 void rankx(/* Real    */ ae_vector* x,
      ae_int_t n,
      apbuffers* buf,
@@ -643,6 +717,7 @@ void mcsrch(ae_int_t n,
      /* Real    */ ae_vector* s,
      double* stp,
      double stpmax,
+     double gtol,
      ae_int_t* info,
      ae_int_t* nfev,
      /* Real    */ ae_vector* wa,
@@ -670,6 +745,12 @@ void _linminstate_clear(linminstate* p);
 ae_bool _armijostate_init(armijostate* p, ae_state *_state, ae_bool make_automatic);
 ae_bool _armijostate_init_copy(armijostate* dst, armijostate* src, ae_state *_state, ae_bool make_automatic);
 void _armijostate_clear(armijostate* p);
+void trimprepare(double f, double* threshold, ae_state *_state);
+void trimfunction(double* f,
+     /* Real    */ ae_vector* g,
+     ae_int_t n,
+     double threshold,
+     ae_state *_state);
 void ftbasegeneratecomplexfftplan(ae_int_t n,
      ftplan* plan,
      ae_state *_state);
diff --git a/contrib/lbfgs/alglibmisc.cpp b/contrib/lbfgs/alglibmisc.cpp
index c1cd80cff96a81e9dad42504ce9004bef626e0d3..e1f201cdd55413ef0c098212b703f4fbca9cdb4c 100755
--- a/contrib/lbfgs/alglibmisc.cpp
+++ b/contrib/lbfgs/alglibmisc.cpp
@@ -405,6 +405,87 @@ kdtree::~kdtree()
 {
 }
 
+
+/*************************************************************************
+This function serializes data structure to string.
+
+Important properties of s_out:
+* it contains alphanumeric characters, dots, underscores, minus signs
+* these symbols are grouped into words, which are separated by spaces
+  and Windows-style (CR+LF) newlines
+* although  serializer  uses  spaces and CR+LF as separators, you can 
+  replace any separator character by arbitrary combination of spaces,
+  tabs, Windows or Unix newlines. It allows flexible reformatting  of
+  the  string  in  case you want to include it into text or XML file. 
+  But you should not insert separators into the middle of the "words"
+  nor you should change case of letters.
+* s_out can be freely moved between 32-bit and 64-bit systems, little
+  and big endian machines, and so on. You can serialize structure  on
+  32-bit machine and unserialize it on 64-bit one (or vice versa), or
+  serialize  it  on  SPARC  and  unserialize  on  x86.  You  can also 
+  serialize  it  in  C++ version of ALGLIB and unserialize in C# one, 
+  and vice versa.
+*************************************************************************/
+void kdtreeserialize(kdtree &obj, std::string &s_out)
+{
+    alglib_impl::ae_state state;
+    alglib_impl::ae_serializer serializer;
+    alglib_impl::ae_int_t ssize;
+
+    alglib_impl::ae_state_init(&state);
+    try
+    {
+        alglib_impl::ae_serializer_init(&serializer);
+        alglib_impl::ae_serializer_alloc_start(&serializer);
+        alglib_impl::kdtreealloc(&serializer, obj.c_ptr(), &state);
+        ssize = alglib_impl::ae_serializer_get_alloc_size(&serializer);
+        s_out.clear();
+        s_out.reserve((size_t)(ssize+1));
+        alglib_impl::ae_serializer_sstart_str(&serializer, &s_out);
+        alglib_impl::kdtreeserialize(&serializer, obj.c_ptr(), &state);
+        alglib_impl::ae_serializer_stop(&serializer);
+        if( s_out.length()>(size_t)ssize )
+            throw ap_error("ALGLIB: serialization integrity error");
+        alglib_impl::ae_serializer_clear(&serializer);
+        alglib_impl::ae_state_clear(&state);
+    }
+    catch(alglib_impl::ae_error_type)
+    {
+        throw ap_error(state.error_msg);
+    }
+    catch(...)
+    {
+        throw;
+    }
+}
+/*************************************************************************
+This function unserializes data structure from string.
+*************************************************************************/
+void kdtreeunserialize(std::string &s_in, kdtree &obj)
+{
+    alglib_impl::ae_state state;
+    alglib_impl::ae_serializer serializer;
+
+    alglib_impl::ae_state_init(&state);
+    try
+    {
+        alglib_impl::ae_serializer_init(&serializer);
+        alglib_impl::ae_serializer_ustart_str(&serializer, &s_in);
+        alglib_impl::kdtreeunserialize(&serializer, obj.c_ptr(), &state);
+        alglib_impl::ae_serializer_stop(&serializer);
+        alglib_impl::ae_serializer_clear(&serializer);
+        alglib_impl::ae_state_clear(&state);
+    }
+    catch(alglib_impl::ae_error_type)
+    {
+        throw ap_error(state.error_msg);
+    }
+    catch(...)
+    {
+        throw;
+    }
+}
+
 /*************************************************************************
 KD-tree creation
 
@@ -1295,6 +1376,7 @@ static ae_int_t hqrnd_hqrndintegerbase(hqrndstate* state,
 
 
 static ae_int_t nearestneighbor_splitnodesize = 6;
+static ae_int_t nearestneighbor_kdtreefirstversion = 0;
 static void nearestneighbor_kdtreesplit(kdtree* kdt,
      ae_int_t i1,
      ae_int_t i2,
@@ -1315,6 +1397,20 @@ static void nearestneighbor_kdtreequerynnrec(kdtree* kdt,
 static void nearestneighbor_kdtreeinitbox(kdtree* kdt,
      /* Real    */ ae_vector* x,
      ae_state *_state);
+static void nearestneighbor_kdtreeallocdatasetindependent(kdtree* kdt,
+     ae_int_t nx,
+     ae_int_t ny,
+     ae_state *_state);
+static void nearestneighbor_kdtreeallocdatasetdependent(kdtree* kdt,
+     ae_int_t n,
+     ae_int_t nx,
+     ae_int_t ny,
+     ae_state *_state);
+static void nearestneighbor_kdtreealloctemporaries(kdtree* kdt,
+     ae_int_t n,
+     ae_int_t nx,
+     ae_int_t ny,
+     ae_state *_state);
 
 
 
@@ -1725,13 +1821,12 @@ void kdtreebuildtagged(/* Real    */ ae_matrix* xy,
     kdt->nx = nx;
     kdt->ny = ny;
     kdt->normtype = normtype;
-    kdt->distmatrixtype = 0;
-    ae_matrix_set_length(&kdt->xy, n, 2*nx+ny, _state);
-    ae_vector_set_length(&kdt->tags, n, _state);
-    ae_vector_set_length(&kdt->idx, n, _state);
-    ae_vector_set_length(&kdt->r, n, _state);
-    ae_vector_set_length(&kdt->x, nx, _state);
-    ae_vector_set_length(&kdt->buf, ae_maxint(n, nx, _state), _state);
+    
+    /*
+     * Allocate
+     */
+    nearestneighbor_kdtreeallocdatasetindependent(kdt, nx, ny, _state);
+    nearestneighbor_kdtreeallocdatasetdependent(kdt, n, nx, ny, _state);
     
     /*
      * Initial fill
@@ -1746,10 +1841,6 @@ void kdtreebuildtagged(/* Real    */ ae_matrix* xy,
     /*
      * Determine bounding box
      */
-    ae_vector_set_length(&kdt->boxmin, nx, _state);
-    ae_vector_set_length(&kdt->boxmax, nx, _state);
-    ae_vector_set_length(&kdt->curboxmin, nx, _state);
-    ae_vector_set_length(&kdt->curboxmax, nx, _state);
     ae_v_move(&kdt->boxmin.ptr.p_double[0], 1, &kdt->xy.ptr.pp_double[0][0], 1, ae_v_len(0,nx-1));
     ae_v_move(&kdt->boxmax.ptr.p_double[0], 1, &kdt->xy.ptr.pp_double[0][0], 1, ae_v_len(0,nx-1));
     for(i=1; i<=n-1; i++)
@@ -2339,6 +2430,111 @@ void kdtreequeryresultsdistancesi(kdtree* kdt,
 }
 
 
+/*************************************************************************
+Serializer: allocation
+
+  -- ALGLIB --
+     Copyright 14.03.2011 by Bochkanov Sergey
+*************************************************************************/
+void kdtreealloc(ae_serializer* s, kdtree* tree, ae_state *_state)
+{
+
+
+    
+    /*
+     * Header
+     */
+    ae_serializer_alloc_entry(s);
+    ae_serializer_alloc_entry(s);
+    
+    /*
+     * Data
+     */
+    ae_serializer_alloc_entry(s);
+    ae_serializer_alloc_entry(s);
+    ae_serializer_alloc_entry(s);
+    ae_serializer_alloc_entry(s);
+    allocrealmatrix(s, &tree->xy, -1, -1, _state);
+    allocintegerarray(s, &tree->tags, -1, _state);
+    allocrealarray(s, &tree->boxmin, -1, _state);
+    allocrealarray(s, &tree->boxmax, -1, _state);
+    allocintegerarray(s, &tree->nodes, -1, _state);
+    allocrealarray(s, &tree->splits, -1, _state);
+}
+
+
+/*************************************************************************
+Serializer: serialization
+
+  -- ALGLIB --
+     Copyright 14.03.2011 by Bochkanov Sergey
+*************************************************************************/
+void kdtreeserialize(ae_serializer* s, kdtree* tree, ae_state *_state)
+{
+
+
+    
+    /*
+     * Header
+     */
+    ae_serializer_serialize_int(s, getkdtreeserializationcode(_state), _state);
+    ae_serializer_serialize_int(s, nearestneighbor_kdtreefirstversion, _state);
+    
+    /*
+     * Data
+     */
+    ae_serializer_serialize_int(s, tree->n, _state);
+    ae_serializer_serialize_int(s, tree->nx, _state);
+    ae_serializer_serialize_int(s, tree->ny, _state);
+    ae_serializer_serialize_int(s, tree->normtype, _state);
+    serializerealmatrix(s, &tree->xy, -1, -1, _state);
+    serializeintegerarray(s, &tree->tags, -1, _state);
+    serializerealarray(s, &tree->boxmin, -1, _state);
+    serializerealarray(s, &tree->boxmax, -1, _state);
+    serializeintegerarray(s, &tree->nodes, -1, _state);
+    serializerealarray(s, &tree->splits, -1, _state);
+}
+
+
+/*************************************************************************
+Serializer: unserialization
+
+  -- ALGLIB --
+     Copyright 14.03.2011 by Bochkanov Sergey
+*************************************************************************/
+void kdtreeunserialize(ae_serializer* s, kdtree* tree, ae_state *_state)
+{
+    ae_int_t i0;
+    ae_int_t i1;
+
+    _kdtree_clear(tree);
+
+    
+    /*
+     * check correctness of header
+     */
+    ae_serializer_unserialize_int(s, &i0, _state);
+    ae_assert(i0==getkdtreeserializationcode(_state), "KDTreeUnserialize: stream header corrupted", _state);
+    ae_serializer_unserialize_int(s, &i1, _state);
+    ae_assert(i1==nearestneighbor_kdtreefirstversion, "KDTreeUnserialize: stream header corrupted", _state);
+    
+    /*
+     * Unserialize data
+     */
+    ae_serializer_unserialize_int(s, &tree->n, _state);
+    ae_serializer_unserialize_int(s, &tree->nx, _state);
+    ae_serializer_unserialize_int(s, &tree->ny, _state);
+    ae_serializer_unserialize_int(s, &tree->normtype, _state);
+    unserializerealmatrix(s, &tree->xy, _state);
+    unserializeintegerarray(s, &tree->tags, _state);
+    unserializerealarray(s, &tree->boxmin, _state);
+    unserializerealarray(s, &tree->boxmax, _state);
+    unserializeintegerarray(s, &tree->nodes, _state);
+    unserializerealarray(s, &tree->splits, _state);
+    nearestneighbor_kdtreealloctemporaries(tree, tree->n, tree->nx, tree->ny, _state);
+}
+
+
 /*************************************************************************
 Rearranges nodes [I1,I2) using partition in D-th dimension with S as threshold.
 Returns split position I3: [I1,I3) and [I3,I2) are created as result.
@@ -2989,6 +3185,86 @@ static void nearestneighbor_kdtreeinitbox(kdtree* kdt,
 }
 
 
+/*************************************************************************
+This function allocates all dataset-independent array  fields  of  KDTree,
+i.e.  such  array  fields  that  their dimensions do not depend on dataset
+size.
+
+This function do not sets KDT.NX or KDT.NY - it just allocates arrays
+
+  -- ALGLIB --
+     Copyright 14.03.2011 by Bochkanov Sergey
+*************************************************************************/
+static void nearestneighbor_kdtreeallocdatasetindependent(kdtree* kdt,
+     ae_int_t nx,
+     ae_int_t ny,
+     ae_state *_state)
+{
+
+
+    ae_vector_set_length(&kdt->x, nx, _state);
+    ae_vector_set_length(&kdt->boxmin, nx, _state);
+    ae_vector_set_length(&kdt->boxmax, nx, _state);
+    ae_vector_set_length(&kdt->curboxmin, nx, _state);
+    ae_vector_set_length(&kdt->curboxmax, nx, _state);
+}
+
+
+/*************************************************************************
+This function allocates all dataset-dependent array fields of KDTree, i.e.
+such array fields that their dimensions depend on dataset size.
+
+This function do not sets KDT.N, KDT.NX or KDT.NY -
+it just allocates arrays.
+
+  -- ALGLIB --
+     Copyright 14.03.2011 by Bochkanov Sergey
+*************************************************************************/
+static void nearestneighbor_kdtreeallocdatasetdependent(kdtree* kdt,
+     ae_int_t n,
+     ae_int_t nx,
+     ae_int_t ny,
+     ae_state *_state)
+{
+
+
+    ae_matrix_set_length(&kdt->xy, n, 2*nx+ny, _state);
+    ae_vector_set_length(&kdt->tags, n, _state);
+    ae_vector_set_length(&kdt->idx, n, _state);
+    ae_vector_set_length(&kdt->r, n, _state);
+    ae_vector_set_length(&kdt->x, nx, _state);
+    ae_vector_set_length(&kdt->buf, ae_maxint(n, nx, _state), _state);
+    ae_vector_set_length(&kdt->nodes, nearestneighbor_splitnodesize*2*n, _state);
+    ae_vector_set_length(&kdt->splits, 2*n, _state);
+}
+
+
+/*************************************************************************
+This function allocates temporaries.
+
+This function do not sets KDT.N, KDT.NX or KDT.NY -
+it just allocates arrays.
+
+  -- ALGLIB --
+     Copyright 14.03.2011 by Bochkanov Sergey
+*************************************************************************/
+static void nearestneighbor_kdtreealloctemporaries(kdtree* kdt,
+     ae_int_t n,
+     ae_int_t nx,
+     ae_int_t ny,
+     ae_state *_state)
+{
+
+
+    ae_vector_set_length(&kdt->x, nx, _state);
+    ae_vector_set_length(&kdt->idx, n, _state);
+    ae_vector_set_length(&kdt->r, n, _state);
+    ae_vector_set_length(&kdt->buf, ae_maxint(n, nx, _state), _state);
+    ae_vector_set_length(&kdt->curboxmin, nx, _state);
+    ae_vector_set_length(&kdt->curboxmax, nx, _state);
+}
+
+
 ae_bool _kdtree_init(kdtree* p, ae_state *_state, ae_bool make_automatic)
 {
     if( !ae_matrix_init(&p->xy, 0, 0, DT_REAL, _state, make_automatic) )
@@ -2999,10 +3275,6 @@ ae_bool _kdtree_init(kdtree* p, ae_state *_state, ae_bool make_automatic)
         return ae_false;
     if( !ae_vector_init(&p->boxmax, 0, DT_REAL, _state, make_automatic) )
         return ae_false;
-    if( !ae_vector_init(&p->curboxmin, 0, DT_REAL, _state, make_automatic) )
-        return ae_false;
-    if( !ae_vector_init(&p->curboxmax, 0, DT_REAL, _state, make_automatic) )
-        return ae_false;
     if( !ae_vector_init(&p->nodes, 0, DT_INT, _state, make_automatic) )
         return ae_false;
     if( !ae_vector_init(&p->splits, 0, DT_REAL, _state, make_automatic) )
@@ -3015,6 +3287,10 @@ ae_bool _kdtree_init(kdtree* p, ae_state *_state, ae_bool make_automatic)
         return ae_false;
     if( !ae_vector_init(&p->buf, 0, DT_REAL, _state, make_automatic) )
         return ae_false;
+    if( !ae_vector_init(&p->curboxmin, 0, DT_REAL, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init(&p->curboxmax, 0, DT_REAL, _state, make_automatic) )
+        return ae_false;
     return ae_true;
 }
 
@@ -3025,7 +3301,6 @@ ae_bool _kdtree_init_copy(kdtree* dst, kdtree* src, ae_state *_state, ae_bool ma
     dst->nx = src->nx;
     dst->ny = src->ny;
     dst->normtype = src->normtype;
-    dst->distmatrixtype = src->distmatrixtype;
     if( !ae_matrix_init_copy(&dst->xy, &src->xy, _state, make_automatic) )
         return ae_false;
     if( !ae_vector_init_copy(&dst->tags, &src->tags, _state, make_automatic) )
@@ -3034,11 +3309,6 @@ ae_bool _kdtree_init_copy(kdtree* dst, kdtree* src, ae_state *_state, ae_bool ma
         return ae_false;
     if( !ae_vector_init_copy(&dst->boxmax, &src->boxmax, _state, make_automatic) )
         return ae_false;
-    if( !ae_vector_init_copy(&dst->curboxmin, &src->curboxmin, _state, make_automatic) )
-        return ae_false;
-    if( !ae_vector_init_copy(&dst->curboxmax, &src->curboxmax, _state, make_automatic) )
-        return ae_false;
-    dst->curdist = src->curdist;
     if( !ae_vector_init_copy(&dst->nodes, &src->nodes, _state, make_automatic) )
         return ae_false;
     if( !ae_vector_init_copy(&dst->splits, &src->splits, _state, make_automatic) )
@@ -3056,6 +3326,11 @@ ae_bool _kdtree_init_copy(kdtree* dst, kdtree* src, ae_state *_state, ae_bool ma
         return ae_false;
     if( !ae_vector_init_copy(&dst->buf, &src->buf, _state, make_automatic) )
         return ae_false;
+    if( !ae_vector_init_copy(&dst->curboxmin, &src->curboxmin, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init_copy(&dst->curboxmax, &src->curboxmax, _state, make_automatic) )
+        return ae_false;
+    dst->curdist = src->curdist;
     dst->debugcounter = src->debugcounter;
     return ae_true;
 }
@@ -3067,14 +3342,14 @@ void _kdtree_clear(kdtree* p)
     ae_vector_clear(&p->tags);
     ae_vector_clear(&p->boxmin);
     ae_vector_clear(&p->boxmax);
-    ae_vector_clear(&p->curboxmin);
-    ae_vector_clear(&p->curboxmax);
     ae_vector_clear(&p->nodes);
     ae_vector_clear(&p->splits);
     ae_vector_clear(&p->x);
     ae_vector_clear(&p->idx);
     ae_vector_clear(&p->r);
     ae_vector_clear(&p->buf);
+    ae_vector_clear(&p->curboxmin);
+    ae_vector_clear(&p->curboxmax);
 }
 
 
diff --git a/contrib/lbfgs/alglibmisc.h b/contrib/lbfgs/alglibmisc.h
index 491fb3314e5a30af380424cbd60ed7834f052399..f60b46d69f49d786c7ae49d2b53afa4a269c5094 100755
--- a/contrib/lbfgs/alglibmisc.h
+++ b/contrib/lbfgs/alglibmisc.h
@@ -41,14 +41,10 @@ typedef struct
     ae_int_t nx;
     ae_int_t ny;
     ae_int_t normtype;
-    ae_int_t distmatrixtype;
     ae_matrix xy;
     ae_vector tags;
     ae_vector boxmin;
     ae_vector boxmax;
-    ae_vector curboxmin;
-    ae_vector curboxmax;
-    double curdist;
     ae_vector nodes;
     ae_vector splits;
     ae_vector x;
@@ -60,6 +56,9 @@ typedef struct
     ae_vector idx;
     ae_vector r;
     ae_vector buf;
+    ae_vector curboxmin;
+    ae_vector curboxmax;
+    double curdist;
     ae_int_t debugcounter;
 } kdtree;
 
@@ -222,6 +221,35 @@ State structure must be initialized with HQRNDRandomize() or HQRNDSeed().
 *************************************************************************/
 double hqrndexponential(const hqrndstate &state, const double lambdav);
 
+/*************************************************************************
+This function serializes data structure to string.
+
+Important properties of s_out:
+* it contains alphanumeric characters, dots, underscores, minus signs
+* these symbols are grouped into words, which are separated by spaces
+  and Windows-style (CR+LF) newlines
+* although  serializer  uses  spaces and CR+LF as separators, you can 
+  replace any separator character by arbitrary combination of spaces,
+  tabs, Windows or Unix newlines. It allows flexible reformatting  of
+  the  string  in  case you want to include it into text or XML file. 
+  But you should not insert separators into the middle of the "words"
+  nor you should change case of letters.
+* s_out can be freely moved between 32-bit and 64-bit systems, little
+  and big endian machines, and so on. You can serialize structure  on
+  32-bit machine and unserialize it on 64-bit one (or vice versa), or
+  serialize  it  on  SPARC  and  unserialize  on  x86.  You  can also 
+  serialize  it  in  C++ version of ALGLIB and unserialize in C# one, 
+  and vice versa.
+*************************************************************************/
+void kdtreeserialize(kdtree &obj, std::string &s_out);
+
+
+/*************************************************************************
+This function unserializes data structure from string.
+*************************************************************************/
+void kdtreeunserialize(std::string &s_in, kdtree &obj);
+
+
 /*************************************************************************
 KD-tree creation
 
@@ -676,6 +704,9 @@ void kdtreequeryresultstagsi(kdtree* kdt,
 void kdtreequeryresultsdistancesi(kdtree* kdt,
      /* Real    */ ae_vector* r,
      ae_state *_state);
+void kdtreealloc(ae_serializer* s, kdtree* tree, ae_state *_state);
+void kdtreeserialize(ae_serializer* s, kdtree* tree, ae_state *_state);
+void kdtreeunserialize(ae_serializer* s, kdtree* tree, ae_state *_state);
 ae_bool _kdtree_init(kdtree* p, ae_state *_state, ae_bool make_automatic);
 ae_bool _kdtree_init_copy(kdtree* dst, kdtree* src, ae_state *_state, ae_bool make_automatic);
 void _kdtree_clear(kdtree* p);
diff --git a/contrib/lbfgs/ap.cpp b/contrib/lbfgs/ap.cpp
index 14bfb10910a813e1013f1580d6596852d3c89daf..5abdba4188e5397ed700f09f255df51db07e07e6 100755
--- a/contrib/lbfgs/ap.cpp
+++ b/contrib/lbfgs/ap.cpp
@@ -60,6 +60,15 @@ namespace alglib_impl
 #define AE_LITTLE_ENDIAN 1
 #define AE_BIG_ENDIAN 2
 #define AE_MIXED_ENDIAN 3
+#define AE_SER_ENTRY_LENGTH 11
+#define AE_SER_ENTRIES_PER_ROW 5
+
+#define AE_SM_DEFAULT 0
+#define AE_SM_ALLOC 1
+#define AE_SM_READY2S 2
+#define AE_SM_TO_STRING 10
+#define AE_SM_FROM_STRING 20
+#define AE_SM_TO_CPPSTRING 11
 
 
 /*
@@ -1013,10 +1022,12 @@ Note: results of this function depend on both CPU and compiler;
 if compiler doesn't support SSE intrinsics, function won't set 
 corresponding flag.
 ************************************************************************/
+static volatile ae_bool _ae_cpuid_initialized = ae_false;
+static volatile ae_bool _ae_cpuid_has_sse2 = ae_false;
 ae_int_t ae_cpuid()
 {
     /*
-     * to speed up CPU detection we cache our data in the static vars.
+     * to speed up CPU detection we cache results from previous attempts
      * there is no synchronization, but it is still thread safe.
      *
      * thread safety is guaranteed on all modern architectures which
@@ -1024,29 +1035,39 @@ ae_int_t ae_cpuid()
      * to the same location will be executed in serial manner.
      *
      */
-    static ae_bool initialized = ae_false;
-    static ae_bool has_sse2 = ae_false;
     ae_int_t result;
     
     /*
      * if not initialized, determine system properties
      */
-    if( !initialized )
+    if( !_ae_cpuid_initialized )
     {
         /*
          * SSE2
          */
 #if defined(AE_CPU)
 #if (AE_CPU==AE_INTEL) && defined(AE_HAS_SSE2_INTRINSICS)
-#if AE_COMPILER==AE_GNUC
-#elif AE_COMPILER==AE_MSVC
+#if AE_COMPILER==AE_MSVC
         {
             int CPUInfo[4];
             __cpuid(CPUInfo, 1);
             if( (CPUInfo[3]&0x04000000)!=0 )
-                has_sse2 = ae_true;
+                _ae_cpuid_has_sse2 = ae_true;
+        }
+#elif AE_COMPILER==AE_GNUC
+        {
+            ae_int_t a,b,c,d;
+            __asm__ __volatile__ ("cpuid": "=a" (a), "=b" (b), "=c" (c), "=d" (d) : "a" (1));
+            if( (d&0x04000000)!=0 )
+                _ae_cpuid_has_sse2 = ae_true;
         }
 #elif AE_COMPILER==AE_SUNC
+        {
+            ae_int_t a,b,c,d;
+            __asm__ __volatile__ ("cpuid": "=a" (a), "=b" (b), "=c" (c), "=d" (d) : "a" (1));
+            if( (d&0x04000000)!=0 )
+                _ae_cpuid_has_sse2 = ae_true;
+        }
 #else
 #endif
 #endif
@@ -1054,14 +1075,14 @@ ae_int_t ae_cpuid()
         /*
          * set initialization flag
          */
-        initialized = ae_true;
+        _ae_cpuid_initialized = ae_true;
     }
     
     /*
      * return
      */
     result = 0;
-    if( has_sse2 )
+    if( _ae_cpuid_has_sse2 )
         result = result|CPU_SSE2;
     return result;
 }
@@ -1173,7 +1194,7 @@ ae_bool ae_isinf_stateless(double x,    ae_int_t endianness)
         low  = u.p[1];
     }
     
-    // 31 least significant bits of high are compared
+    /* 31 least significant bits of high are compared */
     return ((high&0x7FFFFFFF)==0x7FF00000) && (low==0); 
 }
 
@@ -1197,7 +1218,7 @@ ae_bool ae_isposinf_stateless(double x, ae_int_t endianness)
         low  = u.p[1];
     }
     
-    // all 32 bits of high are compared
+    /* all 32 bits of high are compared */
     return (high==(ae_int32_t)0x7FF00000) && (low==0); 
 }
 
@@ -1221,7 +1242,7 @@ ae_bool ae_isneginf_stateless(double x, ae_int_t endianness)
         low  = u.p[1];
     }
     
-    // this code is a bit tricky to avoid comparison of high with 0xFFF00000, which may be unsafe with some buggy compilers
+    /* this code is a bit tricky to avoid comparison of high with 0xFFF00000, which may be unsafe with some buggy compilers */
     return ((high&0x7FFFFFFF)==0x7FF00000) && (high!=(ae_int32_t)0x7FF00000) && (low==0);
 }
 
@@ -2011,6 +2032,657 @@ ae_bool ae_force_hermitian(ae_matrix *a)
     return x_force_hermitian(&x);
 }
 
+/************************************************************************
+This function converts six-bit value (from 0 to 63)  to  character  (only
+digits, lowercase and uppercase letters, minus and underscore are used).
+
+If v is negative or greater than 63, this function returns '?'.
+************************************************************************/
+static char _sixbits2char_tbl[64] = { 
+        '0', '1', '2', '3', '4', '5', '6', '7',
+        '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
+        'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
+        'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
+        'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 
+        'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 
+        'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 
+        'u', 'v', 'w', 'x', 'y', 'z', '-', '_' };
+
+char ae_sixbits2char(ae_int_t v)
+{
+    
+    if( v<0 || v>63 )
+        return '?';
+    return _sixbits2char_tbl[v]; 
+    
+    /* v is correct, process it */
+    /*if( v<10 )
+        return '0'+v;
+    v -= 10;
+    if( v<26 )
+        return 'A'+v;
+    v -= 26;
+    if( v<26 )
+        return 'a'+v;
+    v -= 26;
+    return v==0 ? '-' : '_';*/
+}
+
+/************************************************************************
+This function converts character to six-bit value (from 0 to 63).
+
+This function is inverse of ae_sixbits2char()
+If c is not correct character, this function returns -1.
+************************************************************************/
+static ae_int_t _ae_char2sixbits_tbl[] = {
+    -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, 62, -1, -1,
+     0,  1,  2,  3,  4,  5,  6,  7,
+     8,  9, -1, -1, -1, -1, -1, -1,
+    -1, 10, 11, 12, 13, 14, 15, 16,
+    17, 18, 19, 20, 21, 22, 23, 24,
+    25, 26, 27, 28, 29, 30, 31, 32,
+    33, 34, 35, -1, -1, -1, -1, 63,
+    -1, 36, 37, 38, 39, 40, 41, 42,
+    43, 44, 45, 46, 47, 48, 49, 50,
+    51, 52, 53, 54, 55, 56, 57, 58,
+    59, 60, 61, -1, -1, -1, -1, -1 };
+ae_int_t ae_char2sixbits(char c)
+{
+    return (c>=0 && c<127) ? _ae_char2sixbits_tbl[c] : -1;
+}
+
+/************************************************************************
+This function converts three bytes (24 bits) to four six-bit values 
+(24 bits again).
+
+src     pointer to three bytes
+dst     pointer to four ints
+************************************************************************/
+void ae_threebytes2foursixbits(const unsigned char *src, ae_int_t *dst)
+{
+    dst[0] = src[0] & 0x3F;
+    dst[1] = (src[0]>>6) | ((src[1]&0x0F)<<2);
+    dst[2] = (src[1]>>4) | ((src[2]&0x03)<<4);
+    dst[3] = src[2]>>2;
+}
+
+/************************************************************************
+This function converts four six-bit values (24 bits) to three bytes
+(24 bits again).
+
+src     pointer to four ints
+dst     pointer to three bytes
+************************************************************************/
+void ae_foursixbits2threebytes(const ae_int_t *src, unsigned char *dst)
+{
+    dst[0] = (unsigned char)(     src[0] | ((src[1]&0x03)<<6));
+    dst[1] = (unsigned char)((src[1]>>2) | ((src[2]&0x0F)<<4));
+    dst[2] = (unsigned char)((src[2]>>4) | (src[3]<<2));
+}
+
+/************************************************************************
+This function serializes boolean value into buffer
+
+v           boolean value to be serialized
+buf         buffer, at least 12 characters wide 
+            (11 chars for value, one for trailing zero)
+state       ALGLIB environment state
+************************************************************************/
+void ae_bool2str(ae_bool v, char *buf, ae_state *state)
+{
+    char c = v ? '1' : '0';
+    ae_int_t i;
+    for(i=0; i<AE_SER_ENTRY_LENGTH; i++)
+        buf[i] = c;
+    buf[AE_SER_ENTRY_LENGTH] = 0;
+}
+
+/************************************************************************
+This function unserializes boolean value from buffer
+
+buf         buffer which contains value; leading spaces/tabs/newlines are 
+            ignored, traling spaces/tabs/newlines are treated as  end  of
+            the boolean value.
+state       ALGLIB environment state
+
+This function raises an error in case unexpected symbol is found
+************************************************************************/
+ae_bool ae_str2bool(const char *buf, ae_state *state, const char **pasttheend)
+{
+    ae_bool was0, was1;
+    const char *emsg = "ALGLIB: unable to read boolean value from stream";
+    
+    was0 = ae_false;
+    was1 = ae_false;
+    while( *buf==' ' || *buf=='\t' || *buf=='\n' || *buf=='\r' )
+        buf++;
+    while( *buf!=' ' && *buf!='\t' && *buf!='\n' && *buf!='\r' && *buf!=0 )
+    {
+        if( *buf=='0' )
+        {
+            was0 = ae_true;
+            buf++;
+            continue;
+        }
+        if( *buf=='1' )
+        {
+            was1 = ae_true;
+            buf++;
+            continue;
+        }
+        ae_break(state, ERR_ASSERTION_FAILED, emsg);
+    }
+    *pasttheend = buf;
+    if( (!was0) && (!was1) )
+        ae_break(state, ERR_ASSERTION_FAILED, emsg);
+    if( was0 && was1 )
+        ae_break(state, ERR_ASSERTION_FAILED, emsg);
+    return was1 ? ae_true : ae_false;
+}
+
+/************************************************************************
+This function serializes integer value into buffer
+
+v           integer value to be serialized
+buf         buffer, at least 12 characters wide 
+            (11 chars for value, one for trailing zero)
+state       ALGLIB environment state
+************************************************************************/
+void ae_int2str(ae_int_t v, char *buf, ae_state *state)
+{
+    union _u
+    {
+        ae_int_t ival;
+        unsigned char bytes[9];
+    } u;
+    ae_int_t i;
+    ae_int_t sixbits[12];
+    unsigned char c;
+    
+    /*
+     * copy v to array of chars, sign extending it and 
+     * converting to little endian order
+     *
+     * because we don't want to mention size of ae_int_t explicitly, 
+     * we do it as follows:
+     * 1. we fill u.bytes by zeros or ones (depending on sign of v)
+     * 2. we copy v to u.ival
+     * 3. if we run on big endian architecture, we reorder u.bytes
+     * 4. now we have signed 64-bit representation of v stored in u.bytes
+     * 5. additionally, we set 9th byte of u.bytes to zero in order to
+     *    simplify conversion to six-bit representation
+     */
+    c = v<0 ? (unsigned char)0xFF : (unsigned char)0x00;
+    u.ival = v;
+    for(i=sizeof(ae_int_t); i<=8; i++) /* <=8 is preferred because it avoids unnecessary compiler warnings*/
+        u.bytes[i] = c;
+    u.bytes[8] = 0;
+    if( state->endianness==AE_BIG_ENDIAN )
+    {
+        for(i=0; i<sizeof(ae_int_t)/2; i++)
+        {
+            unsigned char tc;
+            tc = u.bytes[i];
+            u.bytes[i] = u.bytes[sizeof(ae_int_t)-1-i];
+            u.bytes[sizeof(ae_int_t)-1-i] = tc;
+        }
+    }
+    
+    /*
+     * convert to six-bit representation, output
+     *
+     * NOTE: last 12th element of sixbits is always zero, we do not output it
+     */
+    ae_threebytes2foursixbits(u.bytes+0, sixbits+0);
+    ae_threebytes2foursixbits(u.bytes+3, sixbits+4);
+    ae_threebytes2foursixbits(u.bytes+6, sixbits+8);        
+    for(i=0; i<AE_SER_ENTRY_LENGTH; i++)
+        buf[i] = ae_sixbits2char(sixbits[i]);
+    buf[AE_SER_ENTRY_LENGTH] = 0x00;
+}
+
+/************************************************************************
+This function unserializes integer value from string
+
+buf         buffer which contains value; leading spaces/tabs/newlines are 
+            ignored, traling spaces/tabs/newlines are treated as  end  of
+            the boolean value.
+state       ALGLIB environment state
+
+This function raises an error in case unexpected symbol is found
+************************************************************************/
+ae_int_t ae_str2int(const char *buf, ae_state *state, const char **pasttheend)
+{
+    const char *emsg = "ALGLIB: unable to read integer value from stream";
+    ae_int_t sixbits[12];
+    ae_int_t sixbitsread, i;
+    union _u
+    {
+        ae_int_t ival;
+        unsigned char bytes[9];
+    } u;
+    /* 
+     * 1. skip leading spaces
+     * 2. read and decode six-bit digits
+     * 3. set trailing digits to zeros
+     * 4. convert to little endian 64-bit integer representation
+     * 5. convert to big endian representation, if needed
+     */
+    while( *buf==' ' || *buf=='\t' || *buf=='\n' || *buf=='\r' )
+        buf++;
+    sixbitsread = 0;
+    while( *buf!=' ' && *buf!='\t' && *buf!='\n' && *buf!='\r' && *buf!=0 )
+    {
+        ae_int_t d;
+        d = ae_char2sixbits(*buf);
+        if( d<0 || sixbitsread>=AE_SER_ENTRY_LENGTH )
+            ae_break(state, ERR_ASSERTION_FAILED, emsg);
+        sixbits[sixbitsread] = d;
+        sixbitsread++;
+        buf++;
+    }
+    *pasttheend = buf;
+    if( sixbitsread==0 )
+        ae_break(state, ERR_ASSERTION_FAILED, emsg);
+    for(i=sixbitsread; i<12; i++)
+        sixbits[i] = 0;
+    ae_foursixbits2threebytes(sixbits+0, u.bytes+0);
+    ae_foursixbits2threebytes(sixbits+4, u.bytes+3);
+    ae_foursixbits2threebytes(sixbits+8, u.bytes+6);
+    if( state->endianness==AE_BIG_ENDIAN )
+    {
+        for(i=0; i<sizeof(ae_int_t)/2; i++)
+        {
+            unsigned char tc;
+            tc = u.bytes[i];
+            u.bytes[i] = u.bytes[sizeof(ae_int_t)-1-i];
+            u.bytes[sizeof(ae_int_t)-1-i] = tc;
+        }
+    }
+    return u.ival;
+}
+
+
+/************************************************************************
+This function serializes double value into buffer
+
+v           double value to be serialized
+buf         buffer, at least 12 characters wide 
+            (11 chars for value, one for trailing zero)
+state       ALGLIB environment state
+************************************************************************/
+void ae_double2str(double v, char *buf, ae_state *state)
+{
+    union _u
+    {
+        double dval;
+        unsigned char bytes[9];
+    } u;
+    ae_int_t i;
+    ae_int_t sixbits[12];
+
+    /*
+     * handle special quantities
+     */
+    if( ae_isnan(v, state) )
+    {
+        const char *s = ".nan_______";
+        memcpy(buf, s, strlen(s)+1);
+        return;
+    }
+    if( ae_isposinf(v, state) )
+    {
+        const char *s = ".posinf____";
+        memcpy(buf, s, strlen(s)+1);
+        return;
+    }
+    if( ae_isneginf(v, state) )
+    {
+        const char *s = ".neginf____";
+        memcpy(buf, s, strlen(s)+1);
+        return;
+    }
+    
+    /*
+     * process general case:
+     * 1. copy v to array of chars
+     * 2. set 9th byte of u.bytes to zero in order to
+     *    simplify conversion to six-bit representation
+     * 3. convert to little endian (if needed)
+     * 4. convert to six-bit representation
+     *    (last 12th element of sixbits is always zero, we do not output it)
+     */
+    u.dval = v;
+    u.bytes[8] = 0;
+    if( state->endianness==AE_BIG_ENDIAN )
+    {
+        for(i=0; i<sizeof(double)/2; i++)
+        {
+            unsigned char tc;
+            tc = u.bytes[i];
+            u.bytes[i] = u.bytes[sizeof(double)-1-i];
+            u.bytes[sizeof(double)-1-i] = tc;
+        }
+    }
+    ae_threebytes2foursixbits(u.bytes+0, sixbits+0);
+    ae_threebytes2foursixbits(u.bytes+3, sixbits+4);
+    ae_threebytes2foursixbits(u.bytes+6, sixbits+8);
+    for(i=0; i<AE_SER_ENTRY_LENGTH; i++)
+        buf[i] = ae_sixbits2char(sixbits[i]);
+    buf[AE_SER_ENTRY_LENGTH] = 0x00;
+}
+
+/************************************************************************
+This function unserializes double value from string
+
+buf         buffer which contains value; leading spaces/tabs/newlines are 
+            ignored, traling spaces/tabs/newlines are treated as  end  of
+            the boolean value.
+state       ALGLIB environment state
+
+This function raises an error in case unexpected symbol is found
+************************************************************************/
+double ae_str2double(const char *buf, ae_state *state, const char **pasttheend)
+{
+    const char *emsg = "ALGLIB: unable to read double value from stream";
+    ae_int_t sixbits[12];
+    ae_int_t sixbitsread, i;
+    union _u
+    {
+        double dval;
+        unsigned char bytes[9];
+    } u;
+    
+    
+     /* 
+      * skip leading spaces
+      */
+    while( *buf==' ' || *buf=='\t' || *buf=='\n' || *buf=='\r' )
+        buf++;
+      
+    /*
+     * Handle special cases
+     */
+    if( *buf=='.' )
+    {
+        const char *s_nan =    ".nan_______";
+        const char *s_posinf = ".posinf____";
+        const char *s_neginf = ".neginf____";
+        if( strncmp(buf, s_nan, strlen(s_nan))==0 )
+        {
+            *pasttheend = buf+strlen(s_nan);
+            return state->v_nan;
+        }
+        if( strncmp(buf, s_posinf, strlen(s_posinf))==0 )
+        {
+            *pasttheend = buf+strlen(s_posinf);
+            return state->v_posinf;
+        }
+        if( strncmp(buf, s_neginf, strlen(s_neginf))==0 )
+        {
+            *pasttheend = buf+strlen(s_neginf);
+            return state->v_neginf;
+        }
+        ae_break(state, ERR_ASSERTION_FAILED, emsg);
+    }
+    
+    /* 
+     * General case:
+     * 1. read and decode six-bit digits
+     * 2. check that all 11 digits were read
+     * 3. set last 12th digit to zero (needed for simplicity of conversion)
+     * 4. convert to 8 bytes
+     * 5. convert to big endian representation, if needed
+     */
+    sixbitsread = 0;
+    while( *buf!=' ' && *buf!='\t' && *buf!='\n' && *buf!='\r' && *buf!=0 )
+    {
+        ae_int_t d;
+        d = ae_char2sixbits(*buf);
+        if( d<0 || sixbitsread>=AE_SER_ENTRY_LENGTH )
+            ae_break(state, ERR_ASSERTION_FAILED, emsg);
+        sixbits[sixbitsread] = d;
+        sixbitsread++;
+        buf++;
+    }
+    *pasttheend = buf;
+    if( sixbitsread!=AE_SER_ENTRY_LENGTH )
+        ae_break(state, ERR_ASSERTION_FAILED, emsg);
+    sixbits[AE_SER_ENTRY_LENGTH] = 0;
+    ae_foursixbits2threebytes(sixbits+0, u.bytes+0);
+    ae_foursixbits2threebytes(sixbits+4, u.bytes+3);
+    ae_foursixbits2threebytes(sixbits+8, u.bytes+6);
+    if( state->endianness==AE_BIG_ENDIAN )
+    {
+        for(i=0; i<sizeof(double)/2; i++)
+        {
+            unsigned char tc;
+            tc = u.bytes[i];
+            u.bytes[i] = u.bytes[sizeof(double)-1-i];
+            u.bytes[sizeof(double)-1-i] = tc;
+        }
+    }
+    return u.dval;
+}
+
+/************************************************************************
+This function initializes serializer
+************************************************************************/
+void ae_serializer_init(ae_serializer *serializer)
+{
+    serializer->mode = AE_SM_DEFAULT;
+    serializer->entries_needed = 0;
+    serializer->bytes_asked = 0;
+}
+
+void ae_serializer_clear(ae_serializer *serializer)
+{
+}
+
+void ae_serializer_alloc_start(ae_serializer *serializer)
+{
+    serializer->entries_needed = 0;
+    serializer->bytes_asked = 0;
+    serializer->mode = AE_SM_ALLOC;
+}
+
+void ae_serializer_alloc_entry(ae_serializer *serializer)
+{
+    serializer->entries_needed++;
+}
+
+ae_int_t ae_serializer_get_alloc_size(ae_serializer *serializer)
+{
+    ae_int_t rows, lastrowsize, result;
+    
+    serializer->mode = AE_SM_READY2S;
+    
+    /* if no entries needes (degenerate case) */
+    if( serializer->entries_needed==0 )
+    {
+        serializer->bytes_asked = 1;
+        return serializer->bytes_asked;
+    }
+    
+    /* non-degenerate case */
+    rows = serializer->entries_needed/AE_SER_ENTRIES_PER_ROW;
+    lastrowsize = AE_SER_ENTRIES_PER_ROW;
+    if( serializer->entries_needed%AE_SER_ENTRIES_PER_ROW )
+    {
+        lastrowsize = serializer->entries_needed%AE_SER_ENTRIES_PER_ROW;
+        rows++;
+    }
+    
+    /* calculate result size */
+    result  = ((rows-1)*AE_SER_ENTRIES_PER_ROW+lastrowsize)*AE_SER_ENTRY_LENGTH;
+    result +=  (rows-1)*(AE_SER_ENTRIES_PER_ROW-1)+(lastrowsize-1);
+    result += rows*2;
+    serializer->bytes_asked = result;
+    return result;
+}
+
+#ifdef AE_USE_CPP_SERIALIZATION
+void ae_serializer_sstart_str(ae_serializer *serializer, std::string *buf)
+{
+    serializer->mode = AE_SM_TO_CPPSTRING;
+    serializer->out_cppstr = buf;
+    serializer->entries_saved = 0;
+    serializer->bytes_written = 0;
+}
+#endif
+
+#ifdef AE_USE_CPP_SERIALIZATION
+void ae_serializer_ustart_str(ae_serializer *serializer, const std::string *buf)
+{
+    serializer->mode = AE_SM_FROM_STRING;
+    serializer->in_str = buf->c_str();
+}
+#endif
+
+void ae_serializer_sstart_str(ae_serializer *serializer, char *buf)
+{
+    serializer->mode = AE_SM_TO_STRING;
+    serializer->out_str = buf;
+    serializer->out_str[0] = 0;
+    serializer->entries_saved = 0;
+    serializer->bytes_written = 0;
+}
+
+void ae_serializer_ustart_str(ae_serializer *serializer, const char *buf)
+{
+    serializer->mode = AE_SM_FROM_STRING;
+    serializer->in_str = buf;
+}
+
+void ae_serializer_serialize_bool(ae_serializer *serializer, ae_bool v, ae_state *state)
+{
+    char buf[AE_SER_ENTRY_LENGTH+2+1];
+    const char *emsg = "ALGLIB: serialization integrity error";
+    ae_int_t bytes_appended;
+    
+    /* prepare serialization, check consistency */
+    ae_bool2str(v, buf, state);
+    serializer->entries_saved++;
+    if( serializer->entries_saved%AE_SER_ENTRIES_PER_ROW )
+        strcat(buf, " ");
+    else
+        strcat(buf, "\r\n");
+    bytes_appended = (ae_int_t)strlen(buf);
+    if( serializer->bytes_written+bytes_appended > serializer->bytes_asked )
+        ae_break(state, ERR_ASSERTION_FAILED, emsg);
+    serializer->bytes_written += bytes_appended;
+        
+    /* append to buffer */
+#ifdef AE_USE_CPP_SERIALIZATION
+    if( serializer->mode==AE_SM_TO_CPPSTRING )
+    {
+        *(serializer->out_cppstr) += buf;
+        return;
+    }
+#endif
+    if( serializer->mode==AE_SM_TO_STRING )
+    {
+        strcat(serializer->out_str, buf);
+        serializer->out_str += bytes_appended;
+        return;
+    }
+    ae_break(state, ERR_ASSERTION_FAILED, emsg);
+}
+
+void ae_serializer_serialize_int(ae_serializer *serializer, ae_int_t v, ae_state *state)
+{
+    char buf[AE_SER_ENTRY_LENGTH+2+1];
+    const char *emsg = "ALGLIB: serialization integrity error";
+    ae_int_t bytes_appended;
+    
+    /* prepare serialization, check consistency */
+    ae_int2str(v, buf, state);
+    serializer->entries_saved++;
+    if( serializer->entries_saved%AE_SER_ENTRIES_PER_ROW )
+        strcat(buf, " ");
+    else
+        strcat(buf, "\r\n");
+    bytes_appended = (ae_int_t)strlen(buf);
+    if( serializer->bytes_written+bytes_appended > serializer->bytes_asked )
+        ae_break(state, ERR_ASSERTION_FAILED, emsg);
+    serializer->bytes_written += bytes_appended;
+        
+    /* append to buffer */
+#ifdef AE_USE_CPP_SERIALIZATION
+    if( serializer->mode==AE_SM_TO_CPPSTRING )
+    {
+        *(serializer->out_cppstr) += buf;
+        return;
+    }
+#endif
+    if( serializer->mode==AE_SM_TO_STRING )
+    {
+        strcat(serializer->out_str, buf);
+        serializer->out_str += bytes_appended;
+        return;
+    }
+    ae_break(state, ERR_ASSERTION_FAILED, emsg);
+}
+
+void ae_serializer_serialize_double(ae_serializer *serializer, double v, ae_state *state)
+{
+    char buf[AE_SER_ENTRY_LENGTH+2+1];
+    const char *emsg = "ALGLIB: serialization integrity error";
+    ae_int_t bytes_appended;
+    
+    /* prepare serialization, check consistency */
+    ae_double2str(v, buf, state);
+    serializer->entries_saved++;
+    if( serializer->entries_saved%AE_SER_ENTRIES_PER_ROW )
+        strcat(buf, " ");
+    else
+        strcat(buf, "\r\n");
+    bytes_appended = (ae_int_t)strlen(buf);
+    if( serializer->bytes_written+bytes_appended > serializer->bytes_asked )
+        ae_break(state, ERR_ASSERTION_FAILED, emsg);
+    serializer->bytes_written += bytes_appended;
+        
+    /* append to buffer */
+#ifdef AE_USE_CPP_SERIALIZATION
+    if( serializer->mode==AE_SM_TO_CPPSTRING )
+    {
+        *(serializer->out_cppstr) += buf;
+        return;
+    }
+#endif
+    if( serializer->mode==AE_SM_TO_STRING )
+    {
+        strcat(serializer->out_str, buf);
+        serializer->out_str += bytes_appended;
+        return;
+    }
+    ae_break(state, ERR_ASSERTION_FAILED, emsg);
+}
+
+void ae_serializer_unserialize_bool(ae_serializer *serializer, ae_bool *v, ae_state *state)
+{
+    *v = ae_str2bool(serializer->in_str, state, &serializer->in_str);
+}
+
+void ae_serializer_unserialize_int(ae_serializer *serializer, ae_int_t *v, ae_state *state)
+{
+    *v = ae_str2int(serializer->in_str, state, &serializer->in_str);
+}
+
+void ae_serializer_unserialize_double(ae_serializer *serializer, double *v, ae_state *state)
+{
+    *v = ae_str2double(serializer->in_str, state, &serializer->in_str);
+}
+
+void ae_serializer_stop(ae_serializer *serializer)
+{
+}
+
 
 /************************************************************************
 Complex math functions
@@ -3196,12 +3868,13 @@ const alglib_impl::ae_complex* alglib::complex::c_ptr() const
     return (const alglib_impl::ae_complex*)this;
 }
     
-std::string alglib::complex::tostring(int dps) const
+std::string alglib::complex::tostring(int _dps) const
 {
     char mask[32];
     char buf_x[32];
     char buf_y[32];
     char buf_zero[32];
+    int dps = _dps>=0 ? _dps : -_dps;
     if( dps<=0 || dps>=20 )
         throw ap_error("complex::tostring(): incorrect dps");
 
@@ -3212,7 +3885,7 @@ std::string alglib::complex::tostring(int dps) const
         return "INF";
 
     // generate mask
-    if( sprintf(mask, "%%.%df", dps)>=(int)sizeof(mask) )
+    if( sprintf(mask, "%%.%d%s", dps, _dps>=0 ? "f" : "e")>=(int)sizeof(mask) )
         throw ap_error("complex::tostring(): buffer overflow");
 
     // print |x|, |y| and zero with same mask and compare
@@ -5478,15 +6151,16 @@ std::string alglib::arraytostring(const ae_int_t *ptr, ae_int_t n)
     return result;
 }
 
-std::string alglib::arraytostring(const double *ptr, ae_int_t n, int dps)
+std::string alglib::arraytostring(const double *ptr, ae_int_t n, int _dps)
 {
     std::string result;
     ae_int_t i;
     char buf[64];
     char mask1[64];
     char mask2[64];
+    int dps = _dps>=0 ? _dps : -_dps;
     result = "[";
-    if( sprintf(mask1, "%%.%df", dps)>=(int)sizeof(mask1) )
+    if( sprintf(mask1, "%%.%d%s", dps, _dps>=0 ? "f" : "e")>=(int)sizeof(mask1) )
         throw ap_error("arraytostring(): buffer overflow");
     if( sprintf(mask2, ",%s", mask1)>=(int)sizeof(mask2) )
         throw ap_error("arraytostring(): buffer overflow");
@@ -6388,17 +7062,16 @@ This function supports SSE2; it can be used when:
 1. AE_HAS_SSE2_INTRINSICS was defined (checked at compile-time)
 2. ae_cpuid() result contains CPU_SSE2 (checked at run-time)
 
-If (1) is failed, this function will still be defined and callable, but it 
-will do nothing.  If (2)  is  failed , call to this function will probably 
-crash your system. 
+If (1) is failed, this function will be undefined. If (2) is failed,  call 
+to this function will probably crash your system. 
 
 If  you  want  to  know  whether  it  is safe to call it, you should check 
 results  of  ae_cpuid(). If CPU_SSE2 bit is set, this function is callable 
 and will do its work.
 *************************************************************************/
+#if defined(AE_HAS_SSE2_INTRINSICS)
 void _ialglib_rmv_sse2(ae_int_t m, ae_int_t n, const double *a, const double *x, double *y, ae_int_t stride, double alpha, double beta)
 {
-#if defined(AE_HAS_SSE2_INTRINSICS)
     ae_int_t i, k, n2;
     ae_int_t mb3, mtail, nhead, nb8, nb2, ntail;
     const double *pa0, *pa1, *pa2, *pb;
@@ -6671,8 +7344,8 @@ void _ialglib_rmv_sse2(ae_int_t m, ae_int_t n, const double *a, const double *x,
             y[0] = alpha*row0;
         y+=stride;
     }
-#endif
 }
+#endif
 
 
 /*************************************************************************
@@ -6767,17 +7440,16 @@ This function supports SSE2; it can be used when:
 1. AE_HAS_SSE2_INTRINSICS was defined (checked at compile-time)
 2. ae_cpuid() result contains CPU_SSE2 (checked at run-time)
 
-If (1) is failed, this function will still be defined and callable, but it 
-will do nothing.  If (2)  is  failed , call to this function will probably 
-crash your system. 
+If (1) is failed, this function will be undefined. If (2) is failed,  call 
+to this function will probably crash your system. 
 
 If  you  want  to  know  whether  it  is safe to call it, you should check 
 results  of  ae_cpuid(). If CPU_SSE2 bit is set, this function is callable 
 and will do its work.
 *************************************************************************/
+#if defined(AE_HAS_SSE2_INTRINSICS)
 void _ialglib_cmv_sse2(ae_int_t m, ae_int_t n, const double *a, const double *x, ae_complex *cy, double *dy, ae_int_t stride, ae_complex alpha, ae_complex beta)
 {
-#if defined(AE_HAS_SSE2_INTRINSICS)
     ae_int_t i, j, m2;
     const double *pa0, *pa1, *parow, *pb;
     __m128d vbeta, vbetax, vbetay;
@@ -6886,8 +7558,8 @@ void _ialglib_cmv_sse2(ae_int_t m, ae_int_t n, const double *a, const double *x,
         dy += 2*stride;
         parow += 2*alglib_c_block;
     }
-#endif
 }
+#endif
 
 /********************************************************************
 This subroutine sets vector to zero
@@ -7100,17 +7772,16 @@ This function supports SSE2; it can be used when:
 1. AE_HAS_SSE2_INTRINSICS was defined (checked at compile-time)
 2. ae_cpuid() result contains CPU_SSE2 (checked at run-time)
 
-If (1) is failed, this function will still be defined and callable, but it 
-will do nothing.  If (2)  is  failed , call to this function will probably 
-crash your system. 
+If (1) is failed, this function will be undefined. If (2) is failed,  call 
+to this function will probably crash your system. 
 
 If  you  want  to  know  whether  it  is safe to call it, you should check 
 results  of  ae_cpuid(). If CPU_SSE2 bit is set, this function is callable 
 and will do its work.
 ********************************************************************/
+#if defined(AE_HAS_SSE2_INTRINSICS)
 void _ialglib_mcopyblock_sse2(ae_int_t m, ae_int_t n, const double *a, ae_int_t op, ae_int_t stride, double *b)
 {
-#if defined(AE_HAS_SSE2_INTRINSICS)
     ae_int_t i, j, nb8, mb2, ntail;
     const double *psrc0, *psrc1;
     double *pdst;
@@ -7206,8 +7877,8 @@ void _ialglib_mcopyblock_sse2(ae_int_t m, ae_int_t n, const double *a, ae_int_t
                 pdst0[0] = psrc0[0];
         }
     }
-#endif
 }
+#endif
 
 
 /********************************************************************
@@ -7431,11 +8102,13 @@ ae_bool _ialglib_rmatrixgemm(ae_int_t m,
     /*
      * Check for SSE2 support
      */
+#ifdef AE_HAS_SSE2_INTRINSICS
     if( ae_cpuid() & CPU_SSE2 )
     {
         rmv = &_ialglib_rmv_sse2;
         mcopyblock = &_ialglib_mcopyblock_sse2;
-    }    
+    }
+#endif
     
     /*
      * copy b
@@ -7514,10 +8187,12 @@ ae_bool _ialglib_cmatrixgemm(ae_int_t m,
     /*
      * Check for SSE2 support
      */
+#ifdef AE_HAS_SSE2_INTRINSICS
     if( ae_cpuid() & CPU_SSE2 )
     {
         cmv = &_ialglib_cmv_sse2;
     }    
+#endif
     
     /*
      * copy b
@@ -7596,10 +8271,12 @@ ae_bool _ialglib_cmatrixrighttrsm(ae_int_t m,
     /*
      * Check for SSE2 support
      */
+#ifdef AE_HAS_SSE2_INTRINSICS
     if( ae_cpuid() & CPU_SSE2 )
     {
         cmv = &_ialglib_cmv_sse2;
     }    
+#endif
     
     /*
      * Prepare
@@ -7692,11 +8369,13 @@ ae_bool _ialglib_rmatrixrighttrsm(ae_int_t m,
     /*
      * Check for SSE2 support
      */
+#ifdef AE_HAS_SSE2_INTRINSICS
     if( ae_cpuid() & CPU_SSE2 )
     {
         rmv = &_ialglib_rmv_sse2;
         mcopyblock = &_ialglib_mcopyblock_sse2;
     }    
+#endif
     
     /*
      * Prepare
@@ -7773,10 +8452,12 @@ ae_bool _ialglib_cmatrixlefttrsm(ae_int_t m,
     /*
      * Check for SSE2 support
      */
+#ifdef AE_HAS_SSE2_INTRINSICS
     if( ae_cpuid() & CPU_SSE2 )
     {
         cmv = &_ialglib_cmv_sse2;
     }    
+#endif
     
     /*
      * Prepare
@@ -7869,11 +8550,13 @@ ae_bool _ialglib_rmatrixlefttrsm(ae_int_t m,
     /*
      * Check for SSE2 support
      */
+#ifdef AE_HAS_SSE2_INTRINSICS
     if( ae_cpuid() & CPU_SSE2 )
     {
         rmv = &_ialglib_rmv_sse2;
         mcopyblock = &_ialglib_mcopyblock_sse2;
     }    
+#endif
     
     /*
      * Prepare
@@ -8451,14 +9134,11 @@ This function supports SSE2; it can be used when:
 1. AE_HAS_SSE2_INTRINSICS was defined (checked at compile-time)
 2. ae_cpuid() result contains CPU_SSE2 (checked at run-time)
 
-If (1) is failed, this function will still be defined and callable, but it 
-will do nothing.  If (2)  is  failed , call to this function will probably 
-crash your system. 
-
 If  you  want  to  know  whether  it  is safe to call it, you should check 
 results  of  ae_cpuid(). If CPU_SSE2 bit is set, this function is callable 
 and will do its work.
 *************************************************************************/
+#if defined(AE_HAS_SSE2_INTRINSICS)
 void _ialglib_pack_n2_sse2(
     double *col0,
     double *col1,
@@ -8466,7 +9146,6 @@ void _ialglib_pack_n2_sse2(
     ae_int_t src_stride,
     double *dst)
 {
-#if defined(AE_HAS_SSE2_INTRINSICS)
     ae_int_t n2, j, stride2;
     
     /*
@@ -8554,8 +9233,8 @@ void _ialglib_pack_n2_sse2(
         dst[0] = *col0;
         dst[1] = *col1;
     }
-#endif
 }
+#endif
 
 
 /********************************************************************
@@ -8686,9 +9365,9 @@ If  you  want  to  know  whether  it  is safe to call it, you should check
 results  of  ae_cpuid(). If CPU_SSE2 bit is set, this function is callable 
 and will do its work.
 ********************************************************************/
+#if defined(AE_HAS_SSE2_INTRINSICS)
 void _ialglib_mm22_sse2(double alpha, const double *a, const double *b, ae_int_t k, double beta, double *r, ae_int_t stride, ae_int_t store_mode)
 {
-#if defined(AE_HAS_SSE2_INTRINSICS)
     /*
      * We calculate product of two Kx2 matrices (result is 2x2). 
      * VA and VB store result as follows:
@@ -8797,8 +9476,8 @@ void _ialglib_mm22_sse2(double alpha, const double *a, const double *b, ae_int_t
             r[0] = beta*r[0] + buf[0];
         return;
     }
-#endif
 }
+#endif
 
 
 /*************************************************************************
@@ -8857,9 +9536,9 @@ If  you  want  to  know  whether  it  is safe to call it, you should check
 results  of  ae_cpuid(). If CPU_SSE2 bit is set, this function is callable 
 and will do its work.
 *************************************************************************/
+#if defined(AE_HAS_SSE2_INTRINSICS)
 void _ialglib_mm22x2_sse2(double alpha, const double *a, const double *b0, const double *b1, ae_int_t k, double beta, double *r, ae_int_t stride)
 {
-#if defined(AE_HAS_SSE2_INTRINSICS)
     /*
      * We calculate product of two Kx2 matrices (result is 2x2). 
      * V0, V1, V2, V3 store result as follows:
@@ -8946,7 +9625,7 @@ void _ialglib_mm22x2_sse2(double alpha, const double *a, const double *b0, const
         _mm_storeu_pd(r+stride,   _mm_add_pd(_mm_mul_pd(_mm_loadu_pd(r+stride),vbeta),r10));
         _mm_storeu_pd(r+stride+2, _mm_add_pd(_mm_mul_pd(_mm_loadu_pd(r+stride+2),vbeta),r11));
     }    
-#endif
 }
+#endif
 
 }
diff --git a/contrib/lbfgs/ap.h b/contrib/lbfgs/ap.h
index eef1d97acc56d127ccc7323cc9ca8d2954db5bfa..6863b262cb0ed53bb9dcdbfcd70407acb95f2e7b 100755
--- a/contrib/lbfgs/ap.h
+++ b/contrib/lbfgs/ap.h
@@ -63,7 +63,7 @@ namespace alglib_impl
 #undef AE_COMPILER
 #define AE_COMPILER AE_GNUC
 #endif
-#ifdef __SUNPRO_C
+#if defined(__SUNPRO_C)||defined(__SUNPRO_CC)
 #undef AE_COMPILER
 #define AE_COMPILER AE_SUNC
 #endif
@@ -78,6 +78,7 @@ namespace alglib_impl
 #ifdef AE_USE_CPP
 #define AE_USE_CPP_BOOL
 #define AE_USE_CPP_ERROR_HANDLING
+#define AE_USE_CPP_SERIALIZATION
 #endif
 
 
@@ -162,11 +163,17 @@ typedef ptrdiff_t ae_int_t;
 #define AE_HAS_SSE2_INTRINSICS
 #endif
 
-#if (AE_COMPILER==AE_GNUC)||(AE_COMPILER==AE_SUNC)
+#if AE_COMPILER==AE_GNUC
 #include <xmmintrin.h>
 #define AE_HAS_SSE2_INTRINSICS
 #endif
 
+#if AE_COMPILER==AE_SUNC
+#include <xmmintrin.h>
+#include <emmintrin.h>
+#define AE_HAS_SSE2_INTRINSICS
+#endif
+
 #ifdef AE_USE_CPP
 namespace alglib_impl { // namespace declaration continued
 #endif
@@ -319,6 +326,9 @@ typedef struct ae_frame
     ae_dyn_block db_marker;
 } ae_frame;
 
+/************************************************************************
+ALGLIB environment state
+************************************************************************/
 typedef struct
 {
     ae_int_t endianness;
@@ -335,6 +345,24 @@ typedef struct
     const char* volatile error_msg;
 } ae_state;
 
+/************************************************************************
+Serializer
+************************************************************************/
+typedef struct
+{
+    ae_int_t mode;
+    ae_int_t entries_needed;
+    ae_int_t entries_saved;
+    ae_int_t bytes_asked;
+    ae_int_t bytes_written;
+
+#ifdef AE_USE_CPP_SERIALIZATION
+    std::string     *out_cppstr;
+#endif
+    char            *out_str;
+    const char      *in_str;
+} ae_serializer;
+
 typedef void(*ae_deallocator)(void*);
 
 typedef struct ae_vector
@@ -425,6 +453,29 @@ ae_bool ae_is_hermitian(ae_matrix *a);
 ae_bool ae_force_symmetric(ae_matrix *a);
 ae_bool ae_force_hermitian(ae_matrix *a);
 
+void ae_serializer_init(ae_serializer *serializer);
+void ae_serializer_clear(ae_serializer *serializer);
+
+void ae_serializer_alloc_start(ae_serializer *serializer);
+void ae_serializer_alloc_entry(ae_serializer *serializer);
+ae_int_t ae_serializer_get_alloc_size(ae_serializer *serializer);
+
+#ifdef AE_USE_CPP_SERIALIZATION
+void ae_serializer_sstart_str(ae_serializer *serializer, std::string *buf);
+void ae_serializer_ustart_str(ae_serializer *serializer, const std::string *buf);
+#endif
+void ae_serializer_sstart_str(ae_serializer *serializer, char *buf);
+void ae_serializer_ustart_str(ae_serializer *serializer, const char *buf);
+
+void ae_serializer_serialize_bool(ae_serializer *serializer, ae_bool v, ae_state *state);
+void ae_serializer_serialize_int(ae_serializer *serializer, ae_int_t v, ae_state *state);
+void ae_serializer_serialize_double(ae_serializer *serializer, double v, ae_state *state);
+void ae_serializer_unserialize_bool(ae_serializer *serializer, ae_bool *v, ae_state *state);
+void ae_serializer_unserialize_int(ae_serializer *serializer, ae_int_t *v, ae_state *state);
+void ae_serializer_unserialize_double(ae_serializer *serializer, double *v, ae_state *state);
+
+void ae_serializer_stop(ae_serializer *serializer);
+
 /************************************************************************
 Service functions
 ************************************************************************/
diff --git a/contrib/lbfgs/optimization.cpp b/contrib/lbfgs/optimization.cpp
index 2f4c034023420bf241a056d7a65677b4310249cd..8cb580030dac531fe4c7f44c8fab51db3fa71fa3 100755
--- a/contrib/lbfgs/optimization.cpp
+++ b/contrib/lbfgs/optimization.cpp
@@ -38,68 +38,70 @@ namespace alglib
 
 
 /*************************************************************************
+This object stores state of the nonlinear CG optimizer.
 
+You should use ALGLIB functions to work with this object.
 *************************************************************************/
-_minlbfgsstate_owner::_minlbfgsstate_owner()
+_mincgstate_owner::_mincgstate_owner()
 {
-    p_struct = (alglib_impl::minlbfgsstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::minlbfgsstate), NULL);
+    p_struct = (alglib_impl::mincgstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::mincgstate), NULL);
     if( p_struct==NULL )
         throw ap_error("ALGLIB: malloc error");
-    if( !alglib_impl::_minlbfgsstate_init(p_struct, NULL, ae_false) )
+    if( !alglib_impl::_mincgstate_init(p_struct, NULL, ae_false) )
         throw ap_error("ALGLIB: malloc error");
 }
 
-_minlbfgsstate_owner::_minlbfgsstate_owner(const _minlbfgsstate_owner &rhs)
+_mincgstate_owner::_mincgstate_owner(const _mincgstate_owner &rhs)
 {
-    p_struct = (alglib_impl::minlbfgsstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::minlbfgsstate), NULL);
+    p_struct = (alglib_impl::mincgstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::mincgstate), NULL);
     if( p_struct==NULL )
         throw ap_error("ALGLIB: malloc error");
-    if( !alglib_impl::_minlbfgsstate_init_copy(p_struct, const_cast<alglib_impl::minlbfgsstate*>(rhs.p_struct), NULL, ae_false) )
+    if( !alglib_impl::_mincgstate_init_copy(p_struct, const_cast<alglib_impl::mincgstate*>(rhs.p_struct), NULL, ae_false) )
         throw ap_error("ALGLIB: malloc error");
 }
 
-_minlbfgsstate_owner& _minlbfgsstate_owner::operator=(const _minlbfgsstate_owner &rhs)
+_mincgstate_owner& _mincgstate_owner::operator=(const _mincgstate_owner &rhs)
 {
     if( this==&rhs )
         return *this;
-    alglib_impl::_minlbfgsstate_clear(p_struct);
-    if( !alglib_impl::_minlbfgsstate_init_copy(p_struct, const_cast<alglib_impl::minlbfgsstate*>(rhs.p_struct), NULL, ae_false) )
+    alglib_impl::_mincgstate_clear(p_struct);
+    if( !alglib_impl::_mincgstate_init_copy(p_struct, const_cast<alglib_impl::mincgstate*>(rhs.p_struct), NULL, ae_false) )
         throw ap_error("ALGLIB: malloc error");
     return *this;
 }
 
-_minlbfgsstate_owner::~_minlbfgsstate_owner()
+_mincgstate_owner::~_mincgstate_owner()
 {
-    alglib_impl::_minlbfgsstate_clear(p_struct);
+    alglib_impl::_mincgstate_clear(p_struct);
     ae_free(p_struct);
 }
 
-alglib_impl::minlbfgsstate* _minlbfgsstate_owner::c_ptr()
+alglib_impl::mincgstate* _mincgstate_owner::c_ptr()
 {
     return p_struct;
 }
 
-alglib_impl::minlbfgsstate* _minlbfgsstate_owner::c_ptr() const
+alglib_impl::mincgstate* _mincgstate_owner::c_ptr() const
 {
-    return const_cast<alglib_impl::minlbfgsstate*>(p_struct);
+    return const_cast<alglib_impl::mincgstate*>(p_struct);
 }
-minlbfgsstate::minlbfgsstate() : _minlbfgsstate_owner() ,needfg(p_struct->needfg),xupdated(p_struct->xupdated),f(p_struct->f),g(&p_struct->g),x(&p_struct->x)
+mincgstate::mincgstate() : _mincgstate_owner() ,needf(p_struct->needf),needfg(p_struct->needfg),xupdated(p_struct->xupdated),f(p_struct->f),g(&p_struct->g),x(&p_struct->x)
 {
 }
 
-minlbfgsstate::minlbfgsstate(const minlbfgsstate &rhs):_minlbfgsstate_owner(rhs) ,needfg(p_struct->needfg),xupdated(p_struct->xupdated),f(p_struct->f),g(&p_struct->g),x(&p_struct->x)
+mincgstate::mincgstate(const mincgstate &rhs):_mincgstate_owner(rhs) ,needf(p_struct->needf),needfg(p_struct->needfg),xupdated(p_struct->xupdated),f(p_struct->f),g(&p_struct->g),x(&p_struct->x)
 {
 }
 
-minlbfgsstate& minlbfgsstate::operator=(const minlbfgsstate &rhs)
+mincgstate& mincgstate::operator=(const mincgstate &rhs)
 {
     if( this==&rhs )
         return *this;
-    _minlbfgsstate_owner::operator=(rhs);
+    _mincgstate_owner::operator=(rhs);
     return *this;
 }
 
-minlbfgsstate::~minlbfgsstate()
+mincgstate::~mincgstate()
 {
 }
 
@@ -107,80 +109,79 @@ minlbfgsstate::~minlbfgsstate()
 /*************************************************************************
 
 *************************************************************************/
-_minlbfgsreport_owner::_minlbfgsreport_owner()
+_mincgreport_owner::_mincgreport_owner()
 {
-    p_struct = (alglib_impl::minlbfgsreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::minlbfgsreport), NULL);
+    p_struct = (alglib_impl::mincgreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::mincgreport), NULL);
     if( p_struct==NULL )
         throw ap_error("ALGLIB: malloc error");
-    if( !alglib_impl::_minlbfgsreport_init(p_struct, NULL, ae_false) )
+    if( !alglib_impl::_mincgreport_init(p_struct, NULL, ae_false) )
         throw ap_error("ALGLIB: malloc error");
 }
 
-_minlbfgsreport_owner::_minlbfgsreport_owner(const _minlbfgsreport_owner &rhs)
+_mincgreport_owner::_mincgreport_owner(const _mincgreport_owner &rhs)
 {
-    p_struct = (alglib_impl::minlbfgsreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::minlbfgsreport), NULL);
+    p_struct = (alglib_impl::mincgreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::mincgreport), NULL);
     if( p_struct==NULL )
         throw ap_error("ALGLIB: malloc error");
-    if( !alglib_impl::_minlbfgsreport_init_copy(p_struct, const_cast<alglib_impl::minlbfgsreport*>(rhs.p_struct), NULL, ae_false) )
+    if( !alglib_impl::_mincgreport_init_copy(p_struct, const_cast<alglib_impl::mincgreport*>(rhs.p_struct), NULL, ae_false) )
         throw ap_error("ALGLIB: malloc error");
 }
 
-_minlbfgsreport_owner& _minlbfgsreport_owner::operator=(const _minlbfgsreport_owner &rhs)
+_mincgreport_owner& _mincgreport_owner::operator=(const _mincgreport_owner &rhs)
 {
     if( this==&rhs )
         return *this;
-    alglib_impl::_minlbfgsreport_clear(p_struct);
-    if( !alglib_impl::_minlbfgsreport_init_copy(p_struct, const_cast<alglib_impl::minlbfgsreport*>(rhs.p_struct), NULL, ae_false) )
+    alglib_impl::_mincgreport_clear(p_struct);
+    if( !alglib_impl::_mincgreport_init_copy(p_struct, const_cast<alglib_impl::mincgreport*>(rhs.p_struct), NULL, ae_false) )
         throw ap_error("ALGLIB: malloc error");
     return *this;
 }
 
-_minlbfgsreport_owner::~_minlbfgsreport_owner()
+_mincgreport_owner::~_mincgreport_owner()
 {
-    alglib_impl::_minlbfgsreport_clear(p_struct);
+    alglib_impl::_mincgreport_clear(p_struct);
     ae_free(p_struct);
 }
 
-alglib_impl::minlbfgsreport* _minlbfgsreport_owner::c_ptr()
+alglib_impl::mincgreport* _mincgreport_owner::c_ptr()
 {
     return p_struct;
 }
 
-alglib_impl::minlbfgsreport* _minlbfgsreport_owner::c_ptr() const
+alglib_impl::mincgreport* _mincgreport_owner::c_ptr() const
 {
-    return const_cast<alglib_impl::minlbfgsreport*>(p_struct);
+    return const_cast<alglib_impl::mincgreport*>(p_struct);
 }
-minlbfgsreport::minlbfgsreport() : _minlbfgsreport_owner() ,iterationscount(p_struct->iterationscount),nfev(p_struct->nfev),terminationtype(p_struct->terminationtype)
+mincgreport::mincgreport() : _mincgreport_owner() ,iterationscount(p_struct->iterationscount),nfev(p_struct->nfev),terminationtype(p_struct->terminationtype)
 {
 }
 
-minlbfgsreport::minlbfgsreport(const minlbfgsreport &rhs):_minlbfgsreport_owner(rhs) ,iterationscount(p_struct->iterationscount),nfev(p_struct->nfev),terminationtype(p_struct->terminationtype)
+mincgreport::mincgreport(const mincgreport &rhs):_mincgreport_owner(rhs) ,iterationscount(p_struct->iterationscount),nfev(p_struct->nfev),terminationtype(p_struct->terminationtype)
 {
 }
 
-minlbfgsreport& minlbfgsreport::operator=(const minlbfgsreport &rhs)
+mincgreport& mincgreport::operator=(const mincgreport &rhs)
 {
     if( this==&rhs )
         return *this;
-    _minlbfgsreport_owner::operator=(rhs);
+    _mincgreport_owner::operator=(rhs);
     return *this;
 }
 
-minlbfgsreport::~minlbfgsreport()
+mincgreport::~mincgreport()
 {
 }
 
 /*************************************************************************
-        LIMITED MEMORY BFGS METHOD FOR LARGE SCALE OPTIMIZATION
+        NONLINEAR CONJUGATE GRADIENT METHOD
 
 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.
+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:
@@ -189,49 +190,36 @@ Algorithm will request following information during its operation:
 
 
 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
+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 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.
+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
-    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].
-
+    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
 
-
-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.
-
-
   -- ALGLIB --
-     Copyright 02.04.2010 by Bochkanov Sergey
+     Copyright 25.03.2010 by Bochkanov Sergey
 *************************************************************************/
-void minlbfgscreate(const ae_int_t n, const ae_int_t m, const real_1d_array &x, minlbfgsstate &state)
+void mincgcreate(const ae_int_t n, const real_1d_array &x, mincgstate &state)
 {
     alglib_impl::ae_state _alglib_env_state;
     alglib_impl::ae_state_init(&_alglib_env_state);
     try
     {
-        alglib_impl::minlbfgscreate(n, m, const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::minlbfgsstate*>(state.c_ptr()), &_alglib_env_state);
+        alglib_impl::mincgcreate(n, const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::mincgstate*>(state.c_ptr()), &_alglib_env_state);
         alglib_impl::ae_state_clear(&_alglib_env_state);
         return;
     }
@@ -246,16 +234,15 @@ void minlbfgscreate(const ae_int_t n, const ae_int_t m, const real_1d_array &x,
 }
 
 /*************************************************************************
-        LIMITED MEMORY BFGS METHOD FOR LARGE SCALE OPTIMIZATION
+        NONLINEAR CONJUGATE GRADIENT METHOD
 
 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.
+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:
@@ -264,43 +251,30 @@ Algorithm will request following information during its operation:
 
 
 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
+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 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.
+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
-    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].
-
+    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
 
-
-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.
-
-
   -- ALGLIB --
-     Copyright 02.04.2010 by Bochkanov Sergey
+     Copyright 25.03.2010 by Bochkanov Sergey
 *************************************************************************/
-void minlbfgscreate(const ae_int_t m, const real_1d_array &x, minlbfgsstate &state)
+void mincgcreate(const real_1d_array &x, mincgstate &state)
 {
     alglib_impl::ae_state _alglib_env_state;    
     ae_int_t n;
@@ -309,7 +283,7 @@ void minlbfgscreate(const ae_int_t m, const real_1d_array &x, minlbfgsstate &sta
     alglib_impl::ae_state_init(&_alglib_env_state);
     try
     {
-        alglib_impl::minlbfgscreate(n, m, const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::minlbfgsstate*>(state.c_ptr()), &_alglib_env_state);
+        alglib_impl::mincgcreate(n, const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::mincgstate*>(state.c_ptr()), &_alglib_env_state);
 
         alglib_impl::ae_state_clear(&_alglib_env_state);
         return;
@@ -325,37 +299,54 @@ void minlbfgscreate(const ae_int_t m, const real_1d_array &x, minlbfgsstate &sta
 }
 
 /*************************************************************************
-This function sets stopping conditions for L-BFGS optimization algorithm.
+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
-    EpsG    -   >=0
-                The  subroutine  finishes  its  work   if   the  condition
-                ||G||<EpsG is satisfied, where ||.|| means Euclidian norm,
-                G - gradient.
-    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 |X(k+1)-X(k)| <= EpsX is fulfilled.
-    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).
+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.
 
   -- ALGLIB --
-     Copyright 02.04.2010 by Bochkanov Sergey
+     Copyright 16.05.2011 by Bochkanov Sergey
 *************************************************************************/
-void minlbfgssetcond(const minlbfgsstate &state, const double epsg, const double epsf, const double epsx, const ae_int_t maxits)
+void mincgcreatef(const ae_int_t n, const real_1d_array &x, const double diffstep, mincgstate &state)
 {
     alglib_impl::ae_state _alglib_env_state;
     alglib_impl::ae_state_init(&_alglib_env_state);
     try
     {
-        alglib_impl::minlbfgssetcond(const_cast<alglib_impl::minlbfgsstate*>(state.c_ptr()), epsg, epsf, epsx, maxits, &_alglib_env_state);
+        alglib_impl::mincgcreatef(n, const_cast<alglib_impl::ae_vector*>(x.c_ptr()), diffstep, const_cast<alglib_impl::mincgstate*>(state.c_ptr()), &_alglib_env_state);
         alglib_impl::ae_state_clear(&_alglib_env_state);
         return;
     }
@@ -370,26 +361,58 @@ void minlbfgssetcond(const minlbfgsstate &state, const double epsg, const double
 }
 
 /*************************************************************************
-This function turns on/off reporting.
+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:
-    State   -   structure which stores algorithm state
-    NeedXRep-   whether iteration reports are needed or not
+    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
 
-If NeedXRep is True, algorithm will call rep() callback function if  it is
-provided to MinLBFGSOptimize().
+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.
 
   -- ALGLIB --
-     Copyright 02.04.2010 by Bochkanov Sergey
+     Copyright 16.05.2011 by Bochkanov Sergey
 *************************************************************************/
-void minlbfgssetxrep(const minlbfgsstate &state, const bool needxrep)
+void mincgcreatef(const real_1d_array &x, const double diffstep, mincgstate &state)
 {
-    alglib_impl::ae_state _alglib_env_state;
+    alglib_impl::ae_state _alglib_env_state;    
+    ae_int_t n;
+
+    n = x.length();
     alglib_impl::ae_state_init(&_alglib_env_state);
     try
     {
-        alglib_impl::minlbfgssetxrep(const_cast<alglib_impl::minlbfgsstate*>(state.c_ptr()), needxrep, &_alglib_env_state);
+        alglib_impl::mincgcreatef(n, const_cast<alglib_impl::ae_vector*>(x.c_ptr()), diffstep, const_cast<alglib_impl::mincgstate*>(state.c_ptr()), &_alglib_env_state);
+
         alglib_impl::ae_state_clear(&_alglib_env_state);
         return;
     }
@@ -404,29 +427,44 @@ void minlbfgssetxrep(const minlbfgsstate &state, const bool needxrep)
 }
 
 /*************************************************************************
-This function sets maximum step length
+This function sets stopping conditions for CG optimization algorithm.
 
 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.
+    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.
 
-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.
+Passing EpsG=0, EpsF=0, EpsX=0 and MaxIts=0 (simultaneously) will lead to
+automatic stopping criterion selection (small EpsX).
 
   -- ALGLIB --
      Copyright 02.04.2010 by Bochkanov Sergey
 *************************************************************************/
-void minlbfgssetstpmax(const minlbfgsstate &state, const double stpmax)
+void mincgsetcond(const mincgstate &state, const double epsg, const double epsf, const double epsx, const ae_int_t maxits)
 {
     alglib_impl::ae_state _alglib_env_state;
     alglib_impl::ae_state_init(&_alglib_env_state);
     try
     {
-        alglib_impl::minlbfgssetstpmax(const_cast<alglib_impl::minlbfgsstate*>(state.c_ptr()), stpmax, &_alglib_env_state);
+        alglib_impl::mincgsetcond(const_cast<alglib_impl::mincgstate*>(state.c_ptr()), epsg, epsf, epsx, maxits, &_alglib_env_state);
         alglib_impl::ae_state_clear(&_alglib_env_state);
         return;
     }
@@ -441,27 +479,42 @@ void minlbfgssetstpmax(const minlbfgsstate &state, const double stpmax)
 }
 
 /*************************************************************************
-Modification of the preconditioner:
-default preconditioner (simple scaling) is used.
+This function sets scaling coefficients for CG optimizer.
 
-INPUT PARAMETERS:
-    State   -   structure which stores algorithm state
+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
 
-After call to this function preconditioner is changed to the default one.
+Scaling is also used by finite difference variant of CG optimizer  -  step
+along I-th axis is equal to DiffStep*S[I].
 
-NOTE:  you  can  change  preconditioner  "on  the  fly",  during algorithm
-iterations.
+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.
 
   -- ALGLIB --
-     Copyright 13.10.2010 by Bochkanov Sergey
+     Copyright 14.01.2011 by Bochkanov Sergey
 *************************************************************************/
-void minlbfgssetdefaultpreconditioner(const minlbfgsstate &state)
+void mincgsetscale(const mincgstate &state, const real_1d_array &s)
 {
     alglib_impl::ae_state _alglib_env_state;
     alglib_impl::ae_state_init(&_alglib_env_state);
     try
     {
-        alglib_impl::minlbfgssetdefaultpreconditioner(const_cast<alglib_impl::minlbfgsstate*>(state.c_ptr()), &_alglib_env_state);
+        alglib_impl::mincgsetscale(const_cast<alglib_impl::mincgstate*>(state.c_ptr()), const_cast<alglib_impl::ae_vector*>(s.c_ptr()), &_alglib_env_state);
         alglib_impl::ae_state_clear(&_alglib_env_state);
         return;
     }
@@ -476,37 +529,25 @@ void minlbfgssetdefaultpreconditioner(const minlbfgsstate &state)
 }
 
 /*************************************************************************
-Modification of the preconditioner:
-Cholesky factorization of approximate Hessian is used.
+This function turns on/off reporting.
 
 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.
+    NeedXRep-   whether iteration reports are needed or not
 
-NOTE 2:  P  should  be nonsingular. Exception will be thrown otherwise. It
-also should be well conditioned, although only strict  non-singularity  is
-tested.
+If NeedXRep is True, algorithm will call rep() callback function if  it is
+provided to MinCGOptimize().
 
   -- ALGLIB --
-     Copyright 13.10.2010 by Bochkanov Sergey
+     Copyright 02.04.2010 by Bochkanov Sergey
 *************************************************************************/
-void minlbfgssetcholeskypreconditioner(const minlbfgsstate &state, const real_2d_array &p, const bool isupper)
+void mincgsetxrep(const mincgstate &state, const bool needxrep)
 {
     alglib_impl::ae_state _alglib_env_state;
     alglib_impl::ae_state_init(&_alglib_env_state);
     try
     {
-        alglib_impl::minlbfgssetcholeskypreconditioner(const_cast<alglib_impl::minlbfgsstate*>(state.c_ptr()), const_cast<alglib_impl::ae_matrix*>(p.c_ptr()), isupper, &_alglib_env_state);
+        alglib_impl::mincgsetxrep(const_cast<alglib_impl::mincgstate*>(state.c_ptr()), needxrep, &_alglib_env_state);
         alglib_impl::ae_state_clear(&_alglib_env_state);
         return;
     }
@@ -521,19 +562,27 @@ void minlbfgssetcholeskypreconditioner(const minlbfgsstate &state, const real_2d
 }
 
 /*************************************************************************
-This function provides reverse communication interface
-Reverse communication interface is not documented or recommended to use.
-See below for functions which provide better documented API
+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
+
+  -- ALGLIB --
+     Copyright 02.04.2010 by Bochkanov Sergey
 *************************************************************************/
-bool minlbfgsiteration(const minlbfgsstate &state)
+void mincgsetcgtype(const mincgstate &state, const ae_int_t cgtype)
 {
     alglib_impl::ae_state _alglib_env_state;
     alglib_impl::ae_state_init(&_alglib_env_state);
     try
     {
-        ae_bool result = alglib_impl::minlbfgsiteration(const_cast<alglib_impl::minlbfgsstate*>(state.c_ptr()), &_alglib_env_state);
+        alglib_impl::mincgsetcgtype(const_cast<alglib_impl::mincgstate*>(state.c_ptr()), cgtype, &_alglib_env_state);
         alglib_impl::ae_state_clear(&_alglib_env_state);
-        return *(reinterpret_cast<bool*>(&result));
+        return;
     }
     catch(alglib_impl::ae_error_type)
     {
@@ -545,34 +594,32 @@ bool minlbfgsiteration(const minlbfgsstate &state)
     }
 }
 
+/*************************************************************************
+This function sets maximum step length
 
-void minlbfgsoptimize(minlbfgsstate &state,
-    void (*grad)(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr),
-    void  (*rep)(const real_1d_array &x, double func, void *ptr), 
-    void *ptr)
+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.
+
+  -- ALGLIB --
+     Copyright 02.04.2010 by Bochkanov Sergey
+*************************************************************************/
+void mincgsetstpmax(const mincgstate &state, const double stpmax)
 {
     alglib_impl::ae_state _alglib_env_state;
-    if( grad==NULL )
-        throw ap_error("ALGLIB: error in 'minlbfgsoptimize()' (grad is NULL)");
     alglib_impl::ae_state_init(&_alglib_env_state);
     try
     {
-        while( alglib_impl::minlbfgsiteration(state.c_ptr(), &_alglib_env_state) )
-        {
-            if( state.needfg )
-            {
-                grad(state.x, state.f, state.g, ptr);
-                continue;
-            }
-            if( state.xupdated )
-            {
-                if( rep!=NULL )
-                    rep(state.x, state.f, ptr);
-                continue;
-            }
-            throw ap_error("ALGLIB: error in 'minlbfgsoptimize' (some derivatives were not provided?)");
-        }
+        alglib_impl::mincgsetstpmax(const_cast<alglib_impl::mincgstate*>(state.c_ptr()), stpmax, &_alglib_env_state);
         alglib_impl::ae_state_clear(&_alglib_env_state);
+        return;
     }
     catch(alglib_impl::ae_error_type)
     {
@@ -584,41 +631,46 @@ void minlbfgsoptimize(minlbfgsstate &state,
     }
 }
 
+/*************************************************************************
+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.
 
-/*************************************************************************
-L-BFGS algorithm results
+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.
 
-INPUT PARAMETERS:
-    State   -   algorithm state
+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.
 
-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
+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).
 
   -- ALGLIB --
-     Copyright 02.04.2010 by Bochkanov Sergey
+     Copyright 30.07.2010 by Bochkanov Sergey
 *************************************************************************/
-void minlbfgsresults(const minlbfgsstate &state, real_1d_array &x, minlbfgsreport &rep)
+void mincgsuggeststep(const mincgstate &state, const double stp)
 {
     alglib_impl::ae_state _alglib_env_state;
     alglib_impl::ae_state_init(&_alglib_env_state);
     try
     {
-        alglib_impl::minlbfgsresults(const_cast<alglib_impl::minlbfgsstate*>(state.c_ptr()), const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::minlbfgsreport*>(rep.c_ptr()), &_alglib_env_state);
+        alglib_impl::mincgsuggeststep(const_cast<alglib_impl::mincgstate*>(state.c_ptr()), stp, &_alglib_env_state);
         alglib_impl::ae_state_clear(&_alglib_env_state);
         return;
     }
@@ -633,23 +685,24 @@ void minlbfgsresults(const minlbfgsstate &state, real_1d_array &x, minlbfgsrepor
 }
 
 /*************************************************************************
-L-BFGS algorithm results
+Modification of the preconditioner: preconditioning is turned off.
 
-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.
+INPUT PARAMETERS:
+    State   -   structure which stores algorithm state
+
+NOTE:  you  can  change  preconditioner  "on  the  fly",  during algorithm
+iterations.
 
   -- ALGLIB --
-     Copyright 20.08.2010 by Bochkanov Sergey
+     Copyright 13.10.2010 by Bochkanov Sergey
 *************************************************************************/
-void minlbfgsresultsbuf(const minlbfgsstate &state, real_1d_array &x, minlbfgsreport &rep)
+void mincgsetprecdefault(const mincgstate &state)
 {
     alglib_impl::ae_state _alglib_env_state;
     alglib_impl::ae_state_init(&_alglib_env_state);
     try
     {
-        alglib_impl::minlbfgsresultsbuf(const_cast<alglib_impl::minlbfgsstate*>(state.c_ptr()), const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::minlbfgsreport*>(rep.c_ptr()), &_alglib_env_state);
+        alglib_impl::mincgsetprecdefault(const_cast<alglib_impl::mincgstate*>(state.c_ptr()), &_alglib_env_state);
         alglib_impl::ae_state_clear(&_alglib_env_state);
         return;
     }
@@ -664,26 +717,31 @@ void minlbfgsresultsbuf(const minlbfgsstate &state, real_1d_array &x, minlbfgsre
 }
 
 /*************************************************************************
-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.
+Modification  of  the  preconditioner:  diagonal of approximate Hessian is
+used.
 
 INPUT PARAMETERS:
-    State   -   structure used to store algorithm state
-    X       -   new starting point.
+    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.
 
   -- ALGLIB --
-     Copyright 30.07.2010 by Bochkanov Sergey
+     Copyright 13.10.2010 by Bochkanov Sergey
 *************************************************************************/
-void minlbfgsrestartfrom(const minlbfgsstate &state, const real_1d_array &x)
+void mincgsetprecdiag(const mincgstate &state, const real_1d_array &d)
 {
     alglib_impl::ae_state _alglib_env_state;
     alglib_impl::ae_state_init(&_alglib_env_state);
     try
     {
-        alglib_impl::minlbfgsrestartfrom(const_cast<alglib_impl::minlbfgsstate*>(state.c_ptr()), const_cast<alglib_impl::ae_vector*>(x.c_ptr()), &_alglib_env_state);
+        alglib_impl::mincgsetprecdiag(const_cast<alglib_impl::mincgstate*>(state.c_ptr()), const_cast<alglib_impl::ae_vector*>(d.c_ptr()), &_alglib_env_state);
         alglib_impl::ae_state_clear(&_alglib_env_state);
         return;
     }
@@ -698,229 +756,508 @@ void minlbfgsrestartfrom(const minlbfgsstate &state, const real_1d_array &x)
 }
 
 /*************************************************************************
-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.
-*************************************************************************/
-_minlmstate_owner::_minlmstate_owner()
-{
-    p_struct = (alglib_impl::minlmstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::minlmstate), NULL);
-    if( p_struct==NULL )
-        throw ap_error("ALGLIB: malloc error");
-    if( !alglib_impl::_minlmstate_init(p_struct, NULL, ae_false) )
-        throw ap_error("ALGLIB: malloc error");
-}
+Modification of the preconditioner: scale-based diagonal preconditioning.
 
-_minlmstate_owner::_minlmstate_owner(const _minlmstate_owner &rhs)
-{
-    p_struct = (alglib_impl::minlmstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::minlmstate), NULL);
-    if( p_struct==NULL )
-        throw ap_error("ALGLIB: malloc error");
-    if( !alglib_impl::_minlmstate_init_copy(p_struct, const_cast<alglib_impl::minlmstate*>(rhs.p_struct), NULL, ae_false) )
-        throw ap_error("ALGLIB: malloc error");
-}
+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.
 
-_minlmstate_owner& _minlmstate_owner::operator=(const _minlmstate_owner &rhs)
-{
-    if( this==&rhs )
-        return *this;
-    alglib_impl::_minlmstate_clear(p_struct);
-    if( !alglib_impl::_minlmstate_init_copy(p_struct, const_cast<alglib_impl::minlmstate*>(rhs.p_struct), NULL, ae_false) )
-        throw ap_error("ALGLIB: malloc error");
-    return *this;
-}
+In this case simple  scale-based  preconditioner,  with H[i] = 1/(s[i]^2),
+can greatly improve convergence.
 
-_minlmstate_owner::~_minlmstate_owner()
-{
-    alglib_impl::_minlmstate_clear(p_struct);
-    ae_free(p_struct);
-}
+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.
 
-alglib_impl::minlmstate* _minlmstate_owner::c_ptr()
-{
-    return p_struct;
-}
+INPUT PARAMETERS:
+    State   -   structure which stores algorithm state
 
-alglib_impl::minlmstate* _minlmstate_owner::c_ptr() const
-{
-    return const_cast<alglib_impl::minlmstate*>(p_struct);
-}
-minlmstate::minlmstate() : _minlmstate_owner() ,needf(p_struct->needf),needfg(p_struct->needfg),needfgh(p_struct->needfgh),needfi(p_struct->needfi),needfij(p_struct->needfij),xupdated(p_struct->xupdated),f(p_struct->f),fi(&p_struct->fi),g(&p_struct->g),h(&p_struct->h),j(&p_struct->j),x(&p_struct->x)
-{
-}
+NOTE:  you  can  change  preconditioner  "on  the  fly",  during algorithm
+iterations.
 
-minlmstate::minlmstate(const minlmstate &rhs):_minlmstate_owner(rhs) ,needf(p_struct->needf),needfg(p_struct->needfg),needfgh(p_struct->needfgh),needfi(p_struct->needfi),needfij(p_struct->needfij),xupdated(p_struct->xupdated),f(p_struct->f),fi(&p_struct->fi),g(&p_struct->g),h(&p_struct->h),j(&p_struct->j),x(&p_struct->x)
+  -- ALGLIB --
+     Copyright 13.10.2010 by Bochkanov Sergey
+*************************************************************************/
+void mincgsetprecscale(const mincgstate &state)
 {
+    alglib_impl::ae_state _alglib_env_state;
+    alglib_impl::ae_state_init(&_alglib_env_state);
+    try
+    {
+        alglib_impl::mincgsetprecscale(const_cast<alglib_impl::mincgstate*>(state.c_ptr()), &_alglib_env_state);
+        alglib_impl::ae_state_clear(&_alglib_env_state);
+        return;
+    }
+    catch(alglib_impl::ae_error_type)
+    {
+        throw ap_error(_alglib_env_state.error_msg);
+    }
+    catch(...)
+    {
+        throw;
+    }
 }
 
-minlmstate& minlmstate::operator=(const minlmstate &rhs)
+/*************************************************************************
+This function provides reverse communication interface
+Reverse communication interface is not documented or recommended to use.
+See below for functions which provide better documented API
+*************************************************************************/
+bool mincgiteration(const mincgstate &state)
 {
-    if( this==&rhs )
-        return *this;
-    _minlmstate_owner::operator=(rhs);
-    return *this;
+    alglib_impl::ae_state _alglib_env_state;
+    alglib_impl::ae_state_init(&_alglib_env_state);
+    try
+    {
+        ae_bool result = alglib_impl::mincgiteration(const_cast<alglib_impl::mincgstate*>(state.c_ptr()), &_alglib_env_state);
+        alglib_impl::ae_state_clear(&_alglib_env_state);
+        return *(reinterpret_cast<bool*>(&result));
+    }
+    catch(alglib_impl::ae_error_type)
+    {
+        throw ap_error(_alglib_env_state.error_msg);
+    }
+    catch(...)
+    {
+        throw;
+    }
 }
 
-minlmstate::~minlmstate()
+
+void mincgoptimize(mincgstate &state,
+    void (*func)(const real_1d_array &x, double &func, void *ptr),
+    void  (*rep)(const real_1d_array &x, double func, void *ptr), 
+    void *ptr)
+{
+    alglib_impl::ae_state _alglib_env_state;
+    if( func==NULL )
+        throw ap_error("ALGLIB: error in 'mincgoptimize()' (func is NULL)");
+    alglib_impl::ae_state_init(&_alglib_env_state);
+    try
+    {
+        while( alglib_impl::mincgiteration(state.c_ptr(), &_alglib_env_state) )
+        {
+            if( state.needf )
+            {
+                func(state.x, state.f, ptr);
+                continue;
+            }
+            if( state.xupdated )
+            {
+                if( rep!=NULL )
+                    rep(state.x, state.f, ptr);
+                continue;
+            }
+            throw ap_error("ALGLIB: error in 'mincgoptimize' (some derivatives were not provided?)");
+        }
+        alglib_impl::ae_state_clear(&_alglib_env_state);
+    }
+    catch(alglib_impl::ae_error_type)
+    {
+        throw ap_error(_alglib_env_state.error_msg);
+    }
+    catch(...)
+    {
+        throw;
+    }
+}
+
+
+void mincgoptimize(mincgstate &state,
+    void (*grad)(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr),
+    void  (*rep)(const real_1d_array &x, double func, void *ptr), 
+    void *ptr)
 {
+    alglib_impl::ae_state _alglib_env_state;
+    if( grad==NULL )
+        throw ap_error("ALGLIB: error in 'mincgoptimize()' (grad is NULL)");
+    alglib_impl::ae_state_init(&_alglib_env_state);
+    try
+    {
+        while( alglib_impl::mincgiteration(state.c_ptr(), &_alglib_env_state) )
+        {
+            if( state.needfg )
+            {
+                grad(state.x, state.f, state.g, ptr);
+                continue;
+            }
+            if( state.xupdated )
+            {
+                if( rep!=NULL )
+                    rep(state.x, state.f, ptr);
+                continue;
+            }
+            throw ap_error("ALGLIB: error in 'mincgoptimize' (some derivatives were not provided?)");
+        }
+        alglib_impl::ae_state_clear(&_alglib_env_state);
+    }
+    catch(alglib_impl::ae_error_type)
+    {
+        throw ap_error(_alglib_env_state.error_msg);
+    }
+    catch(...)
+    {
+        throw;
+    }
 }
 
 
+
 /*************************************************************************
-Optimization report, filled by MinLMResults() function
+Conjugate gradient results
 
-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
+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
+
+  -- ALGLIB --
+     Copyright 20.04.2009 by Bochkanov Sergey
 *************************************************************************/
-_minlmreport_owner::_minlmreport_owner()
+void mincgresults(const mincgstate &state, real_1d_array &x, mincgreport &rep)
 {
-    p_struct = (alglib_impl::minlmreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::minlmreport), NULL);
+    alglib_impl::ae_state _alglib_env_state;
+    alglib_impl::ae_state_init(&_alglib_env_state);
+    try
+    {
+        alglib_impl::mincgresults(const_cast<alglib_impl::mincgstate*>(state.c_ptr()), const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::mincgreport*>(rep.c_ptr()), &_alglib_env_state);
+        alglib_impl::ae_state_clear(&_alglib_env_state);
+        return;
+    }
+    catch(alglib_impl::ae_error_type)
+    {
+        throw ap_error(_alglib_env_state.error_msg);
+    }
+    catch(...)
+    {
+        throw;
+    }
+}
+
+/*************************************************************************
+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.
+
+  -- ALGLIB --
+     Copyright 20.04.2009 by Bochkanov Sergey
+*************************************************************************/
+void mincgresultsbuf(const mincgstate &state, real_1d_array &x, mincgreport &rep)
+{
+    alglib_impl::ae_state _alglib_env_state;
+    alglib_impl::ae_state_init(&_alglib_env_state);
+    try
+    {
+        alglib_impl::mincgresultsbuf(const_cast<alglib_impl::mincgstate*>(state.c_ptr()), const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::mincgreport*>(rep.c_ptr()), &_alglib_env_state);
+        alglib_impl::ae_state_clear(&_alglib_env_state);
+        return;
+    }
+    catch(alglib_impl::ae_error_type)
+    {
+        throw ap_error(_alglib_env_state.error_msg);
+    }
+    catch(...)
+    {
+        throw;
+    }
+}
+
+/*************************************************************************
+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.
+
+  -- ALGLIB --
+     Copyright 30.07.2010 by Bochkanov Sergey
+*************************************************************************/
+void mincgrestartfrom(const mincgstate &state, const real_1d_array &x)
+{
+    alglib_impl::ae_state _alglib_env_state;
+    alglib_impl::ae_state_init(&_alglib_env_state);
+    try
+    {
+        alglib_impl::mincgrestartfrom(const_cast<alglib_impl::mincgstate*>(state.c_ptr()), const_cast<alglib_impl::ae_vector*>(x.c_ptr()), &_alglib_env_state);
+        alglib_impl::ae_state_clear(&_alglib_env_state);
+        return;
+    }
+    catch(alglib_impl::ae_error_type)
+    {
+        throw ap_error(_alglib_env_state.error_msg);
+    }
+    catch(...)
+    {
+        throw;
+    }
+}
+
+/*************************************************************************
+This object stores nonlinear optimizer state.
+You should use functions provided by MinBLEIC subpackage to work with this
+object
+*************************************************************************/
+_minbleicstate_owner::_minbleicstate_owner()
+{
+    p_struct = (alglib_impl::minbleicstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::minbleicstate), NULL);
     if( p_struct==NULL )
         throw ap_error("ALGLIB: malloc error");
-    if( !alglib_impl::_minlmreport_init(p_struct, NULL, ae_false) )
+    if( !alglib_impl::_minbleicstate_init(p_struct, NULL, ae_false) )
         throw ap_error("ALGLIB: malloc error");
 }
 
-_minlmreport_owner::_minlmreport_owner(const _minlmreport_owner &rhs)
+_minbleicstate_owner::_minbleicstate_owner(const _minbleicstate_owner &rhs)
 {
-    p_struct = (alglib_impl::minlmreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::minlmreport), NULL);
+    p_struct = (alglib_impl::minbleicstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::minbleicstate), NULL);
     if( p_struct==NULL )
         throw ap_error("ALGLIB: malloc error");
-    if( !alglib_impl::_minlmreport_init_copy(p_struct, const_cast<alglib_impl::minlmreport*>(rhs.p_struct), NULL, ae_false) )
+    if( !alglib_impl::_minbleicstate_init_copy(p_struct, const_cast<alglib_impl::minbleicstate*>(rhs.p_struct), NULL, ae_false) )
         throw ap_error("ALGLIB: malloc error");
 }
 
-_minlmreport_owner& _minlmreport_owner::operator=(const _minlmreport_owner &rhs)
+_minbleicstate_owner& _minbleicstate_owner::operator=(const _minbleicstate_owner &rhs)
 {
     if( this==&rhs )
         return *this;
-    alglib_impl::_minlmreport_clear(p_struct);
-    if( !alglib_impl::_minlmreport_init_copy(p_struct, const_cast<alglib_impl::minlmreport*>(rhs.p_struct), NULL, ae_false) )
+    alglib_impl::_minbleicstate_clear(p_struct);
+    if( !alglib_impl::_minbleicstate_init_copy(p_struct, const_cast<alglib_impl::minbleicstate*>(rhs.p_struct), NULL, ae_false) )
         throw ap_error("ALGLIB: malloc error");
     return *this;
 }
 
-_minlmreport_owner::~_minlmreport_owner()
+_minbleicstate_owner::~_minbleicstate_owner()
 {
-    alglib_impl::_minlmreport_clear(p_struct);
+    alglib_impl::_minbleicstate_clear(p_struct);
     ae_free(p_struct);
 }
 
-alglib_impl::minlmreport* _minlmreport_owner::c_ptr()
+alglib_impl::minbleicstate* _minbleicstate_owner::c_ptr()
 {
     return p_struct;
 }
 
-alglib_impl::minlmreport* _minlmreport_owner::c_ptr() const
+alglib_impl::minbleicstate* _minbleicstate_owner::c_ptr() const
 {
-    return const_cast<alglib_impl::minlmreport*>(p_struct);
+    return const_cast<alglib_impl::minbleicstate*>(p_struct);
 }
-minlmreport::minlmreport() : _minlmreport_owner() ,iterationscount(p_struct->iterationscount),terminationtype(p_struct->terminationtype),nfunc(p_struct->nfunc),njac(p_struct->njac),ngrad(p_struct->ngrad),nhess(p_struct->nhess),ncholesky(p_struct->ncholesky)
+minbleicstate::minbleicstate() : _minbleicstate_owner() ,needf(p_struct->needf),needfg(p_struct->needfg),xupdated(p_struct->xupdated),f(p_struct->f),g(&p_struct->g),x(&p_struct->x)
 {
 }
 
-minlmreport::minlmreport(const minlmreport &rhs):_minlmreport_owner(rhs) ,iterationscount(p_struct->iterationscount),terminationtype(p_struct->terminationtype),nfunc(p_struct->nfunc),njac(p_struct->njac),ngrad(p_struct->ngrad),nhess(p_struct->nhess),ncholesky(p_struct->ncholesky)
+minbleicstate::minbleicstate(const minbleicstate &rhs):_minbleicstate_owner(rhs) ,needf(p_struct->needf),needfg(p_struct->needfg),xupdated(p_struct->xupdated),f(p_struct->f),g(&p_struct->g),x(&p_struct->x)
 {
 }
 
-minlmreport& minlmreport::operator=(const minlmreport &rhs)
+minbleicstate& minbleicstate::operator=(const minbleicstate &rhs)
 {
     if( this==&rhs )
         return *this;
-    _minlmreport_owner::operator=(rhs);
+    _minbleicstate_owner::operator=(rhs);
     return *this;
 }
 
-minlmreport::~minlmreport()
+minbleicstate::~minbleicstate()
 {
 }
 
+
 /*************************************************************************
-                IMPROVED LEVENBERG-MARQUARDT METHOD FOR
-                 NON-LINEAR LEAST SQUARES OPTIMIZATION
+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
 
-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[].
+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|
+*************************************************************************/
+_minbleicreport_owner::_minbleicreport_owner()
+{
+    p_struct = (alglib_impl::minbleicreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::minbleicreport), NULL);
+    if( p_struct==NULL )
+        throw ap_error("ALGLIB: malloc error");
+    if( !alglib_impl::_minbleicreport_init(p_struct, NULL, ae_false) )
+        throw ap_error("ALGLIB: malloc error");
+}
 
+_minbleicreport_owner::_minbleicreport_owner(const _minbleicreport_owner &rhs)
+{
+    p_struct = (alglib_impl::minbleicreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::minbleicreport), NULL);
+    if( p_struct==NULL )
+        throw ap_error("ALGLIB: malloc error");
+    if( !alglib_impl::_minbleicreport_init_copy(p_struct, const_cast<alglib_impl::minbleicreport*>(rhs.p_struct), NULL, ae_false) )
+        throw ap_error("ALGLIB: malloc error");
+}
 
-REQUIREMENTS:
-This algorithm will request following information during its operation:
+_minbleicreport_owner& _minbleicreport_owner::operator=(const _minbleicreport_owner &rhs)
+{
+    if( this==&rhs )
+        return *this;
+    alglib_impl::_minbleicreport_clear(p_struct);
+    if( !alglib_impl::_minbleicreport_init_copy(p_struct, const_cast<alglib_impl::minbleicreport*>(rhs.p_struct), NULL, ae_false) )
+        throw ap_error("ALGLIB: malloc error");
+    return *this;
+}
 
-* function vector f[] at given point X
-* function vector f[] and Jacobian of f[] (simultaneously) at given point
+_minbleicreport_owner::~_minbleicreport_owner()
+{
+    alglib_impl::_minbleicreport_clear(p_struct);
+    ae_free(p_struct);
+}
 
-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].
+alglib_impl::minbleicreport* _minbleicreport_owner::c_ptr()
+{
+    return p_struct;
+}
 
-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.
+alglib_impl::minbleicreport* _minbleicreport_owner::c_ptr() const
+{
+    return const_cast<alglib_impl::minbleicreport*>(p_struct);
+}
+minbleicreport::minbleicreport() : _minbleicreport_owner() ,inneriterationscount(p_struct->inneriterationscount),outeriterationscount(p_struct->outeriterationscount),nfev(p_struct->nfev),terminationtype(p_struct->terminationtype),debugeqerr(p_struct->debugeqerr),debugfs(p_struct->debugfs),debugff(p_struct->debugff),debugdx(p_struct->debugdx)
+{
+}
+
+minbleicreport::minbleicreport(const minbleicreport &rhs):_minbleicreport_owner(rhs) ,inneriterationscount(p_struct->inneriterationscount),outeriterationscount(p_struct->outeriterationscount),nfev(p_struct->nfev),terminationtype(p_struct->terminationtype),debugeqerr(p_struct->debugeqerr),debugfs(p_struct->debugfs),debugff(p_struct->debugff),debugdx(p_struct->debugdx)
+{
+}
+
+minbleicreport& minbleicreport::operator=(const minbleicreport &rhs)
+{
+    if( this==&rhs )
+        return *this;
+    _minbleicreport_owner::operator=(rhs);
+    return *this;
+}
+
+minbleicreport::~minbleicreport()
+{
+}
 
+/*************************************************************************
+                     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:
-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.
+
+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       -   dimension, N>1
+    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 functions f[i]
-    X       -   initial solution, array[0..N-1]
+                * 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 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.
+    State   -   structure stores algorithm state
 
   -- ALGLIB --
-     Copyright 30.03.2009 by Bochkanov Sergey
+     Copyright 28.11.2010 by Bochkanov Sergey
 *************************************************************************/
-void minlmcreatevj(const ae_int_t n, const ae_int_t m, const real_1d_array &x, minlmstate &state)
+void minbleiccreate(const ae_int_t n, const real_1d_array &x, minbleicstate &state)
 {
     alglib_impl::ae_state _alglib_env_state;
     alglib_impl::ae_state_init(&_alglib_env_state);
     try
     {
-        alglib_impl::minlmcreatevj(n, m, const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::minlmstate*>(state.c_ptr()), &_alglib_env_state);
+        alglib_impl::minbleiccreate(n, const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::minbleicstate*>(state.c_ptr()), &_alglib_env_state);
         alglib_impl::ae_state_clear(&_alglib_env_state);
         return;
     }
@@ -935,67 +1272,75 @@ void minlmcreatevj(const ae_int_t n, const ae_int_t m, const real_1d_array &x, m
 }
 
 /*************************************************************************
-                IMPROVED LEVENBERG-MARQUARDT METHOD FOR
-                 NON-LINEAR LEAST SQUARES OPTIMIZATION
+                     BOUND CONSTRAINED OPTIMIZATION
+       WITH ADDITIONAL LINEAR EQUALITY AND INEQUALITY CONSTRAINTS
 
 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[].
-
+The  subroutine  minimizes  function   F(x)  of N arguments subject to any
+combination of:
+* bound constraints
+* linear inequality constraints
+* linear equality constraints
 
 REQUIREMENTS:
-This algorithm will request following information during its operation:
+* 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
 
-* function vector f[] at given point X
-* function vector f[] and Jacobian of f[] (simultaneously) at given point
+USAGE:
 
-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].
+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/
 
-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.
+1. User initializes algorithm state with MinBLEICCreate() call
 
+2. USer adds boundary and/or linear constraints by calling
+   MinBLEICSetBC() and MinBLEICSetLC() functions.
 
-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.
+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       -   dimension, N>1
+    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 functions f[i]
-    X       -   initial solution, array[0..N-1]
+                * 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 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.
+    State   -   structure stores algorithm state
 
   -- ALGLIB --
-     Copyright 30.03.2009 by Bochkanov Sergey
+     Copyright 28.11.2010 by Bochkanov Sergey
 *************************************************************************/
-void minlmcreatevj(const ae_int_t m, const real_1d_array &x, minlmstate &state)
+void minbleiccreate(const real_1d_array &x, minbleicstate &state)
 {
     alglib_impl::ae_state _alglib_env_state;    
     ae_int_t n;
@@ -1004,7 +1349,7 @@ void minlmcreatevj(const ae_int_t m, const real_1d_array &x, minlmstate &state)
     alglib_impl::ae_state_init(&_alglib_env_state);
     try
     {
-        alglib_impl::minlmcreatevj(n, m, const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::minlmstate*>(state.c_ptr()), &_alglib_env_state);
+        alglib_impl::minbleiccreate(n, const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::minbleicstate*>(state.c_ptr()), &_alglib_env_state);
 
         alglib_impl::ae_state_clear(&_alglib_env_state);
         return;
@@ -1020,73 +1365,54 @@ void minlmcreatevj(const ae_int_t m, const real_1d_array &x, minlmstate &state)
 }
 
 /*************************************************************************
-                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.
+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       -   dimension, N>1
+    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 functions f[i]
-    X       -   initial solution, array[0..N-1]
+    X       -   starting point, 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.
+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.
 
   -- ALGLIB --
-     Copyright 30.03.2009 by Bochkanov Sergey
+     Copyright 16.05.2011 by Bochkanov Sergey
 *************************************************************************/
-void minlmcreatev(const ae_int_t n, const ae_int_t m, const real_1d_array &x, const double diffstep, minlmstate &state)
+void minbleiccreatef(const ae_int_t n, const real_1d_array &x, const double diffstep, minbleicstate &state)
 {
     alglib_impl::ae_state _alglib_env_state;
     alglib_impl::ae_state_init(&_alglib_env_state);
     try
     {
-        alglib_impl::minlmcreatev(n, m, const_cast<alglib_impl::ae_vector*>(x.c_ptr()), diffstep, const_cast<alglib_impl::minlmstate*>(state.c_ptr()), &_alglib_env_state);
+        alglib_impl::minbleiccreatef(n, const_cast<alglib_impl::ae_vector*>(x.c_ptr()), diffstep, const_cast<alglib_impl::minbleicstate*>(state.c_ptr()), &_alglib_env_state);
         alglib_impl::ae_state_clear(&_alglib_env_state);
         return;
     }
@@ -1101,67 +1427,48 @@ void minlmcreatev(const ae_int_t n, const ae_int_t m, const real_1d_array &x, co
 }
 
 /*************************************************************************
-                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.
+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       -   dimension, N>1
+    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 functions f[i]
-    X       -   initial solution, array[0..N-1]
+    X       -   starting point, 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.
+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.
 
   -- ALGLIB --
-     Copyright 30.03.2009 by Bochkanov Sergey
+     Copyright 16.05.2011 by Bochkanov Sergey
 *************************************************************************/
-void minlmcreatev(const ae_int_t m, const real_1d_array &x, const double diffstep, minlmstate &state)
+void minbleiccreatef(const real_1d_array &x, const double diffstep, minbleicstate &state)
 {
     alglib_impl::ae_state _alglib_env_state;    
     ae_int_t n;
@@ -1170,7 +1477,7 @@ void minlmcreatev(const ae_int_t m, const real_1d_array &x, const double diffste
     alglib_impl::ae_state_init(&_alglib_env_state);
     try
     {
-        alglib_impl::minlmcreatev(n, m, const_cast<alglib_impl::ae_vector*>(x.c_ptr()), diffstep, const_cast<alglib_impl::minlmstate*>(state.c_ptr()), &_alglib_env_state);
+        alglib_impl::minbleiccreatef(n, const_cast<alglib_impl::ae_vector*>(x.c_ptr()), diffstep, const_cast<alglib_impl::minbleicstate*>(state.c_ptr()), &_alglib_env_state);
 
         alglib_impl::ae_state_clear(&_alglib_env_state);
         return;
@@ -1186,74 +1493,39 @@ void minlmcreatev(const ae_int_t m, const real_1d_array &x, const double diffste
 }
 
 /*************************************************************************
-    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.
+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:
-    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]
+    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.
 
-OUTPUT PARAMETERS:
-    State   -   structure which stores algorithm state
+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].
 
-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.
+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)
 
   -- ALGLIB --
-     Copyright 30.03.2009 by Bochkanov Sergey
+     Copyright 28.11.2010 by Bochkanov Sergey
 *************************************************************************/
-void minlmcreatefgh(const ae_int_t n, const real_1d_array &x, minlmstate &state)
+void minbleicsetbc(const minbleicstate &state, const real_1d_array &bndl, const real_1d_array &bndu)
 {
     alglib_impl::ae_state _alglib_env_state;
     alglib_impl::ae_state_init(&_alglib_env_state);
     try
     {
-        alglib_impl::minlmcreatefgh(n, const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::minlmstate*>(state.c_ptr()), &_alglib_env_state);
+        alglib_impl::minbleicsetbc(const_cast<alglib_impl::minbleicstate*>(state.c_ptr()), const_cast<alglib_impl::ae_vector*>(bndl.c_ptr()), const_cast<alglib_impl::ae_vector*>(bndu.c_ptr()), &_alglib_env_state);
         alglib_impl::ae_state_clear(&_alglib_env_state);
         return;
     }
@@ -1268,78 +1540,48 @@ void minlmcreatefgh(const ae_int_t n, const real_1d_array &x, minlmstate &state)
 }
 
 /*************************************************************************
-    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.
+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:
-    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
+    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
 
-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.
+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).
 
   -- ALGLIB --
-     Copyright 30.03.2009 by Bochkanov Sergey
+     Copyright 28.11.2010 by Bochkanov Sergey
 *************************************************************************/
-void minlmcreatefgh(const real_1d_array &x, minlmstate &state)
+void minbleicsetlc(const minbleicstate &state, const real_2d_array &c, const integer_1d_array &ct, const ae_int_t k)
 {
-    alglib_impl::ae_state _alglib_env_state;    
-    ae_int_t n;
-
-    n = x.length();
+    alglib_impl::ae_state _alglib_env_state;
     alglib_impl::ae_state_init(&_alglib_env_state);
     try
     {
-        alglib_impl::minlmcreatefgh(n, const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::minlmstate*>(state.c_ptr()), &_alglib_env_state);
-
+        alglib_impl::minbleicsetlc(const_cast<alglib_impl::minbleicstate*>(state.c_ptr()), const_cast<alglib_impl::ae_matrix*>(c.c_ptr()), const_cast<alglib_impl::ae_vector*>(ct.c_ptr()), k, &_alglib_env_state);
         alglib_impl::ae_state_clear(&_alglib_env_state);
         return;
     }
@@ -1354,82 +1596,53 @@ void minlmcreatefgh(const real_1d_array &x, minlmstate &state)
 }
 
 /*************************************************************************
-                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[]
-* value of Jacobian of f[]
-* gradient of merit function F(x)
-
-This function creates optimizer which uses acceleration strategy 2.  Cheap
-gradient of merit function (which is twice the product of function  vector
-and Jacobian) is used for accelerated iterations (see User Guide for  more
-info on this subject).
-
-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
-* gradient of
-
-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(),  jac()  and  grad()
-callbacks. First one is used to calculate f[] at given point,  second  one
-calculates f[] and Jacobian df[i]/dx[j], last one calculates  gradient  of
-merit function F(x).
-
-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 MinLMCreateVGJ() 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.
+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:
-    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
+    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
 
-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.
+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).
 
   -- ALGLIB --
-     Copyright 30.03.2009 by Bochkanov Sergey
+     Copyright 28.11.2010 by Bochkanov Sergey
 *************************************************************************/
-void minlmcreatevgj(const ae_int_t n, const ae_int_t m, const real_1d_array &x, minlmstate &state)
+void minbleicsetlc(const minbleicstate &state, const real_2d_array &c, const integer_1d_array &ct)
 {
-    alglib_impl::ae_state _alglib_env_state;
+    alglib_impl::ae_state _alglib_env_state;    
+    ae_int_t k;
+    if( (c.rows()!=ct.length()))
+        throw ap_error("Error while calling 'minbleicsetlc': looks like one of arguments has wrong size");
+    k = c.rows();
     alglib_impl::ae_state_init(&_alglib_env_state);
     try
     {
-        alglib_impl::minlmcreatevgj(n, m, const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::minlmstate*>(state.c_ptr()), &_alglib_env_state);
+        alglib_impl::minbleicsetlc(const_cast<alglib_impl::minbleicstate*>(state.c_ptr()), const_cast<alglib_impl::ae_matrix*>(c.c_ptr()), const_cast<alglib_impl::ae_vector*>(ct.c_ptr()), k, &_alglib_env_state);
+
         alglib_impl::ae_state_clear(&_alglib_env_state);
         return;
     }
@@ -1444,86 +1657,47 @@ void minlmcreatevgj(const ae_int_t n, const ae_int_t m, const real_1d_array &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[]
-* value of Jacobian of f[]
-* gradient of merit function F(x)
-
-This function creates optimizer which uses acceleration strategy 2.  Cheap
-gradient of merit function (which is twice the product of function  vector
-and Jacobian) is used for accelerated iterations (see User Guide for  more
-info on this subject).
-
-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
-* gradient of
-
-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(),  jac()  and  grad()
-callbacks. First one is used to calculate f[] at given point,  second  one
-calculates f[] and Jacobian df[i]/dx[j], last one calculates  gradient  of
-merit function F(x).
-
-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 MinLMCreateVGJ() 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.
-
+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:
-    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
+    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()
 
-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.
+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.
 
   -- ALGLIB --
-     Copyright 30.03.2009 by Bochkanov Sergey
+     Copyright 28.11.2010 by Bochkanov Sergey
 *************************************************************************/
-void minlmcreatevgj(const ae_int_t m, const real_1d_array &x, minlmstate &state)
+void minbleicsetinnercond(const minbleicstate &state, const double epsg, const double epsf, const double epsx)
 {
-    alglib_impl::ae_state _alglib_env_state;    
-    ae_int_t n;
-
-    n = x.length();
+    alglib_impl::ae_state _alglib_env_state;
     alglib_impl::ae_state_init(&_alglib_env_state);
     try
     {
-        alglib_impl::minlmcreatevgj(n, m, const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::minlmstate*>(state.c_ptr()), &_alglib_env_state);
-
+        alglib_impl::minbleicsetinnercond(const_cast<alglib_impl::minbleicstate*>(state.c_ptr()), epsg, epsf, epsx, &_alglib_env_state);
         alglib_impl::ae_state_clear(&_alglib_env_state);
         return;
     }
@@ -1538,31 +1712,40 @@ void minlmcreatevgj(const ae_int_t m, const real_1d_array &x, minlmstate &state)
 }
 
 /*************************************************************************
-                   LEVENBERG-MARQUARDT-LIKE METHOD FOR
-                  NON-LINEAR LEAST SQUARES OPTIMIZATION
+This function sets stopping conditions for outer iteration of BLEIC algo.
 
-DESCRIPTION:
+These conditions control accuracy of constraint handling and amount of
+infeasibility allowed in the solution.
 
-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 F(), gradient of F(), function vector f[]  and  Jacobian of
-f[].
+INPUT PARAMETERS:
+    State   -   structure which stores algorithm state
+    EpsX    -   >0, stopping condition on outer iteration step length
+    EpsI    -   >0, stopping condition on infeasibility
 
-This function is considered obsolete since ALGLIB 3.1.0 and is present for
-backward  compatibility  only.  We  recommend to use MinLMCreateVGJ, which
-provides similar, but more consistent interface.
+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.
 
   -- ALGLIB --
-     Copyright 30.03.2009 by Bochkanov Sergey
+     Copyright 28.11.2010 by Bochkanov Sergey
 *************************************************************************/
-void minlmcreatefgj(const ae_int_t n, const ae_int_t m, const real_1d_array &x, minlmstate &state)
+void minbleicsetoutercond(const minbleicstate &state, const double epsx, const double epsi)
 {
     alglib_impl::ae_state _alglib_env_state;
     alglib_impl::ae_state_init(&_alglib_env_state);
     try
     {
-        alglib_impl::minlmcreatefgj(n, m, const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::minlmstate*>(state.c_ptr()), &_alglib_env_state);
+        alglib_impl::minbleicsetoutercond(const_cast<alglib_impl::minbleicstate*>(state.c_ptr()), epsx, epsi, &_alglib_env_state);
         alglib_impl::ae_state_clear(&_alglib_env_state);
         return;
     }
@@ -1577,35 +1760,43 @@ void minlmcreatefgj(const ae_int_t n, const ae_int_t m, const real_1d_array &x,
 }
 
 /*************************************************************************
-                   LEVENBERG-MARQUARDT-LIKE METHOD FOR
-                  NON-LINEAR LEAST SQUARES OPTIMIZATION
+This function sets scaling coefficients for BLEIC optimizer.
 
-DESCRIPTION:
+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
 
-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 F(), gradient of F(), function vector f[]  and  Jacobian of
-f[].
+Scaling is also used by finite difference variant of the optimizer  - step
+along I-th axis is equal to DiffStep*S[I].
 
-This function is considered obsolete since ALGLIB 3.1.0 and is present for
-backward  compatibility  only.  We  recommend to use MinLMCreateVGJ, which
-provides similar, but more consistent interface.
+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.
 
   -- ALGLIB --
-     Copyright 30.03.2009 by Bochkanov Sergey
+     Copyright 14.01.2011 by Bochkanov Sergey
 *************************************************************************/
-void minlmcreatefgj(const ae_int_t m, const real_1d_array &x, minlmstate &state)
+void minbleicsetscale(const minbleicstate &state, const real_1d_array &s)
 {
-    alglib_impl::ae_state _alglib_env_state;    
-    ae_int_t n;
-
-    n = x.length();
+    alglib_impl::ae_state _alglib_env_state;
     alglib_impl::ae_state_init(&_alglib_env_state);
     try
     {
-        alglib_impl::minlmcreatefgj(n, m, const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::minlmstate*>(state.c_ptr()), &_alglib_env_state);
-
+        alglib_impl::minbleicsetscale(const_cast<alglib_impl::minbleicstate*>(state.c_ptr()), const_cast<alglib_impl::ae_vector*>(s.c_ptr()), &_alglib_env_state);
         alglib_impl::ae_state_clear(&_alglib_env_state);
         return;
     }
@@ -1620,29 +1811,21 @@ void minlmcreatefgj(const ae_int_t m, const real_1d_array &x, minlmstate &state)
 }
 
 /*************************************************************************
-    CLASSIC LEVENBERG-MARQUARDT METHOD FOR NON-LINEAR 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  F(),  function  vector  f[] and Jacobian of f[]. Classic
-Levenberg-Marquardt method is used.
+Modification of the preconditioner: preconditioning is turned off.
 
-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.
+INPUT PARAMETERS:
+    State   -   structure which stores algorithm state
 
   -- ALGLIB --
-     Copyright 30.03.2009 by Bochkanov Sergey
+     Copyright 13.10.2010 by Bochkanov Sergey
 *************************************************************************/
-void minlmcreatefj(const ae_int_t n, const ae_int_t m, const real_1d_array &x, minlmstate &state)
+void minbleicsetprecdefault(const minbleicstate &state)
 {
     alglib_impl::ae_state _alglib_env_state;
     alglib_impl::ae_state_init(&_alglib_env_state);
     try
     {
-        alglib_impl::minlmcreatefj(n, m, const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::minlmstate*>(state.c_ptr()), &_alglib_env_state);
+        alglib_impl::minbleicsetprecdefault(const_cast<alglib_impl::minbleicstate*>(state.c_ptr()), &_alglib_env_state);
         alglib_impl::ae_state_clear(&_alglib_env_state);
         return;
     }
@@ -1657,33 +1840,28 @@ void minlmcreatefj(const ae_int_t n, const ae_int_t m, const real_1d_array &x, m
 }
 
 /*************************************************************************
-    CLASSIC LEVENBERG-MARQUARDT METHOD FOR NON-LINEAR OPTIMIZATION
+Modification  of  the  preconditioner:  diagonal of approximate Hessian is
+used.
 
-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  F(),  function  vector  f[] and Jacobian of f[]. Classic
-Levenberg-Marquardt method 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).
 
-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.
+NOTE 1: D[i] should be positive. Exception will be thrown otherwise.
+
+NOTE 2: you should pass diagonal of approximate Hessian - NOT ITS INVERSE.
 
   -- ALGLIB --
-     Copyright 30.03.2009 by Bochkanov Sergey
+     Copyright 13.10.2010 by Bochkanov Sergey
 *************************************************************************/
-void minlmcreatefj(const ae_int_t m, const real_1d_array &x, minlmstate &state)
+void minbleicsetprecdiag(const minbleicstate &state, const real_1d_array &d)
 {
-    alglib_impl::ae_state _alglib_env_state;    
-    ae_int_t n;
-
-    n = x.length();
+    alglib_impl::ae_state _alglib_env_state;
     alglib_impl::ae_state_init(&_alglib_env_state);
     try
     {
-        alglib_impl::minlmcreatefj(n, m, const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::minlmstate*>(state.c_ptr()), &_alglib_env_state);
-
+        alglib_impl::minbleicsetprecdiag(const_cast<alglib_impl::minbleicstate*>(state.c_ptr()), const_cast<alglib_impl::ae_vector*>(d.c_ptr()), &_alglib_env_state);
         alglib_impl::ae_state_clear(&_alglib_env_state);
         return;
     }
@@ -1698,41 +1876,34 @@ void minlmcreatefj(const ae_int_t m, const real_1d_array &x, minlmstate &state)
 }
 
 /*************************************************************************
-This function sets stopping conditions for Levenberg-Marquardt optimization
-algorithm.
+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
-    EpsG    -   >=0
-                The  subroutine  finishes  its  work   if   the  condition
-                ||G||<EpsG is satisfied, where ||.|| means Euclidian norm,
-                G - gradient.
-    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 |X(k+1)-X(k)| <= EpsX is fulfilled.
-    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).
 
   -- ALGLIB --
-     Copyright 02.04.2010 by Bochkanov Sergey
+     Copyright 13.10.2010 by Bochkanov Sergey
 *************************************************************************/
-void minlmsetcond(const minlmstate &state, const double epsg, const double epsf, const double epsx, const ae_int_t maxits)
+void minbleicsetprecscale(const minbleicstate &state)
 {
     alglib_impl::ae_state _alglib_env_state;
     alglib_impl::ae_state_init(&_alglib_env_state);
     try
     {
-        alglib_impl::minlmsetcond(const_cast<alglib_impl::minlmstate*>(state.c_ptr()), epsg, epsf, epsx, maxits, &_alglib_env_state);
+        alglib_impl::minbleicsetprecscale(const_cast<alglib_impl::minbleicstate*>(state.c_ptr()), &_alglib_env_state);
         alglib_impl::ae_state_clear(&_alglib_env_state);
         return;
     }
@@ -1747,26 +1918,24 @@ void minlmsetcond(const minlmstate &state, const double epsg, const double epsf,
 }
 
 /*************************************************************************
-This function turns on/off reporting.
-
+This function allows to stop algorithm after specified number of inner
+iterations.
+
 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.
+    MaxIts  -   maximum number of inner iterations.
+                If MaxIts=0, the number of iterations is unlimited.
 
   -- ALGLIB --
-     Copyright 02.04.2010 by Bochkanov Sergey
+     Copyright 28.11.2010 by Bochkanov Sergey
 *************************************************************************/
-void minlmsetxrep(const minlmstate &state, const bool needxrep)
+void minbleicsetmaxits(const minbleicstate &state, const ae_int_t maxits)
 {
     alglib_impl::ae_state _alglib_env_state;
     alglib_impl::ae_state_init(&_alglib_env_state);
     try
     {
-        alglib_impl::minlmsetxrep(const_cast<alglib_impl::minlmstate*>(state.c_ptr()), needxrep, &_alglib_env_state);
+        alglib_impl::minbleicsetmaxits(const_cast<alglib_impl::minbleicstate*>(state.c_ptr()), maxits, &_alglib_env_state);
         alglib_impl::ae_state_clear(&_alglib_env_state);
         return;
     }
@@ -1781,33 +1950,25 @@ void minlmsetxrep(const minlmstate &state, const bool needxrep)
 }
 
 /*************************************************************************
-This function sets maximum step length
+This function turns on/off reporting.
 
 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.
+    NeedXRep-   whether iteration reports are needed or not
 
-NOTE: non-zero StpMax leads to moderate  performance  degradation  because
-intermediate  step  of  preconditioned L-BFGS optimization is incompatible
-with limits on step size.
+If NeedXRep is True, algorithm will call rep() callback function if  it is
+provided to MinBLEICOptimize().
 
   -- ALGLIB --
-     Copyright 02.04.2010 by Bochkanov Sergey
+     Copyright 28.11.2010 by Bochkanov Sergey
 *************************************************************************/
-void minlmsetstpmax(const minlmstate &state, const double stpmax)
+void minbleicsetxrep(const minbleicstate &state, const bool needxrep)
 {
     alglib_impl::ae_state _alglib_env_state;
     alglib_impl::ae_state_init(&_alglib_env_state);
     try
     {
-        alglib_impl::minlmsetstpmax(const_cast<alglib_impl::minlmstate*>(state.c_ptr()), stpmax, &_alglib_env_state);
+        alglib_impl::minbleicsetxrep(const_cast<alglib_impl::minbleicstate*>(state.c_ptr()), needxrep, &_alglib_env_state);
         alglib_impl::ae_state_clear(&_alglib_env_state);
         return;
     }
@@ -1822,69 +1983,37 @@ void minlmsetstpmax(const minlmstate &state, const double stpmax)
 }
 
 /*************************************************************************
-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=2, after quadratic model is built and LM step is made, we use it
-  as preconditioner for several (5-10) iterations of L-BFGS algorithm.
-
-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.
-
-AccType=2 is recommended when Jacobian is cheap - much more  cheaper  than
-one  Cholesky  factorization.   We   can   reduce   number   of   Cholesky
-factorizations at the cost of increased number of  Jacobian  calculations.
-Sometimes it helps.
-
-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   2   comment
-V           +   +
-VJ          +   +   +
-FGH         +       +
-VGJ         +   +   +   special protocol, not for widespread use
-FJ          +       +   obsolete protocol, not recommended
-FGJ         +       +   obsolete protocol, not recommended
+This function sets maximum step length
 
-DAFAULT VALUES:
+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.
 
-protocol    0   1   2   comment
-V               x       without acceleration it is so slooooooooow
-VJ          x
-FGH         x
-VGJ                 x   we've implicitly turned (2) by passing gradient
-FJ          x           obsolete protocol, not recommended
-FGJ                 x   obsolete protocol, not recommended
+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.
 
-NOTE: this  function should be called before optimization. Attempt to call
-it during algorithm iterations may result in unexpected behavior.
+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.
 
-NOTE: attempt to call this function with unsupported protocol/acceleration
-combination will result in exception being thrown.
+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.
 
   -- ALGLIB --
-     Copyright 14.10.2010 by Bochkanov Sergey
+     Copyright 02.04.2010 by Bochkanov Sergey
 *************************************************************************/
-void minlmsetacctype(const minlmstate &state, const ae_int_t acctype)
+void minbleicsetstpmax(const minbleicstate &state, const double stpmax)
 {
     alglib_impl::ae_state _alglib_env_state;
     alglib_impl::ae_state_init(&_alglib_env_state);
     try
     {
-        alglib_impl::minlmsetacctype(const_cast<alglib_impl::minlmstate*>(state.c_ptr()), acctype, &_alglib_env_state);
+        alglib_impl::minbleicsetstpmax(const_cast<alglib_impl::minbleicstate*>(state.c_ptr()), stpmax, &_alglib_env_state);
         alglib_impl::ae_state_clear(&_alglib_env_state);
         return;
     }
@@ -1903,13 +2032,13 @@ This function provides reverse communication interface
 Reverse communication interface is not documented or recommended to use.
 See below for functions which provide better documented API
 *************************************************************************/
-bool minlmiteration(const minlmstate &state)
+bool minbleiciteration(const minbleicstate &state)
 {
     alglib_impl::ae_state _alglib_env_state;
     alglib_impl::ae_state_init(&_alglib_env_state);
     try
     {
-        ae_bool result = alglib_impl::minlmiteration(const_cast<alglib_impl::minlmstate*>(state.c_ptr()), &_alglib_env_state);
+        ae_bool result = alglib_impl::minbleiciteration(const_cast<alglib_impl::minbleicstate*>(state.c_ptr()), &_alglib_env_state);
         alglib_impl::ae_state_clear(&_alglib_env_state);
         return *(reinterpret_cast<bool*>(&result));
     }
@@ -1924,22 +2053,22 @@ bool minlmiteration(const minlmstate &state)
 }
 
 
-void minlmoptimize(minlmstate &state,
-    void (*fvec)(const real_1d_array &x, real_1d_array &fi, void *ptr),
+void minbleicoptimize(minbleicstate &state,
+    void (*func)(const real_1d_array &x, double &func, void *ptr),
     void  (*rep)(const real_1d_array &x, double func, void *ptr), 
     void *ptr)
 {
     alglib_impl::ae_state _alglib_env_state;
-    if( fvec==NULL )
-        throw ap_error("ALGLIB: error in 'minlmoptimize()' (fvec is NULL)");
+    if( func==NULL )
+        throw ap_error("ALGLIB: error in 'minbleicoptimize()' (func is NULL)");
     alglib_impl::ae_state_init(&_alglib_env_state);
     try
     {
-        while( alglib_impl::minlmiteration(state.c_ptr(), &_alglib_env_state) )
+        while( alglib_impl::minbleiciteration(state.c_ptr(), &_alglib_env_state) )
         {
-            if( state.needfi )
+            if( state.needf )
             {
-                fvec(state.x, state.fi, ptr);
+                func(state.x, state.f, ptr);
                 continue;
             }
             if( state.xupdated )
@@ -1948,7 +2077,7 @@ void minlmoptimize(minlmstate &state,
                     rep(state.x, state.f, ptr);
                 continue;
             }
-            throw ap_error("ALGLIB: error in 'minlmoptimize' (some derivatives were not provided?)");
+            throw ap_error("ALGLIB: error in 'minbleicoptimize' (some derivatives were not provided?)");
         }
         alglib_impl::ae_state_clear(&_alglib_env_state);
     }
@@ -1963,30 +2092,22 @@ void minlmoptimize(minlmstate &state,
 }
 
 
-void minlmoptimize(minlmstate &state,
-    void (*fvec)(const real_1d_array &x, real_1d_array &fi, void *ptr),
-    void  (*jac)(const real_1d_array &x, real_1d_array &fi, real_2d_array &jac, void *ptr),
+void minbleicoptimize(minbleicstate &state,
+    void (*grad)(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr),
     void  (*rep)(const real_1d_array &x, double func, void *ptr), 
     void *ptr)
 {
     alglib_impl::ae_state _alglib_env_state;
-    if( fvec==NULL )
-        throw ap_error("ALGLIB: error in 'minlmoptimize()' (fvec is NULL)");
-    if( jac==NULL )
-        throw ap_error("ALGLIB: error in 'minlmoptimize()' (jac is NULL)");
+    if( grad==NULL )
+        throw ap_error("ALGLIB: error in 'minbleicoptimize()' (grad is NULL)");
     alglib_impl::ae_state_init(&_alglib_env_state);
     try
     {
-        while( alglib_impl::minlmiteration(state.c_ptr(), &_alglib_env_state) )
+        while( alglib_impl::minbleiciteration(state.c_ptr(), &_alglib_env_state) )
         {
-            if( state.needfi )
-            {
-                fvec(state.x, state.fi, ptr);
-                continue;
-            }
-            if( state.needfij )
+            if( state.needfg )
             {
-                jac(state.x, state.fi, state.j, ptr);
+                grad(state.x, state.f, state.g, ptr);
                 continue;
             }
             if( state.xupdated )
@@ -1995,7 +2116,7 @@ void minlmoptimize(minlmstate &state,
                     rep(state.x, state.f, ptr);
                 continue;
             }
-            throw ap_error("ALGLIB: error in 'minlmoptimize' (some derivatives were not provided?)");
+            throw ap_error("ALGLIB: error in 'minbleicoptimize' (some derivatives were not provided?)");
         }
         alglib_impl::ae_state_clear(&_alglib_env_state);
     }
@@ -2010,49 +2131,33 @@ void minlmoptimize(minlmstate &state,
 }
 
 
-void minlmoptimize(minlmstate &state,
-    void (*func)(const real_1d_array &x, double &func, void *ptr),
-    void (*grad)(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr),
-    void (*hess)(const real_1d_array &x, double &func, real_1d_array &grad, real_2d_array &hess, void *ptr),
-    void  (*rep)(const real_1d_array &x, double func, void *ptr), 
-    void *ptr)
+
+/*************************************************************************
+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.
+
+  -- ALGLIB --
+     Copyright 28.11.2010 by Bochkanov Sergey
+*************************************************************************/
+void minbleicresults(const minbleicstate &state, real_1d_array &x, minbleicreport &rep)
 {
     alglib_impl::ae_state _alglib_env_state;
-    if( func==NULL )
-        throw ap_error("ALGLIB: error in 'minlmoptimize()' (func is NULL)");
-    if( grad==NULL )
-        throw ap_error("ALGLIB: error in 'minlmoptimize()' (grad is NULL)");
-    if( hess==NULL )
-        throw ap_error("ALGLIB: error in 'minlmoptimize()' (hess is NULL)");
     alglib_impl::ae_state_init(&_alglib_env_state);
     try
     {
-        while( alglib_impl::minlmiteration(state.c_ptr(), &_alglib_env_state) )
-        {
-            if( state.needf )
-            {
-                func(state.x, state.f, ptr);
-                continue;
-            }
-            if( state.needfg )
-            {
-                grad(state.x, state.f, state.g, ptr);
-                continue;
-            }
-            if( state.needfgh )
-            {
-                hess(state.x, state.f, state.g, state.h, ptr);
-                continue;
-            }
-            if( state.xupdated )
-            {
-                if( rep!=NULL )
-                    rep(state.x, state.f, ptr);
-                continue;
-            }
-            throw ap_error("ALGLIB: error in 'minlmoptimize' (some derivatives were not provided?)");
-        }
+        alglib_impl::minbleicresults(const_cast<alglib_impl::minbleicstate*>(state.c_ptr()), const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::minbleicreport*>(rep.c_ptr()), &_alglib_env_state);
         alglib_impl::ae_state_clear(&_alglib_env_state);
+        return;
     }
     catch(alglib_impl::ae_error_type)
     {
@@ -2064,42 +2169,26 @@ void minlmoptimize(minlmstate &state,
     }
 }
 
+/*************************************************************************
+BLEIC results
 
-void minlmoptimize(minlmstate &state,
-    void (*func)(const real_1d_array &x, double &func, void *ptr),
-    void  (*jac)(const real_1d_array &x, real_1d_array &fi, real_2d_array &jac, void *ptr),
-    void  (*rep)(const real_1d_array &x, double func, void *ptr), 
-    void *ptr)
+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.
+
+  -- ALGLIB --
+     Copyright 28.11.2010 by Bochkanov Sergey
+*************************************************************************/
+void minbleicresultsbuf(const minbleicstate &state, real_1d_array &x, minbleicreport &rep)
 {
     alglib_impl::ae_state _alglib_env_state;
-    if( func==NULL )
-        throw ap_error("ALGLIB: error in 'minlmoptimize()' (func is NULL)");
-    if( jac==NULL )
-        throw ap_error("ALGLIB: error in 'minlmoptimize()' (jac is NULL)");
     alglib_impl::ae_state_init(&_alglib_env_state);
     try
     {
-        while( alglib_impl::minlmiteration(state.c_ptr(), &_alglib_env_state) )
-        {
-            if( state.needf )
-            {
-                func(state.x, state.f, ptr);
-                continue;
-            }
-            if( state.needfij )
-            {
-                jac(state.x, state.fi, state.j, ptr);
-                continue;
-            }
-            if( state.xupdated )
-            {
-                if( rep!=NULL )
-                    rep(state.x, state.f, ptr);
-                continue;
-            }
-            throw ap_error("ALGLIB: error in 'minlmoptimize' (some derivatives were not provided?)");
-        }
+        alglib_impl::minbleicresultsbuf(const_cast<alglib_impl::minbleicstate*>(state.c_ptr()), const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::minbleicreport*>(rep.c_ptr()), &_alglib_env_state);
         alglib_impl::ae_state_clear(&_alglib_env_state);
+        return;
     }
     catch(alglib_impl::ae_error_type)
     {
@@ -2111,150 +2200,27 @@ void minlmoptimize(minlmstate &state,
     }
 }
 
+/*************************************************************************
+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.
 
-void minlmoptimize(minlmstate &state,
-    void (*func)(const real_1d_array &x, double &func, void *ptr),
-    void (*grad)(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr),
-    void  (*jac)(const real_1d_array &x, real_1d_array &fi, real_2d_array &jac, void *ptr),
-    void  (*rep)(const real_1d_array &x, double func, void *ptr), 
-    void *ptr)
+INPUT PARAMETERS:
+    State   -   structure previously allocated with MinBLEICCreate call.
+    X       -   new starting point.
+
+  -- ALGLIB --
+     Copyright 28.11.2010 by Bochkanov Sergey
+*************************************************************************/
+void minbleicrestartfrom(const minbleicstate &state, const real_1d_array &x)
 {
     alglib_impl::ae_state _alglib_env_state;
-    if( func==NULL )
-        throw ap_error("ALGLIB: error in 'minlmoptimize()' (func is NULL)");
-    if( grad==NULL )
-        throw ap_error("ALGLIB: error in 'minlmoptimize()' (grad is NULL)");
-    if( jac==NULL )
-        throw ap_error("ALGLIB: error in 'minlmoptimize()' (jac is NULL)");
     alglib_impl::ae_state_init(&_alglib_env_state);
     try
     {
-        while( alglib_impl::minlmiteration(state.c_ptr(), &_alglib_env_state) )
-        {
-            if( state.needf )
-            {
-                func(state.x, state.f, ptr);
-                continue;
-            }
-            if( state.needfg )
-            {
-                grad(state.x, state.f, state.g, ptr);
-                continue;
-            }
-            if( state.needfij )
-            {
-                jac(state.x, state.fi, state.j, ptr);
-                continue;
-            }
-            if( state.xupdated )
-            {
-                if( rep!=NULL )
-                    rep(state.x, state.f, ptr);
-                continue;
-            }
-            throw ap_error("ALGLIB: error in 'minlmoptimize' (some derivatives were not provided?)");
-        }
-        alglib_impl::ae_state_clear(&_alglib_env_state);
-    }
-    catch(alglib_impl::ae_error_type)
-    {
-        throw ap_error(_alglib_env_state.error_msg);
-    }
-    catch(...)
-    {
-        throw;
-    }
-}
-
-
-
-/*************************************************************************
-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.
-
-  -- ALGLIB --
-     Copyright 10.03.2009 by Bochkanov Sergey
-*************************************************************************/
-void minlmresults(const minlmstate &state, real_1d_array &x, minlmreport &rep)
-{
-    alglib_impl::ae_state _alglib_env_state;
-    alglib_impl::ae_state_init(&_alglib_env_state);
-    try
-    {
-        alglib_impl::minlmresults(const_cast<alglib_impl::minlmstate*>(state.c_ptr()), const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::minlmreport*>(rep.c_ptr()), &_alglib_env_state);
-        alglib_impl::ae_state_clear(&_alglib_env_state);
-        return;
-    }
-    catch(alglib_impl::ae_error_type)
-    {
-        throw ap_error(_alglib_env_state.error_msg);
-    }
-    catch(...)
-    {
-        throw;
-    }
-}
-
-/*************************************************************************
-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.
-
-  -- ALGLIB --
-     Copyright 10.03.2009 by Bochkanov Sergey
-*************************************************************************/
-void minlmresultsbuf(const minlmstate &state, real_1d_array &x, minlmreport &rep)
-{
-    alglib_impl::ae_state _alglib_env_state;
-    alglib_impl::ae_state_init(&_alglib_env_state);
-    try
-    {
-        alglib_impl::minlmresultsbuf(const_cast<alglib_impl::minlmstate*>(state.c_ptr()), const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::minlmreport*>(rep.c_ptr()), &_alglib_env_state);
-        alglib_impl::ae_state_clear(&_alglib_env_state);
-        return;
-    }
-    catch(alglib_impl::ae_error_type)
-    {
-        throw ap_error(_alglib_env_state.error_msg);
-    }
-    catch(...)
-    {
-        throw;
-    }
-}
-
-/*************************************************************************
-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.
-
-  -- ALGLIB --
-     Copyright 30.07.2010 by Bochkanov Sergey
-*************************************************************************/
-void minlmrestartfrom(const minlmstate &state, const real_1d_array &x)
-{
-    alglib_impl::ae_state _alglib_env_state;
-    alglib_impl::ae_state_init(&_alglib_env_state);
-    try
-    {
-        alglib_impl::minlmrestartfrom(const_cast<alglib_impl::minlmstate*>(state.c_ptr()), const_cast<alglib_impl::ae_vector*>(x.c_ptr()), &_alglib_env_state);
+        alglib_impl::minbleicrestartfrom(const_cast<alglib_impl::minbleicstate*>(state.c_ptr()), const_cast<alglib_impl::ae_vector*>(x.c_ptr()), &_alglib_env_state);
         alglib_impl::ae_state_clear(&_alglib_env_state);
         return;
     }
@@ -2271,66 +2237,66 @@ void minlmrestartfrom(const minlmstate &state, const real_1d_array &x)
 /*************************************************************************
 
 *************************************************************************/
-_minasastate_owner::_minasastate_owner()
+_minlbfgsstate_owner::_minlbfgsstate_owner()
 {
-    p_struct = (alglib_impl::minasastate*)alglib_impl::ae_malloc(sizeof(alglib_impl::minasastate), NULL);
+    p_struct = (alglib_impl::minlbfgsstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::minlbfgsstate), NULL);
     if( p_struct==NULL )
         throw ap_error("ALGLIB: malloc error");
-    if( !alglib_impl::_minasastate_init(p_struct, NULL, ae_false) )
+    if( !alglib_impl::_minlbfgsstate_init(p_struct, NULL, ae_false) )
         throw ap_error("ALGLIB: malloc error");
 }
 
-_minasastate_owner::_minasastate_owner(const _minasastate_owner &rhs)
+_minlbfgsstate_owner::_minlbfgsstate_owner(const _minlbfgsstate_owner &rhs)
 {
-    p_struct = (alglib_impl::minasastate*)alglib_impl::ae_malloc(sizeof(alglib_impl::minasastate), NULL);
+    p_struct = (alglib_impl::minlbfgsstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::minlbfgsstate), NULL);
     if( p_struct==NULL )
         throw ap_error("ALGLIB: malloc error");
-    if( !alglib_impl::_minasastate_init_copy(p_struct, const_cast<alglib_impl::minasastate*>(rhs.p_struct), NULL, ae_false) )
+    if( !alglib_impl::_minlbfgsstate_init_copy(p_struct, const_cast<alglib_impl::minlbfgsstate*>(rhs.p_struct), NULL, ae_false) )
         throw ap_error("ALGLIB: malloc error");
 }
 
-_minasastate_owner& _minasastate_owner::operator=(const _minasastate_owner &rhs)
+_minlbfgsstate_owner& _minlbfgsstate_owner::operator=(const _minlbfgsstate_owner &rhs)
 {
     if( this==&rhs )
         return *this;
-    alglib_impl::_minasastate_clear(p_struct);
-    if( !alglib_impl::_minasastate_init_copy(p_struct, const_cast<alglib_impl::minasastate*>(rhs.p_struct), NULL, ae_false) )
+    alglib_impl::_minlbfgsstate_clear(p_struct);
+    if( !alglib_impl::_minlbfgsstate_init_copy(p_struct, const_cast<alglib_impl::minlbfgsstate*>(rhs.p_struct), NULL, ae_false) )
         throw ap_error("ALGLIB: malloc error");
     return *this;
 }
 
-_minasastate_owner::~_minasastate_owner()
+_minlbfgsstate_owner::~_minlbfgsstate_owner()
 {
-    alglib_impl::_minasastate_clear(p_struct);
+    alglib_impl::_minlbfgsstate_clear(p_struct);
     ae_free(p_struct);
 }
 
-alglib_impl::minasastate* _minasastate_owner::c_ptr()
+alglib_impl::minlbfgsstate* _minlbfgsstate_owner::c_ptr()
 {
     return p_struct;
 }
 
-alglib_impl::minasastate* _minasastate_owner::c_ptr() const
+alglib_impl::minlbfgsstate* _minlbfgsstate_owner::c_ptr() const
 {
-    return const_cast<alglib_impl::minasastate*>(p_struct);
+    return const_cast<alglib_impl::minlbfgsstate*>(p_struct);
 }
-minasastate::minasastate() : _minasastate_owner() ,needfg(p_struct->needfg),xupdated(p_struct->xupdated),f(p_struct->f),g(&p_struct->g),x(&p_struct->x)
+minlbfgsstate::minlbfgsstate() : _minlbfgsstate_owner() ,needf(p_struct->needf),needfg(p_struct->needfg),xupdated(p_struct->xupdated),f(p_struct->f),g(&p_struct->g),x(&p_struct->x)
 {
 }
 
-minasastate::minasastate(const minasastate &rhs):_minasastate_owner(rhs) ,needfg(p_struct->needfg),xupdated(p_struct->xupdated),f(p_struct->f),g(&p_struct->g),x(&p_struct->x)
+minlbfgsstate::minlbfgsstate(const minlbfgsstate &rhs):_minlbfgsstate_owner(rhs) ,needf(p_struct->needf),needfg(p_struct->needfg),xupdated(p_struct->xupdated),f(p_struct->f),g(&p_struct->g),x(&p_struct->x)
 {
 }
 
-minasastate& minasastate::operator=(const minasastate &rhs)
+minlbfgsstate& minlbfgsstate::operator=(const minlbfgsstate &rhs)
 {
     if( this==&rhs )
         return *this;
-    _minasastate_owner::operator=(rhs);
+    _minlbfgsstate_owner::operator=(rhs);
     return *this;
 }
 
-minasastate::~minasastate()
+minlbfgsstate::~minlbfgsstate()
 {
 }
 
@@ -2338,80 +2304,80 @@ minasastate::~minasastate()
 /*************************************************************************
 
 *************************************************************************/
-_minasareport_owner::_minasareport_owner()
+_minlbfgsreport_owner::_minlbfgsreport_owner()
 {
-    p_struct = (alglib_impl::minasareport*)alglib_impl::ae_malloc(sizeof(alglib_impl::minasareport), NULL);
+    p_struct = (alglib_impl::minlbfgsreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::minlbfgsreport), NULL);
     if( p_struct==NULL )
         throw ap_error("ALGLIB: malloc error");
-    if( !alglib_impl::_minasareport_init(p_struct, NULL, ae_false) )
+    if( !alglib_impl::_minlbfgsreport_init(p_struct, NULL, ae_false) )
         throw ap_error("ALGLIB: malloc error");
 }
 
-_minasareport_owner::_minasareport_owner(const _minasareport_owner &rhs)
+_minlbfgsreport_owner::_minlbfgsreport_owner(const _minlbfgsreport_owner &rhs)
 {
-    p_struct = (alglib_impl::minasareport*)alglib_impl::ae_malloc(sizeof(alglib_impl::minasareport), NULL);
+    p_struct = (alglib_impl::minlbfgsreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::minlbfgsreport), NULL);
     if( p_struct==NULL )
         throw ap_error("ALGLIB: malloc error");
-    if( !alglib_impl::_minasareport_init_copy(p_struct, const_cast<alglib_impl::minasareport*>(rhs.p_struct), NULL, ae_false) )
+    if( !alglib_impl::_minlbfgsreport_init_copy(p_struct, const_cast<alglib_impl::minlbfgsreport*>(rhs.p_struct), NULL, ae_false) )
         throw ap_error("ALGLIB: malloc error");
 }
 
-_minasareport_owner& _minasareport_owner::operator=(const _minasareport_owner &rhs)
+_minlbfgsreport_owner& _minlbfgsreport_owner::operator=(const _minlbfgsreport_owner &rhs)
 {
     if( this==&rhs )
         return *this;
-    alglib_impl::_minasareport_clear(p_struct);
-    if( !alglib_impl::_minasareport_init_copy(p_struct, const_cast<alglib_impl::minasareport*>(rhs.p_struct), NULL, ae_false) )
+    alglib_impl::_minlbfgsreport_clear(p_struct);
+    if( !alglib_impl::_minlbfgsreport_init_copy(p_struct, const_cast<alglib_impl::minlbfgsreport*>(rhs.p_struct), NULL, ae_false) )
         throw ap_error("ALGLIB: malloc error");
     return *this;
 }
 
-_minasareport_owner::~_minasareport_owner()
+_minlbfgsreport_owner::~_minlbfgsreport_owner()
 {
-    alglib_impl::_minasareport_clear(p_struct);
+    alglib_impl::_minlbfgsreport_clear(p_struct);
     ae_free(p_struct);
 }
 
-alglib_impl::minasareport* _minasareport_owner::c_ptr()
+alglib_impl::minlbfgsreport* _minlbfgsreport_owner::c_ptr()
 {
     return p_struct;
 }
 
-alglib_impl::minasareport* _minasareport_owner::c_ptr() const
+alglib_impl::minlbfgsreport* _minlbfgsreport_owner::c_ptr() const
 {
-    return const_cast<alglib_impl::minasareport*>(p_struct);
+    return const_cast<alglib_impl::minlbfgsreport*>(p_struct);
 }
-minasareport::minasareport() : _minasareport_owner() ,iterationscount(p_struct->iterationscount),nfev(p_struct->nfev),terminationtype(p_struct->terminationtype),activeconstraints(p_struct->activeconstraints)
+minlbfgsreport::minlbfgsreport() : _minlbfgsreport_owner() ,iterationscount(p_struct->iterationscount),nfev(p_struct->nfev),terminationtype(p_struct->terminationtype)
 {
 }
 
-minasareport::minasareport(const minasareport &rhs):_minasareport_owner(rhs) ,iterationscount(p_struct->iterationscount),nfev(p_struct->nfev),terminationtype(p_struct->terminationtype),activeconstraints(p_struct->activeconstraints)
+minlbfgsreport::minlbfgsreport(const minlbfgsreport &rhs):_minlbfgsreport_owner(rhs) ,iterationscount(p_struct->iterationscount),nfev(p_struct->nfev),terminationtype(p_struct->terminationtype)
 {
 }
 
-minasareport& minasareport::operator=(const minasareport &rhs)
+minlbfgsreport& minlbfgsreport::operator=(const minlbfgsreport &rhs)
 {
     if( this==&rhs )
         return *this;
-    _minasareport_owner::operator=(rhs);
+    _minlbfgsreport_owner::operator=(rhs);
     return *this;
 }
 
-minasareport::~minasareport()
+minlbfgsreport::~minlbfgsreport()
 {
 }
 
 /*************************************************************************
-              NONLINEAR BOUND CONSTRAINED OPTIMIZATION USING
-                      MODIFIED ACTIVE SET ALGORITHM
-                   WILLIAM W. HAGER AND HONGCHAO ZHANG
+        LIMITED MEMORY BFGS METHOD FOR LARGE SCALE OPTIMIZATION
 
 DESCRIPTION:
-The  subroutine  minimizes  function  F(x)  of  N  arguments  with   bound
-constraints: BndL[i] <= x[i] <= BndU[i]
-
-This method is  globally  convergent  as  long  as  grad(f)  is  Lipschitz
-continuous on a level set: L = { x : f(x)<=f(x0) }.
+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:
@@ -2420,55 +2386,49 @@ Algorithm will request following information during its operation:
 
 
 USAGE:
-1. User initializes algorithm state with MinASACreate() call
-2. User tunes solver parameters with MinASASetCond() MinASASetStpMax() and
-   other functions
-3. User calls MinASAOptimize() function which takes algorithm  state   and
+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 MinASAResults() to get solution
-5. Optionally, user may call MinASARestartFrom() to solve another  problem
-   with same N but another starting point and/or another function.
-   MinASARestartFrom() allows to reuse already initialized structure.
+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:
-                * if given, only leading N elements of X are used
-                * if not given, automatically determined from sizes of
-                  X/BndL/BndU.
-    X       -   starting point, array[0..N-1].
-    BndL    -   lower bounds, array[0..N-1].
-                all elements MUST be specified,  i.e.  all  variables  are
-                bounded. However, if some (all) variables  are  unbounded,
-                you may specify very small number as bound: -1000,  -1.0E6
-                or -1.0E300, or something like that.
-    BndU    -   upper bounds, array[0..N-1].
-                all elements MUST be specified,  i.e.  all  variables  are
-                bounded. However, if some (all) variables  are  unbounded,
-                you may specify very large number as bound: +1000,  +1.0E6
-                or +1.0E300, or something like that.
+    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 stores algorithm state
+    State   -   structure which stores algorithm state
 
-NOTES:
 
-1. you may tune stopping conditions with MinASASetCond() function
+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 MinASASetStpMax() function to bound algorithm's steps.
-3. this function does NOT support infinite/NaN values in X, BndL, BndU.
+   use MinLBFGSSetStpMax() function to bound algorithm's  steps.  However,
+   L-BFGS rarely needs such a tuning.
+
 
   -- ALGLIB --
-     Copyright 25.03.2010 by Bochkanov Sergey
+     Copyright 02.04.2010 by Bochkanov Sergey
 *************************************************************************/
-void minasacreate(const ae_int_t n, const real_1d_array &x, const real_1d_array &bndl, const real_1d_array &bndu, minasastate &state)
+void minlbfgscreate(const ae_int_t n, const ae_int_t m, const real_1d_array &x, minlbfgsstate &state)
 {
     alglib_impl::ae_state _alglib_env_state;
     alglib_impl::ae_state_init(&_alglib_env_state);
     try
     {
-        alglib_impl::minasacreate(n, const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(bndl.c_ptr()), const_cast<alglib_impl::ae_vector*>(bndu.c_ptr()), const_cast<alglib_impl::minasastate*>(state.c_ptr()), &_alglib_env_state);
+        alglib_impl::minlbfgscreate(n, m, const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::minlbfgsstate*>(state.c_ptr()), &_alglib_env_state);
         alglib_impl::ae_state_clear(&_alglib_env_state);
         return;
     }
@@ -2483,16 +2443,16 @@ void minasacreate(const ae_int_t n, const real_1d_array &x, const real_1d_array
 }
 
 /*************************************************************************
-              NONLINEAR BOUND CONSTRAINED OPTIMIZATION USING
-                      MODIFIED ACTIVE SET ALGORITHM
-                   WILLIAM W. HAGER AND HONGCHAO ZHANG
+        LIMITED MEMORY BFGS METHOD FOR LARGE SCALE OPTIMIZATION
 
 DESCRIPTION:
-The  subroutine  minimizes  function  F(x)  of  N  arguments  with   bound
-constraints: BndL[i] <= x[i] <= BndU[i]
-
-This method is  globally  convergent  as  long  as  grad(f)  is  Lipschitz
-continuous on a level set: L = { x : f(x)<=f(x0) }.
+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:
@@ -2501,59 +2461,52 @@ Algorithm will request following information during its operation:
 
 
 USAGE:
-1. User initializes algorithm state with MinASACreate() call
-2. User tunes solver parameters with MinASASetCond() MinASASetStpMax() and
-   other functions
-3. User calls MinASAOptimize() function which takes algorithm  state   and
+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 MinASAResults() to get solution
-5. Optionally, user may call MinASARestartFrom() to solve another  problem
-   with same N but another starting point and/or another function.
-   MinASARestartFrom() 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 sizes of
-                  X/BndL/BndU.
-    X       -   starting point, array[0..N-1].
-    BndL    -   lower bounds, array[0..N-1].
-                all elements MUST be specified,  i.e.  all  variables  are
-                bounded. However, if some (all) variables  are  unbounded,
-                you may specify very small number as bound: -1000,  -1.0E6
-                or -1.0E300, or something like that.
-    BndU    -   upper bounds, array[0..N-1].
-                all elements MUST be specified,  i.e.  all  variables  are
-                bounded. However, if some (all) variables  are  unbounded,
-                you may specify very large number as bound: +1000,  +1.0E6
-                or +1.0E300, or something like that.
+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 stores algorithm state
+    State   -   structure which stores algorithm state
 
-NOTES:
 
-1. you may tune stopping conditions with MinASASetCond() function
+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 MinASASetStpMax() function to bound algorithm's steps.
-3. this function does NOT support infinite/NaN values in X, BndL, BndU.
+   use MinLBFGSSetStpMax() function to bound algorithm's  steps.  However,
+   L-BFGS rarely needs such a tuning.
+
 
   -- ALGLIB --
-     Copyright 25.03.2010 by Bochkanov Sergey
+     Copyright 02.04.2010 by Bochkanov Sergey
 *************************************************************************/
-void minasacreate(const real_1d_array &x, const real_1d_array &bndl, const real_1d_array &bndu, minasastate &state)
+void minlbfgscreate(const ae_int_t m, const real_1d_array &x, minlbfgsstate &state)
 {
     alglib_impl::ae_state _alglib_env_state;    
     ae_int_t n;
-    if( (x.length()!=bndl.length()) || (x.length()!=bndu.length()))
-        throw ap_error("Error while calling 'minasacreate': looks like one of arguments has wrong size");
+
     n = x.length();
     alglib_impl::ae_state_init(&_alglib_env_state);
     try
     {
-        alglib_impl::minasacreate(n, const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(bndl.c_ptr()), const_cast<alglib_impl::ae_vector*>(bndu.c_ptr()), const_cast<alglib_impl::minasastate*>(state.c_ptr()), &_alglib_env_state);
+        alglib_impl::minlbfgscreate(n, m, const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::minlbfgsstate*>(state.c_ptr()), &_alglib_env_state);
 
         alglib_impl::ae_state_clear(&_alglib_env_state);
         return;
@@ -2569,37 +2522,59 @@ void minasacreate(const real_1d_array &x, const real_1d_array &bndl, const real_
 }
 
 /*************************************************************************
-This function sets stopping conditions for the ASA optimization algorithm.
+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
-    EpsG    -   >=0
-                The  subroutine  finishes  its  work   if   the  condition
-                ||G||<EpsG is satisfied, where ||.|| means Euclidian norm,
-                G - gradient.
-    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 |X(k+1)-X(k)| <= EpsX is fulfilled.
-    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).
+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.
 
   -- ALGLIB --
-     Copyright 02.04.2010 by Bochkanov Sergey
+     Copyright 16.05.2011 by Bochkanov Sergey
 *************************************************************************/
-void minasasetcond(const minasastate &state, const double epsg, const double epsf, const double epsx, const ae_int_t maxits)
+void minlbfgscreatef(const ae_int_t n, const ae_int_t m, const real_1d_array &x, const double diffstep, minlbfgsstate &state)
 {
     alglib_impl::ae_state _alglib_env_state;
     alglib_impl::ae_state_init(&_alglib_env_state);
     try
     {
-        alglib_impl::minasasetcond(const_cast<alglib_impl::minasastate*>(state.c_ptr()), epsg, epsf, epsx, maxits, &_alglib_env_state);
+        alglib_impl::minlbfgscreatef(n, m, const_cast<alglib_impl::ae_vector*>(x.c_ptr()), diffstep, const_cast<alglib_impl::minlbfgsstate*>(state.c_ptr()), &_alglib_env_state);
         alglib_impl::ae_state_clear(&_alglib_env_state);
         return;
     }
@@ -2614,25 +2589,63 @@ void minasasetcond(const minasastate &state, const double epsg, const double eps
 }
 
 /*************************************************************************
-This function turns on/off reporting.
+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
-    NeedXRep-   whether iteration reports are needed or not
 
-If NeedXRep is True, algorithm will call rep() callback function if  it is
-provided to MinASAOptimize().
+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.
 
   -- ALGLIB --
-     Copyright 02.04.2010 by Bochkanov Sergey
+     Copyright 16.05.2011 by Bochkanov Sergey
 *************************************************************************/
-void minasasetxrep(const minasastate &state, const bool needxrep)
+void minlbfgscreatef(const ae_int_t m, const real_1d_array &x, const double diffstep, minlbfgsstate &state)
 {
-    alglib_impl::ae_state _alglib_env_state;
+    alglib_impl::ae_state _alglib_env_state;    
+    ae_int_t n;
+
+    n = x.length();
     alglib_impl::ae_state_init(&_alglib_env_state);
     try
     {
-        alglib_impl::minasasetxrep(const_cast<alglib_impl::minasastate*>(state.c_ptr()), needxrep, &_alglib_env_state);
+        alglib_impl::minlbfgscreatef(n, m, const_cast<alglib_impl::ae_vector*>(x.c_ptr()), diffstep, const_cast<alglib_impl::minlbfgsstate*>(state.c_ptr()), &_alglib_env_state);
+
         alglib_impl::ae_state_clear(&_alglib_env_state);
         return;
     }
@@ -2647,25 +2660,44 @@ void minasasetxrep(const minasastate &state, const bool needxrep)
 }
 
 /*************************************************************************
-This function sets optimization algorithm.
+This function sets stopping conditions for L-BFGS optimization algorithm.
 
 INPUT PARAMETERS:
-    State   -   structure which stores algorithm stat
-    UAType  -   algorithm type:
-                * -1    automatic selection of the best algorithm
-                * 0     DY (Dai and Yuan) algorithm
-                * 1     Hybrid DY-HS algorithm
+    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).
 
   -- ALGLIB --
      Copyright 02.04.2010 by Bochkanov Sergey
 *************************************************************************/
-void minasasetalgorithm(const minasastate &state, const ae_int_t algotype)
+void minlbfgssetcond(const minlbfgsstate &state, const double epsg, const double epsf, const double epsx, const ae_int_t maxits)
 {
     alglib_impl::ae_state _alglib_env_state;
     alglib_impl::ae_state_init(&_alglib_env_state);
     try
     {
-        alglib_impl::minasasetalgorithm(const_cast<alglib_impl::minasastate*>(state.c_ptr()), algotype, &_alglib_env_state);
+        alglib_impl::minlbfgssetcond(const_cast<alglib_impl::minlbfgsstate*>(state.c_ptr()), epsg, epsf, epsx, maxits, &_alglib_env_state);
         alglib_impl::ae_state_clear(&_alglib_env_state);
         return;
     }
@@ -2680,29 +2712,26 @@ void minasasetalgorithm(const minasastate &state, const ae_int_t algotype)
 }
 
 /*************************************************************************
-This function sets maximum step length
+This function turns on/off reporting.
 
 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 (zero by default).
+    NeedXRep-   whether iteration reports are needed or not
+
+If NeedXRep is True, algorithm will call rep() callback function if  it is
+provided to MinLBFGSOptimize().
 
-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.
 
   -- ALGLIB --
      Copyright 02.04.2010 by Bochkanov Sergey
 *************************************************************************/
-void minasasetstpmax(const minasastate &state, const double stpmax)
+void minlbfgssetxrep(const minlbfgsstate &state, const bool needxrep)
 {
     alglib_impl::ae_state _alglib_env_state;
     alglib_impl::ae_state_init(&_alglib_env_state);
     try
     {
-        alglib_impl::minasasetstpmax(const_cast<alglib_impl::minasastate*>(state.c_ptr()), stpmax, &_alglib_env_state);
+        alglib_impl::minlbfgssetxrep(const_cast<alglib_impl::minlbfgsstate*>(state.c_ptr()), needxrep, &_alglib_env_state);
         alglib_impl::ae_state_clear(&_alglib_env_state);
         return;
     }
@@ -2717,19 +2746,31 @@ void minasasetstpmax(const minasastate &state, const double stpmax)
 }
 
 /*************************************************************************
-This function provides reverse communication interface
-Reverse communication interface is not documented or recommended to use.
-See below for functions which provide better documented API
+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.
+
+  -- ALGLIB --
+     Copyright 02.04.2010 by Bochkanov Sergey
 *************************************************************************/
-bool minasaiteration(const minasastate &state)
+void minlbfgssetstpmax(const minlbfgsstate &state, const double stpmax)
 {
     alglib_impl::ae_state _alglib_env_state;
     alglib_impl::ae_state_init(&_alglib_env_state);
     try
     {
-        ae_bool result = alglib_impl::minasaiteration(const_cast<alglib_impl::minasastate*>(state.c_ptr()), &_alglib_env_state);
+        alglib_impl::minlbfgssetstpmax(const_cast<alglib_impl::minlbfgsstate*>(state.c_ptr()), stpmax, &_alglib_env_state);
         alglib_impl::ae_state_clear(&_alglib_env_state);
-        return *(reinterpret_cast<bool*>(&result));
+        return;
     }
     catch(alglib_impl::ae_error_type)
     {
@@ -2741,34 +2782,46 @@ bool minasaiteration(const minasastate &state)
     }
 }
 
+/*************************************************************************
+This function sets scaling coefficients for LBFGS optimizer.
 
-void minasaoptimize(minasastate &state,
-    void (*grad)(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr),
-    void  (*rep)(const real_1d_array &x, double func, void *ptr), 
-    void *ptr)
+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.
+
+  -- ALGLIB --
+     Copyright 14.01.2011 by Bochkanov Sergey
+*************************************************************************/
+void minlbfgssetscale(const minlbfgsstate &state, const real_1d_array &s)
 {
     alglib_impl::ae_state _alglib_env_state;
-    if( grad==NULL )
-        throw ap_error("ALGLIB: error in 'minasaoptimize()' (grad is NULL)");
     alglib_impl::ae_state_init(&_alglib_env_state);
     try
     {
-        while( alglib_impl::minasaiteration(state.c_ptr(), &_alglib_env_state) )
-        {
-            if( state.needfg )
-            {
-                grad(state.x, state.f, state.g, ptr);
-                continue;
-            }
-            if( state.xupdated )
-            {
-                if( rep!=NULL )
-                    rep(state.x, state.f, ptr);
-                continue;
-            }
-            throw ap_error("ALGLIB: error in 'minasaoptimize' (some derivatives were not provided?)");
-        }
+        alglib_impl::minlbfgssetscale(const_cast<alglib_impl::minlbfgsstate*>(state.c_ptr()), const_cast<alglib_impl::ae_vector*>(s.c_ptr()), &_alglib_env_state);
         alglib_impl::ae_state_clear(&_alglib_env_state);
+        return;
     }
     catch(alglib_impl::ae_error_type)
     {
@@ -2780,42 +2833,26 @@ void minasaoptimize(minasastate &state,
     }
 }
 
-
-
 /*************************************************************************
-ASA results
+Modification  of  the  preconditioner:  default  preconditioner    (simple
+scaling, same for all elements of X) is used.
 
 INPUT PARAMETERS:
-    State   -   algorithm state
+    State   -   structure which stores 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
-                * ActiveConstraints contains number of active constraints
+NOTE:  you  can  change  preconditioner  "on  the  fly",  during algorithm
+iterations.
 
   -- ALGLIB --
-     Copyright 20.03.2009 by Bochkanov Sergey
+     Copyright 13.10.2010 by Bochkanov Sergey
 *************************************************************************/
-void minasaresults(const minasastate &state, real_1d_array &x, minasareport &rep)
+void minlbfgssetprecdefault(const minlbfgsstate &state)
 {
     alglib_impl::ae_state _alglib_env_state;
     alglib_impl::ae_state_init(&_alglib_env_state);
     try
     {
-        alglib_impl::minasaresults(const_cast<alglib_impl::minasastate*>(state.c_ptr()), const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::minasareport*>(rep.c_ptr()), &_alglib_env_state);
+        alglib_impl::minlbfgssetprecdefault(const_cast<alglib_impl::minlbfgsstate*>(state.c_ptr()), &_alglib_env_state);
         alglib_impl::ae_state_clear(&_alglib_env_state);
         return;
     }
@@ -2830,23 +2867,35 @@ void minasaresults(const minasastate &state, real_1d_array &x, minasareport &rep
 }
 
 /*************************************************************************
-ASA results
+Modification of the preconditioner: Cholesky factorization of  approximate
+Hessian is used.
 
-Buffered implementation of MinASAResults() 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.
+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.
 
   -- ALGLIB --
-     Copyright 20.03.2009 by Bochkanov Sergey
+     Copyright 13.10.2010 by Bochkanov Sergey
 *************************************************************************/
-void minasaresultsbuf(const minasastate &state, real_1d_array &x, minasareport &rep)
+void minlbfgssetpreccholesky(const minlbfgsstate &state, const real_2d_array &p, const bool isupper)
 {
     alglib_impl::ae_state _alglib_env_state;
     alglib_impl::ae_state_init(&_alglib_env_state);
     try
     {
-        alglib_impl::minasaresultsbuf(const_cast<alglib_impl::minasastate*>(state.c_ptr()), const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::minasareport*>(rep.c_ptr()), &_alglib_env_state);
+        alglib_impl::minlbfgssetpreccholesky(const_cast<alglib_impl::minlbfgsstate*>(state.c_ptr()), const_cast<alglib_impl::ae_matrix*>(p.c_ptr()), isupper, &_alglib_env_state);
         alglib_impl::ae_state_clear(&_alglib_env_state);
         return;
     }
@@ -2861,28 +2910,31 @@ void minasaresultsbuf(const minasastate &state, real_1d_array &x, minasareport &
 }
 
 /*************************************************************************
-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.
+Modification  of  the  preconditioner:  diagonal of approximate Hessian is
+used.
 
 INPUT PARAMETERS:
-    State   -   structure previously allocated with MinCGCreate call.
-    X       -   new starting point.
-    BndL    -   new lower bounds
-    BndU    -   new upper bounds
+    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.
 
   -- ALGLIB --
-     Copyright 30.07.2010 by Bochkanov Sergey
+     Copyright 13.10.2010 by Bochkanov Sergey
 *************************************************************************/
-void minasarestartfrom(const minasastate &state, const real_1d_array &x, const real_1d_array &bndl, const real_1d_array &bndu)
+void minlbfgssetprecdiag(const minlbfgsstate &state, const real_1d_array &d)
 {
     alglib_impl::ae_state _alglib_env_state;
     alglib_impl::ae_state_init(&_alglib_env_state);
     try
     {
-        alglib_impl::minasarestartfrom(const_cast<alglib_impl::minasastate*>(state.c_ptr()), const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(bndl.c_ptr()), const_cast<alglib_impl::ae_vector*>(bndu.c_ptr()), &_alglib_env_state);
+        alglib_impl::minlbfgssetprecdiag(const_cast<alglib_impl::minlbfgsstate*>(state.c_ptr()), const_cast<alglib_impl::ae_vector*>(d.c_ptr()), &_alglib_env_state);
         alglib_impl::ae_state_clear(&_alglib_env_state);
         return;
     }
@@ -2897,188 +2949,34 @@ void minasarestartfrom(const minasastate &state, const real_1d_array &x, const r
 }
 
 /*************************************************************************
-This object stores state of the nonlinear CG optimizer.
+Modification of the preconditioner: scale-based diagonal preconditioning.
 
-You should use ALGLIB functions to work with this object.
-*************************************************************************/
-_mincgstate_owner::_mincgstate_owner()
-{
-    p_struct = (alglib_impl::mincgstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::mincgstate), NULL);
-    if( p_struct==NULL )
-        throw ap_error("ALGLIB: malloc error");
-    if( !alglib_impl::_mincgstate_init(p_struct, NULL, ae_false) )
-        throw ap_error("ALGLIB: malloc error");
-}
-
-_mincgstate_owner::_mincgstate_owner(const _mincgstate_owner &rhs)
-{
-    p_struct = (alglib_impl::mincgstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::mincgstate), NULL);
-    if( p_struct==NULL )
-        throw ap_error("ALGLIB: malloc error");
-    if( !alglib_impl::_mincgstate_init_copy(p_struct, const_cast<alglib_impl::mincgstate*>(rhs.p_struct), NULL, ae_false) )
-        throw ap_error("ALGLIB: malloc error");
-}
-
-_mincgstate_owner& _mincgstate_owner::operator=(const _mincgstate_owner &rhs)
-{
-    if( this==&rhs )
-        return *this;
-    alglib_impl::_mincgstate_clear(p_struct);
-    if( !alglib_impl::_mincgstate_init_copy(p_struct, const_cast<alglib_impl::mincgstate*>(rhs.p_struct), NULL, ae_false) )
-        throw ap_error("ALGLIB: malloc error");
-    return *this;
-}
-
-_mincgstate_owner::~_mincgstate_owner()
-{
-    alglib_impl::_mincgstate_clear(p_struct);
-    ae_free(p_struct);
-}
-
-alglib_impl::mincgstate* _mincgstate_owner::c_ptr()
-{
-    return p_struct;
-}
-
-alglib_impl::mincgstate* _mincgstate_owner::c_ptr() const
-{
-    return const_cast<alglib_impl::mincgstate*>(p_struct);
-}
-mincgstate::mincgstate() : _mincgstate_owner() ,needfg(p_struct->needfg),xupdated(p_struct->xupdated),f(p_struct->f),g(&p_struct->g),x(&p_struct->x)
-{
-}
-
-mincgstate::mincgstate(const mincgstate &rhs):_mincgstate_owner(rhs) ,needfg(p_struct->needfg),xupdated(p_struct->xupdated),f(p_struct->f),g(&p_struct->g),x(&p_struct->x)
-{
-}
-
-mincgstate& mincgstate::operator=(const mincgstate &rhs)
-{
-    if( this==&rhs )
-        return *this;
-    _mincgstate_owner::operator=(rhs);
-    return *this;
-}
-
-mincgstate::~mincgstate()
-{
-}
-
-
-/*************************************************************************
-
-*************************************************************************/
-_mincgreport_owner::_mincgreport_owner()
-{
-    p_struct = (alglib_impl::mincgreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::mincgreport), NULL);
-    if( p_struct==NULL )
-        throw ap_error("ALGLIB: malloc error");
-    if( !alglib_impl::_mincgreport_init(p_struct, NULL, ae_false) )
-        throw ap_error("ALGLIB: malloc error");
-}
-
-_mincgreport_owner::_mincgreport_owner(const _mincgreport_owner &rhs)
-{
-    p_struct = (alglib_impl::mincgreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::mincgreport), NULL);
-    if( p_struct==NULL )
-        throw ap_error("ALGLIB: malloc error");
-    if( !alglib_impl::_mincgreport_init_copy(p_struct, const_cast<alglib_impl::mincgreport*>(rhs.p_struct), NULL, ae_false) )
-        throw ap_error("ALGLIB: malloc error");
-}
-
-_mincgreport_owner& _mincgreport_owner::operator=(const _mincgreport_owner &rhs)
-{
-    if( this==&rhs )
-        return *this;
-    alglib_impl::_mincgreport_clear(p_struct);
-    if( !alglib_impl::_mincgreport_init_copy(p_struct, const_cast<alglib_impl::mincgreport*>(rhs.p_struct), NULL, ae_false) )
-        throw ap_error("ALGLIB: malloc error");
-    return *this;
-}
-
-_mincgreport_owner::~_mincgreport_owner()
-{
-    alglib_impl::_mincgreport_clear(p_struct);
-    ae_free(p_struct);
-}
-
-alglib_impl::mincgreport* _mincgreport_owner::c_ptr()
-{
-    return p_struct;
-}
-
-alglib_impl::mincgreport* _mincgreport_owner::c_ptr() const
-{
-    return const_cast<alglib_impl::mincgreport*>(p_struct);
-}
-mincgreport::mincgreport() : _mincgreport_owner() ,iterationscount(p_struct->iterationscount),nfev(p_struct->nfev),terminationtype(p_struct->terminationtype)
-{
-}
-
-mincgreport::mincgreport(const mincgreport &rhs):_mincgreport_owner(rhs) ,iterationscount(p_struct->iterationscount),nfev(p_struct->nfev),terminationtype(p_struct->terminationtype)
-{
-}
-
-mincgreport& mincgreport::operator=(const mincgreport &rhs)
-{
-    if( this==&rhs )
-        return *this;
-    _mincgreport_owner::operator=(rhs);
-    return *this;
-}
-
-mincgreport::~mincgreport()
-{
-}
-
-/*************************************************************************
-        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
+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.
 
-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.
-
+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:
-    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
 
   -- ALGLIB --
-     Copyright 25.03.2010 by Bochkanov Sergey
+     Copyright 13.10.2010 by Bochkanov Sergey
 *************************************************************************/
-void mincgcreate(const ae_int_t n, const real_1d_array &x, mincgstate &state)
+void minlbfgssetprecscale(const minlbfgsstate &state)
 {
     alglib_impl::ae_state _alglib_env_state;
     alglib_impl::ae_state_init(&_alglib_env_state);
     try
     {
-        alglib_impl::mincgcreate(n, const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::mincgstate*>(state.c_ptr()), &_alglib_env_state);
+        alglib_impl::minlbfgssetprecscale(const_cast<alglib_impl::minlbfgsstate*>(state.c_ptr()), &_alglib_env_state);
         alglib_impl::ae_state_clear(&_alglib_env_state);
         return;
     }
@@ -3093,59 +2991,19 @@ void mincgcreate(const ae_int_t n, const real_1d_array &x, mincgstate &state)
 }
 
 /*************************************************************************
-        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
-
-  -- ALGLIB --
-     Copyright 25.03.2010 by Bochkanov Sergey
+This function provides reverse communication interface
+Reverse communication interface is not documented or recommended to use.
+See below for functions which provide better documented API
 *************************************************************************/
-void mincgcreate(const real_1d_array &x, mincgstate &state)
+bool minlbfgsiteration(const minlbfgsstate &state)
 {
-    alglib_impl::ae_state _alglib_env_state;    
-    ae_int_t n;
-
-    n = x.length();
+    alglib_impl::ae_state _alglib_env_state;
     alglib_impl::ae_state_init(&_alglib_env_state);
     try
     {
-        alglib_impl::mincgcreate(n, const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::mincgstate*>(state.c_ptr()), &_alglib_env_state);
-
+        ae_bool result = alglib_impl::minlbfgsiteration(const_cast<alglib_impl::minlbfgsstate*>(state.c_ptr()), &_alglib_env_state);
         alglib_impl::ae_state_clear(&_alglib_env_state);
-        return;
+        return *(reinterpret_cast<bool*>(&result));
     }
     catch(alglib_impl::ae_error_type)
     {
@@ -3157,217 +3015,34 @@ void mincgcreate(const real_1d_array &x, mincgstate &state)
     }
 }
 
-/*************************************************************************
-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
-                ||G||<EpsG is satisfied, where ||.|| means Euclidian norm,
-                G - gradient.
-    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 |X(k+1)-X(k)| <= EpsX is fulfilled.
-    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).
 
-  -- ALGLIB --
-     Copyright 02.04.2010 by Bochkanov Sergey
-*************************************************************************/
-void mincgsetcond(const mincgstate &state, const double epsg, const double epsf, const double epsx, const ae_int_t maxits)
+void minlbfgsoptimize(minlbfgsstate &state,
+    void (*func)(const real_1d_array &x, double &func, void *ptr),
+    void  (*rep)(const real_1d_array &x, double func, void *ptr), 
+    void *ptr)
 {
     alglib_impl::ae_state _alglib_env_state;
+    if( func==NULL )
+        throw ap_error("ALGLIB: error in 'minlbfgsoptimize()' (func is NULL)");
     alglib_impl::ae_state_init(&_alglib_env_state);
     try
     {
-        alglib_impl::mincgsetcond(const_cast<alglib_impl::mincgstate*>(state.c_ptr()), epsg, epsf, epsx, maxits, &_alglib_env_state);
+        while( alglib_impl::minlbfgsiteration(state.c_ptr(), &_alglib_env_state) )
+        {
+            if( state.needf )
+            {
+                func(state.x, state.f, ptr);
+                continue;
+            }
+            if( state.xupdated )
+            {
+                if( rep!=NULL )
+                    rep(state.x, state.f, ptr);
+                continue;
+            }
+            throw ap_error("ALGLIB: error in 'minlbfgsoptimize' (some derivatives were not provided?)");
+        }
         alglib_impl::ae_state_clear(&_alglib_env_state);
-        return;
-    }
-    catch(alglib_impl::ae_error_type)
-    {
-        throw ap_error(_alglib_env_state.error_msg);
-    }
-    catch(...)
-    {
-        throw;
-    }
-}
-
-/*************************************************************************
-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().
-
-  -- ALGLIB --
-     Copyright 02.04.2010 by Bochkanov Sergey
-*************************************************************************/
-void mincgsetxrep(const mincgstate &state, const bool needxrep)
-{
-    alglib_impl::ae_state _alglib_env_state;
-    alglib_impl::ae_state_init(&_alglib_env_state);
-    try
-    {
-        alglib_impl::mincgsetxrep(const_cast<alglib_impl::mincgstate*>(state.c_ptr()), needxrep, &_alglib_env_state);
-        alglib_impl::ae_state_clear(&_alglib_env_state);
-        return;
-    }
-    catch(alglib_impl::ae_error_type)
-    {
-        throw ap_error(_alglib_env_state.error_msg);
-    }
-    catch(...)
-    {
-        throw;
-    }
-}
-
-/*************************************************************************
-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
-
-  -- ALGLIB --
-     Copyright 02.04.2010 by Bochkanov Sergey
-*************************************************************************/
-void mincgsetcgtype(const mincgstate &state, const ae_int_t cgtype)
-{
-    alglib_impl::ae_state _alglib_env_state;
-    alglib_impl::ae_state_init(&_alglib_env_state);
-    try
-    {
-        alglib_impl::mincgsetcgtype(const_cast<alglib_impl::mincgstate*>(state.c_ptr()), cgtype, &_alglib_env_state);
-        alglib_impl::ae_state_clear(&_alglib_env_state);
-        return;
-    }
-    catch(alglib_impl::ae_error_type)
-    {
-        throw ap_error(_alglib_env_state.error_msg);
-    }
-    catch(...)
-    {
-        throw;
-    }
-}
-
-/*************************************************************************
-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.
-
-  -- ALGLIB --
-     Copyright 02.04.2010 by Bochkanov Sergey
-*************************************************************************/
-void mincgsetstpmax(const mincgstate &state, const double stpmax)
-{
-    alglib_impl::ae_state _alglib_env_state;
-    alglib_impl::ae_state_init(&_alglib_env_state);
-    try
-    {
-        alglib_impl::mincgsetstpmax(const_cast<alglib_impl::mincgstate*>(state.c_ptr()), stpmax, &_alglib_env_state);
-        alglib_impl::ae_state_clear(&_alglib_env_state);
-        return;
-    }
-    catch(alglib_impl::ae_error_type)
-    {
-        throw ap_error(_alglib_env_state.error_msg);
-    }
-    catch(...)
-    {
-        throw;
-    }
-}
-
-/*************************************************************************
-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.
-
-This function influences only first iteration of algorithm. It  should  be
-called between MinCGCreate/MinCGRestartFrom() call and MinCGOptimize call.
-
-INPUT PARAMETERS:
-    State   -   structure used to store algorithm state.
-    Stp     -   initial estimate of the step length.
-                Can be zero (no estimate).
-
-  -- ALGLIB --
-     Copyright 30.07.2010 by Bochkanov Sergey
-*************************************************************************/
-void mincgsuggeststep(const mincgstate &state, const double stp)
-{
-    alglib_impl::ae_state _alglib_env_state;
-    alglib_impl::ae_state_init(&_alglib_env_state);
-    try
-    {
-        alglib_impl::mincgsuggeststep(const_cast<alglib_impl::mincgstate*>(state.c_ptr()), stp, &_alglib_env_state);
-        alglib_impl::ae_state_clear(&_alglib_env_state);
-        return;
-    }
-    catch(alglib_impl::ae_error_type)
-    {
-        throw ap_error(_alglib_env_state.error_msg);
-    }
-    catch(...)
-    {
-        throw;
-    }
-}
-
-/*************************************************************************
-This function provides reverse communication interface
-Reverse communication interface is not documented or recommended to use.
-See below for functions which provide better documented API
-*************************************************************************/
-bool mincgiteration(const mincgstate &state)
-{
-    alglib_impl::ae_state _alglib_env_state;
-    alglib_impl::ae_state_init(&_alglib_env_state);
-    try
-    {
-        ae_bool result = alglib_impl::mincgiteration(const_cast<alglib_impl::mincgstate*>(state.c_ptr()), &_alglib_env_state);
-        alglib_impl::ae_state_clear(&_alglib_env_state);
-        return *(reinterpret_cast<bool*>(&result));
     }
     catch(alglib_impl::ae_error_type)
     {
@@ -3380,18 +3055,18 @@ bool mincgiteration(const mincgstate &state)
 }
 
 
-void mincgoptimize(mincgstate &state,
+void minlbfgsoptimize(minlbfgsstate &state,
     void (*grad)(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr),
     void  (*rep)(const real_1d_array &x, double func, void *ptr), 
     void *ptr)
 {
     alglib_impl::ae_state _alglib_env_state;
     if( grad==NULL )
-        throw ap_error("ALGLIB: error in 'mincgoptimize()' (grad is NULL)");
+        throw ap_error("ALGLIB: error in 'minlbfgsoptimize()' (grad is NULL)");
     alglib_impl::ae_state_init(&_alglib_env_state);
     try
     {
-        while( alglib_impl::mincgiteration(state.c_ptr(), &_alglib_env_state) )
+        while( alglib_impl::minlbfgsiteration(state.c_ptr(), &_alglib_env_state) )
         {
             if( state.needfg )
             {
@@ -3404,7 +3079,7 @@ void mincgoptimize(mincgstate &state,
                     rep(state.x, state.f, ptr);
                 continue;
             }
-            throw ap_error("ALGLIB: error in 'mincgoptimize' (some derivatives were not provided?)");
+            throw ap_error("ALGLIB: error in 'minlbfgsoptimize' (some derivatives were not provided?)");
         }
         alglib_impl::ae_state_clear(&_alglib_env_state);
     }
@@ -3421,7 +3096,7 @@ void mincgoptimize(mincgstate &state,
 
 
 /*************************************************************************
-Conjugate gradient results
+L-BFGS algorithm results
 
 INPUT PARAMETERS:
     State   -   algorithm state
@@ -3430,27 +3105,29 @@ 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,
-                            we return best X found so far
+                            further improvement is impossible
                 * Rep.IterationsCount contains iterations count
                 * NFEV countains number of function calculations
 
   -- ALGLIB --
-     Copyright 20.04.2009 by Bochkanov Sergey
+     Copyright 02.04.2010 by Bochkanov Sergey
 *************************************************************************/
-void mincgresults(const mincgstate &state, real_1d_array &x, mincgreport &rep)
+void minlbfgsresults(const minlbfgsstate &state, real_1d_array &x, minlbfgsreport &rep)
 {
     alglib_impl::ae_state _alglib_env_state;
     alglib_impl::ae_state_init(&_alglib_env_state);
     try
     {
-        alglib_impl::mincgresults(const_cast<alglib_impl::mincgstate*>(state.c_ptr()), const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::mincgreport*>(rep.c_ptr()), &_alglib_env_state);
+        alglib_impl::minlbfgsresults(const_cast<alglib_impl::minlbfgsstate*>(state.c_ptr()), const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::minlbfgsreport*>(rep.c_ptr()), &_alglib_env_state);
         alglib_impl::ae_state_clear(&_alglib_env_state);
         return;
     }
@@ -3465,23 +3142,23 @@ void mincgresults(const mincgstate &state, real_1d_array &x, mincgreport &rep)
 }
 
 /*************************************************************************
-Conjugate gradient results
+L-BFGS algorithm results
 
-Buffered implementation of MinCGResults(), which uses pre-allocated buffer
+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.
 
   -- ALGLIB --
-     Copyright 20.04.2009 by Bochkanov Sergey
+     Copyright 20.08.2010 by Bochkanov Sergey
 *************************************************************************/
-void mincgresultsbuf(const mincgstate &state, real_1d_array &x, mincgreport &rep)
+void minlbfgsresultsbuf(const minlbfgsstate &state, real_1d_array &x, minlbfgsreport &rep)
 {
     alglib_impl::ae_state _alglib_env_state;
     alglib_impl::ae_state_init(&_alglib_env_state);
     try
     {
-        alglib_impl::mincgresultsbuf(const_cast<alglib_impl::mincgstate*>(state.c_ptr()), const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::mincgreport*>(rep.c_ptr()), &_alglib_env_state);
+        alglib_impl::minlbfgsresultsbuf(const_cast<alglib_impl::minlbfgsstate*>(state.c_ptr()), const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::minlbfgsreport*>(rep.c_ptr()), &_alglib_env_state);
         alglib_impl::ae_state_clear(&_alglib_env_state);
         return;
     }
@@ -3496,26 +3173,26 @@ void mincgresultsbuf(const mincgstate &state, real_1d_array &x, mincgreport &rep
 }
 
 /*************************************************************************
-This  subroutine  restarts  CG  algorithm from new point. All optimization
+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.
+    State   -   structure used to store algorithm state
     X       -   new starting point.
 
   -- ALGLIB --
      Copyright 30.07.2010 by Bochkanov Sergey
 *************************************************************************/
-void mincgrestartfrom(const mincgstate &state, const real_1d_array &x)
+void minlbfgsrestartfrom(const minlbfgsstate &state, const real_1d_array &x)
 {
     alglib_impl::ae_state _alglib_env_state;
     alglib_impl::ae_state_init(&_alglib_env_state);
     try
     {
-        alglib_impl::mincgrestartfrom(const_cast<alglib_impl::mincgstate*>(state.c_ptr()), const_cast<alglib_impl::ae_vector*>(x.c_ptr()), &_alglib_env_state);
+        alglib_impl::minlbfgsrestartfrom(const_cast<alglib_impl::minlbfgsstate*>(state.c_ptr()), const_cast<alglib_impl::ae_vector*>(x.c_ptr()), &_alglib_env_state);
         alglib_impl::ae_state_clear(&_alglib_env_state);
         return;
     }
@@ -3531,69 +3208,69 @@ void mincgrestartfrom(const mincgstate &state, const real_1d_array &x)
 
 /*************************************************************************
 This object stores nonlinear optimizer state.
-You should use functions provided by MinBLEIC subpackage to work with this
+You should use functions provided by MinQP subpackage to work with this
 object
 *************************************************************************/
-_minbleicstate_owner::_minbleicstate_owner()
+_minqpstate_owner::_minqpstate_owner()
 {
-    p_struct = (alglib_impl::minbleicstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::minbleicstate), NULL);
+    p_struct = (alglib_impl::minqpstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::minqpstate), NULL);
     if( p_struct==NULL )
         throw ap_error("ALGLIB: malloc error");
-    if( !alglib_impl::_minbleicstate_init(p_struct, NULL, ae_false) )
+    if( !alglib_impl::_minqpstate_init(p_struct, NULL, ae_false) )
         throw ap_error("ALGLIB: malloc error");
 }
 
-_minbleicstate_owner::_minbleicstate_owner(const _minbleicstate_owner &rhs)
+_minqpstate_owner::_minqpstate_owner(const _minqpstate_owner &rhs)
 {
-    p_struct = (alglib_impl::minbleicstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::minbleicstate), NULL);
+    p_struct = (alglib_impl::minqpstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::minqpstate), NULL);
     if( p_struct==NULL )
         throw ap_error("ALGLIB: malloc error");
-    if( !alglib_impl::_minbleicstate_init_copy(p_struct, const_cast<alglib_impl::minbleicstate*>(rhs.p_struct), NULL, ae_false) )
+    if( !alglib_impl::_minqpstate_init_copy(p_struct, const_cast<alglib_impl::minqpstate*>(rhs.p_struct), NULL, ae_false) )
         throw ap_error("ALGLIB: malloc error");
 }
 
-_minbleicstate_owner& _minbleicstate_owner::operator=(const _minbleicstate_owner &rhs)
+_minqpstate_owner& _minqpstate_owner::operator=(const _minqpstate_owner &rhs)
 {
     if( this==&rhs )
         return *this;
-    alglib_impl::_minbleicstate_clear(p_struct);
-    if( !alglib_impl::_minbleicstate_init_copy(p_struct, const_cast<alglib_impl::minbleicstate*>(rhs.p_struct), NULL, ae_false) )
+    alglib_impl::_minqpstate_clear(p_struct);
+    if( !alglib_impl::_minqpstate_init_copy(p_struct, const_cast<alglib_impl::minqpstate*>(rhs.p_struct), NULL, ae_false) )
         throw ap_error("ALGLIB: malloc error");
     return *this;
 }
 
-_minbleicstate_owner::~_minbleicstate_owner()
+_minqpstate_owner::~_minqpstate_owner()
 {
-    alglib_impl::_minbleicstate_clear(p_struct);
+    alglib_impl::_minqpstate_clear(p_struct);
     ae_free(p_struct);
 }
 
-alglib_impl::minbleicstate* _minbleicstate_owner::c_ptr()
+alglib_impl::minqpstate* _minqpstate_owner::c_ptr()
 {
     return p_struct;
 }
 
-alglib_impl::minbleicstate* _minbleicstate_owner::c_ptr() const
+alglib_impl::minqpstate* _minqpstate_owner::c_ptr() const
 {
-    return const_cast<alglib_impl::minbleicstate*>(p_struct);
+    return const_cast<alglib_impl::minqpstate*>(p_struct);
 }
-minbleicstate::minbleicstate() : _minbleicstate_owner() ,needfg(p_struct->needfg),xupdated(p_struct->xupdated),f(p_struct->f),g(&p_struct->g),x(&p_struct->x)
+minqpstate::minqpstate() : _minqpstate_owner() 
 {
 }
 
-minbleicstate::minbleicstate(const minbleicstate &rhs):_minbleicstate_owner(rhs) ,needfg(p_struct->needfg),xupdated(p_struct->xupdated),f(p_struct->f),g(&p_struct->g),x(&p_struct->x)
+minqpstate::minqpstate(const minqpstate &rhs):_minqpstate_owner(rhs) 
 {
 }
 
-minbleicstate& minbleicstate::operator=(const minbleicstate &rhs)
+minqpstate& minqpstate::operator=(const minqpstate &rhs)
 {
     if( this==&rhs )
         return *this;
-    _minbleicstate_owner::operator=(rhs);
+    _minqpstate_owner::operator=(rhs);
     return *this;
 }
 
-minbleicstate::~minbleicstate()
+minqpstate::~minqpstate()
 {
 }
 
@@ -3602,159 +3279,113 @@ minbleicstate::~minbleicstate()
 This structure stores optimization report:
 * InnerIterationsCount      number of inner iterations
 * OuterIterationsCount      number of outer iterations
-* NFEV                      number of gradient evaluations
-
-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|
-*************************************************************************/
-_minbleicreport_owner::_minbleicreport_owner()
-{
-    p_struct = (alglib_impl::minbleicreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::minbleicreport), NULL);
+* 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.
+*************************************************************************/
+_minqpreport_owner::_minqpreport_owner()
+{
+    p_struct = (alglib_impl::minqpreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::minqpreport), NULL);
     if( p_struct==NULL )
         throw ap_error("ALGLIB: malloc error");
-    if( !alglib_impl::_minbleicreport_init(p_struct, NULL, ae_false) )
+    if( !alglib_impl::_minqpreport_init(p_struct, NULL, ae_false) )
         throw ap_error("ALGLIB: malloc error");
 }
 
-_minbleicreport_owner::_minbleicreport_owner(const _minbleicreport_owner &rhs)
+_minqpreport_owner::_minqpreport_owner(const _minqpreport_owner &rhs)
 {
-    p_struct = (alglib_impl::minbleicreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::minbleicreport), NULL);
+    p_struct = (alglib_impl::minqpreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::minqpreport), NULL);
     if( p_struct==NULL )
         throw ap_error("ALGLIB: malloc error");
-    if( !alglib_impl::_minbleicreport_init_copy(p_struct, const_cast<alglib_impl::minbleicreport*>(rhs.p_struct), NULL, ae_false) )
+    if( !alglib_impl::_minqpreport_init_copy(p_struct, const_cast<alglib_impl::minqpreport*>(rhs.p_struct), NULL, ae_false) )
         throw ap_error("ALGLIB: malloc error");
 }
 
-_minbleicreport_owner& _minbleicreport_owner::operator=(const _minbleicreport_owner &rhs)
+_minqpreport_owner& _minqpreport_owner::operator=(const _minqpreport_owner &rhs)
 {
     if( this==&rhs )
         return *this;
-    alglib_impl::_minbleicreport_clear(p_struct);
-    if( !alglib_impl::_minbleicreport_init_copy(p_struct, const_cast<alglib_impl::minbleicreport*>(rhs.p_struct), NULL, ae_false) )
+    alglib_impl::_minqpreport_clear(p_struct);
+    if( !alglib_impl::_minqpreport_init_copy(p_struct, const_cast<alglib_impl::minqpreport*>(rhs.p_struct), NULL, ae_false) )
         throw ap_error("ALGLIB: malloc error");
     return *this;
 }
 
-_minbleicreport_owner::~_minbleicreport_owner()
+_minqpreport_owner::~_minqpreport_owner()
 {
-    alglib_impl::_minbleicreport_clear(p_struct);
+    alglib_impl::_minqpreport_clear(p_struct);
     ae_free(p_struct);
 }
 
-alglib_impl::minbleicreport* _minbleicreport_owner::c_ptr()
+alglib_impl::minqpreport* _minqpreport_owner::c_ptr()
 {
     return p_struct;
 }
 
-alglib_impl::minbleicreport* _minbleicreport_owner::c_ptr() const
+alglib_impl::minqpreport* _minqpreport_owner::c_ptr() const
 {
-    return const_cast<alglib_impl::minbleicreport*>(p_struct);
+    return const_cast<alglib_impl::minqpreport*>(p_struct);
 }
-minbleicreport::minbleicreport() : _minbleicreport_owner() ,inneriterationscount(p_struct->inneriterationscount),outeriterationscount(p_struct->outeriterationscount),nfev(p_struct->nfev),terminationtype(p_struct->terminationtype),debugeqerr(p_struct->debugeqerr),debugfs(p_struct->debugfs),debugff(p_struct->debugff),debugdx(p_struct->debugdx)
+minqpreport::minqpreport() : _minqpreport_owner() ,inneriterationscount(p_struct->inneriterationscount),outeriterationscount(p_struct->outeriterationscount),nmv(p_struct->nmv),ncholesky(p_struct->ncholesky),terminationtype(p_struct->terminationtype)
 {
 }
 
-minbleicreport::minbleicreport(const minbleicreport &rhs):_minbleicreport_owner(rhs) ,inneriterationscount(p_struct->inneriterationscount),outeriterationscount(p_struct->outeriterationscount),nfev(p_struct->nfev),terminationtype(p_struct->terminationtype),debugeqerr(p_struct->debugeqerr),debugfs(p_struct->debugfs),debugff(p_struct->debugff),debugdx(p_struct->debugdx)
+minqpreport::minqpreport(const minqpreport &rhs):_minqpreport_owner(rhs) ,inneriterationscount(p_struct->inneriterationscount),outeriterationscount(p_struct->outeriterationscount),nmv(p_struct->nmv),ncholesky(p_struct->ncholesky),terminationtype(p_struct->terminationtype)
 {
 }
 
-minbleicreport& minbleicreport::operator=(const minbleicreport &rhs)
+minqpreport& minqpreport::operator=(const minqpreport &rhs)
 {
     if( this==&rhs )
         return *this;
-    _minbleicreport_owner::operator=(rhs);
+    _minqpreport_owner::operator=(rhs);
     return *this;
 }
 
-minbleicreport::~minbleicreport()
+minqpreport::~minqpreport()
 {
 }
 
 /*************************************************************************
-                     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:
-* function value and gradient
-* grad(f) must be Lipschitz continuous on a level set: L = { x : f(x)<=f(x0) }
-* function must be defined even in the infeasible points (algorithm make take
-  steps in the infeasible area before converging to the feasible point)
-* starting point X0 must be feasible or not too far away from the feasible set
-* problem must satisfy strict complementary conditions
-
-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. User tunes barrier parameters:
-   * barrier width with MinBLEICSetBarrierWidth() call
-   * (optionally) dynamics of the barrier width with MinBLEICSetBarrierDecay() call
-   These functions control handling of boundary and inequality constraints.
-
-6. Additionally, user may set limit on number of internal iterations
-   by MinBLEICSetMaxIts() call.
-   This function allows to prevent algorithm from looping forever.
-
-7. User calls MinBLEICOptimize() function which takes algorithm  state and
-   pointer (delegate, etc.) to callback function which calculates F/G.
-
-8. User calls MinBLEICResults() to get solution
-
-9. Optionally user may call MinBLEICRestartFrom() to solve another problem
-   with same N but another starting point.
-   MinBLEICRestartFrom() allows to reuse already initialized structure.
+                    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 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.
+    N       -   problem size
 
 OUTPUT PARAMETERS:
-    State   -   structure stores algorithm state
+    State   -   optimizer with zero quadratic/linear terms
+                and no constraints
 
   -- ALGLIB --
-     Copyright 28.11.2010 by Bochkanov Sergey
+     Copyright 11.01.2011 by Bochkanov Sergey
 *************************************************************************/
-void minbleiccreate(const ae_int_t n, const real_1d_array &x, minbleicstate &state)
+void minqpcreate(const ae_int_t n, minqpstate &state)
 {
     alglib_impl::ae_state _alglib_env_state;
     alglib_impl::ae_state_init(&_alglib_env_state);
     try
     {
-        alglib_impl::minbleiccreate(n, const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::minbleicstate*>(state.c_ptr()), &_alglib_env_state);
+        alglib_impl::minqpcreate(n, const_cast<alglib_impl::minqpstate*>(state.c_ptr()), &_alglib_env_state);
         alglib_impl::ae_state_clear(&_alglib_env_state);
         return;
     }
@@ -3769,90 +3400,24 @@ void minbleiccreate(const ae_int_t n, const real_1d_array &x, minbleicstate &sta
 }
 
 /*************************************************************************
-                     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:
-* function value and gradient
-* grad(f) must be Lipschitz continuous on a level set: L = { x : f(x)<=f(x0) }
-* function must be defined even in the infeasible points (algorithm make take
-  steps in the infeasible area before converging to the feasible point)
-* starting point X0 must be feasible or not too far away from the feasible set
-* problem must satisfy strict complementary conditions
-
-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. User tunes barrier parameters:
-   * barrier width with MinBLEICSetBarrierWidth() call
-   * (optionally) dynamics of the barrier width with MinBLEICSetBarrierDecay() call
-   These functions control handling of boundary and inequality constraints.
-
-6. Additionally, user may set limit on number of internal iterations
-   by MinBLEICSetMaxIts() call.
-   This function allows to prevent algorithm from looping forever.
-
-7. User calls MinBLEICOptimize() function which takes algorithm  state and
-   pointer (delegate, etc.) to callback function which calculates F/G.
-
-8. User calls MinBLEICResults() to get solution
-
-9. Optionally user may call MinBLEICRestartFrom() to solve another problem
-   with same N but another starting point.
-   MinBLEICRestartFrom() allows to reuse already initialized structure.
+This function sets linear term for QP solver.
 
+By default, linear term is zero.
 
 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
+    State   -   structure which stores algorithm state
+    B       -   linear term, array[N].
 
   -- ALGLIB --
-     Copyright 28.11.2010 by Bochkanov Sergey
+     Copyright 11.01.2011 by Bochkanov Sergey
 *************************************************************************/
-void minbleiccreate(const real_1d_array &x, minbleicstate &state)
+void minqpsetlinearterm(const minqpstate &state, const real_1d_array &b)
 {
-    alglib_impl::ae_state _alglib_env_state;    
-    ae_int_t n;
-
-    n = x.length();
+    alglib_impl::ae_state _alglib_env_state;
     alglib_impl::ae_state_init(&_alglib_env_state);
     try
     {
-        alglib_impl::minbleiccreate(n, const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::minbleicstate*>(state.c_ptr()), &_alglib_env_state);
-
+        alglib_impl::minqpsetlinearterm(const_cast<alglib_impl::minqpstate*>(state.c_ptr()), const_cast<alglib_impl::ae_vector*>(b.c_ptr()), &_alglib_env_state);
         alglib_impl::ae_state_clear(&_alglib_env_state);
         return;
     }
@@ -3867,30 +3432,39 @@ void minbleiccreate(const real_1d_array &x, minbleicstate &state)
 }
 
 /*************************************************************************
-This function sets boundary constraints for BLEIC optimizer.
+This function sets quadratic term for QP solver.
 
-Boundary constraints are inactive by default (after initial creation).
-They are preserved after algorithm restart with MinBLEICRestartFrom().
+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 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.
+    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.
 
   -- ALGLIB --
-     Copyright 28.11.2010 by Bochkanov Sergey
+     Copyright 11.01.2011 by Bochkanov Sergey
 *************************************************************************/
-void minbleicsetbc(const minbleicstate &state, const real_1d_array &bndl, const real_1d_array &bndu)
+void minqpsetquadraticterm(const minqpstate &state, const real_2d_array &a, const bool isupper)
 {
     alglib_impl::ae_state _alglib_env_state;
     alglib_impl::ae_state_init(&_alglib_env_state);
     try
     {
-        alglib_impl::minbleicsetbc(const_cast<alglib_impl::minbleicstate*>(state.c_ptr()), const_cast<alglib_impl::ae_vector*>(bndl.c_ptr()), const_cast<alglib_impl::ae_vector*>(bndu.c_ptr()), &_alglib_env_state);
+        alglib_impl::minqpsetquadraticterm(const_cast<alglib_impl::minqpstate*>(state.c_ptr()), const_cast<alglib_impl::ae_matrix*>(a.c_ptr()), isupper, &_alglib_env_state);
         alglib_impl::ae_state_clear(&_alglib_env_state);
         return;
     }
@@ -3905,37 +3479,44 @@ void minbleicsetbc(const minbleicstate &state, const real_1d_array &bndl, const
 }
 
 /*************************************************************************
-This function sets linear constraints for BLEIC optimizer.
+This function sets quadratic term for QP solver.
 
-Linear constraints are inactive by default (after initial creation).
-They are preserved after algorithm restart with MinBLEICRestartFrom().
+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 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
+    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.
 
   -- ALGLIB --
-     Copyright 28.11.2010 by Bochkanov Sergey
+     Copyright 11.01.2011 by Bochkanov Sergey
 *************************************************************************/
-void minbleicsetlc(const minbleicstate &state, const real_2d_array &c, const integer_1d_array &ct, const ae_int_t k)
+void minqpsetquadraticterm(const minqpstate &state, const real_2d_array &a)
 {
-    alglib_impl::ae_state _alglib_env_state;
+    alglib_impl::ae_state _alglib_env_state;    
+    bool isupper;
+    if( !alglib_impl::ae_is_symmetric(const_cast<alglib_impl::ae_matrix*>(a.c_ptr())) )
+        throw ap_error("'a' parameter is not symmetric matrix");
+    isupper = false;
     alglib_impl::ae_state_init(&_alglib_env_state);
     try
     {
-        alglib_impl::minbleicsetlc(const_cast<alglib_impl::minbleicstate*>(state.c_ptr()), const_cast<alglib_impl::ae_matrix*>(c.c_ptr()), const_cast<alglib_impl::ae_vector*>(ct.c_ptr()), k, &_alglib_env_state);
+        alglib_impl::minqpsetquadraticterm(const_cast<alglib_impl::minqpstate*>(state.c_ptr()), const_cast<alglib_impl::ae_matrix*>(a.c_ptr()), isupper, &_alglib_env_state);
+
         alglib_impl::ae_state_clear(&_alglib_env_state);
         return;
     }
@@ -3950,42 +3531,24 @@ void minbleicsetlc(const minbleicstate &state, const real_2d_array &c, const int
 }
 
 /*************************************************************************
-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().
+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 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
+    State   -   structure which stores algorithm state
+    X       -   starting point, array[N].
 
   -- ALGLIB --
-     Copyright 28.11.2010 by Bochkanov Sergey
+     Copyright 11.01.2011 by Bochkanov Sergey
 *************************************************************************/
-void minbleicsetlc(const minbleicstate &state, const real_2d_array &c, const integer_1d_array &ct)
+void minqpsetstartingpoint(const minqpstate &state, const real_1d_array &x)
 {
-    alglib_impl::ae_state _alglib_env_state;    
-    ae_int_t k;
-    if( (c.rows()!=ct.length()))
-        throw ap_error("Error while calling 'minbleicsetlc': looks like one of arguments has wrong size");
-    k = c.rows();
+    alglib_impl::ae_state _alglib_env_state;
     alglib_impl::ae_state_init(&_alglib_env_state);
     try
     {
-        alglib_impl::minbleicsetlc(const_cast<alglib_impl::minbleicstate*>(state.c_ptr()), const_cast<alglib_impl::ae_matrix*>(c.c_ptr()), const_cast<alglib_impl::ae_vector*>(ct.c_ptr()), k, &_alglib_env_state);
-
+        alglib_impl::minqpsetstartingpoint(const_cast<alglib_impl::minqpstate*>(state.c_ptr()), const_cast<alglib_impl::ae_vector*>(x.c_ptr()), &_alglib_env_state);
         alglib_impl::ae_state_clear(&_alglib_env_state);
         return;
     }
@@ -4000,39 +3563,29 @@ void minbleicsetlc(const minbleicstate &state, const real_2d_array &c, const int
 }
 
 /*************************************************************************
-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.
+This  function sets origin for QP solver. By default, following QP program
+is solved:
 
-INPUT PARAMETERS:
-    State   -   structure which stores algorithm state
-    EpsG    -   >=0
-                Algorithm finishes its work if 2-norm of the Lagrangian
-                gradient is less than or equal to EpsG.
-    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 |X(k+1)-X(k)| <= EpsX is fulfilled.
+    min(0.5*x'*A*x+b'*x)
 
-Passing EpsG=0, EpsF=0 and EpsX=0 (simultaneously) will lead to
-automatic stopping criterion selection.
+This function allows to solve different problem:
 
-These conditions are used to terminate inner iterations. However, you
-need to tune termination conditions for outer iterations too.
+    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].
 
   -- ALGLIB --
-     Copyright 28.11.2010 by Bochkanov Sergey
+     Copyright 11.01.2011 by Bochkanov Sergey
 *************************************************************************/
-void minbleicsetinnercond(const minbleicstate &state, const double epsg, const double epsf, const double epsx)
+void minqpsetorigin(const minqpstate &state, const real_1d_array &xorigin)
 {
     alglib_impl::ae_state _alglib_env_state;
     alglib_impl::ae_state_init(&_alglib_env_state);
     try
     {
-        alglib_impl::minbleicsetinnercond(const_cast<alglib_impl::minbleicstate*>(state.c_ptr()), epsg, epsf, epsx, &_alglib_env_state);
+        alglib_impl::minqpsetorigin(const_cast<alglib_impl::minqpstate*>(state.c_ptr()), const_cast<alglib_impl::ae_vector*>(xorigin.c_ptr()), &_alglib_env_state);
         alglib_impl::ae_state_clear(&_alglib_env_state);
         return;
     }
@@ -4047,40 +3600,29 @@ void minbleicsetinnercond(const minbleicstate &state, const double epsg, const d
 }
 
 /*************************************************************************
-This function sets stopping conditions for outer iteration of BLEIC algo.
+This function tells solver to use Cholesky-based algorithm.
 
-These conditions control accuracy of constraint handling and amount of
-infeasibility allowed in the solution.
+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
-    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.
 
   -- ALGLIB --
-     Copyright 28.11.2010 by Bochkanov Sergey
+     Copyright 11.01.2011 by Bochkanov Sergey
 *************************************************************************/
-void minbleicsetoutercond(const minbleicstate &state, const double epsx, const double epsi)
+void minqpsetalgocholesky(const minqpstate &state)
 {
     alglib_impl::ae_state _alglib_env_state;
     alglib_impl::ae_state_init(&_alglib_env_state);
     try
     {
-        alglib_impl::minbleicsetoutercond(const_cast<alglib_impl::minbleicstate*>(state.c_ptr()), epsx, epsi, &_alglib_env_state);
+        alglib_impl::minqpsetalgocholesky(const_cast<alglib_impl::minqpstate*>(state.c_ptr()), &_alglib_env_state);
         alglib_impl::ae_state_clear(&_alglib_env_state);
         return;
     }
@@ -4095,45 +3637,36 @@ void minbleicsetoutercond(const minbleicstate &state, const double epsx, const d
 }
 
 /*************************************************************************
-This function sets initial barrier width.
-
-BLEIC optimizer uses  modified  barrier  functions  to  handle  inequality
-constraints. These functions are almost constant in the inner parts of the
-feasible  area,  but  grow rapidly to the infinity OUTSIDE of the feasible
-area. Barrier width is a distance from feasible area to  the  point  where
-modified barrier function becomes infinite.
-
-Barrier width must be:
-* small enough (below some problem-dependent value) in order for algorithm
-  to  converge.  Necessary  condition  is that the target function must be
-  well described by linear model in the areas as small as barrier width.
-* not VERY small (in order to avoid  difficulties  associated  with  rapid
-  changes in the modified function, ill-conditioning, round-off issues).
+This function sets boundary constraints for QP solver
 
-Choosing  appropriate  barrier  width  is  very  important  for  efficient
-optimization, and it often requires error  and  trial.  You  can  use  two
-strategies when choosing barrier width:
-* set barrier width with MinBLEICSetBarrierWidth() call. In this case  you
-  should try different barrier widths and examine results.
-* set decreasing barrier width by combining  MinBLEICSetBarrierWidth() and
-  MinBLEICSetBarrierDecay()  calls.  In  this case algorithm will decrease
-  barrier  width  after  each  outer iteration until it encounters optimal
-  barrier width.
+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 which stores algorithm state
-    Mu      -   >0, initial barrier width
+    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].
 
   -- ALGLIB --
-     Copyright 28.11.2010 by Bochkanov Sergey
+     Copyright 11.01.2011 by Bochkanov Sergey
 *************************************************************************/
-void minbleicsetbarrierwidth(const minbleicstate &state, const double mu)
+void minqpsetbc(const minqpstate &state, const real_1d_array &bndl, const real_1d_array &bndu)
 {
     alglib_impl::ae_state _alglib_env_state;
     alglib_impl::ae_state_init(&_alglib_env_state);
     try
     {
-        alglib_impl::minbleicsetbarrierwidth(const_cast<alglib_impl::minbleicstate*>(state.c_ptr()), mu, &_alglib_env_state);
+        alglib_impl::minqpsetbc(const_cast<alglib_impl::minqpstate*>(state.c_ptr()), const_cast<alglib_impl::ae_vector*>(bndl.c_ptr()), const_cast<alglib_impl::ae_vector*>(bndu.c_ptr()), &_alglib_env_state);
         alglib_impl::ae_state_clear(&_alglib_env_state);
         return;
     }
@@ -4148,35 +3681,25 @@ void minbleicsetbarrierwidth(const minbleicstate &state, const double mu)
 }
 
 /*************************************************************************
-This function sets decay coefficient for barrier width.
-
-By default, no barrier decay is used (Decay=1.0).
-
-BLEIC optimizer uses  modified  barrier  functions  to  handle  inequality
-constraints. These functions are almost constant in the inner parts of the
-feasible  area,  but  grow rapidly to the infinity OUTSIDE of the feasible
-area. Barrier width is a distance from feasible area to  the  point  where
-modified barrier function becomes infinite. Decay coefficient allows us to
-decrease  barrier  width  from  the  initial  (suboptimial)  value   until
-optimal value will be met.
-
-We recommend you either to set MuDecay=1.0 (no decay) or use some moderate
-value like 0.5-0.7
+This function solves quadratic programming problem.
+You should call it after setting solver options with MinQPSet...() calls.
 
 INPUT PARAMETERS:
-    State   -   structure which stores algorithm state
-    MuDecay -   0<MuDecay<=1, decay coefficient
+    State   -   algorithm state
+
+You should use MinQPResults() function to access results after calls
+to this function.
 
   -- ALGLIB --
-     Copyright 28.11.2010 by Bochkanov Sergey
+     Copyright 11.01.2011 by Bochkanov Sergey
 *************************************************************************/
-void minbleicsetbarrierdecay(const minbleicstate &state, const double mudecay)
+void minqpoptimize(const minqpstate &state)
 {
     alglib_impl::ae_state _alglib_env_state;
     alglib_impl::ae_state_init(&_alglib_env_state);
     try
     {
-        alglib_impl::minbleicsetbarrierdecay(const_cast<alglib_impl::minbleicstate*>(state.c_ptr()), mudecay, &_alglib_env_state);
+        alglib_impl::minqpoptimize(const_cast<alglib_impl::minqpstate*>(state.c_ptr()), &_alglib_env_state);
         alglib_impl::ae_state_clear(&_alglib_env_state);
         return;
     }
@@ -4191,24 +3714,28 @@ void minbleicsetbarrierdecay(const minbleicstate &state, const double mudecay)
 }
 
 /*************************************************************************
-This function allows to stop algorithm after specified number of inner
-iterations.
+QP solver results
 
 INPUT PARAMETERS:
-    State   -   structure which stores algorithm state
-    MaxIts  -   maximum number of inner iterations.
-                If MaxIts=0, the number of iterations is unlimited.
+    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.
 
   -- ALGLIB --
-     Copyright 28.11.2010 by Bochkanov Sergey
+     Copyright 11.01.2011 by Bochkanov Sergey
 *************************************************************************/
-void minbleicsetmaxits(const minbleicstate &state, const ae_int_t maxits)
+void minqpresults(const minqpstate &state, real_1d_array &x, minqpreport &rep)
 {
     alglib_impl::ae_state _alglib_env_state;
     alglib_impl::ae_state_init(&_alglib_env_state);
     try
     {
-        alglib_impl::minbleicsetmaxits(const_cast<alglib_impl::minbleicstate*>(state.c_ptr()), maxits, &_alglib_env_state);
+        alglib_impl::minqpresults(const_cast<alglib_impl::minqpstate*>(state.c_ptr()), const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::minqpreport*>(rep.c_ptr()), &_alglib_env_state);
         alglib_impl::ae_state_clear(&_alglib_env_state);
         return;
     }
@@ -4223,25 +3750,23 @@ void minbleicsetmaxits(const minbleicstate &state, const ae_int_t maxits)
 }
 
 /*************************************************************************
-This function turns on/off reporting.
-
-INPUT PARAMETERS:
-    State   -   structure which stores algorithm state
-    NeedXRep-   whether iteration reports are needed or not
+QP results
 
-If NeedXRep is True, algorithm will call rep() callback function if  it is
-provided to MinBLEICOptimize().
+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.
 
   -- ALGLIB --
-     Copyright 28.11.2010 by Bochkanov Sergey
+     Copyright 11.01.2011 by Bochkanov Sergey
 *************************************************************************/
-void minbleicsetxrep(const minbleicstate &state, const bool needxrep)
+void minqpresultsbuf(const minqpstate &state, real_1d_array &x, minqpreport &rep)
 {
     alglib_impl::ae_state _alglib_env_state;
     alglib_impl::ae_state_init(&_alglib_env_state);
     try
     {
-        alglib_impl::minbleicsetxrep(const_cast<alglib_impl::minbleicstate*>(state.c_ptr()), needxrep, &_alglib_env_state);
+        alglib_impl::minqpresultsbuf(const_cast<alglib_impl::minqpstate*>(state.c_ptr()), const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::minqpreport*>(rep.c_ptr()), &_alglib_env_state);
         alglib_impl::ae_state_clear(&_alglib_env_state);
         return;
     }
@@ -4256,29 +3781,229 @@ void minbleicsetxrep(const minbleicstate &state, const bool needxrep)
 }
 
 /*************************************************************************
-This function sets maximum step length
+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.
+*************************************************************************/
+_minlmstate_owner::_minlmstate_owner()
+{
+    p_struct = (alglib_impl::minlmstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::minlmstate), NULL);
+    if( p_struct==NULL )
+        throw ap_error("ALGLIB: malloc error");
+    if( !alglib_impl::_minlmstate_init(p_struct, NULL, ae_false) )
+        throw ap_error("ALGLIB: malloc error");
+}
+
+_minlmstate_owner::_minlmstate_owner(const _minlmstate_owner &rhs)
+{
+    p_struct = (alglib_impl::minlmstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::minlmstate), NULL);
+    if( p_struct==NULL )
+        throw ap_error("ALGLIB: malloc error");
+    if( !alglib_impl::_minlmstate_init_copy(p_struct, const_cast<alglib_impl::minlmstate*>(rhs.p_struct), NULL, ae_false) )
+        throw ap_error("ALGLIB: malloc error");
+}
+
+_minlmstate_owner& _minlmstate_owner::operator=(const _minlmstate_owner &rhs)
+{
+    if( this==&rhs )
+        return *this;
+    alglib_impl::_minlmstate_clear(p_struct);
+    if( !alglib_impl::_minlmstate_init_copy(p_struct, const_cast<alglib_impl::minlmstate*>(rhs.p_struct), NULL, ae_false) )
+        throw ap_error("ALGLIB: malloc error");
+    return *this;
+}
+
+_minlmstate_owner::~_minlmstate_owner()
+{
+    alglib_impl::_minlmstate_clear(p_struct);
+    ae_free(p_struct);
+}
+
+alglib_impl::minlmstate* _minlmstate_owner::c_ptr()
+{
+    return p_struct;
+}
+
+alglib_impl::minlmstate* _minlmstate_owner::c_ptr() const
+{
+    return const_cast<alglib_impl::minlmstate*>(p_struct);
+}
+minlmstate::minlmstate() : _minlmstate_owner() ,needf(p_struct->needf),needfg(p_struct->needfg),needfgh(p_struct->needfgh),needfi(p_struct->needfi),needfij(p_struct->needfij),xupdated(p_struct->xupdated),f(p_struct->f),fi(&p_struct->fi),g(&p_struct->g),h(&p_struct->h),j(&p_struct->j),x(&p_struct->x)
+{
+}
+
+minlmstate::minlmstate(const minlmstate &rhs):_minlmstate_owner(rhs) ,needf(p_struct->needf),needfg(p_struct->needfg),needfgh(p_struct->needfgh),needfi(p_struct->needfi),needfij(p_struct->needfij),xupdated(p_struct->xupdated),f(p_struct->f),fi(&p_struct->fi),g(&p_struct->g),h(&p_struct->h),j(&p_struct->j),x(&p_struct->x)
+{
+}
+
+minlmstate& minlmstate::operator=(const minlmstate &rhs)
+{
+    if( this==&rhs )
+        return *this;
+    _minlmstate_owner::operator=(rhs);
+    return *this;
+}
+
+minlmstate::~minlmstate()
+{
+}
+
+
+/*************************************************************************
+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
+*************************************************************************/
+_minlmreport_owner::_minlmreport_owner()
+{
+    p_struct = (alglib_impl::minlmreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::minlmreport), NULL);
+    if( p_struct==NULL )
+        throw ap_error("ALGLIB: malloc error");
+    if( !alglib_impl::_minlmreport_init(p_struct, NULL, ae_false) )
+        throw ap_error("ALGLIB: malloc error");
+}
+
+_minlmreport_owner::_minlmreport_owner(const _minlmreport_owner &rhs)
+{
+    p_struct = (alglib_impl::minlmreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::minlmreport), NULL);
+    if( p_struct==NULL )
+        throw ap_error("ALGLIB: malloc error");
+    if( !alglib_impl::_minlmreport_init_copy(p_struct, const_cast<alglib_impl::minlmreport*>(rhs.p_struct), NULL, ae_false) )
+        throw ap_error("ALGLIB: malloc error");
+}
+
+_minlmreport_owner& _minlmreport_owner::operator=(const _minlmreport_owner &rhs)
+{
+    if( this==&rhs )
+        return *this;
+    alglib_impl::_minlmreport_clear(p_struct);
+    if( !alglib_impl::_minlmreport_init_copy(p_struct, const_cast<alglib_impl::minlmreport*>(rhs.p_struct), NULL, ae_false) )
+        throw ap_error("ALGLIB: malloc error");
+    return *this;
+}
+
+_minlmreport_owner::~_minlmreport_owner()
+{
+    alglib_impl::_minlmreport_clear(p_struct);
+    ae_free(p_struct);
+}
+
+alglib_impl::minlmreport* _minlmreport_owner::c_ptr()
+{
+    return p_struct;
+}
+
+alglib_impl::minlmreport* _minlmreport_owner::c_ptr() const
+{
+    return const_cast<alglib_impl::minlmreport*>(p_struct);
+}
+minlmreport::minlmreport() : _minlmreport_owner() ,iterationscount(p_struct->iterationscount),terminationtype(p_struct->terminationtype),nfunc(p_struct->nfunc),njac(p_struct->njac),ngrad(p_struct->ngrad),nhess(p_struct->nhess),ncholesky(p_struct->ncholesky)
+{
+}
+
+minlmreport::minlmreport(const minlmreport &rhs):_minlmreport_owner(rhs) ,iterationscount(p_struct->iterationscount),terminationtype(p_struct->terminationtype),nfunc(p_struct->nfunc),njac(p_struct->njac),ngrad(p_struct->ngrad),nhess(p_struct->nhess),ncholesky(p_struct->ncholesky)
+{
+}
+
+minlmreport& minlmreport::operator=(const minlmreport &rhs)
+{
+    if( this==&rhs )
+        return *this;
+    _minlmreport_owner::operator=(rhs);
+    return *this;
+}
+
+minlmreport::~minlmreport()
+{
+}
+
+/*************************************************************************
+                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
-    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.
+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.
 
   -- ALGLIB --
-     Copyright 02.04.2010 by Bochkanov Sergey
+     Copyright 30.03.2009 by Bochkanov Sergey
 *************************************************************************/
-void minbleicsetstpmax(const minbleicstate &state, const double stpmax)
+void minlmcreatevj(const ae_int_t n, const ae_int_t m, const real_1d_array &x, minlmstate &state)
 {
     alglib_impl::ae_state _alglib_env_state;
     alglib_impl::ae_state_init(&_alglib_env_state);
     try
     {
-        alglib_impl::minbleicsetstpmax(const_cast<alglib_impl::minbleicstate*>(state.c_ptr()), stpmax, &_alglib_env_state);
+        alglib_impl::minlmcreatevj(n, m, const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::minlmstate*>(state.c_ptr()), &_alglib_env_state);
         alglib_impl::ae_state_clear(&_alglib_env_state);
         return;
     }
@@ -4293,58 +4018,79 @@ void minbleicsetstpmax(const minbleicstate &state, const double stpmax)
 }
 
 /*************************************************************************
-This function provides reverse communication interface
-Reverse communication interface is not documented or recommended to use.
-See below for functions which provide better documented API
-*************************************************************************/
-bool minbleiciteration(const minbleicstate &state)
-{
-    alglib_impl::ae_state _alglib_env_state;
-    alglib_impl::ae_state_init(&_alglib_env_state);
-    try
-    {
-        ae_bool result = alglib_impl::minbleiciteration(const_cast<alglib_impl::minbleicstate*>(state.c_ptr()), &_alglib_env_state);
-        alglib_impl::ae_state_clear(&_alglib_env_state);
-        return *(reinterpret_cast<bool*>(&result));
-    }
-    catch(alglib_impl::ae_error_type)
-    {
-        throw ap_error(_alglib_env_state.error_msg);
-    }
-    catch(...)
-    {
-        throw;
-    }
-}
+                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[].
 
 
-void minbleicoptimize(minbleicstate &state,
-    void (*grad)(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr),
-    void  (*rep)(const real_1d_array &x, double func, void *ptr), 
-    void *ptr)
+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.
+
+  -- ALGLIB --
+     Copyright 30.03.2009 by Bochkanov Sergey
+*************************************************************************/
+void minlmcreatevj(const ae_int_t m, const real_1d_array &x, minlmstate &state)
 {
-    alglib_impl::ae_state _alglib_env_state;
-    if( grad==NULL )
-        throw ap_error("ALGLIB: error in 'minbleicoptimize()' (grad is NULL)");
+    alglib_impl::ae_state _alglib_env_state;    
+    ae_int_t n;
+
+    n = x.length();
     alglib_impl::ae_state_init(&_alglib_env_state);
     try
     {
-        while( alglib_impl::minbleiciteration(state.c_ptr(), &_alglib_env_state) )
-        {
-            if( state.needfg )
-            {
-                grad(state.x, state.f, state.g, ptr);
-                continue;
-            }
-            if( state.xupdated )
-            {
-                if( rep!=NULL )
-                    rep(state.x, state.f, ptr);
-                continue;
-            }
-            throw ap_error("ALGLIB: error in 'minbleicoptimize' (some derivatives were not provided?)");
-        }
+        alglib_impl::minlmcreatevj(n, m, const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::minlmstate*>(state.c_ptr()), &_alglib_env_state);
+
         alglib_impl::ae_state_clear(&_alglib_env_state);
+        return;
     }
     catch(alglib_impl::ae_error_type)
     {
@@ -4356,43 +4102,74 @@ void minbleicoptimize(minbleicstate &state,
     }
 }
 
+/*************************************************************************
+                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.
 
-/*************************************************************************
-BLEIC results
 
 INPUT PARAMETERS:
-    State   -   algorithm state
+    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:
-    X       -   array[0..N-1], solution
-    Rep     -   optimization report:
-                * Rep.TerminationType completetion code:
-                    * -3    inconsistent constraints. Feasible point is
-                            either nonexistent or too hard to find. Try to
-                            restart optimizer with better initial
-                            approximation
-                    * -2    rounding errors prevent further improvement.
-                            X contains best point found.
-                    *  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.
-                * Rep.IterationsCount contains iterations count
-                * NFEV countains number of function calculations
+    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.
 
   -- ALGLIB --
-     Copyright 28.11.2010 by Bochkanov Sergey
+     Copyright 30.03.2009 by Bochkanov Sergey
 *************************************************************************/
-void minbleicresults(const minbleicstate &state, real_1d_array &x, minbleicreport &rep)
+void minlmcreatev(const ae_int_t n, const ae_int_t m, const real_1d_array &x, const double diffstep, minlmstate &state)
 {
     alglib_impl::ae_state _alglib_env_state;
     alglib_impl::ae_state_init(&_alglib_env_state);
     try
     {
-        alglib_impl::minbleicresults(const_cast<alglib_impl::minbleicstate*>(state.c_ptr()), const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::minbleicreport*>(rep.c_ptr()), &_alglib_env_state);
+        alglib_impl::minlmcreatev(n, m, const_cast<alglib_impl::ae_vector*>(x.c_ptr()), diffstep, const_cast<alglib_impl::minlmstate*>(state.c_ptr()), &_alglib_env_state);
         alglib_impl::ae_state_clear(&_alglib_env_state);
         return;
     }
@@ -4407,23 +4184,77 @@ void minbleicresults(const minbleicstate &state, real_1d_array &x, minbleicrepor
 }
 
 /*************************************************************************
-BLEIC results
+                IMPROVED LEVENBERG-MARQUARDT METHOD FOR
+                 NON-LINEAR LEAST SQUARES OPTIMIZATION
 
-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.
+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.
 
   -- ALGLIB --
-     Copyright 28.11.2010 by Bochkanov Sergey
+     Copyright 30.03.2009 by Bochkanov Sergey
 *************************************************************************/
-void minbleicresultsbuf(const minbleicstate &state, real_1d_array &x, minbleicreport &rep)
+void minlmcreatev(const ae_int_t m, const real_1d_array &x, const double diffstep, minlmstate &state)
 {
-    alglib_impl::ae_state _alglib_env_state;
+    alglib_impl::ae_state _alglib_env_state;    
+    ae_int_t n;
+
+    n = x.length();
     alglib_impl::ae_state_init(&_alglib_env_state);
     try
     {
-        alglib_impl::minbleicresultsbuf(const_cast<alglib_impl::minbleicstate*>(state.c_ptr()), const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::minbleicreport*>(rep.c_ptr()), &_alglib_env_state);
+        alglib_impl::minlmcreatev(n, m, const_cast<alglib_impl::ae_vector*>(x.c_ptr()), diffstep, const_cast<alglib_impl::minlmstate*>(state.c_ptr()), &_alglib_env_state);
+
         alglib_impl::ae_state_clear(&_alglib_env_state);
         return;
     }
@@ -4438,26 +4269,74 @@ void minbleicresultsbuf(const minbleicstate &state, real_1d_array &x, minbleicre
 }
 
 /*************************************************************************
-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.
+    LEVENBERG-MARQUARDT-LIKE METHOD FOR NON-LINEAR OPTIMIZATION
 
-INPUT PARAMETERS:
-    State   -   structure previously allocated with MinBLEICCreate call.
-    X       -   new starting point.
+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.
 
   -- ALGLIB --
-     Copyright 28.11.2010 by Bochkanov Sergey
+     Copyright 30.03.2009 by Bochkanov Sergey
 *************************************************************************/
-void minbleicrestartfrom(const minbleicstate &state, const real_1d_array &x)
+void minlmcreatefgh(const ae_int_t n, const real_1d_array &x, minlmstate &state)
 {
     alglib_impl::ae_state _alglib_env_state;
     alglib_impl::ae_state_init(&_alglib_env_state);
     try
     {
-        alglib_impl::minbleicrestartfrom(const_cast<alglib_impl::minbleicstate*>(state.c_ptr()), const_cast<alglib_impl::ae_vector*>(x.c_ptr()), &_alglib_env_state);
+        alglib_impl::minlmcreatefgh(n, const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::minlmstate*>(state.c_ptr()), &_alglib_env_state);
         alglib_impl::ae_state_clear(&_alglib_env_state);
         return;
     }
@@ -4470,196 +4349,122 @@ void minbleicrestartfrom(const minbleicstate &state, const real_1d_array &x)
         throw;
     }
 }
-}
-
-/////////////////////////////////////////////////////////////////////////
-//
-// THIS SECTION CONTAINS IMPLEMENTATION OF COMPUTATIONAL CORE
-//
-/////////////////////////////////////////////////////////////////////////
-namespace alglib_impl
-{
-static void minlbfgs_clearrequestfields(minlbfgsstate* state,
-     ae_state *_state);
-
-
-static ae_int_t minlm_lmmodefj = 0;
-static ae_int_t minlm_lmmodefgj = 1;
-static ae_int_t minlm_lmmodefgh = 2;
-static ae_int_t minlm_lmflagnoprelbfgs = 1;
-static ae_int_t minlm_lmflagnointlbfgs = 2;
-static ae_int_t minlm_lmprelbfgsm = 5;
-static ae_int_t minlm_lmintlbfgsits = 5;
-static ae_int_t minlm_lbfgsnorealloc = 1;
-static double minlm_lambdaup = 2.0;
-static double minlm_lambdadown = 0.33;
-static double minlm_suspiciousnu = 16;
-static ae_int_t minlm_smallmodelage = 3;
-static ae_int_t minlm_additers = 5;
-static void minlm_lmprepare(ae_int_t n,
-     ae_int_t m,
-     ae_bool havegrad,
-     minlmstate* state,
-     ae_state *_state);
-static void minlm_clearrequestfields(minlmstate* state, ae_state *_state);
-static ae_bool minlm_increaselambda(double* lambdav,
-     double* nu,
-     ae_state *_state);
-static void minlm_decreaselambda(double* lambdav,
-     double* nu,
-     ae_state *_state);
-
-
-static ae_int_t minasa_n1 = 2;
-static ae_int_t minasa_n2 = 2;
-static double minasa_stpmin = 1.0E-300;
-static double minasa_gpaftol = 0.0001;
-static double minasa_gpadecay = 0.5;
-static double minasa_asarho = 0.5;
-static double minasa_asaboundedantigradnorm(minasastate* state,
-     ae_state *_state);
-static double minasa_asaginorm(minasastate* state, ae_state *_state);
-static double minasa_asad1norm(minasastate* state, ae_state *_state);
-static ae_bool minasa_asauisempty(minasastate* state, ae_state *_state);
-static void minasa_clearrequestfields(minasastate* state,
-     ae_state *_state);
-
-
-static ae_int_t mincg_rscountdownlen = 10;
-static void mincg_clearrequestfields(mincgstate* state, ae_state *_state);
-
-
-static double minbleic_svdtol = 100;
-static double minbleic_lmtol = 100;
-static double minbleic_maxlmgrowth = 1000;
-static double minbleic_minlagrangemul = 1.0E-50;
-static double minbleic_maxlagrangemul = 1.0E+50;
-static double minbleic_maxouterits = 20;
-static ae_int_t minbleic_mucountdownlen = 15;
-static ae_int_t minbleic_cscountdownlen = 5;
-static void minbleic_clearrequestfields(minbleicstate* state,
-     ae_state *_state);
-static void minbleic_makeprojection(minbleicstate* state,
-     /* Real    */ ae_vector* x,
-     /* Real    */ ae_vector* r,
-     double* rnorm2,
-     ae_state *_state);
-static void minbleic_modifytargetfunction(minbleicstate* state,
-     /* Real    */ ae_vector* x,
-     /* Real    */ ae_vector* r,
-     double rnorm2,
-     double* f,
-     /* Real    */ ae_vector* g,
-     double* gnorm,
-     double* mpgnorm,
-     double* mba,
-     double* fierr,
-     double* cserr,
-     ae_state *_state);
-static void minbleic_penaltyfunction(minbleicstate* state,
-     /* Real    */ ae_vector* x,
-     double* f,
-     /* Real    */ ae_vector* g,
-     /* Real    */ ae_vector* r,
-     double* mba,
-     double* fierr,
-     ae_state *_state);
-
-
-
-
 
 /*************************************************************************
-        LIMITED MEMORY BFGS METHOD FOR LARGE SCALE OPTIMIZATION
+    LEVENBERG-MARQUARDT-LIKE METHOD FOR NON-LINEAR 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.
+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:
-Algorithm will request following information during its operation:
-* function value F and its gradient G (simultaneously) at given point X
+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 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.
+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       -   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].
-
+    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 MinLBFGSSetCond() function
+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 MinLBFGSSetStpMax() function to bound algorithm's  steps.  However,
-   L-BFGS rarely needs such a tuning.
-
+   use MinLMSetStpMax() function to bound algorithm's steps.
 
   -- ALGLIB --
-     Copyright 02.04.2010 by Bochkanov Sergey
+     Copyright 30.03.2009 by Bochkanov Sergey
 *************************************************************************/
-void minlbfgscreate(ae_int_t n,
-     ae_int_t m,
-     /* Real    */ ae_vector* x,
-     minlbfgsstate* state,
-     ae_state *_state)
+void minlmcreatefgh(const real_1d_array &x, minlmstate &state)
 {
+    alglib_impl::ae_state _alglib_env_state;    
+    ae_int_t n;
 
-    _minlbfgsstate_clear(state);
+    n = x.length();
+    alglib_impl::ae_state_init(&_alglib_env_state);
+    try
+    {
+        alglib_impl::minlmcreatefgh(n, const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::minlmstate*>(state.c_ptr()), &_alglib_env_state);
 
-    ae_assert(n>=1, "MinLBFGSCreate: N<1!", _state);
-    ae_assert(m>=1, "MinLBFGSCreate: M<1", _state);
-    ae_assert(m<=n, "MinLBFGSCreate: M>N", _state);
-    ae_assert(x->cnt>=n, "MinLBFGSCreate: Length(X)<N!", _state);
-    ae_assert(isfinitevector(x, n, _state), "MinLBFGSCreate: X contains infinite or NaN values!", _state);
-    minlbfgscreatex(n, m, x, 0, state, _state);
+        alglib_impl::ae_state_clear(&_alglib_env_state);
+        return;
+    }
+    catch(alglib_impl::ae_error_type)
+    {
+        throw ap_error(_alglib_env_state.error_msg);
+    }
+    catch(...)
+    {
+        throw;
+    }
 }
 
-
 /*************************************************************************
-This function sets stopping conditions for L-BFGS optimization algorithm.
+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
-                ||G||<EpsG is satisfied, where ||.|| means Euclidian norm,
-                G - gradient.
+                |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 |X(k+1)-X(k)| <= EpsX is fulfilled.
+                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.
+                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).
@@ -4667,33 +4472,26 @@ automatic stopping criterion selection (small EpsX).
   -- ALGLIB --
      Copyright 02.04.2010 by Bochkanov Sergey
 *************************************************************************/
-void minlbfgssetcond(minlbfgsstate* state,
-     double epsg,
-     double epsf,
-     double epsx,
-     ae_int_t maxits,
-     ae_state *_state)
+void minlmsetcond(const minlmstate &state, const double epsg, const double epsf, const double epsx, const ae_int_t maxits)
 {
-
-
-    ae_assert(ae_isfinite(epsg, _state), "MinLBFGSSetCond: EpsG is not finite number!", _state);
-    ae_assert(ae_fp_greater_eq(epsg,0), "MinLBFGSSetCond: negative EpsG!", _state);
-    ae_assert(ae_isfinite(epsf, _state), "MinLBFGSSetCond: EpsF is not finite number!", _state);
-    ae_assert(ae_fp_greater_eq(epsf,0), "MinLBFGSSetCond: negative EpsF!", _state);
-    ae_assert(ae_isfinite(epsx, _state), "MinLBFGSSetCond: EpsX is not finite number!", _state);
-    ae_assert(ae_fp_greater_eq(epsx,0), "MinLBFGSSetCond: negative EpsX!", _state);
-    ae_assert(maxits>=0, "MinLBFGSSetCond: negative MaxIts!", _state);
-    if( ((ae_fp_eq(epsg,0)&&ae_fp_eq(epsf,0))&&ae_fp_eq(epsx,0))&&maxits==0 )
+    alglib_impl::ae_state _alglib_env_state;
+    alglib_impl::ae_state_init(&_alglib_env_state);
+    try
     {
-        epsx = 1.0E-6;
+        alglib_impl::minlmsetcond(const_cast<alglib_impl::minlmstate*>(state.c_ptr()), epsg, epsf, epsx, maxits, &_alglib_env_state);
+        alglib_impl::ae_state_clear(&_alglib_env_state);
+        return;
+    }
+    catch(alglib_impl::ae_error_type)
+    {
+        throw ap_error(_alglib_env_state.error_msg);
+    }
+    catch(...)
+    {
+        throw;
     }
-    state->epsg = epsg;
-    state->epsf = epsf;
-    state->epsx = epsx;
-    state->maxits = maxits;
 }
 
-
 /*************************************************************************
 This function turns on/off reporting.
 
@@ -4702,29 +4500,39 @@ INPUT PARAMETERS:
     NeedXRep-   whether iteration reports are needed or not
 
 If NeedXRep is True, algorithm will call rep() callback function if  it is
-provided to MinLBFGSOptimize().
-
+provided to MinLMOptimize(). Both Levenberg-Marquardt and internal  L-BFGS
+iterations are reported.
 
   -- ALGLIB --
      Copyright 02.04.2010 by Bochkanov Sergey
 *************************************************************************/
-void minlbfgssetxrep(minlbfgsstate* state,
-     ae_bool needxrep,
-     ae_state *_state)
+void minlmsetxrep(const minlmstate &state, const bool needxrep)
 {
-
-
-    state->xrep = needxrep;
+    alglib_impl::ae_state _alglib_env_state;
+    alglib_impl::ae_state_init(&_alglib_env_state);
+    try
+    {
+        alglib_impl::minlmsetxrep(const_cast<alglib_impl::minlmstate*>(state.c_ptr()), needxrep, &_alglib_env_state);
+        alglib_impl::ae_state_clear(&_alglib_env_state);
+        return;
+    }
+    catch(alglib_impl::ae_error_type)
+    {
+        throw ap_error(_alglib_env_state.error_msg);
+    }
+    catch(...)
+    {
+        throw;
+    }
 }
 
-
 /*************************************************************************
 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.
+    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
@@ -4732,2483 +4540,2597 @@ 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.
+
   -- ALGLIB --
      Copyright 02.04.2010 by Bochkanov Sergey
 *************************************************************************/
-void minlbfgssetstpmax(minlbfgsstate* state,
-     double stpmax,
-     ae_state *_state)
+void minlmsetstpmax(const minlmstate &state, const double stpmax)
 {
-
-
-    ae_assert(ae_isfinite(stpmax, _state), "MinLBFGSSetStpMax: StpMax is not finite!", _state);
-    ae_assert(ae_fp_greater_eq(stpmax,0), "MinLBFGSSetStpMax: StpMax<0!", _state);
-    state->stpmax = stpmax;
+    alglib_impl::ae_state _alglib_env_state;
+    alglib_impl::ae_state_init(&_alglib_env_state);
+    try
+    {
+        alglib_impl::minlmsetstpmax(const_cast<alglib_impl::minlmstate*>(state.c_ptr()), stpmax, &_alglib_env_state);
+        alglib_impl::ae_state_clear(&_alglib_env_state);
+        return;
+    }
+    catch(alglib_impl::ae_error_type)
+    {
+        throw ap_error(_alglib_env_state.error_msg);
+    }
+    catch(...)
+    {
+        throw;
+    }
 }
 
-
 /*************************************************************************
-Extended subroutine for internal use only.
+This function sets scaling coefficients for LM optimizer.
 
-Accepts additional parameters:
+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
 
-    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.
+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.
 
   -- ALGLIB --
-     Copyright 02.04.2010 by Bochkanov Sergey
+     Copyright 14.01.2011 by Bochkanov Sergey
 *************************************************************************/
-void minlbfgscreatex(ae_int_t n,
-     ae_int_t m,
-     /* Real    */ ae_vector* x,
-     ae_int_t flags,
-     minlbfgsstate* state,
-     ae_state *_state)
+void minlmsetscale(const minlmstate &state, const real_1d_array &s)
 {
-    ae_bool allocatemem;
-
-
-    ae_assert(n>=1, "MinLBFGS: N too small!", _state);
-    ae_assert(m>=1, "MinLBFGS: M too small!", _state);
-    ae_assert(m<=n, "MinLBFGS: M too large!", _state);
-    
-    /*
-     * Initialize
-     */
-    state->n = n;
-    state->m = m;
-    state->flags = flags;
-    allocatemem = flags%2==0;
-    flags = flags/2;
-    if( allocatemem )
+    alglib_impl::ae_state _alglib_env_state;
+    alglib_impl::ae_state_init(&_alglib_env_state);
+    try
     {
-        ae_vector_set_length(&state->rho, m-1+1, _state);
-        ae_vector_set_length(&state->theta, m-1+1, _state);
-        ae_matrix_set_length(&state->y, m-1+1, n-1+1, _state);
-        ae_matrix_set_length(&state->s, m-1+1, n-1+1, _state);
-        ae_vector_set_length(&state->d, n-1+1, _state);
-        ae_vector_set_length(&state->x, n-1+1, _state);
-        ae_vector_set_length(&state->g, n-1+1, _state);
-        ae_vector_set_length(&state->work, n-1+1, _state);
+        alglib_impl::minlmsetscale(const_cast<alglib_impl::minlmstate*>(state.c_ptr()), const_cast<alglib_impl::ae_vector*>(s.c_ptr()), &_alglib_env_state);
+        alglib_impl::ae_state_clear(&_alglib_env_state);
+        return;
+    }
+    catch(alglib_impl::ae_error_type)
+    {
+        throw ap_error(_alglib_env_state.error_msg);
+    }
+    catch(...)
+    {
+        throw;
     }
-    minlbfgssetcond(state, 0, 0, 0, 0, _state);
-    minlbfgssetxrep(state, ae_false, _state);
-    minlbfgssetstpmax(state, 0, _state);
-    minlbfgsrestartfrom(state, x, _state);
-    state->prectype = 0;
 }
 
-
 /*************************************************************************
-Modification of the preconditioner:
-default preconditioner (simple scaling) is used.
+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 which stores algorithm state
+    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).
 
-After call to this function preconditioner is changed to the default one.
+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:  you  can  change  preconditioner  "on  the  fly",  during algorithm
-iterations.
+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
 
   -- ALGLIB --
-     Copyright 13.10.2010 by Bochkanov Sergey
+     Copyright 14.01.2011 by Bochkanov Sergey
 *************************************************************************/
-void minlbfgssetdefaultpreconditioner(minlbfgsstate* state,
-     ae_state *_state)
+void minlmsetbc(const minlmstate &state, const real_1d_array &bndl, const real_1d_array &bndu)
 {
+    alglib_impl::ae_state _alglib_env_state;
+    alglib_impl::ae_state_init(&_alglib_env_state);
+    try
+    {
+        alglib_impl::minlmsetbc(const_cast<alglib_impl::minlmstate*>(state.c_ptr()), const_cast<alglib_impl::ae_vector*>(bndl.c_ptr()), const_cast<alglib_impl::ae_vector*>(bndu.c_ptr()), &_alglib_env_state);
+        alglib_impl::ae_state_clear(&_alglib_env_state);
+        return;
+    }
+    catch(alglib_impl::ae_error_type)
+    {
+        throw ap_error(_alglib_env_state.error_msg);
+    }
+    catch(...)
+    {
+        throw;
+    }
+}
 
+/*************************************************************************
+This function is used to change acceleration settings
 
-    state->prectype = 0;
-}
+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.
 
-/*************************************************************************
-Modification of the preconditioner:
-Cholesky factorization of approximate Hessian is used.
+Table below list  optimization  protocols  (XYZ  protocol  corresponds  to
+MinLMCreateXYZ) and acceleration types they support (and use by  default).
 
-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)
+ACCELERATION TYPES SUPPORTED BY OPTIMIZATION PROTOCOLS:
 
-After call to this function preconditioner is changed to P  (P  is  copied
-into the internal buffer).
+protocol    0   1   comment
+V           +   +
+VJ          +   +
+FGH         +
 
-NOTE:  you  can  change  preconditioner  "on  the  fly",  during algorithm
-iterations.
+DAFAULT VALUES:
 
-NOTE 2:  P  should  be nonsingular. Exception will be thrown otherwise. It
-also should be well conditioned, although only strict  non-singularity  is
-tested.
+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.
 
   -- ALGLIB --
-     Copyright 13.10.2010 by Bochkanov Sergey
+     Copyright 14.10.2010 by Bochkanov Sergey
 *************************************************************************/
-void minlbfgssetcholeskypreconditioner(minlbfgsstate* state,
-     /* Real    */ ae_matrix* p,
-     ae_bool isupper,
-     ae_state *_state)
+void minlmsetacctype(const minlmstate &state, const ae_int_t acctype)
 {
-    ae_int_t i;
-    double mx;
-
-
-    ae_assert(isfinitertrmatrix(p, state->n, isupper, _state), "MinLBFGSSetCholeskyPreconditioner: P contains infinite or NAN values!", _state);
-    mx = 0;
-    for(i=0; i<=state->n-1; i++)
-    {
-        mx = ae_maxreal(mx, ae_fabs(p->ptr.pp_double[i][i], _state), _state);
-    }
-    ae_assert(ae_fp_greater(mx,0), "MinLBFGSSetCholeskyPreconditioner: P is strictly singular!", _state);
-    if( state->denseh.rows<state->n||state->denseh.cols<state->n )
+    alglib_impl::ae_state _alglib_env_state;
+    alglib_impl::ae_state_init(&_alglib_env_state);
+    try
     {
-        ae_matrix_set_length(&state->denseh, state->n, state->n, _state);
+        alglib_impl::minlmsetacctype(const_cast<alglib_impl::minlmstate*>(state.c_ptr()), acctype, &_alglib_env_state);
+        alglib_impl::ae_state_clear(&_alglib_env_state);
+        return;
     }
-    state->prectype = 1;
-    if( isupper )
+    catch(alglib_impl::ae_error_type)
     {
-        rmatrixcopy(state->n, state->n, p, 0, 0, &state->denseh, 0, 0, _state);
+        throw ap_error(_alglib_env_state.error_msg);
     }
-    else
+    catch(...)
     {
-        rmatrixtranspose(state->n, state->n, p, 0, 0, &state->denseh, 0, 0, _state);
+        throw;
     }
 }
 
-
 /*************************************************************************
-
-  -- ALGLIB --
-     Copyright 20.03.2009 by Bochkanov Sergey
+This function provides reverse communication interface
+Reverse communication interface is not documented or recommended to use.
+See below for functions which provide better documented API
 *************************************************************************/
-ae_bool minlbfgsiteration(minlbfgsstate* state, ae_state *_state)
+bool minlmiteration(const minlmstate &state)
 {
-    ae_int_t n;
-    ae_int_t m;
-    ae_int_t maxits;
-    double epsf;
-    double epsg;
-    double epsx;
-    ae_int_t i;
-    ae_int_t j;
-    ae_int_t ic;
-    ae_int_t mcinfo;
-    double v;
-    double vv;
-    ae_bool result;
-
-
-    
-    /*
-     * 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->rstate.stage>=0 )
-    {
-        n = state->rstate.ia.ptr.p_int[0];
-        m = state->rstate.ia.ptr.p_int[1];
-        maxits = state->rstate.ia.ptr.p_int[2];
-        i = state->rstate.ia.ptr.p_int[3];
-        j = state->rstate.ia.ptr.p_int[4];
-        ic = state->rstate.ia.ptr.p_int[5];
-        mcinfo = state->rstate.ia.ptr.p_int[6];
-        epsf = state->rstate.ra.ptr.p_double[0];
-        epsg = state->rstate.ra.ptr.p_double[1];
-        epsx = state->rstate.ra.ptr.p_double[2];
-        v = state->rstate.ra.ptr.p_double[3];
-        vv = state->rstate.ra.ptr.p_double[4];
-    }
-    else
+    alglib_impl::ae_state _alglib_env_state;
+    alglib_impl::ae_state_init(&_alglib_env_state);
+    try
     {
-        n = -983;
-        m = -989;
-        maxits = -834;
-        i = 900;
-        j = -287;
-        ic = 364;
-        mcinfo = 214;
-        epsf = -338;
-        epsg = -686;
-        epsx = 912;
-        v = 585;
-        vv = 497;
+        ae_bool result = alglib_impl::minlmiteration(const_cast<alglib_impl::minlmstate*>(state.c_ptr()), &_alglib_env_state);
+        alglib_impl::ae_state_clear(&_alglib_env_state);
+        return *(reinterpret_cast<bool*>(&result));
     }
-    if( state->rstate.stage==0 )
+    catch(alglib_impl::ae_error_type)
     {
-        goto lbl_0;
+        throw ap_error(_alglib_env_state.error_msg);
     }
-    if( state->rstate.stage==1 )
+    catch(...)
     {
-        goto lbl_1;
+        throw;
     }
-    if( state->rstate.stage==2 )
+}
+
+
+void minlmoptimize(minlmstate &state,
+    void (*fvec)(const real_1d_array &x, real_1d_array &fi, void *ptr),
+    void  (*rep)(const real_1d_array &x, double func, void *ptr), 
+    void *ptr)
+{
+    alglib_impl::ae_state _alglib_env_state;
+    if( fvec==NULL )
+        throw ap_error("ALGLIB: error in 'minlmoptimize()' (fvec is NULL)");
+    alglib_impl::ae_state_init(&_alglib_env_state);
+    try
     {
-        goto lbl_2;
+        while( alglib_impl::minlmiteration(state.c_ptr(), &_alglib_env_state) )
+        {
+            if( state.needfi )
+            {
+                fvec(state.x, state.fi, ptr);
+                continue;
+            }
+            if( state.xupdated )
+            {
+                if( rep!=NULL )
+                    rep(state.x, state.f, ptr);
+                continue;
+            }
+            throw ap_error("ALGLIB: error in 'minlmoptimize' (some derivatives were not provided?)");
+        }
+        alglib_impl::ae_state_clear(&_alglib_env_state);
     }
-    if( state->rstate.stage==3 )
+    catch(alglib_impl::ae_error_type)
     {
-        goto lbl_3;
+        throw ap_error(_alglib_env_state.error_msg);
     }
-    
-    /*
-     * Routine body
-     */
-    
-    /*
-     * Unload frequently used variables from State structure
-     * (just for typing convinience)
-     */
-    n = state->n;
-    m = state->m;
-    epsg = state->epsg;
-    epsf = state->epsf;
-    epsx = state->epsx;
-    maxits = state->maxits;
-    state->repterminationtype = 0;
-    state->repiterationscount = 0;
-    state->repnfev = 0;
-    
-    /*
-     * Calculate F/G at the initial point
-     */
-    minlbfgs_clearrequestfields(state, _state);
-    state->needfg = ae_true;
-    state->rstate.stage = 0;
-    goto lbl_rcomm;
-lbl_0:
-    state->needfg = ae_false;
-    if( !state->xrep )
+    catch(...)
     {
-        goto lbl_4;
+        throw;
     }
-    minlbfgs_clearrequestfields(state, _state);
-    state->xupdated = ae_true;
-    state->rstate.stage = 1;
-    goto lbl_rcomm;
-lbl_1:
-    state->xupdated = ae_false;
-lbl_4:
-    state->repnfev = 1;
-    state->fold = state->f;
-    v = ae_v_dotproduct(&state->g.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    v = ae_sqrt(v, _state);
-    if( ae_fp_less_eq(v,epsg) )
+}
+
+
+void minlmoptimize(minlmstate &state,
+    void (*fvec)(const real_1d_array &x, real_1d_array &fi, void *ptr),
+    void  (*jac)(const real_1d_array &x, real_1d_array &fi, real_2d_array &jac, void *ptr),
+    void  (*rep)(const real_1d_array &x, double func, void *ptr), 
+    void *ptr)
+{
+    alglib_impl::ae_state _alglib_env_state;
+    if( fvec==NULL )
+        throw ap_error("ALGLIB: error in 'minlmoptimize()' (fvec is NULL)");
+    if( jac==NULL )
+        throw ap_error("ALGLIB: error in 'minlmoptimize()' (jac is NULL)");
+    alglib_impl::ae_state_init(&_alglib_env_state);
+    try
     {
-        state->repterminationtype = 4;
-        result = ae_false;
-        return result;
+        while( alglib_impl::minlmiteration(state.c_ptr(), &_alglib_env_state) )
+        {
+            if( state.needfi )
+            {
+                fvec(state.x, state.fi, ptr);
+                continue;
+            }
+            if( state.needfij )
+            {
+                jac(state.x, state.fi, state.j, ptr);
+                continue;
+            }
+            if( state.xupdated )
+            {
+                if( rep!=NULL )
+                    rep(state.x, state.f, ptr);
+                continue;
+            }
+            throw ap_error("ALGLIB: error in 'minlmoptimize' (some derivatives were not provided?)");
+        }
+        alglib_impl::ae_state_clear(&_alglib_env_state);
     }
-    
-    /*
-     * Choose initial step and direction.
-     * Apply preconditioner, if we have something other than default.
-     */
-    if( ae_fp_eq(state->stpmax,0) )
+    catch(alglib_impl::ae_error_type)
     {
-        state->stp = ae_minreal(1.0/v, 1, _state);
+        throw ap_error(_alglib_env_state.error_msg);
     }
-    else
+    catch(...)
     {
-        state->stp = ae_minreal(1.0/v, state->stpmax, _state);
+        throw;
     }
-    ae_v_moveneg(&state->d.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    if( state->prectype==1 )
+}
+
+
+void minlmoptimize(minlmstate &state,
+    void (*func)(const real_1d_array &x, double &func, void *ptr),
+    void (*grad)(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr),
+    void (*hess)(const real_1d_array &x, double &func, real_1d_array &grad, real_2d_array &hess, void *ptr),
+    void  (*rep)(const real_1d_array &x, double func, void *ptr), 
+    void *ptr)
+{
+    alglib_impl::ae_state _alglib_env_state;
+    if( func==NULL )
+        throw ap_error("ALGLIB: error in 'minlmoptimize()' (func is NULL)");
+    if( grad==NULL )
+        throw ap_error("ALGLIB: error in 'minlmoptimize()' (grad is NULL)");
+    if( hess==NULL )
+        throw ap_error("ALGLIB: error in 'minlmoptimize()' (hess is NULL)");
+    alglib_impl::ae_state_init(&_alglib_env_state);
+    try
     {
-        
-        /*
-         * Cholesky preconditioner is used
-         */
-        fblscholeskysolve(&state->denseh, 1.0, n, ae_true, &state->d, &state->autobuf, _state);
+        while( alglib_impl::minlmiteration(state.c_ptr(), &_alglib_env_state) )
+        {
+            if( state.needf )
+            {
+                func(state.x, state.f, ptr);
+                continue;
+            }
+            if( state.needfg )
+            {
+                grad(state.x, state.f, state.g, ptr);
+                continue;
+            }
+            if( state.needfgh )
+            {
+                hess(state.x, state.f, state.g, state.h, ptr);
+                continue;
+            }
+            if( state.xupdated )
+            {
+                if( rep!=NULL )
+                    rep(state.x, state.f, ptr);
+                continue;
+            }
+            throw ap_error("ALGLIB: error in 'minlmoptimize' (some derivatives were not provided?)");
+        }
+        alglib_impl::ae_state_clear(&_alglib_env_state);
     }
-    
-    /*
-     * Main cycle
-     */
-    state->k = 0;
-lbl_6:
-    if( ae_false )
+    catch(alglib_impl::ae_error_type)
     {
-        goto lbl_7;
+        throw ap_error(_alglib_env_state.error_msg);
     }
-    
-    /*
-     * Main cycle: prepare to 1-D line search
-     */
-    state->p = state->k%m;
-    state->q = ae_minint(state->k, m-1, _state);
-    
-    /*
-     * Store X[k], G[k]
-     */
-    ae_v_moveneg(&state->s.ptr.pp_double[state->p][0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    ae_v_moveneg(&state->y.ptr.pp_double[state->p][0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    
-    /*
-     * Minimize F(x+alpha*d)
-     * Calculate S[k], Y[k]
-     */
-    state->mcstage = 0;
-    if( state->k!=0 )
+    catch(...)
     {
-        state->stp = 1.0;
+        throw;
     }
-    linminnormalized(&state->d, &state->stp, n, _state);
-    mcsrch(n, &state->x, &state->f, &state->g, &state->d, &state->stp, state->stpmax, &mcinfo, &state->nfev, &state->work, &state->lstate, &state->mcstage, _state);
-lbl_8:
-    if( state->mcstage==0 )
-    {
-        goto lbl_9;
-    }
-    minlbfgs_clearrequestfields(state, _state);
-    state->needfg = ae_true;
-    state->rstate.stage = 2;
-    goto lbl_rcomm;
-lbl_2:
-    state->needfg = ae_false;
-    mcsrch(n, &state->x, &state->f, &state->g, &state->d, &state->stp, state->stpmax, &mcinfo, &state->nfev, &state->work, &state->lstate, &state->mcstage, _state);
-    goto lbl_8;
-lbl_9:
-    if( !state->xrep )
-    {
-        goto lbl_10;
-    }
-    
-    /*
-     * report
-     */
-    minlbfgs_clearrequestfields(state, _state);
-    state->xupdated = ae_true;
-    state->rstate.stage = 3;
-    goto lbl_rcomm;
-lbl_3:
-    state->xupdated = ae_false;
-lbl_10:
-    state->repnfev = state->repnfev+state->nfev;
-    state->repiterationscount = state->repiterationscount+1;
-    ae_v_add(&state->s.ptr.pp_double[state->p][0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    ae_v_add(&state->y.ptr.pp_double[state->p][0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    
-    /*
-     * Stopping conditions
-     */
-    if( state->repiterationscount>=maxits&&maxits>0 )
+}
+
+
+void minlmoptimize(minlmstate &state,
+    void (*func)(const real_1d_array &x, double &func, void *ptr),
+    void  (*jac)(const real_1d_array &x, real_1d_array &fi, real_2d_array &jac, void *ptr),
+    void  (*rep)(const real_1d_array &x, double func, void *ptr), 
+    void *ptr)
+{
+    alglib_impl::ae_state _alglib_env_state;
+    if( func==NULL )
+        throw ap_error("ALGLIB: error in 'minlmoptimize()' (func is NULL)");
+    if( jac==NULL )
+        throw ap_error("ALGLIB: error in 'minlmoptimize()' (jac is NULL)");
+    alglib_impl::ae_state_init(&_alglib_env_state);
+    try
     {
-        
-        /*
-         * Too many iterations
-         */
-        state->repterminationtype = 5;
-        result = ae_false;
-        return result;
+        while( alglib_impl::minlmiteration(state.c_ptr(), &_alglib_env_state) )
+        {
+            if( state.needf )
+            {
+                func(state.x, state.f, ptr);
+                continue;
+            }
+            if( state.needfij )
+            {
+                jac(state.x, state.fi, state.j, ptr);
+                continue;
+            }
+            if( state.xupdated )
+            {
+                if( rep!=NULL )
+                    rep(state.x, state.f, ptr);
+                continue;
+            }
+            throw ap_error("ALGLIB: error in 'minlmoptimize' (some derivatives were not provided?)");
+        }
+        alglib_impl::ae_state_clear(&_alglib_env_state);
     }
-    v = ae_v_dotproduct(&state->g.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    if( ae_fp_less_eq(ae_sqrt(v, _state),epsg) )
+    catch(alglib_impl::ae_error_type)
     {
-        
-        /*
-         * Gradient is small enough
-         */
-        state->repterminationtype = 4;
-        result = ae_false;
-        return result;
+        throw ap_error(_alglib_env_state.error_msg);
     }
-    if( ae_fp_less_eq(state->fold-state->f,epsf*ae_maxreal(ae_fabs(state->fold, _state), ae_maxreal(ae_fabs(state->f, _state), 1.0, _state), _state)) )
+    catch(...)
     {
-        
-        /*
-         * F(k+1)-F(k) is small enough
-         */
-        state->repterminationtype = 1;
-        result = ae_false;
-        return result;
+        throw;
     }
-    v = ae_v_dotproduct(&state->s.ptr.pp_double[state->p][0], 1, &state->s.ptr.pp_double[state->p][0], 1, ae_v_len(0,n-1));
-    if( ae_fp_less_eq(ae_sqrt(v, _state),epsx) )
+}
+
+
+void minlmoptimize(minlmstate &state,
+    void (*func)(const real_1d_array &x, double &func, void *ptr),
+    void (*grad)(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr),
+    void  (*jac)(const real_1d_array &x, real_1d_array &fi, real_2d_array &jac, void *ptr),
+    void  (*rep)(const real_1d_array &x, double func, void *ptr), 
+    void *ptr)
+{
+    alglib_impl::ae_state _alglib_env_state;
+    if( func==NULL )
+        throw ap_error("ALGLIB: error in 'minlmoptimize()' (func is NULL)");
+    if( grad==NULL )
+        throw ap_error("ALGLIB: error in 'minlmoptimize()' (grad is NULL)");
+    if( jac==NULL )
+        throw ap_error("ALGLIB: error in 'minlmoptimize()' (jac is NULL)");
+    alglib_impl::ae_state_init(&_alglib_env_state);
+    try
     {
-        
-        /*
-         * X(k+1)-X(k) is small enough
-         */
-        state->repterminationtype = 2;
-        result = ae_false;
-        return result;
+        while( alglib_impl::minlmiteration(state.c_ptr(), &_alglib_env_state) )
+        {
+            if( state.needf )
+            {
+                func(state.x, state.f, ptr);
+                continue;
+            }
+            if( state.needfg )
+            {
+                grad(state.x, state.f, state.g, ptr);
+                continue;
+            }
+            if( state.needfij )
+            {
+                jac(state.x, state.fi, state.j, ptr);
+                continue;
+            }
+            if( state.xupdated )
+            {
+                if( rep!=NULL )
+                    rep(state.x, state.f, ptr);
+                continue;
+            }
+            throw ap_error("ALGLIB: error in 'minlmoptimize' (some derivatives were not provided?)");
+        }
+        alglib_impl::ae_state_clear(&_alglib_env_state);
     }
-    
-    /*
-     * 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 )
+    catch(alglib_impl::ae_error_type)
     {
-        
-        /*
-         * 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->fold = state->f;
-        ae_v_moveneg(&state->d.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1));
+        throw ap_error(_alglib_env_state.error_msg);
     }
-    else
+    catch(...)
     {
-        
-        /*
-         * Calculate Rho[k], GammaK
-         */
-        v = ae_v_dotproduct(&state->y.ptr.pp_double[state->p][0], 1, &state->s.ptr.pp_double[state->p][0], 1, ae_v_len(0,n-1));
-        vv = ae_v_dotproduct(&state->y.ptr.pp_double[state->p][0], 1, &state->y.ptr.pp_double[state->p][0], 1, ae_v_len(0,n-1));
-        if( ae_fp_eq(v,0)||ae_fp_eq(vv,0) )
-        {
-            
-            /*
-             * Rounding errors make further iterations impossible.
-             */
-            state->repterminationtype = -2;
-            result = ae_false;
-            return result;
-        }
-        state->rho.ptr.p_double[state->p] = 1/v;
-        state->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)
-         */
-        ae_v_move(&state->work.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1));
-        for(i=state->k; i>=state->k-state->q; i--)
-        {
-            ic = i%m;
-            v = ae_v_dotproduct(&state->s.ptr.pp_double[ic][0], 1, &state->work.ptr.p_double[0], 1, ae_v_len(0,n-1));
-            state->theta.ptr.p_double[ic] = v;
-            vv = v*state->rho.ptr.p_double[ic];
-            ae_v_subd(&state->work.ptr.p_double[0], 1, &state->y.ptr.pp_double[ic][0], 1, ae_v_len(0,n-1), vv);
-        }
-        if( state->prectype==0 )
-        {
-            
-            /*
-             * Simple preconditioner is used
-             */
-            v = state->gammak;
-            ae_v_muld(&state->work.ptr.p_double[0], 1, ae_v_len(0,n-1), v);
-        }
-        if( state->prectype==1 )
-        {
-            
-            /*
-             * Cholesky preconditioner is used
-             */
-            fblscholeskysolve(&state->denseh, 1, n, ae_true, &state->work, &state->autobuf, _state);
-        }
-        for(i=state->k-state->q; i<=state->k; i++)
-        {
-            ic = i%m;
-            v = ae_v_dotproduct(&state->y.ptr.pp_double[ic][0], 1, &state->work.ptr.p_double[0], 1, ae_v_len(0,n-1));
-            vv = state->rho.ptr.p_double[ic]*(-v+state->theta.ptr.p_double[ic]);
-            ae_v_addd(&state->work.ptr.p_double[0], 1, &state->s.ptr.pp_double[ic][0], 1, ae_v_len(0,n-1), vv);
-        }
-        ae_v_moveneg(&state->d.ptr.p_double[0], 1, &state->work.ptr.p_double[0], 1, ae_v_len(0,n-1));
-        
-        /*
-         * Next step
-         */
-        state->fold = state->f;
-        state->k = state->k+1;
+        throw;
     }
-    goto lbl_6;
-lbl_7:
-    result = ae_false;
-    return result;
-    
-    /*
-     * Saving state
-     */
-lbl_rcomm:
-    result = ae_true;
-    state->rstate.ia.ptr.p_int[0] = n;
-    state->rstate.ia.ptr.p_int[1] = m;
-    state->rstate.ia.ptr.p_int[2] = maxits;
-    state->rstate.ia.ptr.p_int[3] = i;
-    state->rstate.ia.ptr.p_int[4] = j;
-    state->rstate.ia.ptr.p_int[5] = ic;
-    state->rstate.ia.ptr.p_int[6] = mcinfo;
-    state->rstate.ra.ptr.p_double[0] = epsf;
-    state->rstate.ra.ptr.p_double[1] = epsg;
-    state->rstate.ra.ptr.p_double[2] = epsx;
-    state->rstate.ra.ptr.p_double[3] = v;
-    state->rstate.ra.ptr.p_double[4] = vv;
-    return result;
 }
 
 
+
 /*************************************************************************
-L-BFGS algorithm results
+Levenberg-Marquardt 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
+    Rep     -   optimization report;
+                see comments for this structure for more info.
 
   -- ALGLIB --
-     Copyright 02.04.2010 by Bochkanov Sergey
+     Copyright 10.03.2009 by Bochkanov Sergey
 *************************************************************************/
-void minlbfgsresults(minlbfgsstate* state,
-     /* Real    */ ae_vector* x,
-     minlbfgsreport* rep,
-     ae_state *_state)
+void minlmresults(const minlmstate &state, real_1d_array &x, minlmreport &rep)
 {
-
-    ae_vector_clear(x);
-    _minlbfgsreport_clear(rep);
-
-    minlbfgsresultsbuf(state, x, rep, _state);
+    alglib_impl::ae_state _alglib_env_state;
+    alglib_impl::ae_state_init(&_alglib_env_state);
+    try
+    {
+        alglib_impl::minlmresults(const_cast<alglib_impl::minlmstate*>(state.c_ptr()), const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::minlmreport*>(rep.c_ptr()), &_alglib_env_state);
+        alglib_impl::ae_state_clear(&_alglib_env_state);
+        return;
+    }
+    catch(alglib_impl::ae_error_type)
+    {
+        throw ap_error(_alglib_env_state.error_msg);
+    }
+    catch(...)
+    {
+        throw;
+    }
 }
 
-
 /*************************************************************************
-L-BFGS algorithm results
+Levenberg-Marquardt algorithm results
 
-Buffered implementation of MinLBFGSResults which uses pre-allocated buffer
+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.
 
   -- ALGLIB --
-     Copyright 20.08.2010 by Bochkanov Sergey
+     Copyright 10.03.2009 by Bochkanov Sergey
 *************************************************************************/
-void minlbfgsresultsbuf(minlbfgsstate* state,
-     /* Real    */ ae_vector* x,
-     minlbfgsreport* rep,
-     ae_state *_state)
+void minlmresultsbuf(const minlmstate &state, real_1d_array &x, minlmreport &rep)
 {
-
-
-    if( x->cnt<state->n )
+    alglib_impl::ae_state _alglib_env_state;
+    alglib_impl::ae_state_init(&_alglib_env_state);
+    try
     {
-        ae_vector_set_length(x, state->n, _state);
+        alglib_impl::minlmresultsbuf(const_cast<alglib_impl::minlmstate*>(state.c_ptr()), const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::minlmreport*>(rep.c_ptr()), &_alglib_env_state);
+        alglib_impl::ae_state_clear(&_alglib_env_state);
+        return;
+    }
+    catch(alglib_impl::ae_error_type)
+    {
+        throw ap_error(_alglib_env_state.error_msg);
+    }
+    catch(...)
+    {
+        throw;
     }
-    ae_v_move(&x->ptr.p_double[0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,state->n-1));
-    rep->iterationscount = state->repiterationscount;
-    rep->nfev = state->repnfev;
-    rep->terminationtype = state->repterminationtype;
 }
 
-
 /*************************************************************************
-This  subroutine restarts LBFGS algorithm from new point. All optimization
+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 to store algorithm state
+    State   -   structure used for reverse communication previously
+                allocated with MinLMCreateXXX call.
     X       -   new starting point.
 
   -- ALGLIB --
      Copyright 30.07.2010 by Bochkanov Sergey
 *************************************************************************/
-void minlbfgsrestartfrom(minlbfgsstate* state,
-     /* Real    */ ae_vector* x,
-     ae_state *_state)
+void minlmrestartfrom(const minlmstate &state, const real_1d_array &x)
 {
+    alglib_impl::ae_state _alglib_env_state;
+    alglib_impl::ae_state_init(&_alglib_env_state);
+    try
+    {
+        alglib_impl::minlmrestartfrom(const_cast<alglib_impl::minlmstate*>(state.c_ptr()), const_cast<alglib_impl::ae_vector*>(x.c_ptr()), &_alglib_env_state);
+        alglib_impl::ae_state_clear(&_alglib_env_state);
+        return;
+    }
+    catch(alglib_impl::ae_error_type)
+    {
+        throw ap_error(_alglib_env_state.error_msg);
+    }
+    catch(...)
+    {
+        throw;
+    }
+}
 
+/*************************************************************************
+This is obsolete function.
 
-    ae_assert(x->cnt>=state->n, "MinLBFGSRestartFrom: Length(X)<N!", _state);
-    ae_assert(isfinitevector(x, state->n, _state), "MinLBFGSRestartFrom: X contains infinite or NaN values!", _state);
-    ae_v_move(&state->x.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,state->n-1));
-    ae_vector_set_length(&state->rstate.ia, 6+1, _state);
-    ae_vector_set_length(&state->rstate.ra, 4+1, _state);
-    state->rstate.stage = -1;
-    minlbfgs_clearrequestfields(state, _state);
-}
+Since ALGLIB 3.3 it is equivalent to MinLMCreateVJ().
 
+  -- ALGLIB --
+     Copyright 30.03.2009 by Bochkanov Sergey
+*************************************************************************/
+void minlmcreatevgj(const ae_int_t n, const ae_int_t m, const real_1d_array &x, minlmstate &state)
+{
+    alglib_impl::ae_state _alglib_env_state;
+    alglib_impl::ae_state_init(&_alglib_env_state);
+    try
+    {
+        alglib_impl::minlmcreatevgj(n, m, const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::minlmstate*>(state.c_ptr()), &_alglib_env_state);
+        alglib_impl::ae_state_clear(&_alglib_env_state);
+        return;
+    }
+    catch(alglib_impl::ae_error_type)
+    {
+        throw ap_error(_alglib_env_state.error_msg);
+    }
+    catch(...)
+    {
+        throw;
+    }
+}
 
 /*************************************************************************
-Clears request fileds (to be sure that we don't forgot to clear something)
+This is obsolete function.
+
+Since ALGLIB 3.3 it is equivalent to MinLMCreateVJ().
+
+  -- ALGLIB --
+     Copyright 30.03.2009 by Bochkanov Sergey
 *************************************************************************/
-static void minlbfgs_clearrequestfields(minlbfgsstate* state,
-     ae_state *_state)
+void minlmcreatevgj(const ae_int_t m, const real_1d_array &x, minlmstate &state)
 {
+    alglib_impl::ae_state _alglib_env_state;    
+    ae_int_t n;
 
+    n = x.length();
+    alglib_impl::ae_state_init(&_alglib_env_state);
+    try
+    {
+        alglib_impl::minlmcreatevgj(n, m, const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::minlmstate*>(state.c_ptr()), &_alglib_env_state);
 
-    state->needfg = ae_false;
-    state->xupdated = ae_false;
+        alglib_impl::ae_state_clear(&_alglib_env_state);
+        return;
+    }
+    catch(alglib_impl::ae_error_type)
+    {
+        throw ap_error(_alglib_env_state.error_msg);
+    }
+    catch(...)
+    {
+        throw;
+    }
 }
 
+/*************************************************************************
+This is obsolete function.
+
+Since ALGLIB 3.3 it is equivalent to MinLMCreateFJ().
 
-ae_bool _minlbfgsstate_init(minlbfgsstate* p, ae_state *_state, ae_bool make_automatic)
+  -- ALGLIB --
+     Copyright 30.03.2009 by Bochkanov Sergey
+*************************************************************************/
+void minlmcreatefgj(const ae_int_t n, const ae_int_t m, const real_1d_array &x, minlmstate &state)
 {
-    if( !ae_vector_init(&p->rho, 0, DT_REAL, _state, make_automatic) )
-        return ae_false;
-    if( !ae_matrix_init(&p->y, 0, 0, DT_REAL, _state, make_automatic) )
-        return ae_false;
-    if( !ae_matrix_init(&p->s, 0, 0, DT_REAL, _state, make_automatic) )
-        return ae_false;
-    if( !ae_vector_init(&p->theta, 0, DT_REAL, _state, make_automatic) )
-        return ae_false;
-    if( !ae_vector_init(&p->d, 0, DT_REAL, _state, make_automatic) )
-        return ae_false;
-    if( !ae_vector_init(&p->work, 0, DT_REAL, _state, make_automatic) )
-        return ae_false;
-    if( !ae_matrix_init(&p->denseh, 0, 0, DT_REAL, _state, make_automatic) )
-        return ae_false;
-    if( !ae_vector_init(&p->autobuf, 0, DT_REAL, _state, make_automatic) )
-        return ae_false;
-    if( !ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic) )
-        return ae_false;
-    if( !ae_vector_init(&p->g, 0, DT_REAL, _state, make_automatic) )
-        return ae_false;
-    if( !_rcommstate_init(&p->rstate, _state, make_automatic) )
-        return ae_false;
-    if( !_linminstate_init(&p->lstate, _state, make_automatic) )
-        return ae_false;
-    return ae_true;
+    alglib_impl::ae_state _alglib_env_state;
+    alglib_impl::ae_state_init(&_alglib_env_state);
+    try
+    {
+        alglib_impl::minlmcreatefgj(n, m, const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::minlmstate*>(state.c_ptr()), &_alglib_env_state);
+        alglib_impl::ae_state_clear(&_alglib_env_state);
+        return;
+    }
+    catch(alglib_impl::ae_error_type)
+    {
+        throw ap_error(_alglib_env_state.error_msg);
+    }
+    catch(...)
+    {
+        throw;
+    }
 }
 
+/*************************************************************************
+This is obsolete function.
+
+Since ALGLIB 3.3 it is equivalent to MinLMCreateFJ().
 
-ae_bool _minlbfgsstate_init_copy(minlbfgsstate* dst, minlbfgsstate* src, ae_state *_state, ae_bool make_automatic)
+  -- ALGLIB --
+     Copyright 30.03.2009 by Bochkanov Sergey
+*************************************************************************/
+void minlmcreatefgj(const ae_int_t m, const real_1d_array &x, minlmstate &state)
 {
-    dst->n = src->n;
-    dst->m = src->m;
-    dst->epsg = src->epsg;
-    dst->epsf = src->epsf;
-    dst->epsx = src->epsx;
-    dst->maxits = src->maxits;
-    dst->flags = src->flags;
-    dst->xrep = src->xrep;
-    dst->stpmax = src->stpmax;
-    dst->nfev = src->nfev;
-    dst->mcstage = src->mcstage;
-    dst->k = src->k;
-    dst->q = src->q;
-    dst->p = src->p;
-    if( !ae_vector_init_copy(&dst->rho, &src->rho, _state, make_automatic) )
-        return ae_false;
-    if( !ae_matrix_init_copy(&dst->y, &src->y, _state, make_automatic) )
-        return ae_false;
-    if( !ae_matrix_init_copy(&dst->s, &src->s, _state, make_automatic) )
-        return ae_false;
-    if( !ae_vector_init_copy(&dst->theta, &src->theta, _state, make_automatic) )
-        return ae_false;
-    if( !ae_vector_init_copy(&dst->d, &src->d, _state, make_automatic) )
-        return ae_false;
-    dst->stp = src->stp;
-    if( !ae_vector_init_copy(&dst->work, &src->work, _state, make_automatic) )
-        return ae_false;
-    dst->fold = src->fold;
-    dst->prectype = src->prectype;
-    dst->gammak = src->gammak;
-    if( !ae_matrix_init_copy(&dst->denseh, &src->denseh, _state, make_automatic) )
-        return ae_false;
-    if( !ae_vector_init_copy(&dst->autobuf, &src->autobuf, _state, make_automatic) )
-        return ae_false;
-    if( !ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic) )
-        return ae_false;
-    dst->f = src->f;
-    if( !ae_vector_init_copy(&dst->g, &src->g, _state, make_automatic) )
-        return ae_false;
-    dst->needfg = src->needfg;
-    dst->xupdated = src->xupdated;
-    if( !_rcommstate_init_copy(&dst->rstate, &src->rstate, _state, make_automatic) )
-        return ae_false;
-    dst->repiterationscount = src->repiterationscount;
-    dst->repnfev = src->repnfev;
-    dst->repterminationtype = src->repterminationtype;
-    if( !_linminstate_init_copy(&dst->lstate, &src->lstate, _state, make_automatic) )
-        return ae_false;
-    return ae_true;
+    alglib_impl::ae_state _alglib_env_state;    
+    ae_int_t n;
+
+    n = x.length();
+    alglib_impl::ae_state_init(&_alglib_env_state);
+    try
+    {
+        alglib_impl::minlmcreatefgj(n, m, const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::minlmstate*>(state.c_ptr()), &_alglib_env_state);
+
+        alglib_impl::ae_state_clear(&_alglib_env_state);
+        return;
+    }
+    catch(alglib_impl::ae_error_type)
+    {
+        throw ap_error(_alglib_env_state.error_msg);
+    }
+    catch(...)
+    {
+        throw;
+    }
 }
 
+/*************************************************************************
+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.
 
-void _minlbfgsstate_clear(minlbfgsstate* p)
+  -- ALGLIB --
+     Copyright 30.03.2009 by Bochkanov Sergey
+*************************************************************************/
+void minlmcreatefj(const ae_int_t n, const ae_int_t m, const real_1d_array &x, minlmstate &state)
 {
-    ae_vector_clear(&p->rho);
-    ae_matrix_clear(&p->y);
-    ae_matrix_clear(&p->s);
-    ae_vector_clear(&p->theta);
-    ae_vector_clear(&p->d);
-    ae_vector_clear(&p->work);
-    ae_matrix_clear(&p->denseh);
-    ae_vector_clear(&p->autobuf);
-    ae_vector_clear(&p->x);
-    ae_vector_clear(&p->g);
-    _rcommstate_clear(&p->rstate);
-    _linminstate_clear(&p->lstate);
+    alglib_impl::ae_state _alglib_env_state;
+    alglib_impl::ae_state_init(&_alglib_env_state);
+    try
+    {
+        alglib_impl::minlmcreatefj(n, m, const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::minlmstate*>(state.c_ptr()), &_alglib_env_state);
+        alglib_impl::ae_state_clear(&_alglib_env_state);
+        return;
+    }
+    catch(alglib_impl::ae_error_type)
+    {
+        throw ap_error(_alglib_env_state.error_msg);
+    }
+    catch(...)
+    {
+        throw;
+    }
 }
 
+/*************************************************************************
+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.
 
-ae_bool _minlbfgsreport_init(minlbfgsreport* p, ae_state *_state, ae_bool make_automatic)
+  -- ALGLIB --
+     Copyright 30.03.2009 by Bochkanov Sergey
+*************************************************************************/
+void minlmcreatefj(const ae_int_t m, const real_1d_array &x, minlmstate &state)
 {
-    return ae_true;
+    alglib_impl::ae_state _alglib_env_state;    
+    ae_int_t n;
+
+    n = x.length();
+    alglib_impl::ae_state_init(&_alglib_env_state);
+    try
+    {
+        alglib_impl::minlmcreatefj(n, m, const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::minlmstate*>(state.c_ptr()), &_alglib_env_state);
+
+        alglib_impl::ae_state_clear(&_alglib_env_state);
+        return;
+    }
+    catch(alglib_impl::ae_error_type)
+    {
+        throw ap_error(_alglib_env_state.error_msg);
+    }
+    catch(...)
+    {
+        throw;
+    }
 }
 
+/*************************************************************************
 
-ae_bool _minlbfgsreport_init_copy(minlbfgsreport* dst, minlbfgsreport* src, ae_state *_state, ae_bool make_automatic)
+*************************************************************************/
+_minasastate_owner::_minasastate_owner()
 {
-    dst->iterationscount = src->iterationscount;
-    dst->nfev = src->nfev;
-    dst->terminationtype = src->terminationtype;
-    return ae_true;
+    p_struct = (alglib_impl::minasastate*)alglib_impl::ae_malloc(sizeof(alglib_impl::minasastate), NULL);
+    if( p_struct==NULL )
+        throw ap_error("ALGLIB: malloc error");
+    if( !alglib_impl::_minasastate_init(p_struct, NULL, ae_false) )
+        throw ap_error("ALGLIB: malloc error");
 }
 
+_minasastate_owner::_minasastate_owner(const _minasastate_owner &rhs)
+{
+    p_struct = (alglib_impl::minasastate*)alglib_impl::ae_malloc(sizeof(alglib_impl::minasastate), NULL);
+    if( p_struct==NULL )
+        throw ap_error("ALGLIB: malloc error");
+    if( !alglib_impl::_minasastate_init_copy(p_struct, const_cast<alglib_impl::minasastate*>(rhs.p_struct), NULL, ae_false) )
+        throw ap_error("ALGLIB: malloc error");
+}
 
-void _minlbfgsreport_clear(minlbfgsreport* p)
+_minasastate_owner& _minasastate_owner::operator=(const _minasastate_owner &rhs)
 {
+    if( this==&rhs )
+        return *this;
+    alglib_impl::_minasastate_clear(p_struct);
+    if( !alglib_impl::_minasastate_init_copy(p_struct, const_cast<alglib_impl::minasastate*>(rhs.p_struct), NULL, ae_false) )
+        throw ap_error("ALGLIB: malloc error");
+    return *this;
 }
 
+_minasastate_owner::~_minasastate_owner()
+{
+    alglib_impl::_minasastate_clear(p_struct);
+    ae_free(p_struct);
+}
 
+alglib_impl::minasastate* _minasastate_owner::c_ptr()
+{
+    return p_struct;
+}
 
+alglib_impl::minasastate* _minasastate_owner::c_ptr() const
+{
+    return const_cast<alglib_impl::minasastate*>(p_struct);
+}
+minasastate::minasastate() : _minasastate_owner() ,needfg(p_struct->needfg),xupdated(p_struct->xupdated),f(p_struct->f),g(&p_struct->g),x(&p_struct->x)
+{
+}
 
-/*************************************************************************
-                IMPROVED LEVENBERG-MARQUARDT METHOD FOR
-                 NON-LINEAR LEAST SQUARES OPTIMIZATION
+minasastate::minasastate(const minasastate &rhs):_minasastate_owner(rhs) ,needfg(p_struct->needfg),xupdated(p_struct->xupdated),f(p_struct->f),g(&p_struct->g),x(&p_struct->x)
+{
+}
 
-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[].
+minasastate& minasastate::operator=(const minasastate &rhs)
+{
+    if( this==&rhs )
+        return *this;
+    _minasastate_owner::operator=(rhs);
+    return *this;
+}
 
+minasastate::~minasastate()
+{
+}
 
-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].
+*************************************************************************/
+_minasareport_owner::_minasareport_owner()
+{
+    p_struct = (alglib_impl::minasareport*)alglib_impl::ae_malloc(sizeof(alglib_impl::minasareport), NULL);
+    if( p_struct==NULL )
+        throw ap_error("ALGLIB: malloc error");
+    if( !alglib_impl::_minasareport_init(p_struct, NULL, ae_false) )
+        throw ap_error("ALGLIB: malloc error");
+}
 
-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.
+_minasareport_owner::_minasareport_owner(const _minasareport_owner &rhs)
+{
+    p_struct = (alglib_impl::minasareport*)alglib_impl::ae_malloc(sizeof(alglib_impl::minasareport), NULL);
+    if( p_struct==NULL )
+        throw ap_error("ALGLIB: malloc error");
+    if( !alglib_impl::_minasareport_init_copy(p_struct, const_cast<alglib_impl::minasareport*>(rhs.p_struct), NULL, ae_false) )
+        throw ap_error("ALGLIB: malloc error");
+}
 
+_minasareport_owner& _minasareport_owner::operator=(const _minasareport_owner &rhs)
+{
+    if( this==&rhs )
+        return *this;
+    alglib_impl::_minasareport_clear(p_struct);
+    if( !alglib_impl::_minasareport_init_copy(p_struct, const_cast<alglib_impl::minasareport*>(rhs.p_struct), NULL, ae_false) )
+        throw ap_error("ALGLIB: malloc error");
+    return *this;
+}
 
-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.
+_minasareport_owner::~_minasareport_owner()
+{
+    alglib_impl::_minasareport_clear(p_struct);
+    ae_free(p_struct);
+}
 
+alglib_impl::minasareport* _minasareport_owner::c_ptr()
+{
+    return p_struct;
+}
 
-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]
+alglib_impl::minasareport* _minasareport_owner::c_ptr() const
+{
+    return const_cast<alglib_impl::minasareport*>(p_struct);
+}
+minasareport::minasareport() : _minasareport_owner() ,iterationscount(p_struct->iterationscount),nfev(p_struct->nfev),terminationtype(p_struct->terminationtype),activeconstraints(p_struct->activeconstraints)
+{
+}
 
-OUTPUT PARAMETERS:
-    State   -   structure which stores algorithm state
+minasareport::minasareport(const minasareport &rhs):_minasareport_owner(rhs) ,iterationscount(p_struct->iterationscount),nfev(p_struct->nfev),terminationtype(p_struct->terminationtype),activeconstraints(p_struct->activeconstraints)
+{
+}
 
-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.
+minasareport& minasareport::operator=(const minasareport &rhs)
+{
+    if( this==&rhs )
+        return *this;
+    _minasareport_owner::operator=(rhs);
+    return *this;
+}
 
-  -- ALGLIB --
-     Copyright 30.03.2009 by Bochkanov Sergey
-*************************************************************************/
-void minlmcreatevj(ae_int_t n,
-     ae_int_t m,
-     /* Real    */ ae_vector* x,
-     minlmstate* state,
-     ae_state *_state)
+minasareport::~minasareport()
 {
+}
 
-    _minlmstate_clear(state);
+/*************************************************************************
+Obsolete function, use MinLBFGSSetPrecDefault() instead.
 
-    ae_assert(n>=1, "MinLMCreateVJ: N<1!", _state);
-    ae_assert(m>=1, "MinLMCreateVJ: M<1!", _state);
-    ae_assert(x->cnt>=n, "MinLMCreateVJ: Length(X)<N!", _state);
-    ae_assert(isfinitevector(x, n, _state), "MinLMCreateVJ: X contains infinite or NaN values!", _state);
-    
-    /*
-     * initialize, check parameters
-     */
-    state->n = n;
-    state->m = m;
-    state->algomode = 1;
-    state->hasf = ae_false;
-    state->hasfi = ae_true;
-    state->hasg = ae_false;
-    
-    /*
-     * second stage of initialization
-     */
-    minlm_lmprepare(n, m, ae_false, state, _state);
-    minlmsetacctype(state, 0, _state);
-    minlmsetcond(state, 0, 0, 0, 0, _state);
-    minlmsetxrep(state, ae_false, _state);
-    minlmsetstpmax(state, 0, _state);
-    minlmrestartfrom(state, x, _state);
+  -- ALGLIB --
+     Copyright 13.10.2010 by Bochkanov Sergey
+*************************************************************************/
+void minlbfgssetdefaultpreconditioner(const minlbfgsstate &state)
+{
+    alglib_impl::ae_state _alglib_env_state;
+    alglib_impl::ae_state_init(&_alglib_env_state);
+    try
+    {
+        alglib_impl::minlbfgssetdefaultpreconditioner(const_cast<alglib_impl::minlbfgsstate*>(state.c_ptr()), &_alglib_env_state);
+        alglib_impl::ae_state_clear(&_alglib_env_state);
+        return;
+    }
+    catch(alglib_impl::ae_error_type)
+    {
+        throw ap_error(_alglib_env_state.error_msg);
+    }
+    catch(...)
+    {
+        throw;
+    }
 }
 
-
 /*************************************************************************
-                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.
+Obsolete function, use MinLBFGSSetCholeskyPreconditioner() instead.
 
-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.
+  -- ALGLIB --
+     Copyright 13.10.2010 by Bochkanov Sergey
+*************************************************************************/
+void minlbfgssetcholeskypreconditioner(const minlbfgsstate &state, const real_2d_array &p, const bool isupper)
+{
+    alglib_impl::ae_state _alglib_env_state;
+    alglib_impl::ae_state_init(&_alglib_env_state);
+    try
+    {
+        alglib_impl::minlbfgssetcholeskypreconditioner(const_cast<alglib_impl::minlbfgsstate*>(state.c_ptr()), const_cast<alglib_impl::ae_matrix*>(p.c_ptr()), isupper, &_alglib_env_state);
+        alglib_impl::ae_state_clear(&_alglib_env_state);
+        return;
+    }
+    catch(alglib_impl::ae_error_type)
+    {
+        throw ap_error(_alglib_env_state.error_msg);
+    }
+    catch(...)
+    {
+        throw;
+    }
+}
 
+/*************************************************************************
+This is obsolete function which was used by previous version of the  BLEIC
+optimizer. It does nothing in the current version of BLEIC.
 
-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.
+  -- ALGLIB --
+     Copyright 28.11.2010 by Bochkanov Sergey
+*************************************************************************/
+void minbleicsetbarrierwidth(const minbleicstate &state, const double mu)
+{
+    alglib_impl::ae_state _alglib_env_state;
+    alglib_impl::ae_state_init(&_alglib_env_state);
+    try
+    {
+        alglib_impl::minbleicsetbarrierwidth(const_cast<alglib_impl::minbleicstate*>(state.c_ptr()), mu, &_alglib_env_state);
+        alglib_impl::ae_state_clear(&_alglib_env_state);
+        return;
+    }
+    catch(alglib_impl::ae_error_type)
+    {
+        throw ap_error(_alglib_env_state.error_msg);
+    }
+    catch(...)
+    {
+        throw;
+    }
+}
 
+/*************************************************************************
+This is obsolete function which was used by previous version of the  BLEIC
+optimizer. It does nothing in the current version of BLEIC.
 
-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
+  -- ALGLIB --
+     Copyright 28.11.2010 by Bochkanov Sergey
+*************************************************************************/
+void minbleicsetbarrierdecay(const minbleicstate &state, const double mudecay)
+{
+    alglib_impl::ae_state _alglib_env_state;
+    alglib_impl::ae_state_init(&_alglib_env_state);
+    try
+    {
+        alglib_impl::minbleicsetbarrierdecay(const_cast<alglib_impl::minbleicstate*>(state.c_ptr()), mudecay, &_alglib_env_state);
+        alglib_impl::ae_state_clear(&_alglib_env_state);
+        return;
+    }
+    catch(alglib_impl::ae_error_type)
+    {
+        throw ap_error(_alglib_env_state.error_msg);
+    }
+    catch(...)
+    {
+        throw;
+    }
+}
 
-OUTPUT PARAMETERS:
-    State   -   structure which stores algorithm state
+/*************************************************************************
+Obsolete optimization algorithm.
+Was replaced by MinBLEIC subpackage.
 
-See also MinLMIteration, MinLMResults.
+  -- ALGLIB --
+     Copyright 25.03.2010 by Bochkanov Sergey
+*************************************************************************/
+void minasacreate(const ae_int_t n, const real_1d_array &x, const real_1d_array &bndl, const real_1d_array &bndu, minasastate &state)
+{
+    alglib_impl::ae_state _alglib_env_state;
+    alglib_impl::ae_state_init(&_alglib_env_state);
+    try
+    {
+        alglib_impl::minasacreate(n, const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(bndl.c_ptr()), const_cast<alglib_impl::ae_vector*>(bndu.c_ptr()), const_cast<alglib_impl::minasastate*>(state.c_ptr()), &_alglib_env_state);
+        alglib_impl::ae_state_clear(&_alglib_env_state);
+        return;
+    }
+    catch(alglib_impl::ae_error_type)
+    {
+        throw ap_error(_alglib_env_state.error_msg);
+    }
+    catch(...)
+    {
+        throw;
+    }
+}
 
-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.
+/*************************************************************************
+Obsolete optimization algorithm.
+Was replaced by MinBLEIC subpackage.
 
   -- ALGLIB --
-     Copyright 30.03.2009 by Bochkanov Sergey
+     Copyright 25.03.2010 by Bochkanov Sergey
 *************************************************************************/
-void minlmcreatev(ae_int_t n,
-     ae_int_t m,
-     /* Real    */ ae_vector* x,
-     double diffstep,
-     minlmstate* state,
-     ae_state *_state)
+void minasacreate(const real_1d_array &x, const real_1d_array &bndl, const real_1d_array &bndu, minasastate &state)
 {
+    alglib_impl::ae_state _alglib_env_state;    
+    ae_int_t n;
+    if( (x.length()!=bndl.length()) || (x.length()!=bndu.length()))
+        throw ap_error("Error while calling 'minasacreate': looks like one of arguments has wrong size");
+    n = x.length();
+    alglib_impl::ae_state_init(&_alglib_env_state);
+    try
+    {
+        alglib_impl::minasacreate(n, const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(bndl.c_ptr()), const_cast<alglib_impl::ae_vector*>(bndu.c_ptr()), const_cast<alglib_impl::minasastate*>(state.c_ptr()), &_alglib_env_state);
 
-    _minlmstate_clear(state);
-
-    ae_assert(ae_isfinite(diffstep, _state), "MinLMCreateV: DiffStep is not finite!", _state);
-    ae_assert(ae_fp_greater(diffstep,0), "MinLMCreateV: DiffStep<=0!", _state);
-    ae_assert(n>=1, "MinLMCreateV: N<1!", _state);
-    ae_assert(m>=1, "MinLMCreateV: M<1!", _state);
-    ae_assert(x->cnt>=n, "MinLMCreateV: Length(X)<N!", _state);
-    ae_assert(isfinitevector(x, n, _state), "MinLMCreateV: X contains infinite or NaN values!", _state);
-    
-    /*
-     * initialize
-     */
-    state->n = n;
-    state->m = m;
-    state->algomode = 0;
-    state->hasf = ae_false;
-    state->hasfi = ae_true;
-    state->hasg = ae_false;
-    state->diffstep = diffstep;
-    
-    /*
-     * second stage of initialization
-     */
-    minlm_lmprepare(n, m, ae_false, state, _state);
-    minlmsetacctype(state, 1, _state);
-    minlmsetcond(state, 0, 0, 0, 0, _state);
-    minlmsetxrep(state, ae_false, _state);
-    minlmsetstpmax(state, 0, _state);
-    minlmrestartfrom(state, x, _state);
+        alglib_impl::ae_state_clear(&_alglib_env_state);
+        return;
+    }
+    catch(alglib_impl::ae_error_type)
+    {
+        throw ap_error(_alglib_env_state.error_msg);
+    }
+    catch(...)
+    {
+        throw;
+    }
 }
 
-
 /*************************************************************************
-    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.
+Obsolete optimization algorithm.
+Was replaced by MinBLEIC subpackage.
 
   -- ALGLIB --
-     Copyright 30.03.2009 by Bochkanov Sergey
+     Copyright 02.04.2010 by Bochkanov Sergey
 *************************************************************************/
-void minlmcreatefgh(ae_int_t n,
-     /* Real    */ ae_vector* x,
-     minlmstate* state,
-     ae_state *_state)
+void minasasetcond(const minasastate &state, const double epsg, const double epsf, const double epsx, const ae_int_t maxits)
 {
-
-    _minlmstate_clear(state);
-
-    ae_assert(n>=1, "MinLMCreateFGH: N<1!", _state);
-    ae_assert(x->cnt>=n, "MinLMCreateFGH: Length(X)<N!", _state);
-    ae_assert(isfinitevector(x, n, _state), "MinLMCreateFGH: X contains infinite or NaN values!", _state);
-    
-    /*
-     * initialize
-     */
-    state->n = n;
-    state->m = 0;
-    state->algomode = 2;
-    state->hasf = ae_true;
-    state->hasfi = ae_false;
-    state->hasg = ae_true;
-    
-    /*
-     * init2
-     */
-    minlm_lmprepare(n, 0, ae_true, state, _state);
-    minlmsetacctype(state, 2, _state);
-    minlmsetcond(state, 0, 0, 0, 0, _state);
-    minlmsetxrep(state, ae_false, _state);
-    minlmsetstpmax(state, 0, _state);
-    minlmrestartfrom(state, x, _state);
+    alglib_impl::ae_state _alglib_env_state;
+    alglib_impl::ae_state_init(&_alglib_env_state);
+    try
+    {
+        alglib_impl::minasasetcond(const_cast<alglib_impl::minasastate*>(state.c_ptr()), epsg, epsf, epsx, maxits, &_alglib_env_state);
+        alglib_impl::ae_state_clear(&_alglib_env_state);
+        return;
+    }
+    catch(alglib_impl::ae_error_type)
+    {
+        throw ap_error(_alglib_env_state.error_msg);
+    }
+    catch(...)
+    {
+        throw;
+    }
 }
 
-
 /*************************************************************************
-                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[]
-* value of Jacobian of f[]
-* gradient of merit function F(x)
-
-This function creates optimizer which uses acceleration strategy 2.  Cheap
-gradient of merit function (which is twice the product of function  vector
-and Jacobian) is used for accelerated iterations (see User Guide for  more
-info on this subject).
-
-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
-* gradient of
-
-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(),  jac()  and  grad()
-callbacks. First one is used to calculate f[] at given point,  second  one
-calculates f[] and Jacobian df[i]/dx[j], last one calculates  gradient  of
-merit function F(x).
-
-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 MinLMCreateVGJ() 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.
+Obsolete optimization algorithm.
+Was replaced by MinBLEIC subpackage.
 
   -- ALGLIB --
-     Copyright 30.03.2009 by Bochkanov Sergey
+     Copyright 02.04.2010 by Bochkanov Sergey
 *************************************************************************/
-void minlmcreatevgj(ae_int_t n,
-     ae_int_t m,
-     /* Real    */ ae_vector* x,
-     minlmstate* state,
-     ae_state *_state)
+void minasasetxrep(const minasastate &state, const bool needxrep)
 {
-
-    _minlmstate_clear(state);
-
-    ae_assert(n>=1, "MinLMCreateVGJ: N<1!", _state);
-    ae_assert(m>=1, "MinLMCreateVGJ: M<1!", _state);
-    ae_assert(x->cnt>=n, "MinLMCreateVGJ: Length(X)<N!", _state);
-    ae_assert(isfinitevector(x, n, _state), "MinLMCreateVGJ: X contains infinite or NaN values!", _state);
-    
-    /*
-     * initialize, check parameters
-     */
-    state->n = n;
-    state->m = m;
-    state->algomode = 1;
-    state->hasf = ae_false;
-    state->hasfi = ae_true;
-    state->hasg = ae_false;
-    
-    /*
-     * second stage of initialization
-     */
-    minlm_lmprepare(n, m, ae_false, state, _state);
-    minlmsetacctype(state, 2, _state);
-    minlmsetcond(state, 0, 0, 0, 0, _state);
-    minlmsetxrep(state, ae_false, _state);
-    minlmsetstpmax(state, 0, _state);
-    minlmrestartfrom(state, x, _state);
+    alglib_impl::ae_state _alglib_env_state;
+    alglib_impl::ae_state_init(&_alglib_env_state);
+    try
+    {
+        alglib_impl::minasasetxrep(const_cast<alglib_impl::minasastate*>(state.c_ptr()), needxrep, &_alglib_env_state);
+        alglib_impl::ae_state_clear(&_alglib_env_state);
+        return;
+    }
+    catch(alglib_impl::ae_error_type)
+    {
+        throw ap_error(_alglib_env_state.error_msg);
+    }
+    catch(...)
+    {
+        throw;
+    }
 }
 
-
 /*************************************************************************
-                   LEVENBERG-MARQUARDT-LIKE 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 F(), gradient of F(), function vector f[]  and  Jacobian of
-f[].
-
-This function is considered obsolete since ALGLIB 3.1.0 and is present for
-backward  compatibility  only.  We  recommend to use MinLMCreateVGJ, which
-provides similar, but more consistent interface.
+Obsolete optimization algorithm.
+Was replaced by MinBLEIC subpackage.
 
   -- ALGLIB --
-     Copyright 30.03.2009 by Bochkanov Sergey
+     Copyright 02.04.2010 by Bochkanov Sergey
 *************************************************************************/
-void minlmcreatefgj(ae_int_t n,
-     ae_int_t m,
-     /* Real    */ ae_vector* x,
-     minlmstate* state,
-     ae_state *_state)
+void minasasetalgorithm(const minasastate &state, const ae_int_t algotype)
 {
-
-    _minlmstate_clear(state);
-
-    ae_assert(n>=1, "MinLMCreateFGJ: N<1!", _state);
-    ae_assert(m>=1, "MinLMCreateFGJ: M<1!", _state);
-    ae_assert(x->cnt>=n, "MinLMCreateFGJ: Length(X)<N!", _state);
-    ae_assert(isfinitevector(x, n, _state), "MinLMCreateFGJ: X contains infinite or NaN values!", _state);
-    
-    /*
-     * initialize
-     */
-    state->n = n;
-    state->m = m;
-    state->algomode = 1;
-    state->hasf = ae_true;
-    state->hasfi = ae_false;
-    state->hasg = ae_true;
-    
-    /*
-     * init2
-     */
-    minlm_lmprepare(n, m, ae_true, state, _state);
-    minlmsetacctype(state, 2, _state);
-    minlmsetcond(state, 0, 0, 0, 0, _state);
-    minlmsetxrep(state, ae_false, _state);
-    minlmsetstpmax(state, 0, _state);
-    minlmrestartfrom(state, x, _state);
+    alglib_impl::ae_state _alglib_env_state;
+    alglib_impl::ae_state_init(&_alglib_env_state);
+    try
+    {
+        alglib_impl::minasasetalgorithm(const_cast<alglib_impl::minasastate*>(state.c_ptr()), algotype, &_alglib_env_state);
+        alglib_impl::ae_state_clear(&_alglib_env_state);
+        return;
+    }
+    catch(alglib_impl::ae_error_type)
+    {
+        throw ap_error(_alglib_env_state.error_msg);
+    }
+    catch(...)
+    {
+        throw;
+    }
 }
 
-
 /*************************************************************************
-    CLASSIC LEVENBERG-MARQUARDT METHOD FOR NON-LINEAR 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  F(),  function  vector  f[] and Jacobian of f[]. Classic
-Levenberg-Marquardt method is used.
-
-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.
+Obsolete optimization algorithm.
+Was replaced by MinBLEIC subpackage.
 
   -- ALGLIB --
-     Copyright 30.03.2009 by Bochkanov Sergey
+     Copyright 02.04.2010 by Bochkanov Sergey
 *************************************************************************/
-void minlmcreatefj(ae_int_t n,
-     ae_int_t m,
-     /* Real    */ ae_vector* x,
-     minlmstate* state,
-     ae_state *_state)
+void minasasetstpmax(const minasastate &state, const double stpmax)
 {
-
-    _minlmstate_clear(state);
-
-    ae_assert(n>=1, "MinLMCreateFJ: N<1!", _state);
-    ae_assert(m>=1, "MinLMCreateFJ: M<1!", _state);
-    ae_assert(x->cnt>=n, "MinLMCreateFJ: Length(X)<N!", _state);
-    ae_assert(isfinitevector(x, n, _state), "MinLMCreateFJ: X contains infinite or NaN values!", _state);
-    
-    /*
-     * initialize
-     */
-    state->n = n;
-    state->m = m;
-    state->algomode = 1;
-    state->hasf = ae_true;
-    state->hasfi = ae_false;
-    state->hasg = ae_false;
-    
-    /*
-     * init 2
-     */
-    minlm_lmprepare(n, m, ae_true, state, _state);
-    minlmsetacctype(state, 0, _state);
-    minlmsetcond(state, 0, 0, 0, 0, _state);
-    minlmsetxrep(state, ae_false, _state);
-    minlmsetstpmax(state, 0, _state);
-    minlmrestartfrom(state, x, _state);
+    alglib_impl::ae_state _alglib_env_state;
+    alglib_impl::ae_state_init(&_alglib_env_state);
+    try
+    {
+        alglib_impl::minasasetstpmax(const_cast<alglib_impl::minasastate*>(state.c_ptr()), stpmax, &_alglib_env_state);
+        alglib_impl::ae_state_clear(&_alglib_env_state);
+        return;
+    }
+    catch(alglib_impl::ae_error_type)
+    {
+        throw ap_error(_alglib_env_state.error_msg);
+    }
+    catch(...)
+    {
+        throw;
+    }
 }
 
-
 /*************************************************************************
-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
-                ||G||<EpsG is satisfied, where ||.|| means Euclidian norm,
-                G - gradient.
-    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 |X(k+1)-X(k)| <= EpsX is fulfilled.
-    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).
-
-  -- ALGLIB --
-     Copyright 02.04.2010 by Bochkanov Sergey
+This function provides reverse communication interface
+Reverse communication interface is not documented or recommended to use.
+See below for functions which provide better documented API
 *************************************************************************/
-void minlmsetcond(minlmstate* state,
-     double epsg,
-     double epsf,
-     double epsx,
-     ae_int_t maxits,
-     ae_state *_state)
+bool minasaiteration(const minasastate &state)
 {
+    alglib_impl::ae_state _alglib_env_state;
+    alglib_impl::ae_state_init(&_alglib_env_state);
+    try
+    {
+        ae_bool result = alglib_impl::minasaiteration(const_cast<alglib_impl::minasastate*>(state.c_ptr()), &_alglib_env_state);
+        alglib_impl::ae_state_clear(&_alglib_env_state);
+        return *(reinterpret_cast<bool*>(&result));
+    }
+    catch(alglib_impl::ae_error_type)
+    {
+        throw ap_error(_alglib_env_state.error_msg);
+    }
+    catch(...)
+    {
+        throw;
+    }
+}
 
 
-    ae_assert(ae_isfinite(epsg, _state), "MinLMSetCond: EpsG is not finite number!", _state);
-    ae_assert(ae_fp_greater_eq(epsg,0), "MinLMSetCond: negative EpsG!", _state);
-    ae_assert(ae_isfinite(epsf, _state), "MinLMSetCond: EpsF is not finite number!", _state);
-    ae_assert(ae_fp_greater_eq(epsf,0), "MinLMSetCond: negative EpsF!", _state);
-    ae_assert(ae_isfinite(epsx, _state), "MinLMSetCond: EpsX is not finite number!", _state);
-    ae_assert(ae_fp_greater_eq(epsx,0), "MinLMSetCond: negative EpsX!", _state);
-    ae_assert(maxits>=0, "MinLMSetCond: negative MaxIts!", _state);
-    if( ((ae_fp_eq(epsg,0)&&ae_fp_eq(epsf,0))&&ae_fp_eq(epsx,0))&&maxits==0 )
+void minasaoptimize(minasastate &state,
+    void (*grad)(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr),
+    void  (*rep)(const real_1d_array &x, double func, void *ptr), 
+    void *ptr)
+{
+    alglib_impl::ae_state _alglib_env_state;
+    if( grad==NULL )
+        throw ap_error("ALGLIB: error in 'minasaoptimize()' (grad is NULL)");
+    alglib_impl::ae_state_init(&_alglib_env_state);
+    try
     {
-        epsx = 1.0E-6;
+        while( alglib_impl::minasaiteration(state.c_ptr(), &_alglib_env_state) )
+        {
+            if( state.needfg )
+            {
+                grad(state.x, state.f, state.g, ptr);
+                continue;
+            }
+            if( state.xupdated )
+            {
+                if( rep!=NULL )
+                    rep(state.x, state.f, ptr);
+                continue;
+            }
+            throw ap_error("ALGLIB: error in 'minasaoptimize' (some derivatives were not provided?)");
+        }
+        alglib_impl::ae_state_clear(&_alglib_env_state);
+    }
+    catch(alglib_impl::ae_error_type)
+    {
+        throw ap_error(_alglib_env_state.error_msg);
+    }
+    catch(...)
+    {
+        throw;
     }
-    state->epsg = epsg;
-    state->epsf = epsf;
-    state->epsx = epsx;
-    state->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.
+/*************************************************************************
+Obsolete optimization algorithm.
+Was replaced by MinBLEIC subpackage.
 
   -- ALGLIB --
-     Copyright 02.04.2010 by Bochkanov Sergey
+     Copyright 20.03.2009 by Bochkanov Sergey
 *************************************************************************/
-void minlmsetxrep(minlmstate* state, ae_bool needxrep, ae_state *_state)
+void minasaresults(const minasastate &state, real_1d_array &x, minasareport &rep)
 {
-
-
-    state->xrep = needxrep;
+    alglib_impl::ae_state _alglib_env_state;
+    alglib_impl::ae_state_init(&_alglib_env_state);
+    try
+    {
+        alglib_impl::minasaresults(const_cast<alglib_impl::minasastate*>(state.c_ptr()), const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::minasareport*>(rep.c_ptr()), &_alglib_env_state);
+        alglib_impl::ae_state_clear(&_alglib_env_state);
+        return;
+    }
+    catch(alglib_impl::ae_error_type)
+    {
+        throw ap_error(_alglib_env_state.error_msg);
+    }
+    catch(...)
+    {
+        throw;
+    }
 }
 
-
 /*************************************************************************
-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.
+Obsolete optimization algorithm.
+Was replaced by MinBLEIC subpackage.
 
   -- ALGLIB --
-     Copyright 02.04.2010 by Bochkanov Sergey
+     Copyright 20.03.2009 by Bochkanov Sergey
 *************************************************************************/
-void minlmsetstpmax(minlmstate* state, double stpmax, ae_state *_state)
+void minasaresultsbuf(const minasastate &state, real_1d_array &x, minasareport &rep)
 {
-
-
-    ae_assert(ae_isfinite(stpmax, _state), "MinLMSetStpMax: StpMax is not finite!", _state);
-    ae_assert(ae_fp_greater_eq(stpmax,0), "MinLMSetStpMax: StpMax<0!", _state);
-    state->stpmax = stpmax;
+    alglib_impl::ae_state _alglib_env_state;
+    alglib_impl::ae_state_init(&_alglib_env_state);
+    try
+    {
+        alglib_impl::minasaresultsbuf(const_cast<alglib_impl::minasastate*>(state.c_ptr()), const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::minasareport*>(rep.c_ptr()), &_alglib_env_state);
+        alglib_impl::ae_state_clear(&_alglib_env_state);
+        return;
+    }
+    catch(alglib_impl::ae_error_type)
+    {
+        throw ap_error(_alglib_env_state.error_msg);
+    }
+    catch(...)
+    {
+        throw;
+    }
 }
 
-
 /*************************************************************************
-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=2, after quadratic model is built and LM step is made, we use it
-  as preconditioner for several (5-10) iterations of L-BFGS algorithm.
-
-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.
-
-AccType=2 is recommended when Jacobian is cheap - much more  cheaper  than
-one  Cholesky  factorization.   We   can   reduce   number   of   Cholesky
-factorizations at the cost of increased number of  Jacobian  calculations.
-Sometimes it helps.
-
-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   2   comment
-V           +   +
-VJ          +   +   +
-FGH         +       +
-VGJ         +   +   +   special protocol, not for widespread use
-FJ          +       +   obsolete protocol, not recommended
-FGJ         +       +   obsolete protocol, not recommended
-
-DAFAULT VALUES:
-
-protocol    0   1   2   comment
-V               x       without acceleration it is so slooooooooow
-VJ          x
-FGH         x
-VGJ                 x   we've implicitly turned (2) by passing gradient
-FJ          x           obsolete protocol, not recommended
-FGJ                 x   obsolete protocol, not recommended
-
-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.
+Obsolete optimization algorithm.
+Was replaced by MinBLEIC subpackage.
 
   -- ALGLIB --
-     Copyright 14.10.2010 by Bochkanov Sergey
+     Copyright 30.07.2010 by Bochkanov Sergey
 *************************************************************************/
-void minlmsetacctype(minlmstate* state,
-     ae_int_t acctype,
-     ae_state *_state)
+void minasarestartfrom(const minasastate &state, const real_1d_array &x, const real_1d_array &bndl, const real_1d_array &bndu)
 {
-
-
-    ae_assert((acctype==0||acctype==1)||acctype==2, "MinLMSetAccType: incorrect AccType!", _state);
-    if( acctype==0 )
+    alglib_impl::ae_state _alglib_env_state;
+    alglib_impl::ae_state_init(&_alglib_env_state);
+    try
     {
-        state->maxmodelage = 0;
-        state->makeadditers = ae_false;
+        alglib_impl::minasarestartfrom(const_cast<alglib_impl::minasastate*>(state.c_ptr()), const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(bndl.c_ptr()), const_cast<alglib_impl::ae_vector*>(bndu.c_ptr()), &_alglib_env_state);
+        alglib_impl::ae_state_clear(&_alglib_env_state);
         return;
     }
-    if( acctype==1 )
+    catch(alglib_impl::ae_error_type)
     {
-        ae_assert(state->hasfi, "MinLMSetAccType: AccType=1 is incompatible with current protocol!", _state);
-        if( state->algomode==0 )
-        {
-            state->maxmodelage = 2*state->n;
-        }
-        else
-        {
-            state->maxmodelage = minlm_smallmodelage;
-        }
-        state->makeadditers = ae_false;
-        return;
+        throw ap_error(_alglib_env_state.error_msg);
     }
-    if( acctype==2 )
+    catch(...)
     {
-        ae_assert(state->algomode==1||state->algomode==2, "MinLMSetAccType: AccType=2 is incompatible with current protocol!", _state);
-        state->maxmodelage = 0;
-        state->makeadditers = ae_true;
-        return;
+        throw;
     }
 }
+}
+
+/////////////////////////////////////////////////////////////////////////
+//
+// THIS SECTION CONTAINS IMPLEMENTATION OF COMPUTATIONAL CORE
+//
+/////////////////////////////////////////////////////////////////////////
+namespace alglib_impl
+{
+static ae_int_t mincg_rscountdownlen = 10;
+static double mincg_gtol = 0.3;
+static void mincg_clearrequestfields(mincgstate* state, ae_state *_state);
+static void mincg_preconditionedmultiply(mincgstate* state,
+     /* Real    */ ae_vector* x,
+     /* Real    */ ae_vector* work0,
+     /* Real    */ ae_vector* work1,
+     ae_state *_state);
+static double mincg_preconditionedmultiply2(mincgstate* state,
+     /* Real    */ ae_vector* x,
+     /* Real    */ ae_vector* y,
+     /* Real    */ ae_vector* work0,
+     /* Real    */ ae_vector* work1,
+     ae_state *_state);
+static void mincg_mincginitinternal(ae_int_t n,
+     double diffstep,
+     mincgstate* state,
+     ae_state *_state);
+
+
+static double minbleic_svdtol = 100;
+static double minbleic_maxouterits = 20;
+static void minbleic_clearrequestfields(minbleicstate* state,
+     ae_state *_state);
+static void minbleic_unscalepoint(minbleicstate* state,
+     /* Real    */ ae_vector* xscaled,
+     /* Real    */ ae_vector* xunscaled,
+     ae_state *_state);
+static void minbleic_projectpointandunscale(minbleicstate* state,
+     /* Real    */ ae_vector* xscaled,
+     /* Real    */ ae_vector* xunscaled,
+     /* Real    */ ae_vector* rscaled,
+     double* rnorm2,
+     ae_state *_state);
+static void minbleic_scalegradientandexpand(minbleicstate* state,
+     /* Real    */ ae_vector* gunscaled,
+     /* Real    */ ae_vector* gscaled,
+     ae_state *_state);
+static void minbleic_modifytargetfunction(minbleicstate* state,
+     /* Real    */ ae_vector* x,
+     /* Real    */ ae_vector* r,
+     double rnorm2,
+     double* f,
+     /* Real    */ ae_vector* g,
+     double* gnorm,
+     double* mpgnorm,
+     ae_state *_state);
+static ae_bool minbleic_additionalcheckforconstraints(minbleicstate* state,
+     /* Real    */ ae_vector* x,
+     ae_state *_state);
+static void minbleic_rebuildcexe(minbleicstate* state, ae_state *_state);
+static void minbleic_makegradientprojection(minbleicstate* state,
+     /* Real    */ ae_vector* pg,
+     ae_state *_state);
+static ae_bool minbleic_prepareconstraintmatrix(minbleicstate* state,
+     /* Real    */ ae_vector* x,
+     /* Real    */ ae_vector* g,
+     /* Real    */ ae_vector* px,
+     /* Real    */ ae_vector* pg,
+     ae_state *_state);
+static void minbleic_minbleicinitinternal(ae_int_t n,
+     /* Real    */ ae_vector* x,
+     double diffstep,
+     minbleicstate* state,
+     ae_state *_state);
+
+
+static double minlbfgs_gtol = 0.4;
+static void minlbfgs_clearrequestfields(minlbfgsstate* state,
+     ae_state *_state);
+
+
+static void minqp_minqpgrad(minqpstate* state, ae_state *_state);
+static double minqp_minqpxtax(minqpstate* state,
+     /* Real    */ ae_vector* x,
+     ae_state *_state);
+
+
+static ae_int_t minlm_lmmodefj = 0;
+static ae_int_t minlm_lmmodefgj = 1;
+static ae_int_t minlm_lmmodefgh = 2;
+static ae_int_t minlm_lmflagnoprelbfgs = 1;
+static ae_int_t minlm_lmflagnointlbfgs = 2;
+static ae_int_t minlm_lmprelbfgsm = 5;
+static ae_int_t minlm_lmintlbfgsits = 5;
+static ae_int_t minlm_lbfgsnorealloc = 1;
+static double minlm_lambdaup = 2.0;
+static double minlm_lambdadown = 0.33;
+static double minlm_suspiciousnu = 16;
+static ae_int_t minlm_smallmodelage = 3;
+static ae_int_t minlm_additers = 5;
+static void minlm_lmprepare(ae_int_t n,
+     ae_int_t m,
+     ae_bool havegrad,
+     minlmstate* state,
+     ae_state *_state);
+static void minlm_clearrequestfields(minlmstate* state, ae_state *_state);
+static ae_bool minlm_increaselambda(double* lambdav,
+     double* nu,
+     ae_state *_state);
+static void minlm_decreaselambda(double* lambdav,
+     double* nu,
+     ae_state *_state);
+static double minlm_boundedscaledantigradnorm(minlmstate* state,
+     /* Real    */ ae_vector* x,
+     /* Real    */ ae_vector* g,
+     ae_state *_state);
+
+
+static ae_int_t mincomp_n1 = 2;
+static ae_int_t mincomp_n2 = 2;
+static double mincomp_stpmin = 1.0E-300;
+static double mincomp_gtol = 0.3;
+static double mincomp_gpaftol = 0.0001;
+static double mincomp_gpadecay = 0.5;
+static double mincomp_asarho = 0.5;
+static double mincomp_asaboundedantigradnorm(minasastate* state,
+     ae_state *_state);
+static double mincomp_asaginorm(minasastate* state, ae_state *_state);
+static double mincomp_asad1norm(minasastate* state, ae_state *_state);
+static ae_bool mincomp_asauisempty(minasastate* state, ae_state *_state);
+static void mincomp_clearrequestfields(minasastate* state,
+     ae_state *_state);
+
+
+
 
 
 /*************************************************************************
-NOTES:
+        NONLINEAR CONJUGATE GRADIENT METHOD
 
-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.
+DESCRIPTION:
+The subroutine minimizes function F(x) of N arguments by using one of  the
+nonlinear conjugate gradient methods.
 
-   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.
+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) }.
 
-   Be careful to avoid such errors because there is no way to find them at
-   compile time - you can see them at runtime only.
+
+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
 
   -- ALGLIB --
-     Copyright 10.03.2009 by Bochkanov Sergey
+     Copyright 25.03.2010 by Bochkanov Sergey
 *************************************************************************/
-ae_bool minlmiteration(minlmstate* state, ae_state *_state)
+void mincgcreate(ae_int_t n,
+     /* Real    */ ae_vector* x,
+     mincgstate* state,
+     ae_state *_state)
 {
-    ae_int_t n;
-    ae_int_t m;
-    ae_bool bflag;
-    ae_int_t iflag;
-    double v;
-    double s;
-    double t;
-    ae_int_t i;
-    ae_int_t k;
-    ae_bool result;
 
+    _mincgstate_clear(state);
 
-    
-    /*
-     * 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->rstate.stage>=0 )
-    {
-        n = state->rstate.ia.ptr.p_int[0];
-        m = state->rstate.ia.ptr.p_int[1];
-        iflag = state->rstate.ia.ptr.p_int[2];
-        i = state->rstate.ia.ptr.p_int[3];
-        k = state->rstate.ia.ptr.p_int[4];
-        bflag = state->rstate.ba.ptr.p_bool[0];
-        v = state->rstate.ra.ptr.p_double[0];
-        s = state->rstate.ra.ptr.p_double[1];
-        t = state->rstate.ra.ptr.p_double[2];
-    }
-    else
-    {
-        n = -983;
-        m = -989;
-        iflag = -834;
-        i = 900;
-        k = -287;
-        bflag = ae_false;
-        v = 214;
-        s = -338;
-        t = -686;
-    }
-    if( state->rstate.stage==0 )
-    {
-        goto lbl_0;
-    }
-    if( state->rstate.stage==1 )
-    {
-        goto lbl_1;
-    }
-    if( state->rstate.stage==2 )
-    {
-        goto lbl_2;
-    }
-    if( state->rstate.stage==3 )
-    {
-        goto lbl_3;
-    }
-    if( state->rstate.stage==4 )
-    {
-        goto lbl_4;
-    }
-    if( state->rstate.stage==5 )
-    {
-        goto lbl_5;
-    }
-    if( state->rstate.stage==6 )
-    {
-        goto lbl_6;
-    }
-    if( state->rstate.stage==7 )
-    {
-        goto lbl_7;
-    }
-    if( state->rstate.stage==8 )
-    {
-        goto lbl_8;
-    }
-    if( state->rstate.stage==9 )
-    {
-        goto lbl_9;
-    }
-    if( state->rstate.stage==10 )
-    {
-        goto lbl_10;
-    }
-    if( state->rstate.stage==11 )
-    {
-        goto lbl_11;
-    }
-    if( state->rstate.stage==12 )
-    {
-        goto lbl_12;
-    }
-    if( state->rstate.stage==13 )
-    {
-        goto lbl_13;
-    }
-    if( state->rstate.stage==14 )
-    {
-        goto lbl_14;
-    }
-    if( state->rstate.stage==15 )
-    {
-        goto lbl_15;
-    }
-    if( state->rstate.stage==16 )
-    {
-        goto lbl_16;
-    }
-    if( state->rstate.stage==17 )
+    ae_assert(n>=1, "MinCGCreate: N too small!", _state);
+    ae_assert(x->cnt>=n, "MinCGCreate: Length(X)<N!", _state);
+    ae_assert(isfinitevector(x, n, _state), "MinCGCreate: X contains infinite or NaN values!", _state);
+    mincg_mincginitinternal(n, 0.0, state, _state);
+    mincgrestartfrom(state, x, _state);
+}
+
+
+/*************************************************************************
+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.
+
+  -- ALGLIB --
+     Copyright 16.05.2011 by Bochkanov Sergey
+*************************************************************************/
+void mincgcreatef(ae_int_t n,
+     /* Real    */ ae_vector* x,
+     double diffstep,
+     mincgstate* state,
+     ae_state *_state)
+{
+
+    _mincgstate_clear(state);
+
+    ae_assert(n>=1, "MinCGCreateF: N too small!", _state);
+    ae_assert(x->cnt>=n, "MinCGCreateF: Length(X)<N!", _state);
+    ae_assert(isfinitevector(x, n, _state), "MinCGCreateF: X contains infinite or NaN values!", _state);
+    ae_assert(ae_isfinite(diffstep, _state), "MinCGCreateF: DiffStep is infinite or NaN!", _state);
+    ae_assert(ae_fp_greater(diffstep,0), "MinCGCreateF: DiffStep is non-positive!", _state);
+    mincg_mincginitinternal(n, diffstep, state, _state);
+    mincgrestartfrom(state, x, _state);
+}
+
+
+/*************************************************************************
+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).
+
+  -- ALGLIB --
+     Copyright 02.04.2010 by Bochkanov Sergey
+*************************************************************************/
+void mincgsetcond(mincgstate* state,
+     double epsg,
+     double epsf,
+     double epsx,
+     ae_int_t maxits,
+     ae_state *_state)
+{
+
+
+    ae_assert(ae_isfinite(epsg, _state), "MinCGSetCond: EpsG is not finite number!", _state);
+    ae_assert(ae_fp_greater_eq(epsg,0), "MinCGSetCond: negative EpsG!", _state);
+    ae_assert(ae_isfinite(epsf, _state), "MinCGSetCond: EpsF is not finite number!", _state);
+    ae_assert(ae_fp_greater_eq(epsf,0), "MinCGSetCond: negative EpsF!", _state);
+    ae_assert(ae_isfinite(epsx, _state), "MinCGSetCond: EpsX is not finite number!", _state);
+    ae_assert(ae_fp_greater_eq(epsx,0), "MinCGSetCond: negative EpsX!", _state);
+    ae_assert(maxits>=0, "MinCGSetCond: negative MaxIts!", _state);
+    if( ((ae_fp_eq(epsg,0)&&ae_fp_eq(epsf,0))&&ae_fp_eq(epsx,0))&&maxits==0 )
     {
-        goto lbl_17;
+        epsx = 1.0E-6;
     }
-    
-    /*
-     * Routine body
-     */
-    
-    /*
-     * prepare
-     */
-    n = state->n;
-    m = state->m;
-    state->repiterationscount = 0;
-    state->repterminationtype = 0;
-    state->repnfunc = 0;
-    state->repnjac = 0;
-    state->repngrad = 0;
-    state->repnhess = 0;
-    state->repncholesky = 0;
-    
-    /*
-     * 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->xrep )
+    state->epsg = epsg;
+    state->epsf = epsf;
+    state->epsx = epsx;
+    state->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.
+
+  -- ALGLIB --
+     Copyright 14.01.2011 by Bochkanov Sergey
+*************************************************************************/
+void mincgsetscale(mincgstate* state,
+     /* Real    */ ae_vector* s,
+     ae_state *_state)
+{
+    ae_int_t i;
+
+
+    ae_assert(s->cnt>=state->n, "MinCGSetScale: Length(S)<N", _state);
+    for(i=0; i<=state->n-1; i++)
     {
-        goto lbl_18;
+        ae_assert(ae_isfinite(s->ptr.p_double[i], _state), "MinCGSetScale: S contains infinite or NAN elements", _state);
+        ae_assert(ae_fp_neq(s->ptr.p_double[i],0), "MinCGSetScale: S contains zero elements", _state);
+        state->s.ptr.p_double[i] = ae_fabs(s->ptr.p_double[i], _state);
     }
-    ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    minlm_clearrequestfields(state, _state);
-    if( !state->hasf )
+}
+
+
+/*************************************************************************
+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().
+
+  -- ALGLIB --
+     Copyright 02.04.2010 by Bochkanov Sergey
+*************************************************************************/
+void mincgsetxrep(mincgstate* state, ae_bool needxrep, ae_state *_state)
+{
+
+
+    state->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.
+
+  -- ALGLIB --
+     Copyright 02.04.2010 by Bochkanov Sergey
+*************************************************************************/
+void mincgsetdrep(mincgstate* state, ae_bool needdrep, ae_state *_state)
+{
+
+
+    state->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
+
+  -- ALGLIB --
+     Copyright 02.04.2010 by Bochkanov Sergey
+*************************************************************************/
+void mincgsetcgtype(mincgstate* state, ae_int_t cgtype, ae_state *_state)
+{
+
+
+    ae_assert(cgtype>=-1&&cgtype<=1, "MinCGSetCGType: incorrect CGType!", _state);
+    if( cgtype==-1 )
     {
-        goto lbl_20;
+        cgtype = 1;
     }
-    state->needf = ae_true;
-    state->rstate.stage = 0;
-    goto lbl_rcomm;
-lbl_0:
-    state->needf = ae_false;
-    goto lbl_21;
-lbl_20:
-    ae_assert(state->hasfi, "MinLM: internal error 2!", _state);
-    state->needfi = ae_true;
-    state->rstate.stage = 1;
-    goto lbl_rcomm;
-lbl_1:
-    state->needfi = ae_false;
-    v = ae_v_dotproduct(&state->fi.ptr.p_double[0], 1, &state->fi.ptr.p_double[0], 1, ae_v_len(0,m-1));
-    state->f = v;
-lbl_21:
-    state->repnfunc = state->repnfunc+1;
-    ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    minlm_clearrequestfields(state, _state);
-    state->xupdated = ae_true;
-    state->rstate.stage = 2;
-    goto lbl_rcomm;
-lbl_2:
-    state->xupdated = ae_false;
-lbl_18:
-    
-    /*
-     * Prepare control variables
-     */
-    state->nu = 1;
-    state->lambdav = -ae_maxrealnumber;
-    state->modelage = state->maxmodelage+1;
-    state->deltaxready = ae_false;
-    state->deltafready = ae_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
-     *
-     */
-lbl_22:
-    if( ae_false )
+    state->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.
+
+  -- ALGLIB --
+     Copyright 02.04.2010 by Bochkanov Sergey
+*************************************************************************/
+void mincgsetstpmax(mincgstate* state, double stpmax, ae_state *_state)
+{
+
+
+    ae_assert(ae_isfinite(stpmax, _state), "MinCGSetStpMax: StpMax is not finite!", _state);
+    ae_assert(ae_fp_greater_eq(stpmax,0), "MinCGSetStpMax: StpMax<0!", _state);
+    state->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).
+
+  -- ALGLIB --
+     Copyright 30.07.2010 by Bochkanov Sergey
+*************************************************************************/
+void mincgsuggeststep(mincgstate* state, double stp, ae_state *_state)
+{
+
+
+    ae_assert(ae_isfinite(stp, _state), "MinCGSuggestStep: Stp is infinite or NAN", _state);
+    ae_assert(ae_fp_greater_eq(stp,0), "MinCGSuggestStep: Stp<0", _state);
+    state->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.
+
+  -- ALGLIB --
+     Copyright 13.10.2010 by Bochkanov Sergey
+*************************************************************************/
+void mincgsetprecdefault(mincgstate* state, ae_state *_state)
+{
+
+
+    state->prectype = 0;
+    state->innerresetneeded = ae_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.
+
+  -- ALGLIB --
+     Copyright 13.10.2010 by Bochkanov Sergey
+*************************************************************************/
+void mincgsetprecdiag(mincgstate* state,
+     /* Real    */ ae_vector* d,
+     ae_state *_state)
+{
+    ae_int_t i;
+
+
+    ae_assert(d->cnt>=state->n, "MinCGSetPrecDiag: D is too short", _state);
+    for(i=0; i<=state->n-1; i++)
     {
-        goto lbl_23;
+        ae_assert(ae_isfinite(d->ptr.p_double[i], _state), "MinCGSetPrecDiag: D contains infinite or NAN elements", _state);
+        ae_assert(ae_fp_greater(d->ptr.p_double[i],0), "MinCGSetPrecDiag: D contains non-positive elements", _state);
     }
+    mincgsetprecdiagfast(state, d, _state);
+}
+
+
+/*************************************************************************
+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.
+
+  -- ALGLIB --
+     Copyright 13.10.2010 by Bochkanov Sergey
+*************************************************************************/
+void mincgsetprecscale(mincgstate* state, ae_state *_state)
+{
+
+
+    state->prectype = 3;
+    state->innerresetneeded = ae_true;
+}
+
+
+/*************************************************************************
+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.
+
+  -- ALGLIB --
+     Copyright 20.04.2009 by Bochkanov Sergey
+*************************************************************************/
+ae_bool mincgiteration(mincgstate* state, ae_state *_state)
+{
+    ae_int_t n;
+    ae_int_t i;
+    double betak;
+    double v;
+    double vv;
+    ae_bool result;
+
+
     
     /*
-     * 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
+     * Reverse communication preparations
+     * I know it looks ugly, but it works the same way
+     * anywhere from C++ to Python.
      *
-     * We also clear DeltaXReady/DeltaFReady flags
-     * after initialization is done.
+     * This code initializes locals by:
+     * * random values determined during code
+     *   generation - on first subroutine call
+     * * values from previous call - on subsequent calls
      */
-    bflag = ae_false;
-    if( !(state->algomode==0||state->algomode==1) )
+    if( state->rstate.stage>=0 )
     {
-        goto lbl_24;
+        n = state->rstate.ia.ptr.p_int[0];
+        i = state->rstate.ia.ptr.p_int[1];
+        betak = state->rstate.ra.ptr.p_double[0];
+        v = state->rstate.ra.ptr.p_double[1];
+        vv = state->rstate.ra.ptr.p_double[2];
     }
-    
-    /*
-     * Calculate f[] and Jacobian
-     */
-    if( !(state->modelage>state->maxmodelage||!(state->deltaxready&&state->deltafready)) )
+    else
     {
-        goto lbl_26;
+        n = -983;
+        i = -989;
+        betak = -834;
+        v = 900;
+        vv = -287;
     }
-    
-    /*
-     * Refresh model (using either finite differences or analytic Jacobian)
-     */
-    if( state->algomode!=0 )
+    if( state->rstate.stage==0 )
     {
-        goto lbl_28;
+        goto lbl_0;
     }
-    
-    /*
-     * Optimization using F values only.
-     * Use finite differences to estimate Jacobian.
-     */
-    ae_assert(state->hasfi, "MinLMIteration: internal error when estimating Jacobian (no f[])", _state);
-    k = 0;
-lbl_30:
-    if( k>n-1 )
+    if( state->rstate.stage==1 )
     {
-        goto lbl_32;
+        goto lbl_1;
     }
-    ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    state->x.ptr.p_double[k] = state->x.ptr.p_double[k]-state->diffstep;
-    minlm_clearrequestfields(state, _state);
-    state->needfi = ae_true;
-    state->rstate.stage = 3;
+    if( state->rstate.stage==2 )
+    {
+        goto lbl_2;
+    }
+    if( state->rstate.stage==3 )
+    {
+        goto lbl_3;
+    }
+    if( state->rstate.stage==4 )
+    {
+        goto lbl_4;
+    }
+    if( state->rstate.stage==5 )
+    {
+        goto lbl_5;
+    }
+    if( state->rstate.stage==6 )
+    {
+        goto lbl_6;
+    }
+    if( state->rstate.stage==7 )
+    {
+        goto lbl_7;
+    }
+    if( state->rstate.stage==8 )
+    {
+        goto lbl_8;
+    }
+    if( state->rstate.stage==9 )
+    {
+        goto lbl_9;
+    }
+    if( state->rstate.stage==10 )
+    {
+        goto lbl_10;
+    }
+    if( state->rstate.stage==11 )
+    {
+        goto lbl_11;
+    }
+    if( state->rstate.stage==12 )
+    {
+        goto lbl_12;
+    }
+    if( state->rstate.stage==13 )
+    {
+        goto lbl_13;
+    }
+    if( state->rstate.stage==14 )
+    {
+        goto lbl_14;
+    }
+    if( state->rstate.stage==15 )
+    {
+        goto lbl_15;
+    }
+    if( state->rstate.stage==16 )
+    {
+        goto lbl_16;
+    }
+    
+    /*
+     * Routine body
+     */
+    
+    /*
+     * Prepare
+     */
+    n = state->n;
+    state->repterminationtype = 0;
+    state->repiterationscount = 0;
+    state->repnfev = 0;
+    state->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
+     */
+    ae_v_move(&state->xk.ptr.p_double[0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,n-1));
+    state->terminationneeded = ae_false;
+    mincg_clearrequestfields(state, _state);
+    if( ae_fp_neq(state->diffstep,0) )
+    {
+        goto lbl_17;
+    }
+    state->needfg = ae_true;
+    state->rstate.stage = 0;
+    goto lbl_rcomm;
+lbl_0:
+    state->needfg = ae_false;
+    goto lbl_18;
+lbl_17:
+    state->needf = ae_true;
+    state->rstate.stage = 1;
+    goto lbl_rcomm;
+lbl_1:
+    state->fbase = state->f;
+    i = 0;
+lbl_19:
+    if( i>n-1 )
+    {
+        goto lbl_21;
+    }
+    v = state->x.ptr.p_double[i];
+    state->x.ptr.p_double[i] = v-state->diffstep*state->s.ptr.p_double[i];
+    state->rstate.stage = 2;
+    goto lbl_rcomm;
+lbl_2:
+    state->fm2 = state->f;
+    state->x.ptr.p_double[i] = v-0.5*state->diffstep*state->s.ptr.p_double[i];
+    state->rstate.stage = 3;
     goto lbl_rcomm;
 lbl_3:
-    state->repnfunc = state->repnfunc+1;
-    ae_v_move(&state->fm1.ptr.p_double[0], 1, &state->fi.ptr.p_double[0], 1, ae_v_len(0,m-1));
-    ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    state->x.ptr.p_double[k] = state->x.ptr.p_double[k]+state->diffstep;
-    minlm_clearrequestfields(state, _state);
-    state->needfi = ae_true;
+    state->fm1 = state->f;
+    state->x.ptr.p_double[i] = v+0.5*state->diffstep*state->s.ptr.p_double[i];
     state->rstate.stage = 4;
     goto lbl_rcomm;
 lbl_4:
-    state->repnfunc = state->repnfunc+1;
-    ae_v_move(&state->fp1.ptr.p_double[0], 1, &state->fi.ptr.p_double[0], 1, ae_v_len(0,m-1));
-    v = 1/(2*state->diffstep);
-    ae_v_moved(&state->j.ptr.pp_double[0][k], state->j.stride, &state->fp1.ptr.p_double[0], 1, ae_v_len(0,m-1), v);
-    ae_v_subd(&state->j.ptr.pp_double[0][k], state->j.stride, &state->fm1.ptr.p_double[0], 1, ae_v_len(0,m-1), v);
-    k = k+1;
-    goto lbl_30;
-lbl_32:
-    
-    /*
-     * Calculate F(XBase)
-     */
-    ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    minlm_clearrequestfields(state, _state);
-    state->needfi = ae_true;
+    state->fp1 = state->f;
+    state->x.ptr.p_double[i] = v+state->diffstep*state->s.ptr.p_double[i];
     state->rstate.stage = 5;
     goto lbl_rcomm;
 lbl_5:
-    state->needfi = ae_false;
-    state->repnfunc = state->repnfunc+1;
-    state->repnjac = state->repnjac+1;
-    
-    /*
-     * New model
-     */
-    state->modelage = 0;
-    goto lbl_29;
-lbl_28:
+    state->fp2 = state->f;
+    state->x.ptr.p_double[i] = v;
+    state->g.ptr.p_double[i] = (8*(state->fp1-state->fm1)-(state->fp2-state->fm2))/(6*state->diffstep*state->s.ptr.p_double[i]);
+    i = i+1;
+    goto lbl_19;
+lbl_21:
+    state->f = state->fbase;
+    state->needf = ae_false;
+lbl_18:
+    if( !state->drep )
+    {
+        goto lbl_22;
+    }
     
     /*
-     * Obtain f[] and Jacobian
+     * Report algorithm powerup (if needed)
      */
-    ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    minlm_clearrequestfields(state, _state);
-    state->needfij = ae_true;
+    mincg_clearrequestfields(state, _state);
+    state->algpowerup = ae_true;
     state->rstate.stage = 6;
     goto lbl_rcomm;
 lbl_6:
-    state->needfij = ae_false;
-    state->repnfunc = state->repnfunc+1;
-    state->repnjac = state->repnjac+1;
+    state->algpowerup = ae_false;
+lbl_22:
+    trimprepare(state->f, &state->trimthreshold, _state);
+    ae_v_moveneg(&state->dk.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1));
+    mincg_preconditionedmultiply(state, &state->dk, &state->work0, &state->work1, _state);
+    if( !state->xrep )
+    {
+        goto lbl_24;
+    }
+    mincg_clearrequestfields(state, _state);
+    state->xupdated = ae_true;
+    state->rstate.stage = 7;
+    goto lbl_rcomm;
+lbl_7:
+    state->xupdated = ae_false;
+lbl_24:
+    if( state->terminationneeded )
+    {
+        ae_v_move(&state->xn.ptr.p_double[0], 1, &state->xk.ptr.p_double[0], 1, ae_v_len(0,n-1));
+        state->repterminationtype = 8;
+        result = ae_false;
+        return result;
+    }
+    v = 0;
+    for(i=0; i<=n-1; i++)
+    {
+        v = v+ae_sqr(state->g.ptr.p_double[i]*state->s.ptr.p_double[i], _state);
+    }
+    if( ae_fp_less_eq(ae_sqrt(v, _state),state->epsg) )
+    {
+        ae_v_move(&state->xn.ptr.p_double[0], 1, &state->xk.ptr.p_double[0], 1, ae_v_len(0,n-1));
+        state->repterminationtype = 4;
+        result = ae_false;
+        return result;
+    }
+    state->repnfev = 1;
+    state->k = 0;
+    state->fold = state->f;
     
     /*
-     * New model
+     * Choose initial step.
+     * Apply preconditioner, if we have something other than default.
      */
-    state->modelage = 0;
-lbl_29:
-    goto lbl_27;
-lbl_26:
+    if( state->prectype==2||state->prectype==3 )
+    {
+        
+        /*
+         * because we use preconditioner, step length must be equal
+         * to the norm of DK
+         */
+        v = ae_v_dotproduct(&state->dk.ptr.p_double[0], 1, &state->dk.ptr.p_double[0], 1, ae_v_len(0,n-1));
+        state->laststep = ae_sqrt(v, _state);
+    }
+    else
+    {
+        
+        /*
+         * No preconditioner is used, we try to use suggested step
+         */
+        if( ae_fp_greater(state->suggestedstep,0) )
+        {
+            state->laststep = state->suggestedstep;
+        }
+        else
+        {
+            v = ae_v_dotproduct(&state->g.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1));
+            v = ae_sqrt(v, _state);
+            if( ae_fp_eq(state->stpmax,0) )
+            {
+                state->laststep = ae_minreal(1.0/v, 1, _state);
+            }
+            else
+            {
+                state->laststep = ae_minreal(1.0/v, state->stpmax, _state);
+            }
+        }
+    }
     
     /*
-     * 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.
+     * Main cycle
      */
-    ae_assert(state->deltaxready&&state->deltafready, "MinLMIteration: uninitialized DeltaX/DeltaF", _state);
-    t = ae_v_dotproduct(&state->deltax.ptr.p_double[0], 1, &state->deltax.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    ae_assert(ae_fp_neq(t,0), "MinLM: internal error (T=0)", _state);
-    for(i=0; i<=m-1; i++)
+    state->rstimer = mincg_rscountdownlen;
+lbl_26:
+    if( ae_false )
     {
-        v = ae_v_dotproduct(&state->j.ptr.pp_double[i][0], 1, &state->deltax.ptr.p_double[0], 1, ae_v_len(0,n-1));
-        v = (state->deltaf.ptr.p_double[i]-v)/t;
-        ae_v_addd(&state->j.ptr.pp_double[i][0], 1, &state->deltax.ptr.p_double[0], 1, ae_v_len(0,n-1), v);
+        goto lbl_27;
     }
-    ae_v_move(&state->fi.ptr.p_double[0], 1, &state->fibase.ptr.p_double[0], 1, ae_v_len(0,m-1));
-    ae_v_add(&state->fi.ptr.p_double[0], 1, &state->deltaf.ptr.p_double[0], 1, ae_v_len(0,m-1));
     
     /*
-     * Increase model age
+     * * 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->modelage = state->modelage+1;
-lbl_27:
+    state->innerresetneeded = ae_false;
+    state->terminationneeded = ae_false;
+    ae_v_moveneg(&state->yk.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1));
+    ae_v_move(&state->d.ptr.p_double[0], 1, &state->dk.ptr.p_double[0], 1, ae_v_len(0,n-1));
+    ae_v_move(&state->x.ptr.p_double[0], 1, &state->xk.ptr.p_double[0], 1, ae_v_len(0,n-1));
+    state->mcstage = 0;
+    state->stp = 1.0;
+    linminnormalized(&state->d, &state->stp, n, _state);
+    if( ae_fp_neq(state->laststep,0) )
+    {
+        state->stp = state->laststep;
+    }
+    state->curstpmax = state->stpmax;
     
     /*
-     * 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.e. it has 0.5 before quadratic term.
+     * Report beginning of line search (if needed)
+     * Terminate algorithm, if user request was detected
      */
-    rmatrixgemm(n, n, m, 2.0, &state->j, 0, 0, 1, &state->j, 0, 0, 0, 0.0, &state->quadraticmodel, 0, 0, _state);
-    rmatrixmv(n, m, &state->j, 0, 0, 1, &state->fi, 0, &state->gbase, 0, _state);
-    ae_v_muld(&state->gbase.ptr.p_double[0], 1, ae_v_len(0,n-1), 2);
-    v = ae_v_dotproduct(&state->fi.ptr.p_double[0], 1, &state->fi.ptr.p_double[0], 1, ae_v_len(0,m-1));
-    state->fbase = v;
-    ae_v_move(&state->fibase.ptr.p_double[0], 1, &state->fi.ptr.p_double[0], 1, ae_v_len(0,m-1));
+    if( !state->drep )
+    {
+        goto lbl_28;
+    }
+    mincg_clearrequestfields(state, _state);
+    state->lsstart = ae_true;
+    state->rstate.stage = 8;
+    goto lbl_rcomm;
+lbl_8:
+    state->lsstart = ae_false;
+lbl_28:
+    if( state->terminationneeded )
+    {
+        ae_v_move(&state->xn.ptr.p_double[0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,n-1));
+        state->repterminationtype = 8;
+        result = ae_false;
+        return result;
+    }
     
     /*
-     * set control variables
+     * Minimization along D
      */
-    bflag = ae_true;
-lbl_24:
-    if( state->algomode!=2 )
+    mcsrch(n, &state->x, &state->f, &state->g, &state->d, &state->stp, state->curstpmax, mincg_gtol, &state->mcinfo, &state->nfev, &state->work0, &state->lstate, &state->mcstage, _state);
+lbl_30:
+    if( state->mcstage==0 )
     {
-        goto lbl_33;
+        goto lbl_31;
     }
-    ae_assert(!state->hasfi, "MinLMIteration: internal error (HasFI is True in Hessian-based mode)", _state);
     
     /*
-     * Obtain F, G, H
+     * Calculate function/gradient using either
+     * analytical gradient supplied by user
+     * or finite difference approximation.
+     *
+     * "Trim" function in order to handle near-singularity points.
      */
-    ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    minlm_clearrequestfields(state, _state);
-    state->needfgh = ae_true;
-    state->rstate.stage = 7;
+    mincg_clearrequestfields(state, _state);
+    if( ae_fp_neq(state->diffstep,0) )
+    {
+        goto lbl_32;
+    }
+    state->needfg = ae_true;
+    state->rstate.stage = 9;
     goto lbl_rcomm;
-lbl_7:
-    state->needfgh = ae_false;
-    state->repnfunc = state->repnfunc+1;
-    state->repngrad = state->repngrad+1;
-    state->repnhess = state->repnhess+1;
-    rmatrixcopy(n, n, &state->h, 0, 0, &state->quadraticmodel, 0, 0, _state);
-    ae_v_move(&state->gbase.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1));
+lbl_9:
+    state->needfg = ae_false;
+    goto lbl_33;
+lbl_32:
+    state->needf = ae_true;
+    state->rstate.stage = 10;
+    goto lbl_rcomm;
+lbl_10:
     state->fbase = state->f;
-    
-    /*
-     * set control variables
-     */
-    bflag = ae_true;
-    state->modelage = 0;
+    i = 0;
+lbl_34:
+    if( i>n-1 )
+    {
+        goto lbl_36;
+    }
+    v = state->x.ptr.p_double[i];
+    state->x.ptr.p_double[i] = v-state->diffstep*state->s.ptr.p_double[i];
+    state->rstate.stage = 11;
+    goto lbl_rcomm;
+lbl_11:
+    state->fm2 = state->f;
+    state->x.ptr.p_double[i] = v-0.5*state->diffstep*state->s.ptr.p_double[i];
+    state->rstate.stage = 12;
+    goto lbl_rcomm;
+lbl_12:
+    state->fm1 = state->f;
+    state->x.ptr.p_double[i] = v+0.5*state->diffstep*state->s.ptr.p_double[i];
+    state->rstate.stage = 13;
+    goto lbl_rcomm;
+lbl_13:
+    state->fp1 = state->f;
+    state->x.ptr.p_double[i] = v+state->diffstep*state->s.ptr.p_double[i];
+    state->rstate.stage = 14;
+    goto lbl_rcomm;
+lbl_14:
+    state->fp2 = state->f;
+    state->x.ptr.p_double[i] = v;
+    state->g.ptr.p_double[i] = (8*(state->fp1-state->fm1)-(state->fp2-state->fm2))/(6*state->diffstep*state->s.ptr.p_double[i]);
+    i = i+1;
+    goto lbl_34;
+lbl_36:
+    state->f = state->fbase;
+    state->needf = ae_false;
 lbl_33:
-    ae_assert(bflag, "MinLM: internal integrity check failed!", _state);
-    state->deltaxready = ae_false;
-    state->deltafready = ae_false;
+    trimfunction(&state->f, &state->g, n, state->trimthreshold, _state);
     
     /*
-     * If Lambda is not initialized, initialize it using quadratic model
+     * Call MCSRCH again
      */
-    if( ae_fp_less(state->lambdav,0) )
-    {
-        state->lambdav = 0;
-        for(i=0; i<=n-1; i++)
-        {
-            state->lambdav = ae_maxreal(state->lambdav, ae_fabs(state->quadraticmodel.ptr.pp_double[i][i], _state), _state);
-        }
-        state->lambdav = 0.001*state->lambdav;
-        if( ae_fp_eq(state->lambdav,0) )
-        {
-            state->lambdav = 1;
-        }
-    }
+    mcsrch(n, &state->x, &state->f, &state->g, &state->d, &state->stp, state->curstpmax, mincg_gtol, &state->mcinfo, &state->nfev, &state->work0, &state->lstate, &state->mcstage, _state);
+    goto lbl_30;
+lbl_31:
     
     /*
-     * Test stopping conditions for function gradient
+     * * report end of line search
+     * * store current point to XN
+     * * report iteration
+     * * terminate algorithm if user request was detected
      */
-    v = ae_v_dotproduct(&state->gbase.ptr.p_double[0], 1, &state->gbase.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    v = ae_sqrt(v, _state);
-    if( ae_fp_greater(v,state->epsg) )
-    {
-        goto lbl_35;
-    }
-    if( state->modelage!=0 )
+    if( !state->drep )
     {
         goto lbl_37;
     }
     
     /*
-     * Model is fresh, we can rely on it and terminate algorithm
+     * Report end of line search (if needed)
      */
-    state->repterminationtype = 4;
+    mincg_clearrequestfields(state, _state);
+    state->lsend = ae_true;
+    state->rstate.stage = 15;
+    goto lbl_rcomm;
+lbl_15:
+    state->lsend = ae_false;
+lbl_37:
+    ae_v_move(&state->xn.ptr.p_double[0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,n-1));
     if( !state->xrep )
     {
         goto lbl_39;
     }
-    ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    state->f = state->fbase;
-    minlm_clearrequestfields(state, _state);
+    mincg_clearrequestfields(state, _state);
     state->xupdated = ae_true;
-    state->rstate.stage = 8;
+    state->rstate.stage = 16;
     goto lbl_rcomm;
-lbl_8:
+lbl_16:
     state->xupdated = ae_false;
 lbl_39:
-    result = ae_false;
-    return result;
-    goto lbl_38;
-lbl_37:
-    
-    /*
-     * Model is not fresh, we should refresh it and test
-     * conditions once more
-     */
-    state->modelage = state->maxmodelage+1;
-    goto lbl_22;
-lbl_38:
-lbl_35:
-    
-    /*
-     * 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:
-     * * -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;
-lbl_41:
-    if( ae_false )
-    {
-        goto lbl_42;
-    }
-    
-    /*
-     * Do we need model update?
-     */
-    if( state->modelage>0&&ae_fp_greater_eq(state->nu,minlm_suspiciousnu) )
-    {
-        iflag = -2;
-        goto lbl_42;
-    }
-    
-    /*
-     * DampedModel = QuadraticModel+lambda*I
-     */
-    rmatrixcopy(n, n, &state->quadraticmodel, 0, 0, &state->dampedmodel, 0, 0, _state);
-    for(i=0; i<=n-1; i++)
+    if( state->terminationneeded )
     {
-        state->dampedmodel.ptr.pp_double[i][i] = state->dampedmodel.ptr.pp_double[i][i]+state->lambdav;
+        ae_v_move(&state->xn.ptr.p_double[0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,n-1));
+        state->repterminationtype = 8;
+        result = ae_false;
+        return result;
     }
     
     /*
-     * 1. try to solve (RawModel+Lambda*I)*dx = -g.
-     *    increase lambda if left part is not positive definite.
-     * 2. bound step by StpMax
-     *    increase lambda if step is larger than StpMax
-     *
-     * 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.
+     * Line search is finished.
+     * * calculate BetaK
+     * * calculate DN
+     * * update timers
+     * * calculate step length
      */
-    bflag = ae_true;
-    state->repncholesky = state->repncholesky+1;
-    if( spdmatrixcholeskyrec(&state->dampedmodel, 0, n, ae_true, &state->choleskybuf, _state) )
+    if( state->mcinfo==1&&!state->innerresetneeded )
     {
-        ae_v_moveneg(&state->xdir.ptr.p_double[0], 1, &state->gbase.ptr.p_double[0], 1, ae_v_len(0,n-1));
-        fblscholeskysolve(&state->dampedmodel, 1.0, n, ae_true, &state->xdir, &state->choleskybuf, _state);
-        v = ae_v_dotproduct(&state->xdir.ptr.p_double[0], 1, &state->xdir.ptr.p_double[0], 1, ae_v_len(0,n-1));
-        if( ae_isfinite(v, _state) )
+        
+        /*
+         * Standard Wolfe conditions hold
+         * Calculate Y[K] and D[K]'*Y[K]
+         */
+        ae_v_add(&state->yk.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1));
+        vv = ae_v_dotproduct(&state->yk.ptr.p_double[0], 1, &state->dk.ptr.p_double[0], 1, ae_v_len(0,n-1));
+        
+        /*
+         * Calculate BetaK according to DY formula
+         */
+        v = mincg_preconditionedmultiply2(state, &state->g, &state->g, &state->work0, &state->work1, _state);
+        state->betady = v/vv;
+        
+        /*
+         * Calculate BetaK according to HS formula
+         */
+        v = mincg_preconditionedmultiply2(state, &state->g, &state->yk, &state->work0, &state->work1, _state);
+        state->betahs = v/vv;
+        
+        /*
+         * Choose BetaK
+         */
+        if( state->cgtype==0 )
         {
-            v = ae_sqrt(v, _state);
-            if( ae_fp_greater(state->stpmax,0)&&ae_fp_greater(v,state->stpmax) )
-            {
-                bflag = ae_false;
-            }
+            betak = state->betady;
         }
-        else
+        if( state->cgtype==1 )
         {
-            bflag = ae_false;
+            betak = ae_maxreal(0, ae_minreal(state->betady, state->betahs, _state), _state);
         }
     }
     else
     {
-        bflag = ae_false;
+        
+        /*
+         * 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->debugrestartscount = state->debugrestartscount+1;
     }
-    if( !bflag )
+    if( state->repiterationscount>0&&state->repiterationscount%(3+n)==0 )
     {
         
         /*
-         * Solution failed:
-         * try to increase lambda to make matrix positive definite and continue.
+         * clear Beta every N iterations
          */
-        if( !minlm_increaselambda(&state->lambdav, &state->nu, _state) )
-        {
-            iflag = -1;
-            goto lbl_42;
-        }
-        goto lbl_41;
+        betak = 0;
     }
-    
-    /*
-     * 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)
-     */
-    ae_v_move(&state->deltax.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    ae_v_add(&state->deltax.ptr.p_double[0], 1, &state->xdir.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    ae_v_sub(&state->deltax.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    state->deltaxready = ae_true;
-    v = ae_v_dotproduct(&state->deltax.ptr.p_double[0], 1, &state->deltax.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    v = ae_sqrt(v, _state);
-    if( ae_fp_greater(v,state->epsx) )
+    if( state->mcinfo==1||state->mcinfo==5 )
     {
-        goto lbl_43;
+        state->rstimer = mincg_rscountdownlen;
     }
-    if( state->modelage!=0 )
+    else
     {
-        goto lbl_45;
+        state->rstimer = state->rstimer-1;
+    }
+    ae_v_moveneg(&state->dn.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1));
+    mincg_preconditionedmultiply(state, &state->dn, &state->work0, &state->work1, _state);
+    ae_v_addd(&state->dn.ptr.p_double[0], 1, &state->dk.ptr.p_double[0], 1, ae_v_len(0,n-1), betak);
+    state->laststep = 0;
+    state->lastscaledstep = 0.0;
+    for(i=0; i<=n-1; i++)
+    {
+        state->laststep = state->laststep+ae_sqr(state->d.ptr.p_double[i], _state);
+        state->lastscaledstep = state->lastscaledstep+ae_sqr(state->d.ptr.p_double[i]/state->s.ptr.p_double[i], _state);
     }
+    state->laststep = state->stp*ae_sqrt(state->laststep, _state);
+    state->lastscaledstep = state->stp*ae_sqrt(state->lastscaledstep, _state);
     
     /*
-     * Step is too short, model is fresh and we can rely on it.
-     * Terminating.
+     * Update information.
+     * Check stopping conditions.
      */
-    state->repterminationtype = 2;
-    if( !state->xrep )
-    {
-        goto lbl_47;
-    }
-    ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    state->f = state->fbase;
-    minlm_clearrequestfields(state, _state);
-    state->xupdated = ae_true;
-    state->rstate.stage = 9;
-    goto lbl_rcomm;
-lbl_9:
-    state->xupdated = ae_false;
-lbl_47:
-    result = ae_false;
-    return result;
-    goto lbl_46;
-lbl_45:
-    
-    /*
-     * Step is suspiciously short, but model is not fresh
-     * and we can't rely on it.
-     */
-    iflag = -2;
-    goto lbl_42;
-lbl_46:
-lbl_43:
-    
-    /*
-     * 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
-     */
-    ae_assert(state->hasfi||state->hasf, "MinLM: internal error 2!", _state);
-    ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    ae_v_add(&state->x.ptr.p_double[0], 1, &state->xdir.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    minlm_clearrequestfields(state, _state);
-    if( !state->hasfi )
-    {
-        goto lbl_49;
-    }
-    state->needfi = ae_true;
-    state->rstate.stage = 10;
-    goto lbl_rcomm;
-lbl_10:
-    state->needfi = ae_false;
-    v = ae_v_dotproduct(&state->fi.ptr.p_double[0], 1, &state->fi.ptr.p_double[0], 1, ae_v_len(0,m-1));
-    state->f = v;
-    ae_v_move(&state->deltaf.ptr.p_double[0], 1, &state->fi.ptr.p_double[0], 1, ae_v_len(0,m-1));
-    ae_v_sub(&state->deltaf.ptr.p_double[0], 1, &state->fibase.ptr.p_double[0], 1, ae_v_len(0,m-1));
-    state->deltafready = ae_true;
-    goto lbl_50;
-lbl_49:
-    state->needf = ae_true;
-    state->rstate.stage = 11;
-    goto lbl_rcomm;
-lbl_11:
-    state->needf = ae_false;
-lbl_50:
-    state->repnfunc = state->repnfunc+1;
-    if( ae_fp_greater_eq(state->f,state->fbase) )
+    state->repnfev = state->repnfev+state->nfev;
+    state->repiterationscount = state->repiterationscount+1;
+    if( state->repiterationscount>=state->maxits&&state->maxits>0 )
     {
         
         /*
-         * Increase lambda and continue
+         * Too many iterations
          */
-        if( !minlm_increaselambda(&state->lambdav, &state->nu, _state) )
-        {
-            iflag = -1;
-            goto lbl_42;
-        }
-        goto lbl_41;
-    }
-    
-    /*
-     * We've found our step!
-     */
-    iflag = 0;
-    goto lbl_42;
-    goto lbl_41;
-lbl_42:
-    state->nu = 1;
-    ae_assert(iflag>=-2&&iflag<=0, "MinLM: internal integrity check failed!", _state);
-    if( iflag==-2 )
-    {
-        state->modelage = state->maxmodelage+1;
-        goto lbl_22;
-    }
-    if( iflag==-1 )
-    {
-        goto lbl_23;
+        state->repterminationtype = 5;
+        result = ae_false;
+        return result;
     }
-    
-    /*
-     * 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.
-     */
-    ae_assert(state->deltaxready, "MinLM: deltaX is not ready", _state);
-    t = 0;
+    v = 0;
     for(i=0; i<=n-1; i++)
     {
-        v = ae_v_dotproduct(&state->quadraticmodel.ptr.pp_double[i][0], 1, &state->deltax.ptr.p_double[0], 1, ae_v_len(0,n-1));
-        t = t+state->deltax.ptr.p_double[i]*state->gbase.ptr.p_double[i]+0.5*state->deltax.ptr.p_double[i]*v;
-    }
-    state->predicteddecrease = -t;
-    state->actualdecrease = -(state->f-state->fbase);
-    if( ae_fp_less_eq(state->predicteddecrease,0) )
-    {
-        goto lbl_23;
-    }
-    v = state->actualdecrease/state->predicteddecrease;
-    if( ae_fp_greater_eq(v,0.1) )
-    {
-        goto lbl_51;
-    }
-    if( minlm_increaselambda(&state->lambdav, &state->nu, _state) )
-    {
-        goto lbl_53;
-    }
-    
-    /*
-     * Lambda is too large, we have to break iterations.
-     */
-    state->repterminationtype = 7;
-    if( !state->xrep )
-    {
-        goto lbl_55;
-    }
-    ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    state->f = state->fbase;
-    minlm_clearrequestfields(state, _state);
-    state->xupdated = ae_true;
-    state->rstate.stage = 12;
-    goto lbl_rcomm;
-lbl_12:
-    state->xupdated = ae_false;
-lbl_55:
-    result = ae_false;
-    return result;
-lbl_53:
-lbl_51:
-    if( ae_fp_greater(v,0.5) )
-    {
-        minlm_decreaselambda(&state->lambdav, &state->nu, _state);
-    }
-    
-    /*
-     * 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.
-     */
-    ae_v_add(&state->xbase.ptr.p_double[0], 1, &state->deltax.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    if( !state->xrep )
-    {
-        goto lbl_57;
+        v = v+ae_sqr(state->g.ptr.p_double[i]*state->s.ptr.p_double[i], _state);
     }
-    ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    minlm_clearrequestfields(state, _state);
-    state->xupdated = ae_true;
-    state->rstate.stage = 13;
-    goto lbl_rcomm;
-lbl_13:
-    state->xupdated = ae_false;
-lbl_57:
-    state->repiterationscount = state->repiterationscount+1;
-    if( state->repiterationscount>=state->maxits&&state->maxits>0 )
+    if( ae_fp_less_eq(ae_sqrt(v, _state),state->epsg) )
     {
-        state->repterminationtype = 5;
+        
+        /*
+         * Gradient is small enough
+         */
+        state->repterminationtype = 4;
+        result = ae_false;
+        return result;
     }
-    if( state->modelage==0 )
+    if( !state->innerresetneeded )
     {
-        if( ae_fp_less_eq(ae_fabs(state->f-state->fbase, _state),state->epsf*ae_maxreal(1, ae_maxreal(ae_fabs(state->f, _state), ae_fabs(state->fbase, _state), _state), _state)) )
+        
+        /*
+         * These conditions are checked only when no inner reset was requested by user
+         */
+        if( ae_fp_less_eq(state->fold-state->f,state->epsf*ae_maxreal(ae_fabs(state->fold, _state), ae_maxreal(ae_fabs(state->f, _state), 1.0, _state), _state)) )
         {
+            
+            /*
+             * F(k+1)-F(k) is small enough
+             */
             state->repterminationtype = 1;
+            result = ae_false;
+            return result;
+        }
+        if( ae_fp_less_eq(state->lastscaledstep,state->epsx) )
+        {
+            
+            /*
+             * X(k+1)-X(k) is small enough
+             */
+            state->repterminationtype = 2;
+            result = ae_false;
+            return result;
         }
     }
-    if( state->repterminationtype<=0 )
-    {
-        goto lbl_59;
-    }
-    if( !state->xrep )
+    if( state->rstimer<=0 )
     {
-        goto lbl_61;
+        
+        /*
+         * Too many subsequent restarts
+         */
+        state->repterminationtype = 7;
+        result = ae_false;
+        return result;
     }
     
     /*
-     * Report: XBase contains new point, F contains function value at new point
+     * Shift Xk/Dk, update other information
      */
-    ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    minlm_clearrequestfields(state, _state);
-    state->xupdated = ae_true;
-    state->rstate.stage = 14;
-    goto lbl_rcomm;
-lbl_14:
-    state->xupdated = ae_false;
-lbl_61:
+    ae_v_move(&state->xk.ptr.p_double[0], 1, &state->xn.ptr.p_double[0], 1, ae_v_len(0,n-1));
+    ae_v_move(&state->dk.ptr.p_double[0], 1, &state->dn.ptr.p_double[0], 1, ae_v_len(0,n-1));
+    state->fold = state->f;
+    state->k = state->k+1;
+    goto lbl_26;
+lbl_27:
     result = ae_false;
     return result;
-lbl_59:
-    state->modelage = state->modelage+1;
-    
-    /*
-     * Additional iterations for unconstrained problems:
-     * preconditioned L-BFGS is used.
-     *
-     * NOTE: additional iterations are incompatible with secant updates
-     * because they invalidate
-     */
-    if( !(ae_fp_eq(state->stpmax,0)&&state->makeadditers) )
-    {
-        goto lbl_63;
-    }
-    ae_assert(state->hasg||state->m!=0, "MinLM: no grad or Jacobian for additional iterations", _state);
     
     /*
-     * Make preconditioned iterations
-     */
-    minlbfgssetcholeskypreconditioner(&state->internalstate, &state->dampedmodel, ae_true, _state);
-    minlbfgsrestartfrom(&state->internalstate, &state->xbase, _state);
-lbl_65:
-    if( !minlbfgsiteration(&state->internalstate, _state) )
-    {
-        goto lbl_66;
-    }
-    if( !state->internalstate.needfg )
-    {
-        goto lbl_67;
-    }
-    ae_v_move(&state->x.ptr.p_double[0], 1, &state->internalstate.x.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    minlm_clearrequestfields(state, _state);
-    if( !state->hasg )
-    {
-        goto lbl_69;
-    }
-    state->needfg = ae_true;
-    state->rstate.stage = 15;
-    goto lbl_rcomm;
-lbl_15:
-    state->needfg = ae_false;
-    state->repngrad = state->repngrad+1;
-    ae_v_move(&state->internalstate.g.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    state->internalstate.f = state->f;
-    goto lbl_70;
-lbl_69:
-    state->needfij = ae_true;
-    state->rstate.stage = 16;
-    goto lbl_rcomm;
-lbl_16:
-    state->needfij = ae_false;
-    state->repnfunc = state->repnfunc+1;
-    state->repnjac = state->repnjac+1;
-    for(i=0; i<=n-1; i++)
-    {
-        state->internalstate.g.ptr.p_double[i] = 0;
-    }
-    for(i=0; i<=m-1; i++)
-    {
-        v = 2*state->fi.ptr.p_double[i];
-        ae_v_addd(&state->internalstate.g.ptr.p_double[0], 1, &state->j.ptr.pp_double[i][0], 1, ae_v_len(0,n-1), v);
-        state->internalstate.f = state->internalstate.f+ae_sqr(state->fi.ptr.p_double[i], _state);
-    }
-lbl_70:
-lbl_67:
-    goto lbl_65;
-lbl_66:
-    minlbfgsresultsbuf(&state->internalstate, &state->xbase, &state->internalrep, _state);
-    
-    /*
-     * Invalidate DeltaX/DeltaF (control variables used for integrity checks)
-     */
-    state->deltaxready = ae_false;
-    state->deltafready = ae_false;
-lbl_63:
-    goto lbl_22;
-lbl_23:
-    
-    /*
-     * Lambda is too large, we have to break iterations.
-     */
-    state->repterminationtype = 7;
-    if( !state->xrep )
-    {
-        goto lbl_71;
-    }
-    ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    state->f = state->fbase;
-    minlm_clearrequestfields(state, _state);
-    state->xupdated = ae_true;
-    state->rstate.stage = 17;
-    goto lbl_rcomm;
-lbl_17:
-    state->xupdated = ae_false;
-lbl_71:
-    result = ae_false;
-    return result;
-    
-    /*
-     * Saving state
+     * Saving state
      */
 lbl_rcomm:
     result = ae_true;
     state->rstate.ia.ptr.p_int[0] = n;
-    state->rstate.ia.ptr.p_int[1] = m;
-    state->rstate.ia.ptr.p_int[2] = iflag;
-    state->rstate.ia.ptr.p_int[3] = i;
-    state->rstate.ia.ptr.p_int[4] = k;
-    state->rstate.ba.ptr.p_bool[0] = bflag;
-    state->rstate.ra.ptr.p_double[0] = v;
-    state->rstate.ra.ptr.p_double[1] = s;
-    state->rstate.ra.ptr.p_double[2] = t;
+    state->rstate.ia.ptr.p_int[1] = i;
+    state->rstate.ra.ptr.p_double[0] = betak;
+    state->rstate.ra.ptr.p_double[1] = v;
+    state->rstate.ra.ptr.p_double[2] = vv;
     return result;
 }
 
 
 /*************************************************************************
-Levenberg-Marquardt algorithm results
+Conjugate gradient 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.
+    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
 
   -- ALGLIB --
-     Copyright 10.03.2009 by Bochkanov Sergey
+     Copyright 20.04.2009 by Bochkanov Sergey
 *************************************************************************/
-void minlmresults(minlmstate* state,
+void mincgresults(mincgstate* state,
      /* Real    */ ae_vector* x,
-     minlmreport* rep,
+     mincgreport* rep,
      ae_state *_state)
 {
 
     ae_vector_clear(x);
-    _minlmreport_clear(rep);
+    _mincgreport_clear(rep);
 
-    minlmresultsbuf(state, x, rep, _state);
+    mincgresultsbuf(state, x, rep, _state);
 }
 
 
 /*************************************************************************
-Levenberg-Marquardt algorithm results
+Conjugate gradient results
 
-Buffered implementation of MinLMResults(), which uses pre-allocated buffer
+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.
 
   -- ALGLIB --
-     Copyright 10.03.2009 by Bochkanov Sergey
+     Copyright 20.04.2009 by Bochkanov Sergey
 *************************************************************************/
-void minlmresultsbuf(minlmstate* state,
+void mincgresultsbuf(mincgstate* state,
      /* Real    */ ae_vector* x,
-     minlmreport* rep,
+     mincgreport* rep,
      ae_state *_state)
 {
 
@@ -7217,356 +7139,556 @@ void minlmresultsbuf(minlmstate* state,
     {
         ae_vector_set_length(x, state->n, _state);
     }
-    ae_v_move(&x->ptr.p_double[0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,state->n-1));
+    ae_v_move(&x->ptr.p_double[0], 1, &state->xn.ptr.p_double[0], 1, ae_v_len(0,state->n-1));
     rep->iterationscount = state->repiterationscount;
+    rep->nfev = state->repnfev;
     rep->terminationtype = state->repterminationtype;
-    rep->nfunc = state->repnfunc;
-    rep->njac = state->repnjac;
-    rep->ngrad = state->repngrad;
-    rep->nhess = state->repnhess;
-    rep->ncholesky = state->repncholesky;
 }
 
 
 /*************************************************************************
-This  subroutine  restarts  LM  algorithm from new point. All optimization
+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 for reverse communication previously
-                allocated with MinLMCreateXXX call.
+    State   -   structure used to store algorithm state.
     X       -   new starting point.
 
   -- ALGLIB --
      Copyright 30.07.2010 by Bochkanov Sergey
 *************************************************************************/
-void minlmrestartfrom(minlmstate* state,
+void mincgrestartfrom(mincgstate* state,
      /* Real    */ ae_vector* x,
      ae_state *_state)
 {
 
 
-    ae_assert(x->cnt>=state->n, "MinLMRestartFrom: Length(X)<N!", _state);
-    ae_assert(isfinitevector(x, state->n, _state), "MinLMRestartFrom: X contains infinite or NaN values!", _state);
-    ae_v_move(&state->xbase.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,state->n-1));
-    ae_vector_set_length(&state->rstate.ia, 4+1, _state);
-    ae_vector_set_length(&state->rstate.ba, 0+1, _state);
+    ae_assert(x->cnt>=state->n, "MinCGRestartFrom: Length(X)<N!", _state);
+    ae_assert(isfinitevector(x, state->n, _state), "MinCGCreate: X contains infinite or NaN values!", _state);
+    ae_v_move(&state->x.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,state->n-1));
+    mincgsuggeststep(state, 0.0, _state);
+    ae_vector_set_length(&state->rstate.ia, 1+1, _state);
     ae_vector_set_length(&state->rstate.ra, 2+1, _state);
     state->rstate.stage = -1;
-    minlm_clearrequestfields(state, _state);
+    mincg_clearrequestfields(state, _state);
 }
 
 
 /*************************************************************************
-Prepare internal structures (except for RComm).
+Faster version of MinCGSetPrecDiag(), for time-critical parts of code,
+without safety checks.
 
-Note: M must be zero for FGH mode, non-zero for V/VJ/FJ/FGJ mode.
+  -- ALGLIB --
+     Copyright 13.10.2010 by Bochkanov Sergey
 *************************************************************************/
-static void minlm_lmprepare(ae_int_t n,
-     ae_int_t m,
-     ae_bool havegrad,
-     minlmstate* state,
+void mincgsetprecdiagfast(mincgstate* state,
+     /* Real    */ ae_vector* d,
      ae_state *_state)
 {
     ae_int_t i;
 
 
-    if( n<=0||m<0 )
+    rvectorsetlengthatleast(&state->diagh, state->n, _state);
+    rvectorsetlengthatleast(&state->diaghl2, state->n, _state);
+    state->prectype = 2;
+    state->vcnt = 0;
+    state->innerresetneeded = ae_true;
+    for(i=0; i<=state->n-1; i++)
+    {
+        state->diagh.ptr.p_double[i] = d->ptr.p_double[i];
+        state->diaghl2.ptr.p_double[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.
+
+  -- ALGLIB --
+     Copyright 13.10.2010 by Bochkanov Sergey
+*************************************************************************/
+void mincgsetpreclowrankfast(mincgstate* state,
+     /* Real    */ ae_vector* d1,
+     /* Real    */ ae_vector* c,
+     /* Real    */ ae_matrix* v,
+     ae_int_t vcnt,
+     ae_state *_state)
+{
+    ae_frame _frame_block;
+    ae_int_t i;
+    ae_int_t j;
+    ae_int_t k;
+    ae_int_t n;
+    double t;
+    ae_matrix b;
+
+    ae_frame_make(_state, &_frame_block);
+    ae_matrix_init(&b, 0, 0, DT_REAL, _state, ae_true);
+
+    if( vcnt==0 )
     {
+        mincgsetprecdiagfast(state, d1, _state);
+        ae_frame_leave(_state);
         return;
     }
-    if( havegrad )
+    n = state->n;
+    ae_matrix_set_length(&b, vcnt, vcnt, _state);
+    rvectorsetlengthatleast(&state->diagh, n, _state);
+    rvectorsetlengthatleast(&state->diaghl2, n, _state);
+    rmatrixsetlengthatleast(&state->vcorr, vcnt, n, _state);
+    state->prectype = 2;
+    state->vcnt = vcnt;
+    state->innerresetneeded = ae_true;
+    for(i=0; i<=n-1; i++)
     {
-        ae_vector_set_length(&state->g, n, _state);
+        state->diagh.ptr.p_double[i] = d1->ptr.p_double[i];
+        state->diaghl2.ptr.p_double[i] = 0.0;
     }
-    if( m!=0 )
+    for(i=0; i<=vcnt-1; i++)
     {
-        ae_matrix_set_length(&state->j, m, n, _state);
-        ae_vector_set_length(&state->fi, m, _state);
-        ae_vector_set_length(&state->fibase, m, _state);
-        ae_vector_set_length(&state->deltaf, m, _state);
-        ae_vector_set_length(&state->fm2, m, _state);
-        ae_vector_set_length(&state->fm1, m, _state);
-        ae_vector_set_length(&state->fp2, m, _state);
-        ae_vector_set_length(&state->fp1, m, _state);
+        for(j=i; j<=vcnt-1; j++)
+        {
+            t = 0;
+            for(k=0; k<=n-1; k++)
+            {
+                t = t+v->ptr.pp_double[i][k]*v->ptr.pp_double[j][k]/d1->ptr.p_double[k];
+            }
+            b.ptr.pp_double[i][j] = t;
+        }
+        b.ptr.pp_double[i][i] = b.ptr.pp_double[i][i]+1.0/c->ptr.p_double[i];
     }
-    else
+    if( !spdmatrixcholeskyrec(&b, 0, vcnt, ae_true, &state->work0, _state) )
     {
-        ae_matrix_set_length(&state->h, n, n, _state);
+        state->vcnt = 0;
+        ae_frame_leave(_state);
+        return;
     }
-    ae_vector_set_length(&state->x, n, _state);
-    ae_vector_set_length(&state->deltax, n, _state);
-    ae_matrix_set_length(&state->quadraticmodel, n, n, _state);
-    ae_matrix_set_length(&state->dampedmodel, n, n, _state);
-    ae_vector_set_length(&state->xbase, n, _state);
-    ae_vector_set_length(&state->gbase, n, _state);
-    ae_vector_set_length(&state->xdir, n, _state);
-    
-    /*
-     * prepare internal L-BFGS
-     */
-    for(i=0; i<=n-1; i++)
+    for(i=0; i<=vcnt-1; i++)
     {
-        state->x.ptr.p_double[i] = 0;
+        ae_v_move(&state->vcorr.ptr.pp_double[i][0], 1, &v->ptr.pp_double[i][0], 1, ae_v_len(0,n-1));
+        for(j=0; j<=i-1; j++)
+        {
+            t = b.ptr.pp_double[j][i];
+            ae_v_subd(&state->vcorr.ptr.pp_double[i][0], 1, &state->vcorr.ptr.pp_double[j][0], 1, ae_v_len(0,n-1), t);
+        }
+        t = 1/b.ptr.pp_double[i][i];
+        ae_v_muld(&state->vcorr.ptr.pp_double[i][0], 1, ae_v_len(0,n-1), t);
     }
-    minlbfgscreate(n, ae_minint(minlm_additers, n, _state), &state->x, &state->internalstate, _state);
-    minlbfgssetcond(&state->internalstate, 0.0, 0.0, 0.0, ae_minint(minlm_additers, n, _state), _state);
+    ae_frame_leave(_state);
 }
 
 
 /*************************************************************************
-Clears request fileds (to be sure that we don't forgot to clear something)
+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.
+
+  -- ALGLIB --
+     Copyright 13.10.2010 by Bochkanov Sergey
 *************************************************************************/
-static void minlm_clearrequestfields(minlmstate* state, ae_state *_state)
+void mincgsetprecvarpart(mincgstate* state,
+     /* Real    */ ae_vector* d2,
+     ae_state *_state)
 {
+    ae_int_t i;
+    ae_int_t n;
 
 
-    state->needf = ae_false;
-    state->needfg = ae_false;
-    state->needfgh = ae_false;
-    state->needfij = ae_false;
-    state->needfi = ae_false;
-    state->xupdated = ae_false;
+    n = state->n;
+    for(i=0; i<=n-1; i++)
+    {
+        state->diaghl2.ptr.p_double[i] = d2->ptr.p_double[i];
+    }
 }
 
 
 /*************************************************************************
-Increases lambda, returns False when there is a danger of overflow
+Clears request fileds (to be sure that we don't forgot to clear something)
 *************************************************************************/
-static ae_bool minlm_increaselambda(double* lambdav,
-     double* nu,
-     ae_state *_state)
+static void mincg_clearrequestfields(mincgstate* state, ae_state *_state)
 {
-    double lnlambda;
-    double lnnu;
-    double lnlambdaup;
-    double lnmax;
-    ae_bool result;
 
 
-    result = ae_false;
-    lnlambda = ae_log(*lambdav, _state);
-    lnlambdaup = ae_log(minlm_lambdaup, _state);
-    lnnu = ae_log(*nu, _state);
-    lnmax = ae_log(ae_maxrealnumber, _state);
-    if( ae_fp_greater(lnlambda+lnlambdaup+lnnu,0.25*lnmax) )
-    {
-        return result;
-    }
-    if( ae_fp_greater(lnnu+ae_log(2, _state),lnmax) )
-    {
-        return result;
-    }
-    *lambdav = *lambdav*minlm_lambdaup*(*nu);
-    *nu = *nu*2;
-    result = ae_true;
-    return result;
+    state->needf = ae_false;
+    state->needfg = ae_false;
+    state->xupdated = ae_false;
+    state->lsstart = ae_false;
+    state->lsend = ae_false;
+    state->algpowerup = ae_false;
 }
 
 
 /*************************************************************************
-Decreases lambda, but leaves it unchanged when there is danger of underflow.
+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).
+
+  -- ALGLIB --
+     Copyright 13.10.2010 by Bochkanov Sergey
 *************************************************************************/
-static void minlm_decreaselambda(double* lambdav,
-     double* nu,
+static void mincg_preconditionedmultiply(mincgstate* state,
+     /* Real    */ ae_vector* x,
+     /* Real    */ ae_vector* work0,
+     /* Real    */ ae_vector* work1,
      ae_state *_state)
 {
+    ae_int_t i;
+    ae_int_t n;
+    ae_int_t vcnt;
+    double v;
 
 
-    *nu = 1;
-    if( ae_fp_less(ae_log(*lambdav, _state)+ae_log(minlm_lambdadown, _state),ae_log(ae_minrealnumber, _state)) )
+    n = state->n;
+    vcnt = state->vcnt;
+    if( state->prectype==0 )
     {
-        *lambdav = ae_minrealnumber;
+        return;
     }
-    else
+    if( state->prectype==3 )
     {
-        *lambdav = *lambdav*minlm_lambdadown;
-    }
+        for(i=0; i<=n-1; i++)
+        {
+            x->ptr.p_double[i] = x->ptr.p_double[i]*state->s.ptr.p_double[i]*state->s.ptr.p_double[i];
+        }
+        return;
+    }
+    ae_assert(state->prectype==2, "MinCG: internal error (unexpected PrecType)", _state);
+    
+    /*
+     * handle part common for VCnt=0 and VCnt<>0
+     */
+    for(i=0; i<=n-1; i++)
+    {
+        x->ptr.p_double[i] = x->ptr.p_double[i]/(state->diagh.ptr.p_double[i]+state->diaghl2.ptr.p_double[i]);
+    }
+    
+    /*
+     * if VCnt>0
+     */
+    if( vcnt>0 )
+    {
+        for(i=0; i<=vcnt-1; i++)
+        {
+            v = ae_v_dotproduct(&state->vcorr.ptr.pp_double[i][0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,n-1));
+            work0->ptr.p_double[i] = v;
+        }
+        for(i=0; i<=n-1; i++)
+        {
+            work1->ptr.p_double[i] = 0;
+        }
+        for(i=0; i<=vcnt-1; i++)
+        {
+            v = work0->ptr.p_double[i];
+            ae_v_addd(&state->work1.ptr.p_double[0], 1, &state->vcorr.ptr.pp_double[i][0], 1, ae_v_len(0,n-1), v);
+        }
+        for(i=0; i<=n-1; i++)
+        {
+            x->ptr.p_double[i] = x->ptr.p_double[i]-state->work1.ptr.p_double[i]/(state->diagh.ptr.p_double[i]+state->diaghl2.ptr.p_double[i]);
+        }
+    }
 }
 
 
-ae_bool _minlmstate_init(minlmstate* p, ae_state *_state, ae_bool make_automatic)
+/*************************************************************************
+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).
+
+  -- ALGLIB --
+     Copyright 13.10.2010 by Bochkanov Sergey
+*************************************************************************/
+static double mincg_preconditionedmultiply2(mincgstate* state,
+     /* Real    */ ae_vector* x,
+     /* Real    */ ae_vector* y,
+     /* Real    */ ae_vector* work0,
+     /* Real    */ ae_vector* work1,
+     ae_state *_state)
 {
-    if( !ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic) )
-        return ae_false;
-    if( !ae_vector_init(&p->fi, 0, DT_REAL, _state, make_automatic) )
+    ae_int_t i;
+    ae_int_t n;
+    ae_int_t vcnt;
+    double v0;
+    double v1;
+    double result;
+
+
+    n = state->n;
+    vcnt = state->vcnt;
+    
+    /*
+     * no preconditioning
+     */
+    if( state->prectype==0 )
+    {
+        v0 = ae_v_dotproduct(&x->ptr.p_double[0], 1, &y->ptr.p_double[0], 1, ae_v_len(0,n-1));
+        result = v0;
+        return result;
+    }
+    if( state->prectype==3 )
+    {
+        result = 0;
+        for(i=0; i<=n-1; i++)
+        {
+            result = result+x->ptr.p_double[i]*state->s.ptr.p_double[i]*state->s.ptr.p_double[i]*y->ptr.p_double[i];
+        }
+        return result;
+    }
+    ae_assert(state->prectype==2, "MinCG: internal error (unexpected PrecType)", _state);
+    
+    /*
+     * low rank preconditioning
+     */
+    result = 0.0;
+    for(i=0; i<=n-1; i++)
+    {
+        result = result+x->ptr.p_double[i]*y->ptr.p_double[i]/(state->diagh.ptr.p_double[i]+state->diaghl2.ptr.p_double[i]);
+    }
+    if( vcnt>0 )
+    {
+        for(i=0; i<=n-1; i++)
+        {
+            work0->ptr.p_double[i] = x->ptr.p_double[i]/(state->diagh.ptr.p_double[i]+state->diaghl2.ptr.p_double[i]);
+            work1->ptr.p_double[i] = y->ptr.p_double[i]/(state->diagh.ptr.p_double[i]+state->diaghl2.ptr.p_double[i]);
+        }
+        for(i=0; i<=vcnt-1; i++)
+        {
+            v0 = ae_v_dotproduct(&work0->ptr.p_double[0], 1, &state->vcorr.ptr.pp_double[i][0], 1, ae_v_len(0,n-1));
+            v1 = ae_v_dotproduct(&work1->ptr.p_double[0], 1, &state->vcorr.ptr.pp_double[i][0], 1, ae_v_len(0,n-1));
+            result = result-v0*v1;
+        }
+    }
+    return result;
+}
+
+
+/*************************************************************************
+Internal initialization subroutine
+
+  -- ALGLIB --
+     Copyright 16.05.2011 by Bochkanov Sergey
+*************************************************************************/
+static void mincg_mincginitinternal(ae_int_t n,
+     double diffstep,
+     mincgstate* state,
+     ae_state *_state)
+{
+    ae_int_t i;
+
+
+    state->n = n;
+    state->diffstep = diffstep;
+    mincgsetcond(state, 0, 0, 0, 0, _state);
+    mincgsetxrep(state, ae_false, _state);
+    mincgsetdrep(state, ae_false, _state);
+    mincgsetstpmax(state, 0, _state);
+    mincgsetcgtype(state, -1, _state);
+    mincgsetprecdefault(state, _state);
+    ae_vector_set_length(&state->xk, n, _state);
+    ae_vector_set_length(&state->dk, n, _state);
+    ae_vector_set_length(&state->xn, n, _state);
+    ae_vector_set_length(&state->dn, n, _state);
+    ae_vector_set_length(&state->x, n, _state);
+    ae_vector_set_length(&state->d, n, _state);
+    ae_vector_set_length(&state->g, n, _state);
+    ae_vector_set_length(&state->work0, n, _state);
+    ae_vector_set_length(&state->work1, n, _state);
+    ae_vector_set_length(&state->yk, n, _state);
+    ae_vector_set_length(&state->s, n, _state);
+    for(i=0; i<=n-1; i++)
+    {
+        state->s.ptr.p_double[i] = 1.0;
+    }
+}
+
+
+ae_bool _mincgstate_init(mincgstate* p, ae_state *_state, ae_bool make_automatic)
+{
+    if( !ae_vector_init(&p->diagh, 0, DT_REAL, _state, make_automatic) )
         return ae_false;
-    if( !ae_matrix_init(&p->j, 0, 0, DT_REAL, _state, make_automatic) )
+    if( !ae_vector_init(&p->diaghl2, 0, DT_REAL, _state, make_automatic) )
         return ae_false;
-    if( !ae_matrix_init(&p->h, 0, 0, DT_REAL, _state, make_automatic) )
+    if( !ae_matrix_init(&p->vcorr, 0, 0, DT_REAL, _state, make_automatic) )
         return ae_false;
-    if( !ae_vector_init(&p->g, 0, DT_REAL, _state, make_automatic) )
+    if( !ae_vector_init(&p->s, 0, DT_REAL, _state, make_automatic) )
         return ae_false;
-    if( !ae_vector_init(&p->xbase, 0, DT_REAL, _state, make_automatic) )
+    if( !ae_vector_init(&p->xk, 0, DT_REAL, _state, make_automatic) )
         return ae_false;
-    if( !ae_vector_init(&p->fibase, 0, DT_REAL, _state, make_automatic) )
+    if( !ae_vector_init(&p->dk, 0, DT_REAL, _state, make_automatic) )
         return ae_false;
-    if( !ae_vector_init(&p->gbase, 0, DT_REAL, _state, make_automatic) )
+    if( !ae_vector_init(&p->xn, 0, DT_REAL, _state, make_automatic) )
         return ae_false;
-    if( !ae_matrix_init(&p->quadraticmodel, 0, 0, DT_REAL, _state, make_automatic) )
+    if( !ae_vector_init(&p->dn, 0, DT_REAL, _state, make_automatic) )
         return ae_false;
-    if( !ae_matrix_init(&p->dampedmodel, 0, 0, DT_REAL, _state, make_automatic) )
+    if( !ae_vector_init(&p->d, 0, DT_REAL, _state, make_automatic) )
         return ae_false;
-    if( !ae_vector_init(&p->xdir, 0, DT_REAL, _state, make_automatic) )
+    if( !ae_vector_init(&p->yk, 0, DT_REAL, _state, make_automatic) )
         return ae_false;
-    if( !ae_vector_init(&p->deltax, 0, DT_REAL, _state, make_automatic) )
+    if( !ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic) )
         return ae_false;
-    if( !ae_vector_init(&p->deltaf, 0, DT_REAL, _state, make_automatic) )
+    if( !ae_vector_init(&p->g, 0, DT_REAL, _state, make_automatic) )
         return ae_false;
     if( !_rcommstate_init(&p->rstate, _state, make_automatic) )
         return ae_false;
-    if( !ae_vector_init(&p->choleskybuf, 0, DT_REAL, _state, make_automatic) )
-        return ae_false;
-    if( !ae_vector_init(&p->fm2, 0, DT_REAL, _state, make_automatic) )
-        return ae_false;
-    if( !ae_vector_init(&p->fm1, 0, DT_REAL, _state, make_automatic) )
-        return ae_false;
-    if( !ae_vector_init(&p->fp2, 0, DT_REAL, _state, make_automatic) )
-        return ae_false;
-    if( !ae_vector_init(&p->fp1, 0, DT_REAL, _state, make_automatic) )
+    if( !_linminstate_init(&p->lstate, _state, make_automatic) )
         return ae_false;
-    if( !_minlbfgsstate_init(&p->internalstate, _state, make_automatic) )
+    if( !ae_vector_init(&p->work0, 0, DT_REAL, _state, make_automatic) )
         return ae_false;
-    if( !_minlbfgsreport_init(&p->internalrep, _state, make_automatic) )
+    if( !ae_vector_init(&p->work1, 0, DT_REAL, _state, make_automatic) )
         return ae_false;
     return ae_true;
 }
 
 
-ae_bool _minlmstate_init_copy(minlmstate* dst, minlmstate* src, ae_state *_state, ae_bool make_automatic)
+ae_bool _mincgstate_init_copy(mincgstate* dst, mincgstate* src, ae_state *_state, ae_bool make_automatic)
 {
     dst->n = src->n;
-    dst->m = src->m;
-    dst->diffstep = src->diffstep;
     dst->epsg = src->epsg;
     dst->epsf = src->epsf;
     dst->epsx = src->epsx;
     dst->maxits = src->maxits;
-    dst->xrep = src->xrep;
     dst->stpmax = src->stpmax;
-    dst->maxmodelage = src->maxmodelage;
-    dst->makeadditers = src->makeadditers;
-    if( !ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic) )
+    dst->suggestedstep = src->suggestedstep;
+    dst->xrep = src->xrep;
+    dst->drep = src->drep;
+    dst->cgtype = src->cgtype;
+    dst->prectype = src->prectype;
+    if( !ae_vector_init_copy(&dst->diagh, &src->diagh, _state, make_automatic) )
         return ae_false;
-    dst->f = src->f;
-    if( !ae_vector_init_copy(&dst->fi, &src->fi, _state, make_automatic) )
+    if( !ae_vector_init_copy(&dst->diaghl2, &src->diaghl2, _state, make_automatic) )
         return ae_false;
-    if( !ae_matrix_init_copy(&dst->j, &src->j, _state, make_automatic) )
+    if( !ae_matrix_init_copy(&dst->vcorr, &src->vcorr, _state, make_automatic) )
         return ae_false;
-    if( !ae_matrix_init_copy(&dst->h, &src->h, _state, make_automatic) )
+    dst->vcnt = src->vcnt;
+    if( !ae_vector_init_copy(&dst->s, &src->s, _state, make_automatic) )
         return ae_false;
-    if( !ae_vector_init_copy(&dst->g, &src->g, _state, make_automatic) )
+    dst->diffstep = src->diffstep;
+    dst->nfev = src->nfev;
+    dst->mcstage = src->mcstage;
+    dst->k = src->k;
+    if( !ae_vector_init_copy(&dst->xk, &src->xk, _state, make_automatic) )
         return ae_false;
-    dst->needf = src->needf;
-    dst->needfg = src->needfg;
-    dst->needfgh = src->needfgh;
-    dst->needfij = src->needfij;
-    dst->needfi = src->needfi;
-    dst->xupdated = src->xupdated;
-    dst->algomode = src->algomode;
-    dst->hasf = src->hasf;
-    dst->hasfi = src->hasfi;
-    dst->hasg = src->hasg;
-    if( !ae_vector_init_copy(&dst->xbase, &src->xbase, _state, make_automatic) )
+    if( !ae_vector_init_copy(&dst->dk, &src->dk, _state, make_automatic) )
         return ae_false;
-    dst->fbase = src->fbase;
-    if( !ae_vector_init_copy(&dst->fibase, &src->fibase, _state, make_automatic) )
+    if( !ae_vector_init_copy(&dst->xn, &src->xn, _state, make_automatic) )
         return ae_false;
-    if( !ae_vector_init_copy(&dst->gbase, &src->gbase, _state, make_automatic) )
+    if( !ae_vector_init_copy(&dst->dn, &src->dn, _state, make_automatic) )
         return ae_false;
-    if( !ae_matrix_init_copy(&dst->quadraticmodel, &src->quadraticmodel, _state, make_automatic) )
+    if( !ae_vector_init_copy(&dst->d, &src->d, _state, make_automatic) )
         return ae_false;
-    dst->lambdav = src->lambdav;
-    dst->nu = src->nu;
-    if( !ae_matrix_init_copy(&dst->dampedmodel, &src->dampedmodel, _state, make_automatic) )
+    dst->fold = src->fold;
+    dst->stp = src->stp;
+    dst->curstpmax = src->curstpmax;
+    if( !ae_vector_init_copy(&dst->yk, &src->yk, _state, make_automatic) )
         return ae_false;
-    dst->modelage = src->modelage;
-    if( !ae_vector_init_copy(&dst->xdir, &src->xdir, _state, make_automatic) )
+    dst->laststep = src->laststep;
+    dst->lastscaledstep = src->lastscaledstep;
+    dst->mcinfo = src->mcinfo;
+    dst->innerresetneeded = src->innerresetneeded;
+    dst->terminationneeded = src->terminationneeded;
+    dst->trimthreshold = src->trimthreshold;
+    dst->rstimer = src->rstimer;
+    if( !ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic) )
         return ae_false;
-    if( !ae_vector_init_copy(&dst->deltax, &src->deltax, _state, make_automatic) )
+    dst->f = src->f;
+    if( !ae_vector_init_copy(&dst->g, &src->g, _state, make_automatic) )
         return ae_false;
-    if( !ae_vector_init_copy(&dst->deltaf, &src->deltaf, _state, make_automatic) )
+    dst->needf = src->needf;
+    dst->needfg = src->needfg;
+    dst->xupdated = src->xupdated;
+    dst->algpowerup = src->algpowerup;
+    dst->lsstart = src->lsstart;
+    dst->lsend = src->lsend;
+    if( !_rcommstate_init_copy(&dst->rstate, &src->rstate, _state, make_automatic) )
         return ae_false;
-    dst->deltaxready = src->deltaxready;
-    dst->deltafready = src->deltafready;
     dst->repiterationscount = src->repiterationscount;
+    dst->repnfev = src->repnfev;
     dst->repterminationtype = src->repterminationtype;
-    dst->repnfunc = src->repnfunc;
-    dst->repnjac = src->repnjac;
-    dst->repngrad = src->repngrad;
-    dst->repnhess = src->repnhess;
-    dst->repncholesky = src->repncholesky;
-    if( !_rcommstate_init_copy(&dst->rstate, &src->rstate, _state, make_automatic) )
-        return ae_false;
-    if( !ae_vector_init_copy(&dst->choleskybuf, &src->choleskybuf, _state, make_automatic) )
-        return ae_false;
-    dst->actualdecrease = src->actualdecrease;
-    dst->predicteddecrease = src->predicteddecrease;
-    if( !ae_vector_init_copy(&dst->fm2, &src->fm2, _state, make_automatic) )
-        return ae_false;
-    if( !ae_vector_init_copy(&dst->fm1, &src->fm1, _state, make_automatic) )
-        return ae_false;
-    if( !ae_vector_init_copy(&dst->fp2, &src->fp2, _state, make_automatic) )
-        return ae_false;
-    if( !ae_vector_init_copy(&dst->fp1, &src->fp1, _state, make_automatic) )
+    dst->debugrestartscount = src->debugrestartscount;
+    if( !_linminstate_init_copy(&dst->lstate, &src->lstate, _state, make_automatic) )
         return ae_false;
-    if( !_minlbfgsstate_init_copy(&dst->internalstate, &src->internalstate, _state, make_automatic) )
+    dst->fbase = src->fbase;
+    dst->fm2 = src->fm2;
+    dst->fm1 = src->fm1;
+    dst->fp1 = src->fp1;
+    dst->fp2 = src->fp2;
+    dst->betahs = src->betahs;
+    dst->betady = src->betady;
+    if( !ae_vector_init_copy(&dst->work0, &src->work0, _state, make_automatic) )
         return ae_false;
-    if( !_minlbfgsreport_init_copy(&dst->internalrep, &src->internalrep, _state, make_automatic) )
+    if( !ae_vector_init_copy(&dst->work1, &src->work1, _state, make_automatic) )
         return ae_false;
     return ae_true;
 }
 
 
-void _minlmstate_clear(minlmstate* p)
+void _mincgstate_clear(mincgstate* p)
 {
+    ae_vector_clear(&p->diagh);
+    ae_vector_clear(&p->diaghl2);
+    ae_matrix_clear(&p->vcorr);
+    ae_vector_clear(&p->s);
+    ae_vector_clear(&p->xk);
+    ae_vector_clear(&p->dk);
+    ae_vector_clear(&p->xn);
+    ae_vector_clear(&p->dn);
+    ae_vector_clear(&p->d);
+    ae_vector_clear(&p->yk);
     ae_vector_clear(&p->x);
-    ae_vector_clear(&p->fi);
-    ae_matrix_clear(&p->j);
-    ae_matrix_clear(&p->h);
     ae_vector_clear(&p->g);
-    ae_vector_clear(&p->xbase);
-    ae_vector_clear(&p->fibase);
-    ae_vector_clear(&p->gbase);
-    ae_matrix_clear(&p->quadraticmodel);
-    ae_matrix_clear(&p->dampedmodel);
-    ae_vector_clear(&p->xdir);
-    ae_vector_clear(&p->deltax);
-    ae_vector_clear(&p->deltaf);
     _rcommstate_clear(&p->rstate);
-    ae_vector_clear(&p->choleskybuf);
-    ae_vector_clear(&p->fm2);
-    ae_vector_clear(&p->fm1);
-    ae_vector_clear(&p->fp2);
-    ae_vector_clear(&p->fp1);
-    _minlbfgsstate_clear(&p->internalstate);
-    _minlbfgsreport_clear(&p->internalrep);
+    _linminstate_clear(&p->lstate);
+    ae_vector_clear(&p->work0);
+    ae_vector_clear(&p->work1);
 }
 
 
-ae_bool _minlmreport_init(minlmreport* p, ae_state *_state, ae_bool make_automatic)
+ae_bool _mincgreport_init(mincgreport* p, ae_state *_state, ae_bool make_automatic)
 {
     return ae_true;
 }
 
 
-ae_bool _minlmreport_init_copy(minlmreport* dst, minlmreport* src, ae_state *_state, ae_bool make_automatic)
+ae_bool _mincgreport_init_copy(mincgreport* dst, mincgreport* src, ae_state *_state, ae_bool make_automatic)
 {
     dst->iterationscount = src->iterationscount;
+    dst->nfev = src->nfev;
     dst->terminationtype = src->terminationtype;
-    dst->nfunc = src->nfunc;
-    dst->njac = src->njac;
-    dst->ngrad = src->ngrad;
-    dst->nhess = src->nhess;
-    dst->ncholesky = src->ncholesky;
     return ae_true;
 }
 
 
-void _minlmreport_clear(minlmreport* p)
+void _mincgreport_clear(mincgreport* p)
 {
 }
 
@@ -7574,261 +7696,647 @@ void _minlmreport_clear(minlmreport* p)
 
 
 /*************************************************************************
-              NONLINEAR BOUND CONSTRAINED OPTIMIZATION USING
-                      MODIFIED ACTIVE SET ALGORITHM
-                   WILLIAM W. HAGER AND HONGCHAO ZHANG
+                     BOUND CONSTRAINED OPTIMIZATION
+       WITH ADDITIONAL LINEAR EQUALITY AND INEQUALITY CONSTRAINTS
 
 DESCRIPTION:
-The  subroutine  minimizes  function  F(x)  of  N  arguments  with   bound
-constraints: BndL[i] <= x[i] <= BndU[i]
+The  subroutine  minimizes  function   F(x)  of N arguments subject to any
+combination of:
+* bound constraints
+* linear inequality constraints
+* linear equality constraints
 
-This method is  globally  convergent  as  long  as  grad(f)  is  Lipschitz
-continuous on a level set: L = { x : f(x)<=f(x0) }.
+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:
 
-REQUIREMENTS:
-Algorithm will request following information during its operation:
-* function value F and its gradient G (simultaneously) at given point X
+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
 
-USAGE:
-1. User initializes algorithm state with MinASACreate() call
-2. User tunes solver parameters with MinASASetCond() MinASASetStpMax() and
-   other functions
-3. User calls MinASAOptimize() function which takes algorithm  state   and
+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.
-4. User calls MinASAResults() to get solution
-5. Optionally, user may call MinASARestartFrom() to solve another  problem
-   with same N but another starting point and/or another function.
-   MinASARestartFrom() allows to reuse already initialized structure.
+
+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 sizes of
-                  X/BndL/BndU.
-    X       -   starting point, array[0..N-1].
-    BndL    -   lower bounds, array[0..N-1].
-                all elements MUST be specified,  i.e.  all  variables  are
-                bounded. However, if some (all) variables  are  unbounded,
-                you may specify very small number as bound: -1000,  -1.0E6
-                or -1.0E300, or something like that.
-    BndU    -   upper bounds, array[0..N-1].
-                all elements MUST be specified,  i.e.  all  variables  are
-                bounded. However, if some (all) variables  are  unbounded,
-                you may specify very large number as bound: +1000,  +1.0E6
-                or +1.0E300, or something like that.
+                * 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
 
-NOTES:
-
-1. you may tune stopping conditions with MinASASetCond() function
-2. if target function contains exp() or other fast growing functions,  and
-   optimization algorithm makes too large steps which leads  to  overflow,
-   use MinASASetStpMax() function to bound algorithm's steps.
-3. this function does NOT support infinite/NaN values in X, BndL, BndU.
-
   -- ALGLIB --
-     Copyright 25.03.2010 by Bochkanov Sergey
+     Copyright 28.11.2010 by Bochkanov Sergey
 *************************************************************************/
-void minasacreate(ae_int_t n,
+void minbleiccreate(ae_int_t n,
      /* Real    */ ae_vector* x,
-     /* Real    */ ae_vector* bndl,
-     /* Real    */ ae_vector* bndu,
-     minasastate* state,
+     minbleicstate* state,
      ae_state *_state)
 {
-    ae_int_t i;
+    ae_frame _frame_block;
+    ae_matrix c;
+    ae_vector ct;
 
-    _minasastate_clear(state);
+    ae_frame_make(_state, &_frame_block);
+    _minbleicstate_clear(state);
+    ae_matrix_init(&c, 0, 0, DT_REAL, _state, ae_true);
+    ae_vector_init(&ct, 0, DT_INT, _state, ae_true);
 
-    ae_assert(n>=1, "MinASA: N too small!", _state);
-    ae_assert(x->cnt>=n, "MinCGCreate: Length(X)<N!", _state);
-    ae_assert(isfinitevector(x, n, _state), "MinCGCreate: X contains infinite or NaN values!", _state);
-    ae_assert(bndl->cnt>=n, "MinCGCreate: Length(BndL)<N!", _state);
-    ae_assert(isfinitevector(bndl, n, _state), "MinCGCreate: BndL contains infinite or NaN values!", _state);
-    ae_assert(bndu->cnt>=n, "MinCGCreate: Length(BndU)<N!", _state);
-    ae_assert(isfinitevector(bndu, n, _state), "MinCGCreate: BndU contains infinite or NaN values!", _state);
-    for(i=0; i<=n-1; i++)
-    {
-        ae_assert(ae_fp_less_eq(bndl->ptr.p_double[i],bndu->ptr.p_double[i]), "MinASA: inconsistent bounds!", _state);
-        ae_assert(ae_fp_less_eq(bndl->ptr.p_double[i],x->ptr.p_double[i]), "MinASA: infeasible X!", _state);
-        ae_assert(ae_fp_less_eq(x->ptr.p_double[i],bndu->ptr.p_double[i]), "MinASA: infeasible X!", _state);
-    }
-    
-    /*
-     * Initialize
-     */
-    state->n = n;
-    minasasetcond(state, 0, 0, 0, 0, _state);
-    minasasetxrep(state, ae_false, _state);
-    minasasetstpmax(state, 0, _state);
-    minasasetalgorithm(state, -1, _state);
-    ae_vector_set_length(&state->bndl, n, _state);
-    ae_vector_set_length(&state->bndu, n, _state);
-    ae_vector_set_length(&state->ak, n, _state);
-    ae_vector_set_length(&state->xk, n, _state);
-    ae_vector_set_length(&state->dk, n, _state);
-    ae_vector_set_length(&state->an, n, _state);
-    ae_vector_set_length(&state->xn, n, _state);
-    ae_vector_set_length(&state->dn, n, _state);
-    ae_vector_set_length(&state->x, n, _state);
-    ae_vector_set_length(&state->d, n, _state);
-    ae_vector_set_length(&state->g, n, _state);
-    ae_vector_set_length(&state->gc, n, _state);
-    ae_vector_set_length(&state->work, n, _state);
-    ae_vector_set_length(&state->yk, n, _state);
-    minasarestartfrom(state, x, bndl, bndu, _state);
+    ae_assert(n>=1, "MinBLEICCreate: N<1", _state);
+    ae_assert(x->cnt>=n, "MinBLEICCreate: Length(X)<N", _state);
+    ae_assert(isfinitevector(x, n, _state), "MinBLEICCreate: X contains infinite or NaN values!", _state);
+    minbleic_minbleicinitinternal(n, x, 0.0, state, _state);
+    ae_frame_leave(_state);
 }
 
 
 /*************************************************************************
-This function sets stopping conditions for the ASA optimization algorithm.
+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
-    EpsG    -   >=0
-                The  subroutine  finishes  its  work   if   the  condition
-                ||G||<EpsG is satisfied, where ||.|| means Euclidian norm,
-                G - gradient.
-    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 |X(k+1)-X(k)| <= EpsX is fulfilled.
-    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).
+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.
 
   -- ALGLIB --
-     Copyright 02.04.2010 by Bochkanov Sergey
+     Copyright 16.05.2011 by Bochkanov Sergey
 *************************************************************************/
-void minasasetcond(minasastate* state,
-     double epsg,
-     double epsf,
-     double epsx,
-     ae_int_t maxits,
+void minbleiccreatef(ae_int_t n,
+     /* Real    */ ae_vector* x,
+     double diffstep,
+     minbleicstate* state,
      ae_state *_state)
 {
+    ae_frame _frame_block;
+    ae_matrix c;
+    ae_vector ct;
 
+    ae_frame_make(_state, &_frame_block);
+    _minbleicstate_clear(state);
+    ae_matrix_init(&c, 0, 0, DT_REAL, _state, ae_true);
+    ae_vector_init(&ct, 0, DT_INT, _state, ae_true);
 
-    ae_assert(ae_isfinite(epsg, _state), "MinASASetCond: EpsG is not finite number!", _state);
-    ae_assert(ae_fp_greater_eq(epsg,0), "MinASASetCond: negative EpsG!", _state);
-    ae_assert(ae_isfinite(epsf, _state), "MinASASetCond: EpsF is not finite number!", _state);
-    ae_assert(ae_fp_greater_eq(epsf,0), "MinASASetCond: negative EpsF!", _state);
-    ae_assert(ae_isfinite(epsx, _state), "MinASASetCond: EpsX is not finite number!", _state);
-    ae_assert(ae_fp_greater_eq(epsx,0), "MinASASetCond: negative EpsX!", _state);
-    ae_assert(maxits>=0, "MinASASetCond: negative MaxIts!", _state);
-    if( ((ae_fp_eq(epsg,0)&&ae_fp_eq(epsf,0))&&ae_fp_eq(epsx,0))&&maxits==0 )
-    {
-        epsx = 1.0E-6;
-    }
-    state->epsg = epsg;
-    state->epsf = epsf;
-    state->epsx = epsx;
-    state->maxits = maxits;
+    ae_assert(n>=1, "MinBLEICCreateF: N<1", _state);
+    ae_assert(x->cnt>=n, "MinBLEICCreateF: Length(X)<N", _state);
+    ae_assert(isfinitevector(x, n, _state), "MinBLEICCreateF: X contains infinite or NaN values!", _state);
+    ae_assert(ae_isfinite(diffstep, _state), "MinBLEICCreateF: DiffStep is infinite or NaN!", _state);
+    ae_assert(ae_fp_greater(diffstep,0), "MinBLEICCreateF: DiffStep is non-positive!", _state);
+    minbleic_minbleicinitinternal(n, x, diffstep, state, _state);
+    ae_frame_leave(_state);
 }
 
 
 /*************************************************************************
-This function turns on/off reporting.
+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 which stores algorithm state
-    NeedXRep-   whether iteration reports are needed or not
+    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.
 
-If NeedXRep is True, algorithm will call rep() callback function if  it is
-provided to MinASAOptimize().
+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)
 
   -- ALGLIB --
-     Copyright 02.04.2010 by Bochkanov Sergey
+     Copyright 28.11.2010 by Bochkanov Sergey
 *************************************************************************/
-void minasasetxrep(minasastate* state, ae_bool needxrep, ae_state *_state)
+void minbleicsetbc(minbleicstate* state,
+     /* Real    */ ae_vector* bndl,
+     /* Real    */ ae_vector* bndu,
+     ae_state *_state)
 {
+    ae_int_t i;
+    ae_int_t n;
 
 
-    state->xrep = needxrep;
+    n = state->nmain;
+    ae_assert(bndl->cnt>=n, "MinBLEICSetBC: Length(BndL)<N", _state);
+    ae_assert(bndu->cnt>=n, "MinBLEICSetBC: Length(BndU)<N", _state);
+    for(i=0; i<=n-1; i++)
+    {
+        ae_assert(ae_isfinite(bndl->ptr.p_double[i], _state)||ae_isneginf(bndl->ptr.p_double[i], _state), "MinBLEICSetBC: BndL contains NAN or +INF", _state);
+        ae_assert(ae_isfinite(bndu->ptr.p_double[i], _state)||ae_isposinf(bndu->ptr.p_double[i], _state), "MinBLEICSetBC: BndL contains NAN or -INF", _state);
+        state->bndloriginal.ptr.p_double[i] = bndl->ptr.p_double[i];
+        state->hasbndl.ptr.p_bool[i] = ae_isfinite(bndl->ptr.p_double[i], _state);
+        state->bnduoriginal.ptr.p_double[i] = bndu->ptr.p_double[i];
+        state->hasbndu.ptr.p_bool[i] = ae_isfinite(bndu->ptr.p_double[i], _state);
+    }
 }
 
 
 /*************************************************************************
-This function sets optimization algorithm.
+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 which stores algorithm stat
-    UAType  -   algorithm type:
-                * -1    automatic selection of the best algorithm
-                * 0     DY (Dai and Yuan) algorithm
-                * 1     Hybrid DY-HS algorithm
+    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).
 
   -- ALGLIB --
-     Copyright 02.04.2010 by Bochkanov Sergey
+     Copyright 28.11.2010 by Bochkanov Sergey
 *************************************************************************/
-void minasasetalgorithm(minasastate* state,
-     ae_int_t algotype,
+void minbleicsetlc(minbleicstate* state,
+     /* Real    */ ae_matrix* c,
+     /* Integer */ ae_vector* ct,
+     ae_int_t k,
      ae_state *_state)
 {
+    ae_int_t nmain;
+    ae_int_t i;
 
 
-    ae_assert(algotype>=-1&&algotype<=1, "MinASASetAlgorithm: incorrect AlgoType!", _state);
-    if( algotype==-1 )
+    nmain = state->nmain;
+    
+    /*
+     * First, check for errors in the inputs
+     */
+    ae_assert(k>=0, "MinBLEICSetLC: K<0", _state);
+    ae_assert(c->cols>=nmain+1||k==0, "MinBLEICSetLC: Cols(C)<N+1", _state);
+    ae_assert(c->rows>=k, "MinBLEICSetLC: Rows(C)<K", _state);
+    ae_assert(ct->cnt>=k, "MinBLEICSetLC: Length(CT)<K", _state);
+    ae_assert(apservisfinitematrix(c, k, nmain+1, _state), "MinBLEICSetLC: C contains infinite or NaN values!", _state);
+    
+    /*
+     * Determine number of constraints,
+     * allocate space and copy
+     */
+    state->cecnt = k;
+    rmatrixsetlengthatleast(&state->ceoriginal, state->cecnt, nmain+1, _state);
+    ivectorsetlengthatleast(&state->ct, state->cecnt, _state);
+    for(i=0; i<=k-1; i++)
     {
-        algotype = 1;
+        state->ct.ptr.p_int[i] = ct->ptr.p_int[i];
+        ae_v_move(&state->ceoriginal.ptr.pp_double[i][0], 1, &c->ptr.pp_double[i][0], 1, ae_v_len(0,nmain));
     }
-    state->cgtype = algotype;
 }
 
 
 /*************************************************************************
-This function sets maximum step length
+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
-    StpMax  -   maximum step length, >=0. Set StpMax to 0.0,  if you don't
-                want to limit step length (zero by default).
-
-Use this subroutine when you optimize target function which contains exp()
+    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.
+
+  -- ALGLIB --
+     Copyright 28.11.2010 by Bochkanov Sergey
+*************************************************************************/
+void minbleicsetinnercond(minbleicstate* state,
+     double epsg,
+     double epsf,
+     double epsx,
+     ae_state *_state)
+{
+
+
+    ae_assert(ae_isfinite(epsg, _state), "MinBLEICSetInnerCond: EpsG is not finite number", _state);
+    ae_assert(ae_fp_greater_eq(epsg,0), "MinBLEICSetInnerCond: negative EpsG", _state);
+    ae_assert(ae_isfinite(epsf, _state), "MinBLEICSetInnerCond: EpsF is not finite number", _state);
+    ae_assert(ae_fp_greater_eq(epsf,0), "MinBLEICSetInnerCond: negative EpsF", _state);
+    ae_assert(ae_isfinite(epsx, _state), "MinBLEICSetInnerCond: EpsX is not finite number", _state);
+    ae_assert(ae_fp_greater_eq(epsx,0), "MinBLEICSetInnerCond: negative EpsX", _state);
+    state->innerepsg = epsg;
+    state->innerepsf = epsf;
+    state->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.
+
+  -- ALGLIB --
+     Copyright 28.11.2010 by Bochkanov Sergey
+*************************************************************************/
+void minbleicsetoutercond(minbleicstate* state,
+     double epsx,
+     double epsi,
+     ae_state *_state)
+{
+
+
+    ae_assert(ae_isfinite(epsx, _state), "MinBLEICSetOuterCond: EpsX is not finite number", _state);
+    ae_assert(ae_fp_greater(epsx,0), "MinBLEICSetOuterCond: non-positive EpsX", _state);
+    ae_assert(ae_isfinite(epsi, _state), "MinBLEICSetOuterCond: EpsI is not finite number", _state);
+    ae_assert(ae_fp_greater(epsi,0), "MinBLEICSetOuterCond: non-positive EpsI", _state);
+    state->outerepsx = epsx;
+    state->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.
+
+  -- ALGLIB --
+     Copyright 14.01.2011 by Bochkanov Sergey
+*************************************************************************/
+void minbleicsetscale(minbleicstate* state,
+     /* Real    */ ae_vector* s,
+     ae_state *_state)
+{
+    ae_int_t i;
+
+
+    ae_assert(s->cnt>=state->nmain, "MinBLEICSetScale: Length(S)<N", _state);
+    for(i=0; i<=state->nmain-1; i++)
+    {
+        ae_assert(ae_isfinite(s->ptr.p_double[i], _state), "MinBLEICSetScale: S contains infinite or NAN elements", _state);
+        ae_assert(ae_fp_neq(s->ptr.p_double[i],0), "MinBLEICSetScale: S contains zero elements", _state);
+        state->soriginal.ptr.p_double[i] = ae_fabs(s->ptr.p_double[i], _state);
+    }
+}
+
+
+/*************************************************************************
+Modification of the preconditioner: preconditioning is turned off.
+
+INPUT PARAMETERS:
+    State   -   structure which stores algorithm state
+
+  -- ALGLIB --
+     Copyright 13.10.2010 by Bochkanov Sergey
+*************************************************************************/
+void minbleicsetprecdefault(minbleicstate* state, ae_state *_state)
+{
+
+
+    state->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.
+
+  -- ALGLIB --
+     Copyright 13.10.2010 by Bochkanov Sergey
+*************************************************************************/
+void minbleicsetprecdiag(minbleicstate* state,
+     /* Real    */ ae_vector* d,
+     ae_state *_state)
+{
+    ae_int_t i;
+
+
+    ae_assert(d->cnt>=state->nmain, "MinBLEICSetPrecDiag: D is too short", _state);
+    for(i=0; i<=state->nmain-1; i++)
+    {
+        ae_assert(ae_isfinite(d->ptr.p_double[i], _state), "MinBLEICSetPrecDiag: D contains infinite or NAN elements", _state);
+        ae_assert(ae_fp_greater(d->ptr.p_double[i],0), "MinBLEICSetPrecDiag: D contains non-positive elements", _state);
+    }
+    rvectorsetlengthatleast(&state->diaghoriginal, state->nmain, _state);
+    state->prectype = 2;
+    for(i=0; i<=state->nmain-1; i++)
+    {
+        state->diaghoriginal.ptr.p_double[i] = d->ptr.p_double[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
+
+  -- ALGLIB --
+     Copyright 13.10.2010 by Bochkanov Sergey
+*************************************************************************/
+void minbleicsetprecscale(minbleicstate* state, ae_state *_state)
+{
+
+
+    state->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.
+
+  -- ALGLIB --
+     Copyright 28.11.2010 by Bochkanov Sergey
+*************************************************************************/
+void minbleicsetmaxits(minbleicstate* state,
+     ae_int_t maxits,
+     ae_state *_state)
+{
+
+
+    ae_assert(maxits>=0, "MinBLEICSetMaxIts: negative MaxIts!", _state);
+    state->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().
+
+  -- ALGLIB --
+     Copyright 28.11.2010 by Bochkanov Sergey
+*************************************************************************/
+void minbleicsetxrep(minbleicstate* state,
+     ae_bool needxrep,
+     ae_state *_state)
+{
+
+
+    state->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  leads  to overflow. This function allows us to reject
+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.
 
   -- ALGLIB --
      Copyright 02.04.2010 by Bochkanov Sergey
 *************************************************************************/
-void minasasetstpmax(minasastate* state, double stpmax, ae_state *_state)
+void minbleicsetstpmax(minbleicstate* state,
+     double stpmax,
+     ae_state *_state)
 {
 
 
-    ae_assert(ae_isfinite(stpmax, _state), "MinASASetStpMax: StpMax is not finite!", _state);
-    ae_assert(ae_fp_greater_eq(stpmax,0), "MinASASetStpMax: StpMax<0!", _state);
+    ae_assert(ae_isfinite(stpmax, _state), "MinBLEICSetStpMax: StpMax is not finite!", _state);
+    ae_assert(ae_fp_greater_eq(stpmax,0), "MinBLEICSetStpMax: StpMax<0!", _state);
     state->stpmax = stpmax;
 }
 
 
 /*************************************************************************
+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.
 
   -- ALGLIB --
-     Copyright 20.03.2009 by Bochkanov Sergey
+     Copyright 28.11.2010 by Bochkanov Sergey
 *************************************************************************/
-ae_bool minasaiteration(minasastate* state, ae_state *_state)
+ae_bool minbleiciteration(minbleicstate* state, ae_state *_state)
 {
-    ae_int_t n;
+    ae_int_t nmain;
+    ae_int_t nslack;
+    ae_int_t m;
     ae_int_t i;
-    double betak;
+    ae_int_t j;
     double v;
     double vv;
-    ae_int_t mcinfo;
     ae_bool b;
-    ae_bool stepfound;
-    ae_int_t diffcnt;
     ae_bool result;
 
 
@@ -7845,27 +8353,25 @@ ae_bool minasaiteration(minasastate* state, ae_state *_state)
      */
     if( state->rstate.stage>=0 )
     {
-        n = state->rstate.ia.ptr.p_int[0];
-        i = state->rstate.ia.ptr.p_int[1];
-        mcinfo = state->rstate.ia.ptr.p_int[2];
-        diffcnt = state->rstate.ia.ptr.p_int[3];
+        nmain = state->rstate.ia.ptr.p_int[0];
+        nslack = state->rstate.ia.ptr.p_int[1];
+        m = state->rstate.ia.ptr.p_int[2];
+        i = state->rstate.ia.ptr.p_int[3];
+        j = state->rstate.ia.ptr.p_int[4];
         b = state->rstate.ba.ptr.p_bool[0];
-        stepfound = state->rstate.ba.ptr.p_bool[1];
-        betak = state->rstate.ra.ptr.p_double[0];
-        v = state->rstate.ra.ptr.p_double[1];
-        vv = state->rstate.ra.ptr.p_double[2];
+        v = state->rstate.ra.ptr.p_double[0];
+        vv = state->rstate.ra.ptr.p_double[1];
     }
     else
     {
-        n = -983;
-        i = -989;
-        mcinfo = -834;
-        diffcnt = 900;
-        b = ae_true;
-        stepfound = ae_false;
-        betak = 214;
-        v = -338;
-        vv = -686;
+        nmain = -983;
+        nslack = -989;
+        m = -834;
+        i = 900;
+        j = -287;
+        b = ae_false;
+        v = 214;
+        vv = -338;
     }
     if( state->rstate.stage==0 )
     {
@@ -7919,1180 +8425,1663 @@ ae_bool minasaiteration(minasastate* state, ae_state *_state)
     {
         goto lbl_12;
     }
-    if( state->rstate.stage==13 )
-    {
-        goto lbl_13;
-    }
-    if( state->rstate.stage==14 )
-    {
-        goto lbl_14;
-    }
     
     /*
      * Routine body
      */
     
     /*
-     * Prepare
+     * Prepare:
+     * * calculate number of slack variables
+     * * initialize locals
+     * * initialize debug fields
+     * * make quick check
      */
-    n = state->n;
-    state->repterminationtype = 0;
-    state->repiterationscount = 0;
-    state->repnfev = 0;
-    state->debugrestartscount = 0;
-    state->cgtype = 1;
-    ae_v_move(&state->xk.ptr.p_double[0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    for(i=0; i<=n-1; i++)
+    nmain = state->nmain;
+    nslack = 0;
+    for(i=0; i<=state->cecnt-1; i++)
     {
-        if( ae_fp_eq(state->xk.ptr.p_double[i],state->bndl.ptr.p_double[i])||ae_fp_eq(state->xk.ptr.p_double[i],state->bndu.ptr.p_double[i]) )
-        {
-            state->ak.ptr.p_double[i] = 0;
-        }
-        else
+        if( state->ct.ptr.p_int[i]!=0 )
         {
-            state->ak.ptr.p_double[i] = 1;
+            nslack = nslack+1;
         }
     }
-    state->mu = 0.1;
-    state->curalgo = 0;
-    
-    /*
-     * Calculate F/G, initialize algorithm
-     */
-    minasa_clearrequestfields(state, _state);
-    state->needfg = ae_true;
-    state->rstate.stage = 0;
-    goto lbl_rcomm;
-lbl_0:
-    state->needfg = ae_false;
-    if( !state->xrep )
+    state->nslack = nslack;
+    state->repterminationtype = 0;
+    state->repinneriterationscount = 0;
+    state->repouteriterationscount = 0;
+    state->repnfev = 0;
+    state->repdebugeqerr = 0.0;
+    state->repdebugfs = _state->v_nan;
+    state->repdebugff = _state->v_nan;
+    state->repdebugdx = _state->v_nan;
+    if( ae_fp_neq(state->stpmax,0)&&state->prectype!=0 )
     {
-        goto lbl_15;
+        state->repterminationtype = -10;
+        result = ae_false;
+        return result;
     }
     
     /*
-     * progress report
+     * allocate
      */
-    minasa_clearrequestfields(state, _state);
-    state->xupdated = ae_true;
-    state->rstate.stage = 1;
-    goto lbl_rcomm;
-lbl_1:
-    state->xupdated = ae_false;
-lbl_15:
-    if( ae_fp_less_eq(minasa_asaboundedantigradnorm(state, _state),state->epsg) )
-    {
-        state->repterminationtype = 4;
-        result = ae_false;
-        return result;
-    }
-    state->repnfev = state->repnfev+1;
+    rvectorsetlengthatleast(&state->r, nmain+nslack, _state);
+    rvectorsetlengthatleast(&state->diagh, nmain+nslack, _state);
+    rvectorsetlengthatleast(&state->tmp0, nmain+nslack, _state);
+    rvectorsetlengthatleast(&state->tmp1, nmain+nslack, _state);
+    rvectorsetlengthatleast(&state->tmp2, nmain+nslack, _state);
+    rmatrixsetlengthatleast(&state->cecurrent, state->cecnt, nmain+nslack+1, _state);
+    bvectorsetlengthatleast(&state->activeconstraints, nmain+nslack, _state);
+    rvectorsetlengthatleast(&state->constrainedvalues, nmain+nslack, _state);
+    rvectorsetlengthatleast(&state->lastg, nmain+nslack, _state);
+    rvectorsetlengthatleast(&state->xe, nmain+nslack, _state);
+    rvectorsetlengthatleast(&state->xcur, nmain+nslack, _state);
+    rvectorsetlengthatleast(&state->xprev, nmain+nslack, _state);
+    rvectorsetlengthatleast(&state->xend, nmain, _state);
     
     /*
-     * Main cycle
+     * Create/restart optimizer.
      *
-     * 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
+     * State.OptDim is used to determine current state of optimizer.
      */
-lbl_17:
-    if( ae_false )
+    if( state->optdim!=nmain+nslack )
     {
-        goto lbl_18;
+        for(i=0; i<=nmain+nslack-1; i++)
+        {
+            state->tmp1.ptr.p_double[i] = 0.0;
+        }
+        mincgcreate(nmain+nslack, &state->tmp1, &state->cgstate, _state);
+        state->optdim = nmain+nslack;
     }
     
     /*
-     * GPA algorithm
+     * 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]
      */
-    if( state->curalgo!=0 )
+    rvectorsetlengthatleast(&state->transforms, nmain, _state);
+    for(i=0; i<=nmain-1; i++)
     {
-        goto lbl_19;
+        if( state->prectype==2 )
+        {
+            state->transforms.ptr.p_double[i] = 1/ae_sqrt(state->diaghoriginal.ptr.p_double[i], _state);
+            continue;
+        }
+        if( state->prectype==3 )
+        {
+            state->transforms.ptr.p_double[i] = state->soriginal.ptr.p_double[i];
+            continue;
+        }
+        state->transforms.ptr.p_double[i] = 1;
     }
-    state->k = 0;
-    state->acount = 0;
-lbl_21:
-    if( ae_false )
+    rvectorsetlengthatleast(&state->seffective, nmain+nslack, _state);
+    for(i=0; i<=nmain-1; i++)
     {
-        goto lbl_22;
+        state->seffective.ptr.p_double[i] = state->soriginal.ptr.p_double[i]/state->transforms.ptr.p_double[i];
+    }
+    for(i=0; i<=nslack-1; i++)
+    {
+        state->seffective.ptr.p_double[nmain+i] = 1;
     }
+    mincgsetscale(&state->cgstate, &state->seffective, _state);
     
     /*
-     * Determine Dk = proj(xk - gk)-xk
+     * 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<=n-1; i++)
+    for(i=0; i<=nmain-1; i++)
     {
-        state->d.ptr.p_double[i] = boundval(state->xk.ptr.p_double[i]-state->g.ptr.p_double[i], state->bndl.ptr.p_double[i], state->bndu.ptr.p_double[i], _state)-state->xk.ptr.p_double[i];
+        if( state->hasbndl.ptr.p_bool[i] )
+        {
+            state->bndleffective.ptr.p_double[i] = state->bndloriginal.ptr.p_double[i]/state->transforms.ptr.p_double[i];
+        }
+        if( state->hasbndu.ptr.p_bool[i] )
+        {
+            state->bndueffective.ptr.p_double[i] = state->bnduoriginal.ptr.p_double[i]/state->transforms.ptr.p_double[i];
+        }
+    }
+    for(i=0; i<=nmain-1; i++)
+    {
+        if( state->hasbndl.ptr.p_bool[i]&&state->hasbndu.ptr.p_bool[i] )
+        {
+            if( ae_fp_greater(state->bndleffective.ptr.p_double[i],state->bndueffective.ptr.p_double[i]) )
+            {
+                state->repterminationtype = -3;
+                result = ae_false;
+                return result;
+            }
+        }
+    }
+    rmatrixsetlengthatleast(&state->ceeffective, state->cecnt, nmain+nslack+1, _state);
+    m = 0;
+    for(i=0; i<=state->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->ceeffective.ptr.pp_double[i][j] = state->ceoriginal.ptr.pp_double[i][j]*state->transforms.ptr.p_double[j];
+            v = ae_maxreal(v, ae_fabs(state->ceeffective.ptr.pp_double[i][j], _state), _state);
+        }
+        if( ae_fp_eq(v,0) )
+        {
+            v = 1;
+        }
+        for(j=0; j<=nslack-1; j++)
+        {
+            state->ceeffective.ptr.pp_double[i][nmain+j] = 0.0;
+        }
+        state->ceeffective.ptr.pp_double[i][nmain+nslack] = state->ceoriginal.ptr.pp_double[i][nmain];
+        if( state->ct.ptr.p_int[i]<0 )
+        {
+            state->ceeffective.ptr.pp_double[i][nmain+m] = v;
+            m = m+1;
+        }
+        if( state->ct.ptr.p_int[i]>0 )
+        {
+            state->ceeffective.ptr.pp_double[i][nmain+m] = -v;
+            m = m+1;
+        }
     }
     
     /*
-     * 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.
+     * Find feasible point.
      *
-     * 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.
+     * 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.
      */
-    v = ae_v_dotproduct(&state->d.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    state->dginit = v;
-    state->finit = state->f;
-    if( !(ae_fp_less_eq(minasa_asad1norm(state, _state),state->stpmax)||ae_fp_eq(state->stpmax,0)) )
+    for(i=0; i<=nmain-1; i++)
     {
-        goto lbl_23;
+        state->tmp0.ptr.p_double[i] = state->xstart.ptr.p_double[i]/state->transforms.ptr.p_double[i];
+    }
+    m = 0;
+    for(i=0; i<=state->cecnt-1; i++)
+    {
+        v = ae_v_dotproduct(&state->ceeffective.ptr.pp_double[i][0], 1, &state->tmp0.ptr.p_double[0], 1, ae_v_len(0,nmain-1));
+        if( state->ct.ptr.p_int[i]<0 )
+        {
+            state->tmp0.ptr.p_double[nmain+m] = state->ceeffective.ptr.pp_double[i][nmain+nslack]-v;
+            m = m+1;
+        }
+        if( state->ct.ptr.p_int[i]>0 )
+        {
+            state->tmp0.ptr.p_double[nmain+m] = v-state->ceeffective.ptr.pp_double[i][nmain+nslack];
+            m = m+1;
+        }
+    }
+    for(i=0; i<=nmain+nslack-1; i++)
+    {
+        state->tmp1.ptr.p_double[i] = 0;
+    }
+    for(i=0; i<=nmain+nslack-1; i++)
+    {
+        state->activeconstraints.ptr.p_bool[i] = ae_false;
+    }
+    b = minbleic_prepareconstraintmatrix(state, &state->tmp0, &state->tmp1, &state->xcur, &state->tmp2, _state);
+    state->repdebugeqerr = 0.0;
+    for(i=0; i<=state->cecnt-1; i++)
+    {
+        v = ae_v_dotproduct(&state->ceeffective.ptr.pp_double[i][0], 1, &state->xcur.ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1));
+        state->repdebugeqerr = state->repdebugeqerr+ae_sqr(v-state->ceeffective.ptr.pp_double[i][nmain+nslack], _state);
+    }
+    state->repdebugeqerr = ae_sqrt(state->repdebugeqerr, _state);
+    if( !b )
+    {
+        state->repterminationtype = -3;
+        result = ae_false;
+        return result;
     }
     
     /*
-     * Try alpha=1 step first
+     * Initialize RepDebugFS with function value at initial point
      */
-    for(i=0; i<=n-1; i++)
+    minbleic_unscalepoint(state, &state->xcur, &state->x, _state);
+    minbleic_clearrequestfields(state, _state);
+    if( ae_fp_neq(state->diffstep,0) )
     {
-        state->x.ptr.p_double[i] = boundval(state->xk.ptr.p_double[i]-state->g.ptr.p_double[i], state->bndl.ptr.p_double[i], state->bndu.ptr.p_double[i], _state);
+        goto lbl_13;
     }
-    minasa_clearrequestfields(state, _state);
     state->needfg = ae_true;
-    state->rstate.stage = 2;
+    state->rstate.stage = 0;
     goto lbl_rcomm;
-lbl_2:
+lbl_0:
     state->needfg = ae_false;
+    goto lbl_14;
+lbl_13:
+    state->needf = ae_true;
+    state->rstate.stage = 1;
+    goto lbl_rcomm;
+lbl_1:
+    state->needf = ae_false;
+lbl_14:
+    trimprepare(state->f, &state->trimthreshold, _state);
     state->repnfev = state->repnfev+1;
-    stepfound = ae_fp_less_eq(state->f,state->finit+minasa_gpaftol*state->dginit);
-    goto lbl_24;
-lbl_23:
-    stepfound = ae_false;
-lbl_24:
-    if( !stepfound )
-    {
-        goto lbl_25;
-    }
+    state->repdebugfs = state->f;
     
     /*
-     * we are at the boundary(ies)
+     * Outer cycle
      */
-    ae_v_move(&state->xn.ptr.p_double[0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    state->stp = 1;
-    goto lbl_26;
-lbl_25:
+    state->itsleft = state->maxits;
+    ae_v_move(&state->xprev.ptr.p_double[0], 1, &state->xcur.ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1));
+lbl_15:
+    if( ae_false )
+    {
+        goto lbl_16;
+    }
+    ae_assert(state->prectype==0||ae_fp_eq(state->stpmax,0), "MinBLEIC: internal error (-10)", _state);
     
     /*
-     * alpha=1 is too large, try smaller values
+     * Inner cycle: CG with projections and penalty functions
      */
-    state->stp = 1;
-    linminnormalized(&state->d, &state->stp, n, _state);
-    state->dginit = state->dginit/state->stp;
-    state->stp = minasa_gpadecay*state->stp;
-    if( ae_fp_greater(state->stpmax,0) )
-    {
-        state->stp = ae_minreal(state->stp, state->stpmax, _state);
-    }
-lbl_27:
-    if( ae_false )
+    ae_v_move(&state->tmp0.ptr.p_double[0], 1, &state->xcur.ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1));
+    for(i=0; i<=nmain+nslack-1; i++)
     {
-        goto lbl_28;
+        state->tmp1.ptr.p_double[i] = 0;
+        state->activeconstraints.ptr.p_bool[i] = ae_false;
     }
-    v = state->stp;
-    ae_v_move(&state->x.ptr.p_double[0], 1, &state->xk.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    ae_v_addd(&state->x.ptr.p_double[0], 1, &state->d.ptr.p_double[0], 1, ae_v_len(0,n-1), v);
-    minasa_clearrequestfields(state, _state);
-    state->needfg = ae_true;
-    state->rstate.stage = 3;
-    goto lbl_rcomm;
-lbl_3:
-    state->needfg = ae_false;
-    state->repnfev = state->repnfev+1;
-    if( ae_fp_less_eq(state->stp,minasa_stpmin) )
+    if( !minbleic_prepareconstraintmatrix(state, &state->tmp0, &state->tmp1, &state->xcur, &state->tmp2, _state) )
     {
-        goto lbl_28;
+        state->repterminationtype = -3;
+        result = ae_false;
+        return result;
     }
-    if( ae_fp_less_eq(state->f,state->finit+state->stp*minasa_gpaftol*state->dginit) )
+    for(i=0; i<=nmain+nslack-1; i++)
     {
-        goto lbl_28;
+        state->activeconstraints.ptr.p_bool[i] = ae_false;
     }
-    state->stp = state->stp*minasa_gpadecay;
-    goto lbl_27;
-lbl_28:
-    ae_v_move(&state->xn.ptr.p_double[0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,n-1));
-lbl_26:
-    state->repiterationscount = state->repiterationscount+1;
-    if( !state->xrep )
+    minbleic_rebuildcexe(state, _state);
+    mincgrestartfrom(&state->cgstate, &state->xcur, _state);
+    mincgsetcond(&state->cgstate, state->innerepsg, state->innerepsf, state->innerepsx, state->itsleft, _state);
+    mincgsetxrep(&state->cgstate, state->xrep, _state);
+    mincgsetdrep(&state->cgstate, ae_true, _state);
+    mincgsetstpmax(&state->cgstate, state->stpmax, _state);
+lbl_17:
+    if( !mincgiteration(&state->cgstate, _state) )
     {
-        goto lbl_29;
+        goto lbl_18;
     }
     
     /*
-     * progress report
+     * process different requests/reports of inner optimizer
      */
-    minasa_clearrequestfields(state, _state);
-    state->xupdated = ae_true;
-    state->rstate.stage = 4;
-    goto lbl_rcomm;
-lbl_4:
-    state->xupdated = ae_false;
-lbl_29:
-    
-    /*
-     * 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++)
+    if( state->cgstate.algpowerup )
     {
-        if( ae_fp_eq(state->xn.ptr.p_double[i],state->bndl.ptr.p_double[i])||ae_fp_eq(state->xn.ptr.p_double[i],state->bndu.ptr.p_double[i]) )
+        for(i=0; i<=nmain+nslack-1; i++)
         {
-            state->an.ptr.p_double[i] = 0;
+            state->activeconstraints.ptr.p_bool[i] = ae_false;
         }
-        else
+        do
         {
-            state->an.ptr.p_double[i] = 1;
+            minbleic_rebuildcexe(state, _state);
+            ae_v_move(&state->tmp1.ptr.p_double[0], 1, &state->cgstate.g.ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1));
+            minbleic_makegradientprojection(state, &state->tmp1, _state);
+            b = ae_false;
+            for(i=0; i<=nmain-1; i++)
+            {
+                if( !state->activeconstraints.ptr.p_bool[i] )
+                {
+                    if( state->hasbndl.ptr.p_bool[i] )
+                    {
+                        if( ae_fp_eq(state->cgstate.x.ptr.p_double[i],state->bndleffective.ptr.p_double[i])&&ae_fp_greater_eq(state->tmp1.ptr.p_double[i],0) )
+                        {
+                            state->activeconstraints.ptr.p_bool[i] = ae_true;
+                            state->constrainedvalues.ptr.p_double[i] = state->bndleffective.ptr.p_double[i];
+                            b = ae_true;
+                        }
+                    }
+                    if( state->hasbndu.ptr.p_bool[i] )
+                    {
+                        if( ae_fp_eq(state->cgstate.x.ptr.p_double[i],state->bndueffective.ptr.p_double[i])&&ae_fp_less_eq(state->tmp1.ptr.p_double[i],0) )
+                        {
+                            state->activeconstraints.ptr.p_bool[i] = ae_true;
+                            state->constrainedvalues.ptr.p_double[i] = state->bndueffective.ptr.p_double[i];
+                            b = ae_true;
+                        }
+                    }
+                }
+            }
+            for(i=0; i<=nslack-1; i++)
+            {
+                if( !state->activeconstraints.ptr.p_bool[nmain+i] )
+                {
+                    if( ae_fp_eq(state->cgstate.x.ptr.p_double[nmain+i],0)&&ae_fp_greater_eq(state->tmp1.ptr.p_double[nmain+i],0) )
+                    {
+                        state->activeconstraints.ptr.p_bool[nmain+i] = ae_true;
+                        state->constrainedvalues.ptr.p_double[nmain+i] = 0;
+                        b = ae_true;
+                    }
+                }
+            }
         }
+        while(b);
+        ae_v_move(&state->cgstate.g.ptr.p_double[0], 1, &state->tmp1.ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1));
+        goto lbl_17;
     }
-    for(i=0; i<=n-1; i++)
+    if( state->cgstate.lsstart )
     {
-        if( ae_fp_neq(state->ak.ptr.p_double[i],state->an.ptr.p_double[i]) )
+        
+        /*
+         * Beginning of the line search: set upper limit on step size
+         * to prevent algo from leaving feasible area.
+         */
+        state->variabletofreeze = -1;
+        if( ae_fp_eq(state->cgstate.curstpmax,0) )
         {
-            state->acount = -1;
-            break;
+            state->cgstate.curstpmax = 1.0E50;
+        }
+        for(i=0; i<=nmain-1; i++)
+        {
+            if( state->hasbndl.ptr.p_bool[i]&&ae_fp_less(state->cgstate.d.ptr.p_double[i],0) )
+            {
+                v = state->cgstate.curstpmax;
+                vv = state->cgstate.x.ptr.p_double[i]-state->bndleffective.ptr.p_double[i];
+                if( ae_fp_less(vv,0) )
+                {
+                    vv = 0;
+                }
+                state->cgstate.curstpmax = safeminposrv(vv, -state->cgstate.d.ptr.p_double[i], state->cgstate.curstpmax, _state);
+                if( ae_fp_less(state->cgstate.curstpmax,v) )
+                {
+                    state->variabletofreeze = i;
+                    state->valuetofreeze = state->bndleffective.ptr.p_double[i];
+                }
+            }
+            if( state->hasbndu.ptr.p_bool[i]&&ae_fp_greater(state->cgstate.d.ptr.p_double[i],0) )
+            {
+                v = state->cgstate.curstpmax;
+                vv = state->bndueffective.ptr.p_double[i]-state->cgstate.x.ptr.p_double[i];
+                if( ae_fp_less(vv,0) )
+                {
+                    vv = 0;
+                }
+                state->cgstate.curstpmax = safeminposrv(vv, state->cgstate.d.ptr.p_double[i], state->cgstate.curstpmax, _state);
+                if( ae_fp_less(state->cgstate.curstpmax,v) )
+                {
+                    state->variabletofreeze = i;
+                    state->valuetofreeze = state->bndueffective.ptr.p_double[i];
+                }
+            }
+        }
+        for(i=0; i<=nslack-1; i++)
+        {
+            if( ae_fp_less(state->cgstate.d.ptr.p_double[nmain+i],0) )
+            {
+                v = state->cgstate.curstpmax;
+                vv = state->cgstate.x.ptr.p_double[nmain+i];
+                if( ae_fp_less(vv,0) )
+                {
+                    vv = 0;
+                }
+                state->cgstate.curstpmax = safeminposrv(vv, -state->cgstate.d.ptr.p_double[nmain+i], state->cgstate.curstpmax, _state);
+                if( ae_fp_less(state->cgstate.curstpmax,v) )
+                {
+                    state->variabletofreeze = nmain+i;
+                    state->valuetofreeze = 0;
+                }
+            }
+        }
+        if( ae_fp_eq(state->cgstate.curstpmax,0) )
+        {
+            state->activeconstraints.ptr.p_bool[state->variabletofreeze] = ae_true;
+            state->constrainedvalues.ptr.p_double[state->variabletofreeze] = state->valuetofreeze;
+            state->cgstate.x.ptr.p_double[state->variabletofreeze] = state->valuetofreeze;
+            state->cgstate.terminationneeded = ae_true;
         }
+        goto lbl_17;
     }
-    state->acount = state->acount+1;
-    ae_v_move(&state->xk.ptr.p_double[0], 1, &state->xn.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    ae_v_move(&state->ak.ptr.p_double[0], 1, &state->an.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    
-    /*
-     * Stopping conditions
-     */
-    if( !(state->repiterationscount>=state->maxits&&state->maxits>0) )
+    if( state->cgstate.lsend )
     {
-        goto lbl_31;
+        
+        /*
+         * Line search just finished.
+         * Maybe we should activate some constraints?
+         */
+        b = ae_fp_greater_eq(state->cgstate.stp,state->cgstate.curstpmax)&&state->variabletofreeze>=0;
+        if( b )
+        {
+            state->activeconstraints.ptr.p_bool[state->variabletofreeze] = ae_true;
+            state->constrainedvalues.ptr.p_double[state->variabletofreeze] = state->valuetofreeze;
+        }
+        
+        /*
+         * Additional activation of constraints
+         */
+        b = b||minbleic_additionalcheckforconstraints(state, &state->cgstate.x, _state);
+        
+        /*
+         * If at least one constraint was activated we have to rebuild constraint matrices
+         */
+        if( b )
+        {
+            ae_v_move(&state->tmp0.ptr.p_double[0], 1, &state->cgstate.x.ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1));
+            ae_v_move(&state->tmp1.ptr.p_double[0], 1, &state->lastg.ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1));
+            if( !minbleic_prepareconstraintmatrix(state, &state->tmp0, &state->tmp1, &state->cgstate.x, &state->cgstate.g, _state) )
+            {
+                state->repterminationtype = -3;
+                result = ae_false;
+                return result;
+            }
+            state->cgstate.innerresetneeded = ae_true;
+        }
+        goto lbl_17;
     }
-    
-    /*
-     * Too many iterations
-     */
-    state->repterminationtype = 5;
-    if( !state->xrep )
+    if( !state->cgstate.needfg )
     {
-        goto lbl_33;
+        goto lbl_19;
     }
-    minasa_clearrequestfields(state, _state);
-    state->xupdated = ae_true;
-    state->rstate.stage = 5;
+    ae_v_move(&state->tmp1.ptr.p_double[0], 1, &state->cgstate.x.ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1));
+    minbleic_projectpointandunscale(state, &state->tmp1, &state->x, &state->r, &vv, _state);
+    minbleic_clearrequestfields(state, _state);
+    if( ae_fp_neq(state->diffstep,0) )
+    {
+        goto lbl_21;
+    }
+    state->needfg = ae_true;
+    state->rstate.stage = 2;
     goto lbl_rcomm;
-lbl_5:
-    state->xupdated = ae_false;
-lbl_33:
-    result = ae_false;
-    return result;
-lbl_31:
-    if( ae_fp_greater(minasa_asaboundedantigradnorm(state, _state),state->epsg) )
+lbl_2:
+    state->needfg = ae_false;
+    goto lbl_22;
+lbl_21:
+    state->needf = ae_true;
+    state->rstate.stage = 3;
+    goto lbl_rcomm;
+lbl_3:
+    state->fbase = state->f;
+    i = 0;
+lbl_23:
+    if( i>nmain-1 )
     {
-        goto lbl_35;
+        goto lbl_25;
     }
-    
-    /*
-     * Gradient is small enough
-     */
-    state->repterminationtype = 4;
-    if( !state->xrep )
+    v = state->x.ptr.p_double[i];
+    b = ae_false;
+    if( state->hasbndl.ptr.p_bool[i] )
     {
-        goto lbl_37;
+        b = b||ae_fp_less(v-state->diffstep*state->soriginal.ptr.p_double[i],state->bndloriginal.ptr.p_double[i]);
     }
-    minasa_clearrequestfields(state, _state);
-    state->xupdated = ae_true;
-    state->rstate.stage = 6;
-    goto lbl_rcomm;
-lbl_6:
-    state->xupdated = ae_false;
-lbl_37:
-    result = ae_false;
-    return result;
-lbl_35:
-    v = ae_v_dotproduct(&state->d.ptr.p_double[0], 1, &state->d.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    if( ae_fp_greater(ae_sqrt(v, _state)*state->stp,state->epsx) )
+    if( state->hasbndu.ptr.p_bool[i] )
     {
-        goto lbl_39;
+        b = b||ae_fp_greater(v+state->diffstep*state->soriginal.ptr.p_double[i],state->bnduoriginal.ptr.p_double[i]);
     }
-    
-    /*
-     * Step size is too small, no further improvement is
-     * possible
-     */
-    state->repterminationtype = 2;
-    if( !state->xrep )
+    if( b )
     {
-        goto lbl_41;
+        goto lbl_26;
     }
-    minasa_clearrequestfields(state, _state);
-    state->xupdated = ae_true;
+    state->x.ptr.p_double[i] = v-state->diffstep*state->soriginal.ptr.p_double[i];
+    state->rstate.stage = 4;
+    goto lbl_rcomm;
+lbl_4:
+    state->fm2 = state->f;
+    state->x.ptr.p_double[i] = v-0.5*state->diffstep*state->soriginal.ptr.p_double[i];
+    state->rstate.stage = 5;
+    goto lbl_rcomm;
+lbl_5:
+    state->fm1 = state->f;
+    state->x.ptr.p_double[i] = v+0.5*state->diffstep*state->soriginal.ptr.p_double[i];
+    state->rstate.stage = 6;
+    goto lbl_rcomm;
+lbl_6:
+    state->fp1 = state->f;
+    state->x.ptr.p_double[i] = v+state->diffstep*state->soriginal.ptr.p_double[i];
     state->rstate.stage = 7;
     goto lbl_rcomm;
 lbl_7:
-    state->xupdated = ae_false;
-lbl_41:
-    result = ae_false;
-    return result;
-lbl_39:
-    if( ae_fp_greater(state->finit-state->f,state->epsf*ae_maxreal(ae_fabs(state->finit, _state), ae_maxreal(ae_fabs(state->f, _state), 1.0, _state), _state)) )
-    {
-        goto lbl_43;
-    }
-    
-    /*
-     * F(k+1)-F(k) is small enough
-     */
-    state->repterminationtype = 1;
-    if( !state->xrep )
-    {
-        goto lbl_45;
-    }
-    minasa_clearrequestfields(state, _state);
-    state->xupdated = ae_true;
+    state->fp2 = state->f;
+    state->g.ptr.p_double[i] = (8*(state->fp1-state->fm1)-(state->fp2-state->fm2))/(6*state->diffstep*state->soriginal.ptr.p_double[i]);
+    goto lbl_27;
+lbl_26:
+    state->xm1 = ae_maxreal(v-state->diffstep*state->soriginal.ptr.p_double[i], state->bndloriginal.ptr.p_double[i], _state);
+    state->x.ptr.p_double[i] = state->xm1;
     state->rstate.stage = 8;
     goto lbl_rcomm;
 lbl_8:
-    state->xupdated = ae_false;
-lbl_45:
-    result = ae_false;
-    return result;
-lbl_43:
-    
-    /*
-     * Decide - should we switch algorithm or not
-     */
-    if( minasa_asauisempty(state, _state) )
+    state->fm1 = state->f;
+    state->xp1 = ae_minreal(v+state->diffstep*state->soriginal.ptr.p_double[i], state->bnduoriginal.ptr.p_double[i], _state);
+    state->x.ptr.p_double[i] = state->xp1;
+    state->rstate.stage = 9;
+    goto lbl_rcomm;
+lbl_9:
+    state->fp1 = state->f;
+    state->g.ptr.p_double[i] = (state->fp1-state->fm1)/(state->xp1-state->xm1);
+lbl_27:
+    state->x.ptr.p_double[i] = v;
+    i = i+1;
+    goto lbl_23;
+lbl_25:
+    state->f = state->fbase;
+    state->needf = ae_false;
+lbl_22:
+    if( ae_fp_less(state->f,state->trimthreshold) )
     {
-        if( ae_fp_greater_eq(minasa_asaginorm(state, _state),state->mu*minasa_asad1norm(state, _state)) )
-        {
-            state->curalgo = 1;
-            goto lbl_22;
-        }
-        else
-        {
-            state->mu = state->mu*minasa_asarho;
-        }
+        
+        /*
+         * normal processing
+         */
+        state->cgstate.f = state->f;
+        minbleic_scalegradientandexpand(state, &state->g, &state->cgstate.g, _state);
+        ae_v_move(&state->lastg.ptr.p_double[0], 1, &state->cgstate.g.ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1));
+        minbleic_modifytargetfunction(state, &state->tmp1, &state->r, vv, &state->cgstate.f, &state->cgstate.g, &state->gnorm, &state->mpgnorm, _state);
     }
     else
     {
-        if( state->acount==minasa_n1 )
+        
+        /*
+         * function value is too high, trim it
+         */
+        state->cgstate.f = state->trimthreshold;
+        for(i=0; i<=nmain+nslack-1; i++)
         {
-            if( ae_fp_greater_eq(minasa_asaginorm(state, _state),state->mu*minasa_asad1norm(state, _state)) )
-            {
-                state->curalgo = 1;
-                goto lbl_22;
-            }
+            state->cgstate.g.ptr.p_double[i] = 0.0;
         }
     }
-    
-    /*
-     * Next iteration
-     */
-    state->k = state->k+1;
-    goto lbl_21;
-lbl_22:
+    goto lbl_17;
 lbl_19:
+    if( !state->cgstate.xupdated )
+    {
+        goto lbl_28;
+    }
     
     /*
-     * CG algorithm
+     * Report
      */
-    if( state->curalgo!=1 )
-    {
-        goto lbl_47;
-    }
+    minbleic_unscalepoint(state, &state->cgstate.x, &state->x, _state);
+    state->f = state->cgstate.f;
+    minbleic_clearrequestfields(state, _state);
+    state->xupdated = ae_true;
+    state->rstate.stage = 10;
+    goto lbl_rcomm;
+lbl_10:
+    state->xupdated = ae_false;
+    goto lbl_17;
+lbl_28:
+    goto lbl_17;
+lbl_18:
+    mincgresults(&state->cgstate, &state->xcur, &state->cgrep, _state);
+    minbleic_unscalepoint(state, &state->xcur, &state->xend, _state);
+    state->repinneriterationscount = state->repinneriterationscount+state->cgrep.iterationscount;
+    state->repouteriterationscount = state->repouteriterationscount+1;
+    state->repnfev = state->repnfev+state->cgrep.nfev;
     
     /*
-     * first, check that there are non-active constraints.
-     * move to GPA algorithm, if all constraints are active
+     * Update RepDebugFF with function value at current point
      */
-    b = ae_true;
-    for(i=0; i<=n-1; i++)
+    minbleic_unscalepoint(state, &state->xcur, &state->x, _state);
+    minbleic_clearrequestfields(state, _state);
+    if( ae_fp_neq(state->diffstep,0) )
     {
-        if( ae_fp_neq(state->ak.ptr.p_double[i],0) )
-        {
-            b = ae_false;
-            break;
-        }
-    }
-    if( b )
-    {
-        state->curalgo = 0;
-        goto lbl_17;
+        goto lbl_30;
     }
+    state->needfg = ae_true;
+    state->rstate.stage = 11;
+    goto lbl_rcomm;
+lbl_11:
+    state->needfg = ae_false;
+    goto lbl_31;
+lbl_30:
+    state->needf = ae_true;
+    state->rstate.stage = 12;
+    goto lbl_rcomm;
+lbl_12:
+    state->needf = ae_false;
+lbl_31:
+    state->repnfev = state->repnfev+1;
+    state->repdebugff = state->f;
     
     /*
-     * CG iterations
+     * 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
      */
-    state->fold = state->f;
-    ae_v_move(&state->xk.ptr.p_double[0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    for(i=0; i<=n-1; i++)
+    v = 0;
+    for(i=0; i<=nmain-1; i++)
     {
-        state->dk.ptr.p_double[i] = -state->g.ptr.p_double[i]*state->ak.ptr.p_double[i];
-        state->gc.ptr.p_double[i] = state->g.ptr.p_double[i]*state->ak.ptr.p_double[i];
+        v = v+ae_sqr((state->xcur.ptr.p_double[i]-state->xprev.ptr.p_double[i])/state->seffective.ptr.p_double[i], _state);
     }
-lbl_49:
-    if( ae_false )
+    v = ae_sqrt(v, _state);
+    if( ae_fp_less_eq(v,state->outerepsx) )
     {
-        goto lbl_50;
+        state->repterminationtype = 4;
+        goto lbl_16;
+    }
+    if( state->maxits>0 )
+    {
+        state->itsleft = state->itsleft-state->cgrep.iterationscount;
+        if( state->itsleft<=0 )
+        {
+            state->repterminationtype = 5;
+            goto lbl_16;
+        }
+    }
+    if( ae_fp_greater_eq(state->repouteriterationscount,minbleic_maxouterits) )
+    {
+        state->repterminationtype = 5;
+        goto lbl_16;
     }
     
     /*
-     * Store G[k] for later calculation of Y[k]
+     * Next iteration
      */
-    for(i=0; i<=n-1; i++)
-    {
-        state->yk.ptr.p_double[i] = -state->gc.ptr.p_double[i];
-    }
+    ae_v_move(&state->xprev.ptr.p_double[0], 1, &state->xcur.ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1));
+    goto lbl_15;
+lbl_16:
     
     /*
-     * 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.
+     * We've stopped, fill debug information
      */
-    ae_v_move(&state->d.ptr.p_double[0], 1, &state->dk.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    ae_v_move(&state->xn.ptr.p_double[0], 1, &state->xk.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    state->mcstage = 0;
-    state->stp = 1;
-    linminnormalized(&state->d, &state->stp, n, _state);
-    if( ae_fp_neq(state->laststep,0) )
+    state->repdebugeqerr = 0.0;
+    for(i=0; i<=state->cecnt-1; i++)
     {
-        state->stp = state->laststep;
+        v = ae_v_dotproduct(&state->ceeffective.ptr.pp_double[i][0], 1, &state->xcur.ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1));
+        state->repdebugeqerr = state->repdebugeqerr+ae_sqr(v-state->ceeffective.ptr.pp_double[i][nmain+nslack], _state);
     }
-    mcsrch(n, &state->xn, &state->f, &state->gc, &state->d, &state->stp, state->stpmax, &mcinfo, &state->nfev, &state->work, &state->lstate, &state->mcstage, _state);
-lbl_51:
-    if( state->mcstage==0 )
+    state->repdebugeqerr = ae_sqrt(state->repdebugeqerr, _state);
+    state->repdebugdx = 0;
+    for(i=0; i<=nmain-1; i++)
     {
-        goto lbl_52;
+        state->repdebugdx = state->repdebugdx+ae_sqr(state->xcur.ptr.p_double[i]-state->xstart.ptr.p_double[i], _state);
     }
+    state->repdebugdx = ae_sqrt(state->repdebugdx, _state);
+    result = ae_false;
+    return result;
     
     /*
-     * preprocess data: bound State.XN so it belongs to the
-     * feasible set and store it in the State.X
+     * Saving state
      */
-    for(i=0; i<=n-1; i++)
+lbl_rcomm:
+    result = ae_true;
+    state->rstate.ia.ptr.p_int[0] = nmain;
+    state->rstate.ia.ptr.p_int[1] = nslack;
+    state->rstate.ia.ptr.p_int[2] = m;
+    state->rstate.ia.ptr.p_int[3] = i;
+    state->rstate.ia.ptr.p_int[4] = j;
+    state->rstate.ba.ptr.p_bool[0] = b;
+    state->rstate.ra.ptr.p_double[0] = v;
+    state->rstate.ra.ptr.p_double[1] = vv;
+    return result;
+}
+
+
+/*************************************************************************
+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.
+
+  -- ALGLIB --
+     Copyright 28.11.2010 by Bochkanov Sergey
+*************************************************************************/
+void minbleicresults(minbleicstate* state,
+     /* Real    */ ae_vector* x,
+     minbleicreport* rep,
+     ae_state *_state)
+{
+
+    ae_vector_clear(x);
+    _minbleicreport_clear(rep);
+
+    minbleicresultsbuf(state, x, rep, _state);
+}
+
+
+/*************************************************************************
+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.
+
+  -- ALGLIB --
+     Copyright 28.11.2010 by Bochkanov Sergey
+*************************************************************************/
+void minbleicresultsbuf(minbleicstate* state,
+     /* Real    */ ae_vector* x,
+     minbleicreport* rep,
+     ae_state *_state)
+{
+    ae_int_t i;
+
+
+    if( x->cnt<state->nmain )
     {
-        state->x.ptr.p_double[i] = boundval(state->xn.ptr.p_double[i], state->bndl.ptr.p_double[i], state->bndu.ptr.p_double[i], _state);
+        ae_vector_set_length(x, state->nmain, _state);
     }
-    
-    /*
-     * RComm
-     */
-    minasa_clearrequestfields(state, _state);
-    state->needfg = ae_true;
-    state->rstate.stage = 9;
-    goto lbl_rcomm;
-lbl_9:
-    state->needfg = ae_false;
-    
-    /*
-     * postprocess data: zero components of G corresponding to
-     * the active constraints
-     */
-    for(i=0; i<=n-1; i++)
+    rep->inneriterationscount = state->repinneriterationscount;
+    rep->outeriterationscount = state->repouteriterationscount;
+    rep->nfev = state->repnfev;
+    rep->terminationtype = state->repterminationtype;
+    if( state->repterminationtype>0 )
     {
-        if( ae_fp_eq(state->x.ptr.p_double[i],state->bndl.ptr.p_double[i])||ae_fp_eq(state->x.ptr.p_double[i],state->bndu.ptr.p_double[i]) )
-        {
-            state->gc.ptr.p_double[i] = 0;
-        }
-        else
-        {
-            state->gc.ptr.p_double[i] = state->g.ptr.p_double[i];
-        }
+        ae_v_move(&x->ptr.p_double[0], 1, &state->xend.ptr.p_double[0], 1, ae_v_len(0,state->nmain-1));
     }
-    mcsrch(n, &state->xn, &state->f, &state->gc, &state->d, &state->stp, state->stpmax, &mcinfo, &state->nfev, &state->work, &state->lstate, &state->mcstage, _state);
-    goto lbl_51;
-lbl_52:
-    diffcnt = 0;
-    for(i=0; i<=n-1; i++)
+    else
     {
-        
-        /*
-         * XN contains unprojected result, project it,
-         * save copy to X (will be used for progress reporting)
-         */
-        state->xn.ptr.p_double[i] = boundval(state->xn.ptr.p_double[i], state->bndl.ptr.p_double[i], state->bndu.ptr.p_double[i], _state);
-        
-        /*
-         * update active set
-         */
-        if( ae_fp_eq(state->xn.ptr.p_double[i],state->bndl.ptr.p_double[i])||ae_fp_eq(state->xn.ptr.p_double[i],state->bndu.ptr.p_double[i]) )
-        {
-            state->an.ptr.p_double[i] = 0;
-        }
-        else
-        {
-            state->an.ptr.p_double[i] = 1;
-        }
-        if( ae_fp_neq(state->an.ptr.p_double[i],state->ak.ptr.p_double[i]) )
+        for(i=0; i<=state->nmain-1; i++)
         {
-            diffcnt = diffcnt+1;
+            x->ptr.p_double[i] = _state->v_nan;
         }
-        state->ak.ptr.p_double[i] = state->an.ptr.p_double[i];
-    }
-    ae_v_move(&state->xk.ptr.p_double[0], 1, &state->xn.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    state->repnfev = state->repnfev+state->nfev;
-    state->repiterationscount = state->repiterationscount+1;
-    if( !state->xrep )
-    {
-        goto lbl_53;
     }
+    rep->debugeqerr = state->repdebugeqerr;
+    rep->debugfs = state->repdebugfs;
+    rep->debugff = state->repdebugff;
+    rep->debugdx = state->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.
+
+  -- ALGLIB --
+     Copyright 28.11.2010 by Bochkanov Sergey
+*************************************************************************/
+void minbleicrestartfrom(minbleicstate* state,
+     /* Real    */ ae_vector* x,
+     ae_state *_state)
+{
+    ae_int_t n;
+
+
+    n = state->nmain;
     
     /*
-     * progress report
+     * First, check for errors in the inputs
      */
-    minasa_clearrequestfields(state, _state);
-    state->xupdated = ae_true;
-    state->rstate.stage = 10;
-    goto lbl_rcomm;
-lbl_10:
-    state->xupdated = ae_false;
-lbl_53:
+    ae_assert(x->cnt>=n, "MinBLEICRestartFrom: Length(X)<N", _state);
+    ae_assert(isfinitevector(x, n, _state), "MinBLEICRestartFrom: X contains infinite or NaN values!", _state);
     
     /*
-     * Update info about step length
+     * Set XC
      */
-    v = ae_v_dotproduct(&state->d.ptr.p_double[0], 1, &state->d.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    state->laststep = ae_sqrt(v, _state)*state->stp;
+    ae_v_move(&state->xstart.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,n-1));
     
     /*
-     * Check stopping conditions.
+     * prepare RComm facilities
      */
-    if( ae_fp_greater(minasa_asaboundedantigradnorm(state, _state),state->epsg) )
-    {
-        goto lbl_55;
-    }
-    
-    /*
-     * Gradient is small enough
-     */
-    state->repterminationtype = 4;
-    if( !state->xrep )
-    {
-        goto lbl_57;
-    }
-    minasa_clearrequestfields(state, _state);
-    state->xupdated = ae_true;
-    state->rstate.stage = 11;
-    goto lbl_rcomm;
-lbl_11:
+    ae_vector_set_length(&state->rstate.ia, 4+1, _state);
+    ae_vector_set_length(&state->rstate.ba, 0+1, _state);
+    ae_vector_set_length(&state->rstate.ra, 1+1, _state);
+    state->rstate.stage = -1;
+    minbleic_clearrequestfields(state, _state);
+}
+
+
+/*************************************************************************
+Clears request fileds (to be sure that we don't forget to clear something)
+*************************************************************************/
+static void minbleic_clearrequestfields(minbleicstate* state,
+     ae_state *_state)
+{
+
+
+    state->needf = ae_false;
+    state->needfg = ae_false;
     state->xupdated = ae_false;
-lbl_57:
-    result = ae_false;
-    return result;
-lbl_55:
-    if( !(state->repiterationscount>=state->maxits&&state->maxits>0) )
+}
+
+
+/*************************************************************************
+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 minbleic_unscalepoint(minbleicstate* state,
+     /* Real    */ ae_vector* xscaled,
+     /* Real    */ ae_vector* xunscaled,
+     ae_state *_state)
+{
+    ae_int_t i;
+    double v;
+
+
+    for(i=0; i<=state->nmain-1; i++)
     {
-        goto lbl_59;
+        v = xscaled->ptr.p_double[i]*state->transforms.ptr.p_double[i];
+        if( state->hasbndl.ptr.p_bool[i] )
+        {
+            if( ae_fp_less(v,state->bndloriginal.ptr.p_double[i]) )
+            {
+                v = state->bndloriginal.ptr.p_double[i];
+            }
+        }
+        if( state->hasbndu.ptr.p_bool[i] )
+        {
+            if( ae_fp_greater(v,state->bnduoriginal.ptr.p_double[i]) )
+            {
+                v = state->bnduoriginal.ptr.p_double[i];
+            }
+        }
+        xunscaled->ptr.p_double[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 minbleic_projectpointandunscale(minbleicstate* state,
+     /* Real    */ ae_vector* xscaled,
+     /* Real    */ ae_vector* xunscaled,
+     /* Real    */ ae_vector* rscaled,
+     double* rnorm2,
+     ae_state *_state)
+{
+    double v;
+    ae_int_t i;
+    ae_int_t nmain;
+    ae_int_t nslack;
+
+    *rnorm2 = 0;
+
+    nmain = state->nmain;
+    nslack = state->nslack;
     
     /*
-     * Too many iterations
+     * * 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
      */
-    state->repterminationtype = 5;
-    if( !state->xrep )
+    ae_v_sub(&xscaled->ptr.p_double[0], 1, &state->xe.ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1));
+    *rnorm2 = 0;
+    for(i=0; i<=nmain+nslack-1; i++)
     {
-        goto lbl_61;
+        rscaled->ptr.p_double[i] = 0;
     }
-    minasa_clearrequestfields(state, _state);
-    state->xupdated = ae_true;
-    state->rstate.stage = 12;
-    goto lbl_rcomm;
-lbl_12:
-    state->xupdated = ae_false;
-lbl_61:
-    result = ae_false;
-    return result;
-lbl_59:
-    if( !(ae_fp_greater_eq(minasa_asaginorm(state, _state),state->mu*minasa_asad1norm(state, _state))&&diffcnt==0) )
+    for(i=0; i<=nmain+nslack-1; i++)
     {
-        goto lbl_63;
+        if( state->activeconstraints.ptr.p_bool[i] )
+        {
+            v = xscaled->ptr.p_double[i];
+            xscaled->ptr.p_double[i] = 0;
+            rscaled->ptr.p_double[i] = rscaled->ptr.p_double[i]+v;
+            *rnorm2 = *rnorm2+ae_sqr(v, _state);
+        }
     }
-    
-    /*
-     * 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( ae_fp_greater(state->fold-state->f,state->epsf*ae_maxreal(ae_fabs(state->fold, _state), ae_maxreal(ae_fabs(state->f, _state), 1.0, _state), _state)) )
+    for(i=0; i<=state->cecnt-1; i++)
     {
-        goto lbl_65;
+        v = ae_v_dotproduct(&xscaled->ptr.p_double[0], 1, &state->cecurrent.ptr.pp_double[i][0], 1, ae_v_len(0,nmain+nslack-1));
+        ae_v_subd(&xscaled->ptr.p_double[0], 1, &state->cecurrent.ptr.pp_double[i][0], 1, ae_v_len(0,nmain+nslack-1), v);
+        ae_v_addd(&rscaled->ptr.p_double[0], 1, &state->cecurrent.ptr.pp_double[i][0], 1, ae_v_len(0,nmain+nslack-1), v);
+        *rnorm2 = *rnorm2+ae_sqr(v, _state);
     }
-    
-    /*
-     * F(k+1)-F(k) is small enough
-     */
-    state->repterminationtype = 1;
-    if( !state->xrep )
+    ae_v_add(&xscaled->ptr.p_double[0], 1, &state->xe.ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1));
+    minbleic_unscalepoint(state, xscaled, xunscaled, _state);
+}
+
+
+/*************************************************************************
+This function scales and copies NMain elements of GUnscaled into GScaled.
+Other NSlack components of GScaled are set to zero.
+*************************************************************************/
+static void minbleic_scalegradientandexpand(minbleicstate* state,
+     /* Real    */ ae_vector* gunscaled,
+     /* Real    */ ae_vector* gscaled,
+     ae_state *_state)
+{
+    ae_int_t i;
+
+
+    for(i=0; i<=state->nmain-1; i++)
     {
-        goto lbl_67;
+        gscaled->ptr.p_double[i] = gunscaled->ptr.p_double[i]*state->transforms.ptr.p_double[i];
     }
-    minasa_clearrequestfields(state, _state);
-    state->xupdated = ae_true;
-    state->rstate.stage = 13;
-    goto lbl_rcomm;
-lbl_13:
-    state->xupdated = ae_false;
-lbl_67:
-    result = ae_false;
-    return result;
-lbl_65:
-    if( ae_fp_greater(state->laststep,state->epsx) )
+    for(i=0; i<=state->nslack-1; i++)
     {
-        goto lbl_69;
+        gscaled->ptr.p_double[state->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 minbleic_modifytargetfunction(minbleicstate* state,
+     /* Real    */ ae_vector* x,
+     /* Real    */ ae_vector* r,
+     double rnorm2,
+     double* f,
+     /* Real    */ ae_vector* g,
+     double* gnorm,
+     double* mpgnorm,
+     ae_state *_state)
+{
+    double v;
+    ae_int_t i;
+    ae_int_t nmain;
+    ae_int_t nslack;
+    ae_bool hasconstraints;
+
+    *gnorm = 0;
+    *mpgnorm = 0;
+
+    nmain = state->nmain;
+    nslack = state->nslack;
+    hasconstraints = ae_false;
     
     /*
-     * X(k+1)-X(k) is small enough
+     * GNorm
      */
-    state->repterminationtype = 2;
-    if( !state->xrep )
-    {
-        goto lbl_71;
-    }
-    minasa_clearrequestfields(state, _state);
-    state->xupdated = ae_true;
-    state->rstate.stage = 14;
-    goto lbl_rcomm;
-lbl_14:
-    state->xupdated = ae_false;
-lbl_71:
-    result = ae_false;
-    return result;
-lbl_69:
-lbl_63:
+    v = ae_v_dotproduct(&g->ptr.p_double[0], 1, &g->ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1));
+    *gnorm = ae_sqrt(v, _state);
     
     /*
-     * Check conditions for switching
+     * 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
      */
-    if( ae_fp_less(minasa_asaginorm(state, _state),state->mu*minasa_asad1norm(state, _state)) )
-    {
-        state->curalgo = 0;
-        goto lbl_50;
-    }
-    if( diffcnt>0 )
+    *f = *f+rnorm2;
+    for(i=0; i<=nmain+nslack-1; i++)
     {
-        if( minasa_asauisempty(state, _state)||diffcnt>=minasa_n2 )
-        {
-            state->curalgo = 1;
-        }
-        else
+        if( state->activeconstraints.ptr.p_bool[i] )
         {
-            state->curalgo = 0;
+            g->ptr.p_double[i] = 0;
         }
-        goto lbl_50;
     }
+    for(i=0; i<=state->cecnt-1; i++)
+    {
+        v = ae_v_dotproduct(&g->ptr.p_double[0], 1, &state->cecurrent.ptr.pp_double[i][0], 1, ae_v_len(0,nmain+nslack-1));
+        ae_v_subd(&g->ptr.p_double[0], 1, &state->cecurrent.ptr.pp_double[i][0], 1, ae_v_len(0,nmain+nslack-1), v);
+    }
+    ae_v_addd(&g->ptr.p_double[0], 1, &r->ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1), 2);
     
     /*
-     * 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)
+     * MPGNorm
      */
-    if( mcinfo==1 )
-    {
-        
-        /*
-         * Standard Wolfe conditions are satisfied:
-         * * calculate Y[K] and BetaK
-         */
-        ae_v_add(&state->yk.ptr.p_double[0], 1, &state->gc.ptr.p_double[0], 1, ae_v_len(0,n-1));
-        vv = ae_v_dotproduct(&state->yk.ptr.p_double[0], 1, &state->dk.ptr.p_double[0], 1, ae_v_len(0,n-1));
-        v = ae_v_dotproduct(&state->gc.ptr.p_double[0], 1, &state->gc.ptr.p_double[0], 1, ae_v_len(0,n-1));
-        state->betady = v/vv;
-        v = ae_v_dotproduct(&state->gc.ptr.p_double[0], 1, &state->yk.ptr.p_double[0], 1, ae_v_len(0,n-1));
-        state->betahs = v/vv;
-        if( state->cgtype==0 )
-        {
-            betak = state->betady;
-        }
-        if( state->cgtype==1 )
-        {
-            betak = ae_maxreal(0, ae_minreal(state->betady, state->betahs, _state), _state);
-        }
-    }
-    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->debugrestartscount = state->debugrestartscount+1;
-    }
-    ae_v_moveneg(&state->dn.ptr.p_double[0], 1, &state->gc.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    ae_v_addd(&state->dn.ptr.p_double[0], 1, &state->dk.ptr.p_double[0], 1, ae_v_len(0,n-1), betak);
-    ae_v_move(&state->dk.ptr.p_double[0], 1, &state->dn.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    
-    /*
-     * update other information
-     */
-    state->fold = state->f;
-    state->k = state->k+1;
-    goto lbl_49;
-lbl_50:
-lbl_47:
-    goto lbl_17;
-lbl_18:
-    result = ae_false;
-    return result;
-    
-    /*
-     * Saving state
-     */
-lbl_rcomm:
-    result = ae_true;
-    state->rstate.ia.ptr.p_int[0] = n;
-    state->rstate.ia.ptr.p_int[1] = i;
-    state->rstate.ia.ptr.p_int[2] = mcinfo;
-    state->rstate.ia.ptr.p_int[3] = diffcnt;
-    state->rstate.ba.ptr.p_bool[0] = b;
-    state->rstate.ba.ptr.p_bool[1] = stepfound;
-    state->rstate.ra.ptr.p_double[0] = betak;
-    state->rstate.ra.ptr.p_double[1] = v;
-    state->rstate.ra.ptr.p_double[2] = vv;
-    return result;
+    v = ae_v_dotproduct(&g->ptr.p_double[0], 1, &g->ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1));
+    *mpgnorm = ae_sqrt(v, _state);
 }
 
 
 /*************************************************************************
-ASA results
-
-INPUT PARAMETERS:
-    State   -   algorithm state
+This function makes additional check for constraints which can be activated.
 
-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
-                * ActiveConstraints contains number of active constraints
+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.
 
-  -- ALGLIB --
-     Copyright 20.03.2009 by Bochkanov Sergey
+It will return True, if at least one constraint was activated by this function.
 *************************************************************************/
-void minasaresults(minasastate* state,
+static ae_bool minbleic_additionalcheckforconstraints(minbleicstate* state,
      /* Real    */ ae_vector* x,
-     minasareport* rep,
      ae_state *_state)
 {
+    ae_int_t i;
+    ae_int_t nmain;
+    ae_int_t nslack;
+    ae_bool result;
 
-    ae_vector_clear(x);
-    _minasareport_clear(rep);
 
-    minasaresultsbuf(state, x, rep, _state);
+    result = ae_false;
+    nmain = state->nmain;
+    nslack = state->nslack;
+    for(i=0; i<=nmain-1; i++)
+    {
+        if( !state->activeconstraints.ptr.p_bool[i] )
+        {
+            if( state->hasbndl.ptr.p_bool[i] )
+            {
+                if( ae_fp_less_eq(x->ptr.p_double[i],state->bndleffective.ptr.p_double[i]) )
+                {
+                    state->activeconstraints.ptr.p_bool[i] = ae_true;
+                    state->constrainedvalues.ptr.p_double[i] = state->bndleffective.ptr.p_double[i];
+                    result = ae_true;
+                }
+            }
+            if( state->hasbndu.ptr.p_bool[i] )
+            {
+                if( ae_fp_greater_eq(x->ptr.p_double[i],state->bndueffective.ptr.p_double[i]) )
+                {
+                    state->activeconstraints.ptr.p_bool[i] = ae_true;
+                    state->constrainedvalues.ptr.p_double[i] = state->bndueffective.ptr.p_double[i];
+                    result = ae_true;
+                }
+            }
+        }
+    }
+    for(i=0; i<=nslack-1; i++)
+    {
+        if( !state->activeconstraints.ptr.p_bool[nmain+i] )
+        {
+            if( ae_fp_less_eq(x->ptr.p_double[nmain+i],0) )
+            {
+                state->activeconstraints.ptr.p_bool[nmain+i] = ae_true;
+                state->constrainedvalues.ptr.p_double[nmain+i] = 0;
+                result = ae_true;
+            }
+        }
+    }
+    return result;
 }
 
 
 /*************************************************************************
-ASA results
-
-Buffered implementation of MinASAResults() 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.
-
-  -- ALGLIB --
-     Copyright 20.03.2009 by Bochkanov Sergey
+This function rebuilds CECurrent and XE according to current set of
+active bound constraints.
 *************************************************************************/
-void minasaresultsbuf(minasastate* state,
-     /* Real    */ ae_vector* x,
-     minasareport* rep,
-     ae_state *_state)
+static void minbleic_rebuildcexe(minbleicstate* state, ae_state *_state)
 {
     ae_int_t i;
+    ae_int_t j;
+    ae_int_t k;
+    ae_int_t nmain;
+    ae_int_t nslack;
+    double v;
 
 
-    if( x->cnt<state->n )
+    nmain = state->nmain;
+    nslack = state->nslack;
+    rmatrixcopy(state->cecnt, nmain+nslack+1, &state->ceeffective, 0, 0, &state->cecurrent, 0, 0, _state);
+    for(i=0; i<=state->cecnt-1; i++)
     {
-        ae_vector_set_length(x, state->n, _state);
+        
+        /*
+         * "Subtract" active bound constraints from I-th linear constraint
+         */
+        for(j=0; j<=nmain+nslack-1; j++)
+        {
+            if( state->activeconstraints.ptr.p_bool[j] )
+            {
+                state->cecurrent.ptr.pp_double[i][nmain+nslack] = state->cecurrent.ptr.pp_double[i][nmain+nslack]-state->cecurrent.ptr.pp_double[i][j]*state->constrainedvalues.ptr.p_double[j];
+                state->cecurrent.ptr.pp_double[i][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 = ae_v_dotproduct(&state->cecurrent.ptr.pp_double[k][0], 1, &state->cecurrent.ptr.pp_double[i][0], 1, ae_v_len(0,nmain+nslack-1));
+            ae_v_subd(&state->cecurrent.ptr.pp_double[i][0], 1, &state->cecurrent.ptr.pp_double[k][0], 1, ae_v_len(0,nmain+nslack), v);
+        }
+        
+        /*
+         * 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 = ae_v_dotproduct(&state->cecurrent.ptr.pp_double[i][0], 1, &state->cecurrent.ptr.pp_double[i][0], 1, ae_v_len(0,nmain+nslack-1));
+        v = ae_sqrt(v, _state);
+        if( ae_fp_greater(v,10000*ae_machineepsilon) )
+        {
+            v = 1/v;
+            ae_v_muld(&state->cecurrent.ptr.pp_double[i][0], 1, ae_v_len(0,nmain+nslack), v);
+        }
+        else
+        {
+            for(j=0; j<=nmain+nslack; j++)
+            {
+                state->cecurrent.ptr.pp_double[i][j] = 0;
+            }
+        }
     }
-    ae_v_move(&x->ptr.p_double[0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,state->n-1));
-    rep->iterationscount = state->repiterationscount;
-    rep->nfev = state->repnfev;
-    rep->terminationtype = state->repterminationtype;
-    rep->activeconstraints = 0;
-    for(i=0; i<=state->n-1; i++)
+    for(j=0; j<=nmain+nslack-1; j++)
     {
-        if( ae_fp_eq(state->ak.ptr.p_double[i],0) )
+        state->xe.ptr.p_double[j] = 0;
+    }
+    for(i=0; i<=nmain+nslack-1; i++)
+    {
+        if( state->activeconstraints.ptr.p_bool[i] )
         {
-            rep->activeconstraints = rep->activeconstraints+1;
+            state->xe.ptr.p_double[i] = state->xe.ptr.p_double[i]+state->constrainedvalues.ptr.p_double[i];
         }
     }
+    for(i=0; i<=state->cecnt-1; i++)
+    {
+        v = state->cecurrent.ptr.pp_double[i][nmain+nslack];
+        ae_v_addd(&state->xe.ptr.p_double[0], 1, &state->cecurrent.ptr.pp_double[i][0], 1, ae_v_len(0,nmain+nslack-1), v);
+    }
 }
 
 
 /*************************************************************************
-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 previously allocated with MinCGCreate call.
-    X       -   new starting point.
-    BndL    -   new lower bounds
-    BndU    -   new upper bounds
-
-  -- ALGLIB --
-     Copyright 30.07.2010 by Bochkanov Sergey
+This function projects gradient onto equality constrained subspace
 *************************************************************************/
-void minasarestartfrom(minasastate* state,
-     /* Real    */ ae_vector* x,
-     /* Real    */ ae_vector* bndl,
-     /* Real    */ ae_vector* bndu,
+static void minbleic_makegradientprojection(minbleicstate* state,
+     /* Real    */ ae_vector* pg,
      ae_state *_state)
 {
+    ae_int_t i;
+    ae_int_t nmain;
+    ae_int_t nslack;
+    double v;
 
 
-    ae_assert(x->cnt>=state->n, "MinASARestartFrom: Length(X)<N!", _state);
-    ae_assert(isfinitevector(x, state->n, _state), "MinASARestartFrom: X contains infinite or NaN values!", _state);
-    ae_assert(bndl->cnt>=state->n, "MinASARestartFrom: Length(BndL)<N!", _state);
-    ae_assert(isfinitevector(bndl, state->n, _state), "MinASARestartFrom: BndL contains infinite or NaN values!", _state);
-    ae_assert(bndu->cnt>=state->n, "MinASARestartFrom: Length(BndU)<N!", _state);
-    ae_assert(isfinitevector(bndu, state->n, _state), "MinASARestartFrom: BndU contains infinite or NaN values!", _state);
-    ae_v_move(&state->x.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,state->n-1));
-    ae_v_move(&state->bndl.ptr.p_double[0], 1, &bndl->ptr.p_double[0], 1, ae_v_len(0,state->n-1));
-    ae_v_move(&state->bndu.ptr.p_double[0], 1, &bndu->ptr.p_double[0], 1, ae_v_len(0,state->n-1));
-    state->laststep = 0;
-    ae_vector_set_length(&state->rstate.ia, 3+1, _state);
-    ae_vector_set_length(&state->rstate.ba, 1+1, _state);
-    ae_vector_set_length(&state->rstate.ra, 2+1, _state);
-    state->rstate.stage = -1;
-    minasa_clearrequestfields(state, _state);
+    nmain = state->nmain;
+    nslack = state->nslack;
+    for(i=0; i<=nmain+nslack-1; i++)
+    {
+        if( state->activeconstraints.ptr.p_bool[i] )
+        {
+            pg->ptr.p_double[i] = 0;
+        }
+    }
+    for(i=0; i<=state->cecnt-1; i++)
+    {
+        v = ae_v_dotproduct(&pg->ptr.p_double[0], 1, &state->cecurrent.ptr.pp_double[i][0], 1, ae_v_len(0,nmain+nslack-1));
+        ae_v_subd(&pg->ptr.p_double[0], 1, &state->cecurrent.ptr.pp_double[i][0], 1, ae_v_len(0,nmain+nslack-1), v);
+    }
 }
 
 
 /*************************************************************************
-Returns norm of bounded anti-gradient.
+This function prepares equality constrained subproblem:
 
-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.
+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.
 
-  -- ALGLIB --
-     Copyright 20.03.2009 by Bochkanov Sergey
+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 double minasa_asaboundedantigradnorm(minasastate* state,
+static ae_bool minbleic_prepareconstraintmatrix(minbleicstate* state,
+     /* Real    */ ae_vector* x,
+     /* Real    */ ae_vector* g,
+     /* Real    */ ae_vector* px,
+     /* Real    */ ae_vector* pg,
      ae_state *_state)
 {
     ae_int_t i;
+    ae_int_t nmain;
+    ae_int_t nslack;
     double v;
-    double result;
+    double ferr;
+    ae_bool result;
 
 
-    result = 0;
-    for(i=0; i<=state->n-1; i++)
+    nmain = state->nmain;
+    nslack = state->nslack;
+    result = ae_true;
+    
+    /*
+     * Step 1
+     */
+    minbleic_additionalcheckforconstraints(state, x, _state);
+    
+    /*
+     * Steps 2-5
+     */
+    do
     {
-        v = -state->g.ptr.p_double[i];
-        if( ae_fp_eq(state->x.ptr.p_double[i],state->bndl.ptr.p_double[i])&&ae_fp_less(-state->g.ptr.p_double[i],0) )
+        
+        /*
+         * Steps 2-3
+         */
+        minbleic_rebuildcexe(state, _state);
+        
+        /*
+         * Step 4
+         *
+         * Calculate PX, PG
+         */
+        ae_v_move(&px->ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1));
+        ae_v_sub(&px->ptr.p_double[0], 1, &state->xe.ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1));
+        ae_v_move(&pg->ptr.p_double[0], 1, &g->ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1));
+        for(i=0; i<=nmain+nslack-1; i++)
         {
-            v = 0;
+            if( state->activeconstraints.ptr.p_bool[i] )
+            {
+                px->ptr.p_double[i] = 0;
+                pg->ptr.p_double[i] = 0;
+            }
         }
-        if( ae_fp_eq(state->x.ptr.p_double[i],state->bndu.ptr.p_double[i])&&ae_fp_greater(-state->g.ptr.p_double[i],0) )
+        for(i=0; i<=state->cecnt-1; i++)
         {
-            v = 0;
+            v = ae_v_dotproduct(&px->ptr.p_double[0], 1, &state->cecurrent.ptr.pp_double[i][0], 1, ae_v_len(0,nmain+nslack-1));
+            ae_v_subd(&px->ptr.p_double[0], 1, &state->cecurrent.ptr.pp_double[i][0], 1, ae_v_len(0,nmain+nslack-1), v);
+            v = ae_v_dotproduct(&pg->ptr.p_double[0], 1, &state->cecurrent.ptr.pp_double[i][0], 1, ae_v_len(0,nmain+nslack-1));
+            ae_v_subd(&pg->ptr.p_double[0], 1, &state->cecurrent.ptr.pp_double[i][0], 1, ae_v_len(0,nmain+nslack-1), v);
         }
-        result = result+ae_sqr(v, _state);
+        ae_v_add(&px->ptr.p_double[0], 1, &state->xe.ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1));
+        
+        /*
+         * Step 5 (loop condition below)
+         */
     }
-    result = ae_sqrt(result, _state);
-    return 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.
-
-  -- ALGLIB --
-     Copyright 20.03.2009 by Bochkanov Sergey
-*************************************************************************/
-static double minasa_asaginorm(minasastate* state, ae_state *_state)
-{
-    ae_int_t i;
-    double result;
-
-
-    result = 0;
-    for(i=0; i<=state->n-1; i++)
-    {
-        if( ae_fp_neq(state->x.ptr.p_double[i],state->bndl.ptr.p_double[i])&&ae_fp_neq(state->x.ptr.p_double[i],state->bndu.ptr.p_double[i]) )
-        {
-            result = result+ae_sqr(state->g.ptr.p_double[i], _state);
-        }
-    }
-    result = ae_sqrt(result, _state);
-    return 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.
-
-  -- ALGLIB --
-     Copyright 20.03.2009 by Bochkanov Sergey
-*************************************************************************/
-static double minasa_asad1norm(minasastate* state, ae_state *_state)
-{
-    ae_int_t i;
-    double result;
-
-
-    result = 0;
-    for(i=0; i<=state->n-1; i++)
+    while(minbleic_additionalcheckforconstraints(state, px, _state));
+    
+    /*
+     * Step 6
+     */
+    ferr = 0;
+    for(i=0; i<=state->cecnt-1; i++)
     {
-        result = result+ae_sqr(boundval(state->x.ptr.p_double[i]-state->g.ptr.p_double[i], state->bndl.ptr.p_double[i], state->bndu.ptr.p_double[i], _state)-state->x.ptr.p_double[i], _state);
+        v = ae_v_dotproduct(&px->ptr.p_double[0], 1, &state->ceeffective.ptr.pp_double[i][0], 1, ae_v_len(0,nmain+nslack-1));
+        v = v-state->ceeffective.ptr.pp_double[i][nmain+nslack];
+        ferr = ae_maxreal(ferr, ae_fabs(v, _state), _state);
     }
-    result = ae_sqrt(result, _state);
+    result = ae_fp_less_eq(ferr,state->outerepsi);
     return 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.
-
-  -- ALGLIB --
-     Copyright 20.03.2009 by Bochkanov Sergey
+Internal initialization subroutine
 *************************************************************************/
-static ae_bool minasa_asauisempty(minasastate* state, ae_state *_state)
+static void minbleic_minbleicinitinternal(ae_int_t n,
+     /* Real    */ ae_vector* x,
+     double diffstep,
+     minbleicstate* state,
+     ae_state *_state)
 {
+    ae_frame _frame_block;
     ae_int_t i;
-    double d;
-    double d2;
-    double d32;
-    ae_bool result;
+    ae_matrix c;
+    ae_vector ct;
 
+    ae_frame_make(_state, &_frame_block);
+    ae_matrix_init(&c, 0, 0, DT_REAL, _state, ae_true);
+    ae_vector_init(&ct, 0, DT_INT, _state, ae_true);
 
-    d = minasa_asad1norm(state, _state);
-    d2 = ae_sqrt(d, _state);
-    d32 = d*d2;
-    result = ae_true;
-    for(i=0; i<=state->n-1; i++)
+    state->nmain = n;
+    state->optdim = 0;
+    state->diffstep = diffstep;
+    ae_vector_set_length(&state->bndloriginal, n, _state);
+    ae_vector_set_length(&state->bndleffective, n, _state);
+    ae_vector_set_length(&state->hasbndl, n, _state);
+    ae_vector_set_length(&state->bnduoriginal, n, _state);
+    ae_vector_set_length(&state->bndueffective, n, _state);
+    ae_vector_set_length(&state->hasbndu, n, _state);
+    ae_vector_set_length(&state->xstart, n, _state);
+    ae_vector_set_length(&state->soriginal, n, _state);
+    ae_vector_set_length(&state->x, n, _state);
+    ae_vector_set_length(&state->g, n, _state);
+    for(i=0; i<=n-1; i++)
     {
-        if( ae_fp_greater_eq(ae_fabs(state->g.ptr.p_double[i], _state),d2)&&ae_fp_greater_eq(ae_minreal(state->x.ptr.p_double[i]-state->bndl.ptr.p_double[i], state->bndu.ptr.p_double[i]-state->x.ptr.p_double[i], _state),d32) )
-        {
-            result = ae_false;
-            return result;
-        }
+        state->bndloriginal.ptr.p_double[i] = _state->v_neginf;
+        state->hasbndl.ptr.p_bool[i] = ae_false;
+        state->bnduoriginal.ptr.p_double[i] = _state->v_posinf;
+        state->hasbndu.ptr.p_bool[i] = ae_false;
+        state->soriginal.ptr.p_double[i] = 1.0;
     }
-    return result;
-}
-
-
-/*************************************************************************
-Clears request fileds (to be sure that we don't forgot to clear something)
-*************************************************************************/
-static void minasa_clearrequestfields(minasastate* state,
-     ae_state *_state)
-{
-
-
-    state->needfg = ae_false;
-    state->xupdated = ae_false;
+    minbleicsetlc(state, &c, &ct, 0, _state);
+    minbleicsetinnercond(state, 0.0, 0.0, 0.0, _state);
+    minbleicsetoutercond(state, 1.0E-6, 1.0E-6, _state);
+    minbleicsetmaxits(state, 0, _state);
+    minbleicsetxrep(state, ae_false, _state);
+    minbleicsetstpmax(state, 0.0, _state);
+    minbleicsetprecdefault(state, _state);
+    minbleicrestartfrom(state, x, _state);
+    ae_frame_leave(_state);
 }
 
 
-ae_bool _minasastate_init(minasastate* p, ae_state *_state, ae_bool make_automatic)
+ae_bool _minbleicstate_init(minbleicstate* p, ae_state *_state, ae_bool make_automatic)
 {
-    if( !ae_vector_init(&p->bndl, 0, DT_REAL, _state, make_automatic) )
+    if( !ae_vector_init(&p->diaghoriginal, 0, DT_REAL, _state, make_automatic) )
         return ae_false;
-    if( !ae_vector_init(&p->bndu, 0, DT_REAL, _state, make_automatic) )
+    if( !ae_vector_init(&p->diagh, 0, DT_REAL, _state, make_automatic) )
         return ae_false;
-    if( !ae_vector_init(&p->ak, 0, DT_REAL, _state, make_automatic) )
+    if( !ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic) )
         return ae_false;
-    if( !ae_vector_init(&p->xk, 0, DT_REAL, _state, make_automatic) )
+    if( !ae_vector_init(&p->g, 0, DT_REAL, _state, make_automatic) )
         return ae_false;
-    if( !ae_vector_init(&p->dk, 0, DT_REAL, _state, make_automatic) )
+    if( !_rcommstate_init(&p->rstate, _state, make_automatic) )
         return ae_false;
-    if( !ae_vector_init(&p->an, 0, DT_REAL, _state, make_automatic) )
+    if( !ae_vector_init(&p->xcur, 0, DT_REAL, _state, make_automatic) )
         return ae_false;
-    if( !ae_vector_init(&p->xn, 0, DT_REAL, _state, make_automatic) )
+    if( !ae_vector_init(&p->xprev, 0, DT_REAL, _state, make_automatic) )
         return ae_false;
-    if( !ae_vector_init(&p->dn, 0, DT_REAL, _state, make_automatic) )
+    if( !ae_vector_init(&p->xstart, 0, DT_REAL, _state, make_automatic) )
         return ae_false;
-    if( !ae_vector_init(&p->d, 0, DT_REAL, _state, make_automatic) )
+    if( !ae_vector_init(&p->xend, 0, DT_REAL, _state, make_automatic) )
         return ae_false;
-    if( !ae_vector_init(&p->work, 0, DT_REAL, _state, make_automatic) )
+    if( !ae_vector_init(&p->lastg, 0, DT_REAL, _state, make_automatic) )
         return ae_false;
-    if( !ae_vector_init(&p->yk, 0, DT_REAL, _state, make_automatic) )
+    if( !ae_matrix_init(&p->ceoriginal, 0, 0, DT_REAL, _state, make_automatic) )
         return ae_false;
-    if( !ae_vector_init(&p->gc, 0, DT_REAL, _state, make_automatic) )
+    if( !ae_matrix_init(&p->ceeffective, 0, 0, DT_REAL, _state, make_automatic) )
         return ae_false;
-    if( !ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic) )
+    if( !ae_matrix_init(&p->cecurrent, 0, 0, DT_REAL, _state, make_automatic) )
         return ae_false;
-    if( !ae_vector_init(&p->g, 0, DT_REAL, _state, make_automatic) )
+    if( !ae_vector_init(&p->ct, 0, DT_INT, _state, make_automatic) )
         return ae_false;
-    if( !_rcommstate_init(&p->rstate, _state, make_automatic) )
+    if( !ae_vector_init(&p->xe, 0, DT_REAL, _state, make_automatic) )
         return ae_false;
-    if( !_linminstate_init(&p->lstate, _state, make_automatic) )
+    if( !ae_vector_init(&p->hasbndl, 0, DT_BOOL, _state, make_automatic) )
         return ae_false;
-    return ae_true;
-}
-
-
-ae_bool _minasastate_init_copy(minasastate* dst, minasastate* src, ae_state *_state, ae_bool make_automatic)
-{
-    dst->n = src->n;
-    dst->epsg = src->epsg;
-    dst->epsf = src->epsf;
-    dst->epsx = src->epsx;
-    dst->maxits = src->maxits;
-    dst->xrep = src->xrep;
-    dst->stpmax = src->stpmax;
-    dst->cgtype = src->cgtype;
-    dst->k = src->k;
-    dst->nfev = src->nfev;
-    dst->mcstage = src->mcstage;
-    if( !ae_vector_init_copy(&dst->bndl, &src->bndl, _state, make_automatic) )
+    if( !ae_vector_init(&p->hasbndu, 0, DT_BOOL, _state, make_automatic) )
         return ae_false;
-    if( !ae_vector_init_copy(&dst->bndu, &src->bndu, _state, make_automatic) )
+    if( !ae_vector_init(&p->bndloriginal, 0, DT_REAL, _state, make_automatic) )
         return ae_false;
-    dst->curalgo = src->curalgo;
-    dst->acount = src->acount;
-    dst->mu = src->mu;
-    dst->finit = src->finit;
-    dst->dginit = src->dginit;
-    if( !ae_vector_init_copy(&dst->ak, &src->ak, _state, make_automatic) )
+    if( !ae_vector_init(&p->bnduoriginal, 0, DT_REAL, _state, make_automatic) )
         return ae_false;
-    if( !ae_vector_init_copy(&dst->xk, &src->xk, _state, make_automatic) )
+    if( !ae_vector_init(&p->bndleffective, 0, DT_REAL, _state, make_automatic) )
         return ae_false;
-    if( !ae_vector_init_copy(&dst->dk, &src->dk, _state, make_automatic) )
+    if( !ae_vector_init(&p->bndueffective, 0, DT_REAL, _state, make_automatic) )
         return ae_false;
-    if( !ae_vector_init_copy(&dst->an, &src->an, _state, make_automatic) )
+    if( !ae_vector_init(&p->activeconstraints, 0, DT_BOOL, _state, make_automatic) )
         return ae_false;
-    if( !ae_vector_init_copy(&dst->xn, &src->xn, _state, make_automatic) )
+    if( !ae_vector_init(&p->constrainedvalues, 0, DT_REAL, _state, make_automatic) )
         return ae_false;
-    if( !ae_vector_init_copy(&dst->dn, &src->dn, _state, make_automatic) )
+    if( !ae_vector_init(&p->transforms, 0, DT_REAL, _state, make_automatic) )
         return ae_false;
-    if( !ae_vector_init_copy(&dst->d, &src->d, _state, make_automatic) )
+    if( !ae_vector_init(&p->seffective, 0, DT_REAL, _state, make_automatic) )
         return ae_false;
-    dst->fold = src->fold;
-    dst->stp = src->stp;
-    if( !ae_vector_init_copy(&dst->work, &src->work, _state, make_automatic) )
+    if( !ae_vector_init(&p->soriginal, 0, DT_REAL, _state, make_automatic) )
         return ae_false;
-    if( !ae_vector_init_copy(&dst->yk, &src->yk, _state, make_automatic) )
+    if( !ae_vector_init(&p->w, 0, DT_REAL, _state, make_automatic) )
         return ae_false;
-    if( !ae_vector_init_copy(&dst->gc, &src->gc, _state, make_automatic) )
+    if( !ae_vector_init(&p->tmp0, 0, DT_REAL, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init(&p->tmp1, 0, DT_REAL, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init(&p->tmp2, 0, DT_REAL, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init(&p->r, 0, DT_REAL, _state, make_automatic) )
+        return ae_false;
+    if( !ae_matrix_init(&p->lmmatrix, 0, 0, DT_REAL, _state, make_automatic) )
+        return ae_false;
+    if( !_mincgstate_init(&p->cgstate, _state, make_automatic) )
+        return ae_false;
+    if( !_mincgreport_init(&p->cgrep, _state, make_automatic) )
+        return ae_false;
+    return ae_true;
+}
+
+
+ae_bool _minbleicstate_init_copy(minbleicstate* dst, minbleicstate* src, ae_state *_state, ae_bool make_automatic)
+{
+    dst->nmain = src->nmain;
+    dst->nslack = src->nslack;
+    dst->innerepsg = src->innerepsg;
+    dst->innerepsf = src->innerepsf;
+    dst->innerepsx = src->innerepsx;
+    dst->outerepsx = src->outerepsx;
+    dst->outerepsi = src->outerepsi;
+    dst->maxits = src->maxits;
+    dst->xrep = src->xrep;
+    dst->stpmax = src->stpmax;
+    dst->diffstep = src->diffstep;
+    dst->prectype = src->prectype;
+    if( !ae_vector_init_copy(&dst->diaghoriginal, &src->diaghoriginal, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init_copy(&dst->diagh, &src->diagh, _state, make_automatic) )
         return ae_false;
-    dst->laststep = src->laststep;
     if( !ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic) )
         return ae_false;
     dst->f = src->f;
     if( !ae_vector_init_copy(&dst->g, &src->g, _state, make_automatic) )
         return ae_false;
+    dst->needf = src->needf;
     dst->needfg = src->needfg;
     dst->xupdated = src->xupdated;
     if( !_rcommstate_init_copy(&dst->rstate, &src->rstate, _state, make_automatic) )
         return ae_false;
-    dst->repiterationscount = src->repiterationscount;
+    dst->repinneriterationscount = src->repinneriterationscount;
+    dst->repouteriterationscount = src->repouteriterationscount;
     dst->repnfev = src->repnfev;
     dst->repterminationtype = src->repterminationtype;
-    dst->debugrestartscount = src->debugrestartscount;
-    if( !_linminstate_init_copy(&dst->lstate, &src->lstate, _state, make_automatic) )
+    dst->repdebugeqerr = src->repdebugeqerr;
+    dst->repdebugfs = src->repdebugfs;
+    dst->repdebugff = src->repdebugff;
+    dst->repdebugdx = src->repdebugdx;
+    if( !ae_vector_init_copy(&dst->xcur, &src->xcur, _state, make_automatic) )
         return ae_false;
-    dst->betahs = src->betahs;
-    dst->betady = src->betady;
-    return ae_true;
-}
-
-
-void _minasastate_clear(minasastate* p)
-{
-    ae_vector_clear(&p->bndl);
-    ae_vector_clear(&p->bndu);
-    ae_vector_clear(&p->ak);
-    ae_vector_clear(&p->xk);
-    ae_vector_clear(&p->dk);
-    ae_vector_clear(&p->an);
-    ae_vector_clear(&p->xn);
-    ae_vector_clear(&p->dn);
-    ae_vector_clear(&p->d);
-    ae_vector_clear(&p->work);
-    ae_vector_clear(&p->yk);
-    ae_vector_clear(&p->gc);
-    ae_vector_clear(&p->x);
-    ae_vector_clear(&p->g);
-    _rcommstate_clear(&p->rstate);
-    _linminstate_clear(&p->lstate);
-}
-
-
-ae_bool _minasareport_init(minasareport* p, ae_state *_state, ae_bool make_automatic)
-{
-    return ae_true;
-}
-
-
-ae_bool _minasareport_init_copy(minasareport* dst, minasareport* src, ae_state *_state, ae_bool make_automatic)
-{
-    dst->iterationscount = src->iterationscount;
+    if( !ae_vector_init_copy(&dst->xprev, &src->xprev, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init_copy(&dst->xstart, &src->xstart, _state, make_automatic) )
+        return ae_false;
+    dst->itsleft = src->itsleft;
+    if( !ae_vector_init_copy(&dst->xend, &src->xend, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init_copy(&dst->lastg, &src->lastg, _state, make_automatic) )
+        return ae_false;
+    dst->trimthreshold = src->trimthreshold;
+    if( !ae_matrix_init_copy(&dst->ceoriginal, &src->ceoriginal, _state, make_automatic) )
+        return ae_false;
+    if( !ae_matrix_init_copy(&dst->ceeffective, &src->ceeffective, _state, make_automatic) )
+        return ae_false;
+    if( !ae_matrix_init_copy(&dst->cecurrent, &src->cecurrent, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init_copy(&dst->ct, &src->ct, _state, make_automatic) )
+        return ae_false;
+    dst->cecnt = src->cecnt;
+    dst->cedim = src->cedim;
+    if( !ae_vector_init_copy(&dst->xe, &src->xe, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init_copy(&dst->hasbndl, &src->hasbndl, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init_copy(&dst->hasbndu, &src->hasbndu, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init_copy(&dst->bndloriginal, &src->bndloriginal, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init_copy(&dst->bnduoriginal, &src->bnduoriginal, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init_copy(&dst->bndleffective, &src->bndleffective, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init_copy(&dst->bndueffective, &src->bndueffective, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init_copy(&dst->activeconstraints, &src->activeconstraints, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init_copy(&dst->constrainedvalues, &src->constrainedvalues, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init_copy(&dst->transforms, &src->transforms, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init_copy(&dst->seffective, &src->seffective, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init_copy(&dst->soriginal, &src->soriginal, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init_copy(&dst->w, &src->w, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init_copy(&dst->tmp0, &src->tmp0, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init_copy(&dst->tmp1, &src->tmp1, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init_copy(&dst->tmp2, &src->tmp2, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init_copy(&dst->r, &src->r, _state, make_automatic) )
+        return ae_false;
+    if( !ae_matrix_init_copy(&dst->lmmatrix, &src->lmmatrix, _state, make_automatic) )
+        return ae_false;
+    dst->v0 = src->v0;
+    dst->v1 = src->v1;
+    dst->v2 = src->v2;
+    dst->t = src->t;
+    dst->errfeas = src->errfeas;
+    dst->gnorm = src->gnorm;
+    dst->mpgnorm = src->mpgnorm;
+    dst->mba = src->mba;
+    dst->variabletofreeze = src->variabletofreeze;
+    dst->valuetofreeze = src->valuetofreeze;
+    dst->fbase = src->fbase;
+    dst->fm2 = src->fm2;
+    dst->fm1 = src->fm1;
+    dst->fp1 = src->fp1;
+    dst->fp2 = src->fp2;
+    dst->xm1 = src->xm1;
+    dst->xp1 = src->xp1;
+    if( !_mincgstate_init_copy(&dst->cgstate, &src->cgstate, _state, make_automatic) )
+        return ae_false;
+    if( !_mincgreport_init_copy(&dst->cgrep, &src->cgrep, _state, make_automatic) )
+        return ae_false;
+    dst->optdim = src->optdim;
+    return ae_true;
+}
+
+
+void _minbleicstate_clear(minbleicstate* p)
+{
+    ae_vector_clear(&p->diaghoriginal);
+    ae_vector_clear(&p->diagh);
+    ae_vector_clear(&p->x);
+    ae_vector_clear(&p->g);
+    _rcommstate_clear(&p->rstate);
+    ae_vector_clear(&p->xcur);
+    ae_vector_clear(&p->xprev);
+    ae_vector_clear(&p->xstart);
+    ae_vector_clear(&p->xend);
+    ae_vector_clear(&p->lastg);
+    ae_matrix_clear(&p->ceoriginal);
+    ae_matrix_clear(&p->ceeffective);
+    ae_matrix_clear(&p->cecurrent);
+    ae_vector_clear(&p->ct);
+    ae_vector_clear(&p->xe);
+    ae_vector_clear(&p->hasbndl);
+    ae_vector_clear(&p->hasbndu);
+    ae_vector_clear(&p->bndloriginal);
+    ae_vector_clear(&p->bnduoriginal);
+    ae_vector_clear(&p->bndleffective);
+    ae_vector_clear(&p->bndueffective);
+    ae_vector_clear(&p->activeconstraints);
+    ae_vector_clear(&p->constrainedvalues);
+    ae_vector_clear(&p->transforms);
+    ae_vector_clear(&p->seffective);
+    ae_vector_clear(&p->soriginal);
+    ae_vector_clear(&p->w);
+    ae_vector_clear(&p->tmp0);
+    ae_vector_clear(&p->tmp1);
+    ae_vector_clear(&p->tmp2);
+    ae_vector_clear(&p->r);
+    ae_matrix_clear(&p->lmmatrix);
+    _mincgstate_clear(&p->cgstate);
+    _mincgreport_clear(&p->cgrep);
+}
+
+
+ae_bool _minbleicreport_init(minbleicreport* p, ae_state *_state, ae_bool make_automatic)
+{
+    return ae_true;
+}
+
+
+ae_bool _minbleicreport_init_copy(minbleicreport* dst, minbleicreport* src, ae_state *_state, ae_bool make_automatic)
+{
+    dst->inneriterationscount = src->inneriterationscount;
+    dst->outeriterationscount = src->outeriterationscount;
     dst->nfev = src->nfev;
     dst->terminationtype = src->terminationtype;
-    dst->activeconstraints = src->activeconstraints;
+    dst->debugeqerr = src->debugeqerr;
+    dst->debugfs = src->debugfs;
+    dst->debugff = src->debugff;
+    dst->debugdx = src->debugdx;
     return ae_true;
 }
 
 
-void _minasareport_clear(minasareport* p)
+void _minbleicreport_clear(minbleicreport* p)
 {
 }
 
@@ -9100,15 +10089,16 @@ void _minasareport_clear(minasareport* p)
 
 
 /*************************************************************************
-        NONLINEAR CONJUGATE GRADIENT METHOD
+        LIMITED MEMORY BFGS METHOD FOR LARGE SCALE OPTIMIZATION
 
 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) }.
+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:
@@ -9117,79 +10107,151 @@ Algorithm will request following information during its operation:
 
 
 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
+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 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.
+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.
+
+
+  -- ALGLIB --
+     Copyright 02.04.2010 by Bochkanov Sergey
+*************************************************************************/
+void minlbfgscreate(ae_int_t n,
+     ae_int_t m,
+     /* Real    */ ae_vector* x,
+     minlbfgsstate* state,
+     ae_state *_state)
+{
+
+    _minlbfgsstate_clear(state);
+
+    ae_assert(n>=1, "MinLBFGSCreate: N<1!", _state);
+    ae_assert(m>=1, "MinLBFGSCreate: M<1", _state);
+    ae_assert(m<=n, "MinLBFGSCreate: M>N", _state);
+    ae_assert(x->cnt>=n, "MinLBFGSCreate: Length(X)<N!", _state);
+    ae_assert(isfinitevector(x, n, _state), "MinLBFGSCreate: X contains infinite or NaN values!", _state);
+    minlbfgscreatex(n, m, x, 0, 0.0, state, _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.
+
   -- ALGLIB --
-     Copyright 25.03.2010 by Bochkanov Sergey
+     Copyright 16.05.2011 by Bochkanov Sergey
 *************************************************************************/
-void mincgcreate(ae_int_t n,
+void minlbfgscreatef(ae_int_t n,
+     ae_int_t m,
      /* Real    */ ae_vector* x,
-     mincgstate* state,
+     double diffstep,
+     minlbfgsstate* state,
      ae_state *_state)
 {
 
-    _mincgstate_clear(state);
+    _minlbfgsstate_clear(state);
 
-    ae_assert(n>=1, "MinCGCreate: N too small!", _state);
-    ae_assert(x->cnt>=n, "MinCGCreate: Length(X)<N!", _state);
-    ae_assert(isfinitevector(x, n, _state), "MinCGCreate: X contains infinite or NaN values!", _state);
-    
-    /*
-     * Initialize
-     */
-    state->n = n;
-    mincgsetcond(state, 0, 0, 0, 0, _state);
-    mincgsetxrep(state, ae_false, _state);
-    mincgsetdrep(state, ae_false, _state);
-    mincgsetstpmax(state, 0, _state);
-    mincgsetcgtype(state, -1, _state);
-    ae_vector_set_length(&state->xk, n, _state);
-    ae_vector_set_length(&state->dk, n, _state);
-    ae_vector_set_length(&state->xn, n, _state);
-    ae_vector_set_length(&state->dn, n, _state);
-    ae_vector_set_length(&state->x, n, _state);
-    ae_vector_set_length(&state->d, n, _state);
-    ae_vector_set_length(&state->g, n, _state);
-    ae_vector_set_length(&state->work, n, _state);
-    ae_vector_set_length(&state->yk, n, _state);
-    mincgrestartfrom(state, x, _state);
+    ae_assert(n>=1, "MinLBFGSCreateF: N too small!", _state);
+    ae_assert(m>=1, "MinLBFGSCreateF: M<1", _state);
+    ae_assert(m<=n, "MinLBFGSCreateF: M>N", _state);
+    ae_assert(x->cnt>=n, "MinLBFGSCreateF: Length(X)<N!", _state);
+    ae_assert(isfinitevector(x, n, _state), "MinLBFGSCreateF: X contains infinite or NaN values!", _state);
+    ae_assert(ae_isfinite(diffstep, _state), "MinLBFGSCreateF: DiffStep is infinite or NaN!", _state);
+    ae_assert(ae_fp_greater(diffstep,0), "MinLBFGSCreateF: DiffStep is non-positive!", _state);
+    minlbfgscreatex(n, m, x, 0, diffstep, state, _state);
 }
 
 
 /*************************************************************************
-This function sets stopping conditions for CG optimization algorithm.
+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
-                ||G||<EpsG is satisfied, where ||.|| means Euclidian norm,
-                G - gradient.
+                |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 |X(k+1)-X(k)| <= EpsX is fulfilled.
+                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.
 
@@ -9199,7 +10261,7 @@ automatic stopping criterion selection (small EpsX).
   -- ALGLIB --
      Copyright 02.04.2010 by Bochkanov Sergey
 *************************************************************************/
-void mincgsetcond(mincgstate* state,
+void minlbfgssetcond(minlbfgsstate* state,
      double epsg,
      double epsf,
      double epsx,
@@ -9208,13 +10270,13 @@ void mincgsetcond(mincgstate* state,
 {
 
 
-    ae_assert(ae_isfinite(epsg, _state), "MinCGSetCond: EpsG is not finite number!", _state);
-    ae_assert(ae_fp_greater_eq(epsg,0), "MinCGSetCond: negative EpsG!", _state);
-    ae_assert(ae_isfinite(epsf, _state), "MinCGSetCond: EpsF is not finite number!", _state);
-    ae_assert(ae_fp_greater_eq(epsf,0), "MinCGSetCond: negative EpsF!", _state);
-    ae_assert(ae_isfinite(epsx, _state), "MinCGSetCond: EpsX is not finite number!", _state);
-    ae_assert(ae_fp_greater_eq(epsx,0), "MinCGSetCond: negative EpsX!", _state);
-    ae_assert(maxits>=0, "MinCGSetCond: negative MaxIts!", _state);
+    ae_assert(ae_isfinite(epsg, _state), "MinLBFGSSetCond: EpsG is not finite number!", _state);
+    ae_assert(ae_fp_greater_eq(epsg,0), "MinLBFGSSetCond: negative EpsG!", _state);
+    ae_assert(ae_isfinite(epsf, _state), "MinLBFGSSetCond: EpsF is not finite number!", _state);
+    ae_assert(ae_fp_greater_eq(epsf,0), "MinLBFGSSetCond: negative EpsF!", _state);
+    ae_assert(ae_isfinite(epsx, _state), "MinLBFGSSetCond: EpsX is not finite number!", _state);
+    ae_assert(ae_fp_greater_eq(epsx,0), "MinLBFGSSetCond: negative EpsX!", _state);
+    ae_assert(maxits>=0, "MinLBFGSSetCond: negative MaxIts!", _state);
     if( ((ae_fp_eq(epsg,0)&&ae_fp_eq(epsf,0))&&ae_fp_eq(epsx,0))&&maxits==0 )
     {
         epsx = 1.0E-6;
@@ -9234,12 +10296,15 @@ INPUT PARAMETERS:
     NeedXRep-   whether iteration reports are needed or not
 
 If NeedXRep is True, algorithm will call rep() callback function if  it is
-provided to MinCGOptimize().
+provided to MinLBFGSOptimize().
+
 
   -- ALGLIB --
      Copyright 02.04.2010 by Bochkanov Sergey
 *************************************************************************/
-void mincgsetxrep(mincgstate* state, ae_bool needxrep, ae_state *_state)
+void minlbfgssetxrep(minlbfgsstate* state,
+     ae_bool needxrep,
+     ae_state *_state)
 {
 
 
@@ -9248,133 +10313,340 @@ void mincgsetxrep(mincgstate* state, ae_bool needxrep, ae_state *_state)
 
 
 /*************************************************************************
-This function turns on/off line search reports.
-These reports are described in more details in developer-only  comments on
-MinCGState object.
+This function sets maximum step length
 
 INPUT PARAMETERS:
     State   -   structure which stores algorithm state
-    NeedDRep-   whether line search reports are needed or not
+    StpMax  -   maximum step length, >=0. Set StpMax to 0.0 (default),  if
+                you don't want to limit step length.
 
-This function is intended for private use only. Turning it on artificially
-may cause program failure.
+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.
 
   -- ALGLIB --
      Copyright 02.04.2010 by Bochkanov Sergey
 *************************************************************************/
-void mincgsetdrep(mincgstate* state, ae_bool needdrep, ae_state *_state)
+void minlbfgssetstpmax(minlbfgsstate* state,
+     double stpmax,
+     ae_state *_state)
 {
 
 
-    state->drep = needdrep;
+    ae_assert(ae_isfinite(stpmax, _state), "MinLBFGSSetStpMax: StpMax is not finite!", _state);
+    ae_assert(ae_fp_greater_eq(stpmax,0), "MinLBFGSSetStpMax: StpMax<0!", _state);
+    state->stpmax = stpmax;
 }
 
 
 /*************************************************************************
-This function sets CG algorithm.
+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 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
+    State   -   structure stores algorithm state
+    S       -   array[N], non-zero scaling coefficients
+                S[i] may be negative, sign doesn't matter.
+
+  -- ALGLIB --
+     Copyright 14.01.2011 by Bochkanov Sergey
+*************************************************************************/
+void minlbfgssetscale(minlbfgsstate* state,
+     /* Real    */ ae_vector* s,
+     ae_state *_state)
+{
+    ae_int_t i;
+
+
+    ae_assert(s->cnt>=state->n, "MinLBFGSSetScale: Length(S)<N", _state);
+    for(i=0; i<=state->n-1; i++)
+    {
+        ae_assert(ae_isfinite(s->ptr.p_double[i], _state), "MinLBFGSSetScale: S contains infinite or NAN elements", _state);
+        ae_assert(ae_fp_neq(s->ptr.p_double[i],0), "MinLBFGSSetScale: S contains zero elements", _state);
+        state->s.ptr.p_double[i] = ae_fabs(s->ptr.p_double[i], _state);
+    }
+}
+
+
+/*************************************************************************
+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
 
   -- ALGLIB --
      Copyright 02.04.2010 by Bochkanov Sergey
 *************************************************************************/
-void mincgsetcgtype(mincgstate* state, ae_int_t cgtype, ae_state *_state)
+void minlbfgscreatex(ae_int_t n,
+     ae_int_t m,
+     /* Real    */ ae_vector* x,
+     ae_int_t flags,
+     double diffstep,
+     minlbfgsstate* state,
+     ae_state *_state)
 {
+    ae_bool allocatemem;
+    ae_int_t i;
 
 
-    ae_assert(cgtype>=-1&&cgtype<=1, "MinCGSetCGType: incorrect CGType!", _state);
-    if( cgtype==-1 )
+    ae_assert(n>=1, "MinLBFGS: N too small!", _state);
+    ae_assert(m>=1, "MinLBFGS: M too small!", _state);
+    ae_assert(m<=n, "MinLBFGS: M too large!", _state);
+    
+    /*
+     * Initialize
+     */
+    state->diffstep = diffstep;
+    state->n = n;
+    state->m = m;
+    allocatemem = flags%2==0;
+    flags = flags/2;
+    if( allocatemem )
     {
-        cgtype = 1;
+        ae_vector_set_length(&state->rho, m, _state);
+        ae_vector_set_length(&state->theta, m, _state);
+        ae_matrix_set_length(&state->yk, m, n, _state);
+        ae_matrix_set_length(&state->sk, m, n, _state);
+        ae_vector_set_length(&state->d, n, _state);
+        ae_vector_set_length(&state->x, n, _state);
+        ae_vector_set_length(&state->s, n, _state);
+        ae_vector_set_length(&state->g, n, _state);
+        ae_vector_set_length(&state->work, n, _state);
     }
-    state->cgtype = cgtype;
+    minlbfgssetcond(state, 0, 0, 0, 0, _state);
+    minlbfgssetxrep(state, ae_false, _state);
+    minlbfgssetstpmax(state, 0, _state);
+    minlbfgsrestartfrom(state, x, _state);
+    for(i=0; i<=n-1; i++)
+    {
+        state->s.ptr.p_double[i] = 1.0;
+    }
+    state->prectype = 0;
 }
 
 
 /*************************************************************************
-This function sets maximum step length
+Modification  of  the  preconditioner:  default  preconditioner    (simple
+scaling, same for all elements of X) is used.
 
 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:  you  can  change  preconditioner  "on  the  fly",  during algorithm
+iterations.
 
   -- ALGLIB --
-     Copyright 02.04.2010 by Bochkanov Sergey
+     Copyright 13.10.2010 by Bochkanov Sergey
 *************************************************************************/
-void mincgsetstpmax(mincgstate* state, double stpmax, ae_state *_state)
+void minlbfgssetprecdefault(minlbfgsstate* state, ae_state *_state)
 {
 
 
-    ae_assert(ae_isfinite(stpmax, _state), "MinCGSetStpMax: StpMax is not finite!", _state);
-    ae_assert(ae_fp_greater_eq(stpmax,0), "MinCGSetStpMax: StpMax<0!", _state);
-    state->stpmax = stpmax;
+    state->prectype = 0;
 }
 
 
 /*************************************************************************
-This function allows to suggest initial step length to the CG algorithm.
+Modification of the preconditioner: Cholesky factorization of  approximate
+Hessian is used.
 
-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.
+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)
 
-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.
+After call to this function preconditioner is changed to P  (P  is  copied
+into the internal buffer).
 
-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.
+NOTE:  you  can  change  preconditioner  "on  the  fly",  during algorithm
+iterations.
 
-This function influences only first iteration of algorithm. It  should  be
-called between MinCGCreate/MinCGRestartFrom() call and MinCGOptimize call.
+NOTE 2:  P  should  be nonsingular. Exception will be thrown otherwise.
+
+  -- ALGLIB --
+     Copyright 13.10.2010 by Bochkanov Sergey
+*************************************************************************/
+void minlbfgssetpreccholesky(minlbfgsstate* state,
+     /* Real    */ ae_matrix* p,
+     ae_bool isupper,
+     ae_state *_state)
+{
+    ae_int_t i;
+    double mx;
+
+
+    ae_assert(isfinitertrmatrix(p, state->n, isupper, _state), "MinLBFGSSetPrecCholesky: P contains infinite or NAN values!", _state);
+    mx = 0;
+    for(i=0; i<=state->n-1; i++)
+    {
+        mx = ae_maxreal(mx, ae_fabs(p->ptr.pp_double[i][i], _state), _state);
+    }
+    ae_assert(ae_fp_greater(mx,0), "MinLBFGSSetPrecCholesky: P is strictly singular!", _state);
+    if( state->denseh.rows<state->n||state->denseh.cols<state->n )
+    {
+        ae_matrix_set_length(&state->denseh, state->n, state->n, _state);
+    }
+    state->prectype = 1;
+    if( isupper )
+    {
+        rmatrixcopy(state->n, state->n, p, 0, 0, &state->denseh, 0, 0, _state);
+    }
+    else
+    {
+        rmatrixtranspose(state->n, state->n, p, 0, 0, &state->denseh, 0, 0, _state);
+    }
+}
+
+
+/*************************************************************************
+Modification  of  the  preconditioner:  diagonal of approximate Hessian is
+used.
 
 INPUT PARAMETERS:
-    State   -   structure used to store algorithm state.
-    Stp     -   initial estimate of the step length.
-                Can be zero (no estimate).
+    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.
 
   -- ALGLIB --
-     Copyright 30.07.2010 by Bochkanov Sergey
+     Copyright 13.10.2010 by Bochkanov Sergey
 *************************************************************************/
-void mincgsuggeststep(mincgstate* state, double stp, ae_state *_state)
+void minlbfgssetprecdiag(minlbfgsstate* state,
+     /* Real    */ ae_vector* d,
+     ae_state *_state)
 {
+    ae_int_t i;
 
 
-    ae_assert(ae_isfinite(stp, _state), "MinCGSuggestStep: Stp is infinite or NAN", _state);
-    ae_assert(ae_fp_greater_eq(stp,0), "MinCGSuggestStep: Stp<0", _state);
-    state->suggestedstep = stp;
+    ae_assert(d->cnt>=state->n, "MinLBFGSSetPrecDiag: D is too short", _state);
+    for(i=0; i<=state->n-1; i++)
+    {
+        ae_assert(ae_isfinite(d->ptr.p_double[i], _state), "MinLBFGSSetPrecDiag: D contains infinite or NAN elements", _state);
+        ae_assert(ae_fp_greater(d->ptr.p_double[i],0), "MinLBFGSSetPrecDiag: D contains non-positive elements", _state);
+    }
+    rvectorsetlengthatleast(&state->diagh, state->n, _state);
+    state->prectype = 2;
+    for(i=0; i<=state->n-1; i++)
+    {
+        state->diagh.ptr.p_double[i] = d->ptr.p_double[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
 
   -- ALGLIB --
-     Copyright 20.04.2009 by Bochkanov Sergey
+     Copyright 13.10.2010 by Bochkanov Sergey
 *************************************************************************/
-ae_bool mincgiteration(mincgstate* state, ae_state *_state)
+void minlbfgssetprecscale(minlbfgsstate* state, ae_state *_state)
+{
+
+
+    state->prectype = 3;
+}
+
+
+/*************************************************************************
+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.
+
+  -- ALGLIB --
+     Copyright 20.03.2009 by Bochkanov Sergey
+*************************************************************************/
+ae_bool minlbfgsiteration(minlbfgsstate* state, ae_state *_state)
 {
     ae_int_t n;
+    ae_int_t m;
     ae_int_t i;
-    double betak;
+    ae_int_t j;
+    ae_int_t ic;
+    ae_int_t mcinfo;
     double v;
     double vv;
-    ae_int_t mcinfo;
     ae_bool result;
 
 
@@ -9392,20 +10664,24 @@ ae_bool mincgiteration(mincgstate* state, ae_state *_state)
     if( state->rstate.stage>=0 )
     {
         n = state->rstate.ia.ptr.p_int[0];
-        i = state->rstate.ia.ptr.p_int[1];
-        mcinfo = state->rstate.ia.ptr.p_int[2];
-        betak = state->rstate.ra.ptr.p_double[0];
-        v = state->rstate.ra.ptr.p_double[1];
-        vv = state->rstate.ra.ptr.p_double[2];
+        m = state->rstate.ia.ptr.p_int[1];
+        i = state->rstate.ia.ptr.p_int[2];
+        j = state->rstate.ia.ptr.p_int[3];
+        ic = state->rstate.ia.ptr.p_int[4];
+        mcinfo = state->rstate.ia.ptr.p_int[5];
+        v = state->rstate.ra.ptr.p_double[0];
+        vv = state->rstate.ra.ptr.p_double[1];
     }
     else
     {
         n = -983;
-        i = -989;
-        mcinfo = -834;
-        betak = 900;
-        v = -287;
-        vv = 364;
+        m = -989;
+        i = -834;
+        j = 900;
+        ic = -287;
+        mcinfo = 364;
+        v = 214;
+        vv = -338;
     }
     if( state->rstate.stage==0 )
     {
@@ -9431,202 +10707,307 @@ ae_bool mincgiteration(mincgstate* state, ae_state *_state)
     {
         goto lbl_5;
     }
+    if( state->rstate.stage==6 )
+    {
+        goto lbl_6;
+    }
+    if( state->rstate.stage==7 )
+    {
+        goto lbl_7;
+    }
+    if( state->rstate.stage==8 )
+    {
+        goto lbl_8;
+    }
+    if( state->rstate.stage==9 )
+    {
+        goto lbl_9;
+    }
+    if( state->rstate.stage==10 )
+    {
+        goto lbl_10;
+    }
+    if( state->rstate.stage==11 )
+    {
+        goto lbl_11;
+    }
+    if( state->rstate.stage==12 )
+    {
+        goto lbl_12;
+    }
+    if( state->rstate.stage==13 )
+    {
+        goto lbl_13;
+    }
     
     /*
      * Routine body
      */
     
     /*
-     * Prepare
+     * Unload frequently used variables from State structure
+     * (just for typing convinience)
      */
     n = state->n;
+    m = state->m;
     state->repterminationtype = 0;
     state->repiterationscount = 0;
     state->repnfev = 0;
-    state->debugrestartscount = 0;
     
     /*
-     * Calculate F/G, XK and DK, initialize algorithm
+     * Calculate F/G at the initial point
      */
-    ae_v_move(&state->xk.ptr.p_double[0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    mincg_clearrequestfields(state, _state);
+    minlbfgs_clearrequestfields(state, _state);
+    if( ae_fp_neq(state->diffstep,0) )
+    {
+        goto lbl_14;
+    }
     state->needfg = ae_true;
     state->rstate.stage = 0;
     goto lbl_rcomm;
 lbl_0:
     state->needfg = ae_false;
-    ae_v_moveneg(&state->dk.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    if( !state->xrep )
-    {
-        goto lbl_6;
-    }
-    mincg_clearrequestfields(state, _state);
-    state->xupdated = ae_true;
+    goto lbl_15;
+lbl_14:
+    state->needf = ae_true;
     state->rstate.stage = 1;
     goto lbl_rcomm;
 lbl_1:
-    state->xupdated = ae_false;
-lbl_6:
-    v = ae_v_dotproduct(&state->g.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    v = ae_sqrt(v, _state);
-    if( ae_fp_eq(v,0) )
-    {
-        ae_v_move(&state->xn.ptr.p_double[0], 1, &state->xk.ptr.p_double[0], 1, ae_v_len(0,n-1));
-        state->repterminationtype = 4;
-        result = ae_false;
-        return result;
-    }
-    state->repnfev = 1;
-    state->k = 0;
-    state->fold = state->f;
-    
-    /*
-     * Main cycle
-     */
-    state->laststep = state->suggestedstep;
-    state->rstimer = mincg_rscountdownlen;
-lbl_8:
-    if( ae_false )
-    {
-        goto lbl_9;
-    }
-    
-    /*
-     * Store G[k] for later calculation of Y[k]
-     */
-    ae_v_moveneg(&state->yk.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    
-    /*
-     * Calculate X(k+1): minimize F(x+alpha*d)
-     */
-    ae_v_move(&state->d.ptr.p_double[0], 1, &state->dk.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    ae_v_move(&state->x.ptr.p_double[0], 1, &state->xk.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    state->mcstage = 0;
-    state->stp = 1.0;
-    linminnormalized(&state->d, &state->stp, n, _state);
-    if( ae_fp_neq(state->laststep,0) )
-    {
-        state->stp = state->laststep;
-    }
-    state->curstpmax = state->stpmax;
-    if( !state->drep )
+    state->fbase = state->f;
+    i = 0;
+lbl_16:
+    if( i>n-1 )
     {
-        goto lbl_10;
+        goto lbl_18;
     }
-    
-    /*
-     * Report beginning of line search (if needed)
-     */
-    mincg_clearrequestfields(state, _state);
-    state->lsstart = ae_true;
+    v = state->x.ptr.p_double[i];
+    state->x.ptr.p_double[i] = v-state->diffstep*state->s.ptr.p_double[i];
     state->rstate.stage = 2;
     goto lbl_rcomm;
 lbl_2:
-    state->lsstart = ae_false;
-lbl_10:
-    mcsrch(n, &state->x, &state->f, &state->g, &state->d, &state->stp, state->curstpmax, &mcinfo, &state->nfev, &state->work, &state->lstate, &state->mcstage, _state);
-lbl_12:
-    if( state->mcstage==0 )
-    {
-        goto lbl_13;
-    }
-    mincg_clearrequestfields(state, _state);
-    state->needfg = ae_true;
+    state->fm2 = state->f;
+    state->x.ptr.p_double[i] = v-0.5*state->diffstep*state->s.ptr.p_double[i];
     state->rstate.stage = 3;
     goto lbl_rcomm;
 lbl_3:
-    state->needfg = ae_false;
-    mcsrch(n, &state->x, &state->f, &state->g, &state->d, &state->stp, state->curstpmax, &mcinfo, &state->nfev, &state->work, &state->lstate, &state->mcstage, _state);
-    goto lbl_12;
-lbl_13:
-    if( !state->drep )
-    {
-        goto lbl_14;
-    }
-    
-    /*
-     * Report end of line search (if needed)
-     */
-    mincg_clearrequestfields(state, _state);
-    state->lsend = ae_true;
+    state->fm1 = state->f;
+    state->x.ptr.p_double[i] = v+0.5*state->diffstep*state->s.ptr.p_double[i];
     state->rstate.stage = 4;
     goto lbl_rcomm;
 lbl_4:
-    state->lsend = ae_false;
-lbl_14:
+    state->fp1 = state->f;
+    state->x.ptr.p_double[i] = v+state->diffstep*state->s.ptr.p_double[i];
+    state->rstate.stage = 5;
+    goto lbl_rcomm;
+lbl_5:
+    state->fp2 = state->f;
+    state->x.ptr.p_double[i] = v;
+    state->g.ptr.p_double[i] = (8*(state->fp1-state->fm1)-(state->fp2-state->fm2))/(6*state->diffstep*state->s.ptr.p_double[i]);
+    i = i+1;
+    goto lbl_16;
+lbl_18:
+    state->f = state->fbase;
+    state->needf = ae_false;
+lbl_15:
+    trimprepare(state->f, &state->trimthreshold, _state);
     if( !state->xrep )
     {
-        goto lbl_16;
+        goto lbl_19;
     }
-    mincg_clearrequestfields(state, _state);
+    minlbfgs_clearrequestfields(state, _state);
     state->xupdated = ae_true;
-    state->rstate.stage = 5;
+    state->rstate.stage = 6;
     goto lbl_rcomm;
-lbl_5:
+lbl_6:
     state->xupdated = ae_false;
-lbl_16:
-    ae_v_move(&state->xn.ptr.p_double[0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    if( mcinfo==1 )
+lbl_19:
+    state->repnfev = 1;
+    state->fold = state->f;
+    v = 0;
+    for(i=0; i<=n-1; i++)
+    {
+        v = v+ae_sqr(state->g.ptr.p_double[i]*state->s.ptr.p_double[i], _state);
+    }
+    if( ae_fp_less_eq(ae_sqrt(v, _state),state->epsg) )
+    {
+        state->repterminationtype = 4;
+        result = ae_false;
+        return result;
+    }
+    
+    /*
+     * Choose initial step and direction.
+     * Apply preconditioner, if we have something other than default.
+     */
+    ae_v_moveneg(&state->d.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1));
+    if( state->prectype==0 )
     {
         
         /*
-         * Standard Wolfe conditions hold
-         * Calculate Y[K] and BetaK
+         * Default preconditioner is used, but we can't use it before iterations will start
          */
-        ae_v_add(&state->yk.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1));
-        vv = ae_v_dotproduct(&state->yk.ptr.p_double[0], 1, &state->dk.ptr.p_double[0], 1, ae_v_len(0,n-1));
         v = ae_v_dotproduct(&state->g.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1));
-        state->betady = v/vv;
-        v = ae_v_dotproduct(&state->g.ptr.p_double[0], 1, &state->yk.ptr.p_double[0], 1, ae_v_len(0,n-1));
-        state->betahs = v/vv;
-        if( state->cgtype==0 )
+        v = ae_sqrt(v, _state);
+        if( ae_fp_eq(state->stpmax,0) )
         {
-            betak = state->betady;
+            state->stp = ae_minreal(1.0/v, 1, _state);
         }
-        if( state->cgtype==1 )
+        else
         {
-            betak = ae_maxreal(0, ae_minreal(state->betady, state->betahs, _state), _state);
+            state->stp = ae_minreal(1.0/v, state->stpmax, _state);
         }
     }
-    else
+    if( state->prectype==1 )
     {
         
         /*
-         * 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.
+         * Cholesky preconditioner is used
          */
-        betak = 0;
-        state->debugrestartscount = state->debugrestartscount+1;
+        fblscholeskysolve(&state->denseh, 1.0, n, ae_true, &state->d, &state->autobuf, _state);
+        state->stp = 1;
     }
-    if( mcinfo==1||mcinfo==5 )
+    if( state->prectype==2 )
     {
-        state->rstimer = mincg_rscountdownlen;
+        
+        /*
+         * diagonal approximation is used
+         */
+        for(i=0; i<=n-1; i++)
+        {
+            state->d.ptr.p_double[i] = state->d.ptr.p_double[i]/state->diagh.ptr.p_double[i];
+        }
+        state->stp = 1;
     }
-    else
+    if( state->prectype==3 )
     {
-        state->rstimer = state->rstimer-1;
+        
+        /*
+         * scale-based preconditioner is used
+         */
+        for(i=0; i<=n-1; i++)
+        {
+            state->d.ptr.p_double[i] = state->d.ptr.p_double[i]*state->s.ptr.p_double[i]*state->s.ptr.p_double[i];
+        }
+        state->stp = 1;
     }
     
     /*
-     * Calculate D(k+1)
+     * Main cycle
      */
-    ae_v_moveneg(&state->dn.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    ae_v_addd(&state->dn.ptr.p_double[0], 1, &state->dk.ptr.p_double[0], 1, ae_v_len(0,n-1), betak);
+    state->k = 0;
+lbl_21:
+    if( ae_false )
+    {
+        goto lbl_22;
+    }
     
     /*
-     * Update info about step length
+     * Main cycle: prepare to 1-D line search
      */
-    v = ae_v_dotproduct(&state->d.ptr.p_double[0], 1, &state->d.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    state->laststep = ae_sqrt(v, _state)*state->stp;
+    state->p = state->k%m;
+    state->q = ae_minint(state->k, m-1, _state);
     
     /*
-     * Update information and Hessian.
-     * Check stopping conditions.
+     * Store X[k], G[k]
+     */
+    ae_v_moveneg(&state->sk.ptr.pp_double[state->p][0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,n-1));
+    ae_v_moveneg(&state->yk.ptr.pp_double[state->p][0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1));
+    
+    /*
+     * Minimize F(x+alpha*d)
+     * Calculate S[k], Y[k]
+     */
+    state->mcstage = 0;
+    if( state->k!=0 )
+    {
+        state->stp = 1.0;
+    }
+    linminnormalized(&state->d, &state->stp, n, _state);
+    mcsrch(n, &state->x, &state->f, &state->g, &state->d, &state->stp, state->stpmax, minlbfgs_gtol, &mcinfo, &state->nfev, &state->work, &state->lstate, &state->mcstage, _state);
+lbl_23:
+    if( state->mcstage==0 )
+    {
+        goto lbl_24;
+    }
+    minlbfgs_clearrequestfields(state, _state);
+    if( ae_fp_neq(state->diffstep,0) )
+    {
+        goto lbl_25;
+    }
+    state->needfg = ae_true;
+    state->rstate.stage = 7;
+    goto lbl_rcomm;
+lbl_7:
+    state->needfg = ae_false;
+    goto lbl_26;
+lbl_25:
+    state->needf = ae_true;
+    state->rstate.stage = 8;
+    goto lbl_rcomm;
+lbl_8:
+    state->fbase = state->f;
+    i = 0;
+lbl_27:
+    if( i>n-1 )
+    {
+        goto lbl_29;
+    }
+    v = state->x.ptr.p_double[i];
+    state->x.ptr.p_double[i] = v-state->diffstep*state->s.ptr.p_double[i];
+    state->rstate.stage = 9;
+    goto lbl_rcomm;
+lbl_9:
+    state->fm2 = state->f;
+    state->x.ptr.p_double[i] = v-0.5*state->diffstep*state->s.ptr.p_double[i];
+    state->rstate.stage = 10;
+    goto lbl_rcomm;
+lbl_10:
+    state->fm1 = state->f;
+    state->x.ptr.p_double[i] = v+0.5*state->diffstep*state->s.ptr.p_double[i];
+    state->rstate.stage = 11;
+    goto lbl_rcomm;
+lbl_11:
+    state->fp1 = state->f;
+    state->x.ptr.p_double[i] = v+state->diffstep*state->s.ptr.p_double[i];
+    state->rstate.stage = 12;
+    goto lbl_rcomm;
+lbl_12:
+    state->fp2 = state->f;
+    state->x.ptr.p_double[i] = v;
+    state->g.ptr.p_double[i] = (8*(state->fp1-state->fm1)-(state->fp2-state->fm2))/(6*state->diffstep*state->s.ptr.p_double[i]);
+    i = i+1;
+    goto lbl_27;
+lbl_29:
+    state->f = state->fbase;
+    state->needf = ae_false;
+lbl_26:
+    trimfunction(&state->f, &state->g, n, state->trimthreshold, _state);
+    mcsrch(n, &state->x, &state->f, &state->g, &state->d, &state->stp, state->stpmax, minlbfgs_gtol, &mcinfo, &state->nfev, &state->work, &state->lstate, &state->mcstage, _state);
+    goto lbl_23;
+lbl_24:
+    if( !state->xrep )
+    {
+        goto lbl_30;
+    }
+    
+    /*
+     * report
      */
+    minlbfgs_clearrequestfields(state, _state);
+    state->xupdated = ae_true;
+    state->rstate.stage = 13;
+    goto lbl_rcomm;
+lbl_13:
+    state->xupdated = ae_false;
+lbl_30:
     state->repnfev = state->repnfev+state->nfev;
     state->repiterationscount = state->repiterationscount+1;
+    ae_v_add(&state->sk.ptr.pp_double[state->p][0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,n-1));
+    ae_v_add(&state->yk.ptr.pp_double[state->p][0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1));
+    
+    /*
+     * Stopping conditions
+     */
     if( state->repiterationscount>=state->maxits&&state->maxits>0 )
     {
         
@@ -9637,9 +11018,13 @@ lbl_16:
         result = ae_false;
         return result;
     }
-    v = ae_v_dotproduct(&state->g.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    if( ae_fp_less_eq(ae_sqrt(v, _state),state->epsg) )
-    {
+    v = 0;
+    for(i=0; i<=n-1; i++)
+    {
+        v = v+ae_sqr(state->g.ptr.p_double[i]*state->s.ptr.p_double[i], _state);
+    }
+    if( ae_fp_less_eq(ae_sqrt(v, _state),state->epsg) )
+    {
         
         /*
          * Gradient is small enough
@@ -9658,7 +11043,12 @@ lbl_16:
         result = ae_false;
         return result;
     }
-    if( ae_fp_less_eq(state->laststep,state->epsx) )
+    v = 0;
+    for(i=0; i<=n-1; i++)
+    {
+        v = v+ae_sqr(state->sk.ptr.pp_double[state->p][i]/state->s.ptr.p_double[i], _state);
+    }
+    if( ae_fp_less_eq(ae_sqrt(v, _state),state->epsx) )
     {
         
         /*
@@ -9668,26 +11058,127 @@ lbl_16:
         result = ae_false;
         return result;
     }
-    if( state->rstimer<=0 )
+    
+    /*
+     * 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 )
     {
         
         /*
-         * Too many subsequent restarts
+         * 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->repterminationtype = 7;
-        result = ae_false;
-        return result;
+        state->fold = state->f;
+        ae_v_moveneg(&state->d.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1));
     }
-    
-    /*
-     * Shift Xk/Dk, update other information
-     */
-    ae_v_move(&state->xk.ptr.p_double[0], 1, &state->xn.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    ae_v_move(&state->dk.ptr.p_double[0], 1, &state->dn.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    state->fold = state->f;
-    state->k = state->k+1;
-    goto lbl_8;
-lbl_9:
+    else
+    {
+        
+        /*
+         * Calculate Rho[k], GammaK
+         */
+        v = ae_v_dotproduct(&state->yk.ptr.pp_double[state->p][0], 1, &state->sk.ptr.pp_double[state->p][0], 1, ae_v_len(0,n-1));
+        vv = ae_v_dotproduct(&state->yk.ptr.pp_double[state->p][0], 1, &state->yk.ptr.pp_double[state->p][0], 1, ae_v_len(0,n-1));
+        if( ae_fp_eq(v,0)||ae_fp_eq(vv,0) )
+        {
+            
+            /*
+             * Rounding errors make further iterations impossible.
+             */
+            state->repterminationtype = -2;
+            result = ae_false;
+            return result;
+        }
+        state->rho.ptr.p_double[state->p] = 1/v;
+        state->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)
+         */
+        ae_v_move(&state->work.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1));
+        for(i=state->k; i>=state->k-state->q; i--)
+        {
+            ic = i%m;
+            v = ae_v_dotproduct(&state->sk.ptr.pp_double[ic][0], 1, &state->work.ptr.p_double[0], 1, ae_v_len(0,n-1));
+            state->theta.ptr.p_double[ic] = v;
+            vv = v*state->rho.ptr.p_double[ic];
+            ae_v_subd(&state->work.ptr.p_double[0], 1, &state->yk.ptr.pp_double[ic][0], 1, ae_v_len(0,n-1), vv);
+        }
+        if( state->prectype==0 )
+        {
+            
+            /*
+             * Simple preconditioner is used
+             */
+            v = state->gammak;
+            ae_v_muld(&state->work.ptr.p_double[0], 1, ae_v_len(0,n-1), v);
+        }
+        if( state->prectype==1 )
+        {
+            
+            /*
+             * Cholesky preconditioner is used
+             */
+            fblscholeskysolve(&state->denseh, 1, n, ae_true, &state->work, &state->autobuf, _state);
+        }
+        if( state->prectype==2 )
+        {
+            
+            /*
+             * diagonal approximation is used
+             */
+            for(i=0; i<=n-1; i++)
+            {
+                state->work.ptr.p_double[i] = state->work.ptr.p_double[i]/state->diagh.ptr.p_double[i];
+            }
+        }
+        if( state->prectype==3 )
+        {
+            
+            /*
+             * scale-based preconditioner is used
+             */
+            for(i=0; i<=n-1; i++)
+            {
+                state->work.ptr.p_double[i] = state->work.ptr.p_double[i]*state->s.ptr.p_double[i]*state->s.ptr.p_double[i];
+            }
+        }
+        for(i=state->k-state->q; i<=state->k; i++)
+        {
+            ic = i%m;
+            v = ae_v_dotproduct(&state->yk.ptr.pp_double[ic][0], 1, &state->work.ptr.p_double[0], 1, ae_v_len(0,n-1));
+            vv = state->rho.ptr.p_double[ic]*(-v+state->theta.ptr.p_double[ic]);
+            ae_v_addd(&state->work.ptr.p_double[0], 1, &state->sk.ptr.pp_double[ic][0], 1, ae_v_len(0,n-1), vv);
+        }
+        ae_v_moveneg(&state->d.ptr.p_double[0], 1, &state->work.ptr.p_double[0], 1, ae_v_len(0,n-1));
+        
+        /*
+         * Next step
+         */
+        state->fold = state->f;
+        state->k = state->k+1;
+    }
+    goto lbl_21;
+lbl_22:
     result = ae_false;
     return result;
     
@@ -9697,17 +11188,19 @@ lbl_9:
 lbl_rcomm:
     result = ae_true;
     state->rstate.ia.ptr.p_int[0] = n;
-    state->rstate.ia.ptr.p_int[1] = i;
-    state->rstate.ia.ptr.p_int[2] = mcinfo;
-    state->rstate.ra.ptr.p_double[0] = betak;
-    state->rstate.ra.ptr.p_double[1] = v;
-    state->rstate.ra.ptr.p_double[2] = vv;
+    state->rstate.ia.ptr.p_int[1] = m;
+    state->rstate.ia.ptr.p_int[2] = i;
+    state->rstate.ia.ptr.p_int[3] = j;
+    state->rstate.ia.ptr.p_int[4] = ic;
+    state->rstate.ia.ptr.p_int[5] = mcinfo;
+    state->rstate.ra.ptr.p_double[0] = v;
+    state->rstate.ra.ptr.p_double[1] = vv;
     return result;
 }
 
 
 /*************************************************************************
-Conjugate gradient results
+L-BFGS algorithm results
 
 INPUT PARAMETERS:
     State   -   algorithm state
@@ -9716,47 +11209,49 @@ 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,
-                            we return best X found so far
+                            further improvement is impossible
                 * Rep.IterationsCount contains iterations count
                 * NFEV countains number of function calculations
 
   -- ALGLIB --
-     Copyright 20.04.2009 by Bochkanov Sergey
+     Copyright 02.04.2010 by Bochkanov Sergey
 *************************************************************************/
-void mincgresults(mincgstate* state,
+void minlbfgsresults(minlbfgsstate* state,
      /* Real    */ ae_vector* x,
-     mincgreport* rep,
+     minlbfgsreport* rep,
      ae_state *_state)
 {
 
     ae_vector_clear(x);
-    _mincgreport_clear(rep);
+    _minlbfgsreport_clear(rep);
 
-    mincgresultsbuf(state, x, rep, _state);
+    minlbfgsresultsbuf(state, x, rep, _state);
 }
 
 
 /*************************************************************************
-Conjugate gradient results
+L-BFGS algorithm results
 
-Buffered implementation of MinCGResults(), which uses pre-allocated buffer
+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.
 
   -- ALGLIB --
-     Copyright 20.04.2009 by Bochkanov Sergey
+     Copyright 20.08.2010 by Bochkanov Sergey
 *************************************************************************/
-void mincgresultsbuf(mincgstate* state,
+void minlbfgsresultsbuf(minlbfgsstate* state,
      /* Real    */ ae_vector* x,
-     mincgreport* rep,
+     minlbfgsreport* rep,
      ae_state *_state)
 {
 
@@ -9765,7 +11260,7 @@ void mincgresultsbuf(mincgstate* state,
     {
         ae_vector_set_length(x, state->n, _state);
     }
-    ae_v_move(&x->ptr.p_double[0], 1, &state->xn.ptr.p_double[0], 1, ae_v_len(0,state->n-1));
+    ae_v_move(&x->ptr.p_double[0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,state->n-1));
     rep->iterationscount = state->repiterationscount;
     rep->nfev = state->repnfev;
     rep->terminationtype = state->repterminationtype;
@@ -9773,65 +11268,70 @@ void mincgresultsbuf(mincgstate* state,
 
 
 /*************************************************************************
-This  subroutine  restarts  CG  algorithm from new point. All optimization
+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.
+    State   -   structure used to store algorithm state
     X       -   new starting point.
 
   -- ALGLIB --
      Copyright 30.07.2010 by Bochkanov Sergey
 *************************************************************************/
-void mincgrestartfrom(mincgstate* state,
+void minlbfgsrestartfrom(minlbfgsstate* state,
      /* Real    */ ae_vector* x,
      ae_state *_state)
 {
 
 
-    ae_assert(x->cnt>=state->n, "MinCGRestartFrom: Length(X)<N!", _state);
-    ae_assert(isfinitevector(x, state->n, _state), "MinCGCreate: X contains infinite or NaN values!", _state);
+    ae_assert(x->cnt>=state->n, "MinLBFGSRestartFrom: Length(X)<N!", _state);
+    ae_assert(isfinitevector(x, state->n, _state), "MinLBFGSRestartFrom: X contains infinite or NaN values!", _state);
     ae_v_move(&state->x.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,state->n-1));
-    mincgsuggeststep(state, 0.0, _state);
-    ae_vector_set_length(&state->rstate.ia, 2+1, _state);
-    ae_vector_set_length(&state->rstate.ra, 2+1, _state);
+    ae_vector_set_length(&state->rstate.ia, 5+1, _state);
+    ae_vector_set_length(&state->rstate.ra, 1+1, _state);
     state->rstate.stage = -1;
-    mincg_clearrequestfields(state, _state);
+    minlbfgs_clearrequestfields(state, _state);
 }
 
 
 /*************************************************************************
 Clears request fileds (to be sure that we don't forgot to clear something)
 *************************************************************************/
-static void mincg_clearrequestfields(mincgstate* state, ae_state *_state)
+static void minlbfgs_clearrequestfields(minlbfgsstate* state,
+     ae_state *_state)
 {
 
 
+    state->needf = ae_false;
     state->needfg = ae_false;
     state->xupdated = ae_false;
-    state->lsstart = ae_false;
-    state->lsend = ae_false;
 }
 
 
-ae_bool _mincgstate_init(mincgstate* p, ae_state *_state, ae_bool make_automatic)
+ae_bool _minlbfgsstate_init(minlbfgsstate* p, ae_state *_state, ae_bool make_automatic)
 {
-    if( !ae_vector_init(&p->xk, 0, DT_REAL, _state, make_automatic) )
+    if( !ae_vector_init(&p->s, 0, DT_REAL, _state, make_automatic) )
         return ae_false;
-    if( !ae_vector_init(&p->dk, 0, DT_REAL, _state, make_automatic) )
+    if( !ae_vector_init(&p->rho, 0, DT_REAL, _state, make_automatic) )
         return ae_false;
-    if( !ae_vector_init(&p->xn, 0, DT_REAL, _state, make_automatic) )
+    if( !ae_matrix_init(&p->yk, 0, 0, DT_REAL, _state, make_automatic) )
         return ae_false;
-    if( !ae_vector_init(&p->dn, 0, DT_REAL, _state, make_automatic) )
+    if( !ae_matrix_init(&p->sk, 0, 0, DT_REAL, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init(&p->theta, 0, DT_REAL, _state, make_automatic) )
         return ae_false;
     if( !ae_vector_init(&p->d, 0, DT_REAL, _state, make_automatic) )
         return ae_false;
     if( !ae_vector_init(&p->work, 0, DT_REAL, _state, make_automatic) )
         return ae_false;
-    if( !ae_vector_init(&p->yk, 0, DT_REAL, _state, make_automatic) )
+    if( !ae_matrix_init(&p->denseh, 0, 0, DT_REAL, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init(&p->diagh, 0, DT_REAL, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init(&p->autobuf, 0, DT_REAL, _state, make_automatic) )
         return ae_false;
     if( !ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic) )
         return ae_false;
@@ -9845,72 +11345,83 @@ ae_bool _mincgstate_init(mincgstate* p, ae_state *_state, ae_bool make_automatic
 }
 
 
-ae_bool _mincgstate_init_copy(mincgstate* dst, mincgstate* src, ae_state *_state, ae_bool make_automatic)
+ae_bool _minlbfgsstate_init_copy(minlbfgsstate* dst, minlbfgsstate* src, ae_state *_state, ae_bool make_automatic)
 {
     dst->n = src->n;
+    dst->m = src->m;
     dst->epsg = src->epsg;
     dst->epsf = src->epsf;
     dst->epsx = src->epsx;
     dst->maxits = src->maxits;
-    dst->stpmax = src->stpmax;
-    dst->suggestedstep = src->suggestedstep;
     dst->xrep = src->xrep;
-    dst->drep = src->drep;
-    dst->cgtype = src->cgtype;
+    dst->stpmax = src->stpmax;
+    if( !ae_vector_init_copy(&dst->s, &src->s, _state, make_automatic) )
+        return ae_false;
+    dst->diffstep = src->diffstep;
     dst->nfev = src->nfev;
     dst->mcstage = src->mcstage;
     dst->k = src->k;
-    if( !ae_vector_init_copy(&dst->xk, &src->xk, _state, make_automatic) )
+    dst->q = src->q;
+    dst->p = src->p;
+    if( !ae_vector_init_copy(&dst->rho, &src->rho, _state, make_automatic) )
         return ae_false;
-    if( !ae_vector_init_copy(&dst->dk, &src->dk, _state, make_automatic) )
+    if( !ae_matrix_init_copy(&dst->yk, &src->yk, _state, make_automatic) )
         return ae_false;
-    if( !ae_vector_init_copy(&dst->xn, &src->xn, _state, make_automatic) )
+    if( !ae_matrix_init_copy(&dst->sk, &src->sk, _state, make_automatic) )
         return ae_false;
-    if( !ae_vector_init_copy(&dst->dn, &src->dn, _state, make_automatic) )
+    if( !ae_vector_init_copy(&dst->theta, &src->theta, _state, make_automatic) )
         return ae_false;
     if( !ae_vector_init_copy(&dst->d, &src->d, _state, make_automatic) )
         return ae_false;
-    dst->fold = src->fold;
     dst->stp = src->stp;
-    dst->curstpmax = src->curstpmax;
     if( !ae_vector_init_copy(&dst->work, &src->work, _state, make_automatic) )
         return ae_false;
-    if( !ae_vector_init_copy(&dst->yk, &src->yk, _state, make_automatic) )
+    dst->fold = src->fold;
+    dst->trimthreshold = src->trimthreshold;
+    dst->prectype = src->prectype;
+    dst->gammak = src->gammak;
+    if( !ae_matrix_init_copy(&dst->denseh, &src->denseh, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init_copy(&dst->diagh, &src->diagh, _state, make_automatic) )
+        return ae_false;
+    dst->fbase = src->fbase;
+    dst->fm2 = src->fm2;
+    dst->fm1 = src->fm1;
+    dst->fp1 = src->fp1;
+    dst->fp2 = src->fp2;
+    if( !ae_vector_init_copy(&dst->autobuf, &src->autobuf, _state, make_automatic) )
         return ae_false;
-    dst->laststep = src->laststep;
-    dst->rstimer = src->rstimer;
     if( !ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic) )
         return ae_false;
     dst->f = src->f;
     if( !ae_vector_init_copy(&dst->g, &src->g, _state, make_automatic) )
         return ae_false;
+    dst->needf = src->needf;
     dst->needfg = src->needfg;
     dst->xupdated = src->xupdated;
-    dst->lsstart = src->lsstart;
-    dst->lsend = src->lsend;
     if( !_rcommstate_init_copy(&dst->rstate, &src->rstate, _state, make_automatic) )
         return ae_false;
     dst->repiterationscount = src->repiterationscount;
     dst->repnfev = src->repnfev;
     dst->repterminationtype = src->repterminationtype;
-    dst->debugrestartscount = src->debugrestartscount;
     if( !_linminstate_init_copy(&dst->lstate, &src->lstate, _state, make_automatic) )
         return ae_false;
-    dst->betahs = src->betahs;
-    dst->betady = src->betady;
     return ae_true;
 }
 
 
-void _mincgstate_clear(mincgstate* p)
+void _minlbfgsstate_clear(minlbfgsstate* p)
 {
-    ae_vector_clear(&p->xk);
-    ae_vector_clear(&p->dk);
-    ae_vector_clear(&p->xn);
-    ae_vector_clear(&p->dn);
+    ae_vector_clear(&p->s);
+    ae_vector_clear(&p->rho);
+    ae_matrix_clear(&p->yk);
+    ae_matrix_clear(&p->sk);
+    ae_vector_clear(&p->theta);
     ae_vector_clear(&p->d);
     ae_vector_clear(&p->work);
-    ae_vector_clear(&p->yk);
+    ae_matrix_clear(&p->denseh);
+    ae_vector_clear(&p->diagh);
+    ae_vector_clear(&p->autobuf);
     ae_vector_clear(&p->x);
     ae_vector_clear(&p->g);
     _rcommstate_clear(&p->rstate);
@@ -9918,13 +11429,13 @@ void _mincgstate_clear(mincgstate* p)
 }
 
 
-ae_bool _mincgreport_init(mincgreport* p, ae_state *_state, ae_bool make_automatic)
+ae_bool _minlbfgsreport_init(minlbfgsreport* p, ae_state *_state, ae_bool make_automatic)
 {
     return ae_true;
 }
 
 
-ae_bool _mincgreport_init_copy(mincgreport* dst, mincgreport* src, ae_state *_state, ae_bool make_automatic)
+ae_bool _minlbfgsreport_init_copy(minlbfgsreport* dst, minlbfgsreport* src, ae_state *_state, ae_bool make_automatic)
 {
     dst->iterationscount = src->iterationscount;
     dst->nfev = src->nfev;
@@ -9933,7 +11444,7 @@ ae_bool _mincgreport_init_copy(mincgreport* dst, mincgreport* src, ae_state *_st
 }
 
 
-void _mincgreport_clear(mincgreport* p)
+void _minlbfgsreport_clear(minlbfgsreport* p)
 {
 }
 
@@ -9941,152 +11452,239 @@ void _mincgreport_clear(mincgreport* p)
 
 
 /*************************************************************************
-                     BOUND CONSTRAINED OPTIMIZATION
-       WITH ADDITIONAL LINEAR EQUALITY AND INEQUALITY CONSTRAINTS
+                    CONSTRAINED QUADRATIC PROGRAMMING
 
-DESCRIPTION:
-The  subroutine  minimizes  function   F(x)  of N arguments subject to any
-combination of:
-* bound constraints
-* linear inequality constraints
-* linear equality constraints
+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.
 
-REQUIREMENTS:
-* function value and gradient
-* grad(f) must be Lipschitz continuous on a level set: L = { x : f(x)<=f(x0) }
-* function must be defined even in the infeasible points (algorithm make take
-  steps in the infeasible area before converging to the feasible point)
-* starting point X0 must be feasible or not too far away from the feasible set
-* problem must satisfy strict complementary conditions
+INPUT PARAMETERS:
+    N       -   problem size
+    
+OUTPUT PARAMETERS:
+    State   -   optimizer with zero quadratic/linear terms
+                and no constraints
 
-USAGE:
+  -- ALGLIB --
+     Copyright 11.01.2011 by Bochkanov Sergey
+*************************************************************************/
+void minqpcreate(ae_int_t n, minqpstate* state, ae_state *_state)
+{
+    ae_int_t i;
 
-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/
+    _minqpstate_clear(state);
 
-1. User initializes algorithm state with MinBLEICCreate() call
+    ae_assert(n>=1, "MinQPCreate: N<1", _state);
+    
+    /*
+     * initialize QP solver
+     */
+    state->n = n;
+    state->akind = -1;
+    state->repterminationtype = 0;
+    ae_vector_set_length(&state->b, n, _state);
+    ae_vector_set_length(&state->bndl, n, _state);
+    ae_vector_set_length(&state->bndu, n, _state);
+    ae_vector_set_length(&state->workbndl, n, _state);
+    ae_vector_set_length(&state->workbndu, n, _state);
+    ae_vector_set_length(&state->havebndl, n, _state);
+    ae_vector_set_length(&state->havebndu, n, _state);
+    ae_vector_set_length(&state->startx, n, _state);
+    ae_vector_set_length(&state->xorigin, n, _state);
+    ae_vector_set_length(&state->xc, n, _state);
+    ae_vector_set_length(&state->gc, n, _state);
+    for(i=0; i<=n-1; i++)
+    {
+        state->b.ptr.p_double[i] = 0.0;
+        state->workbndl.ptr.p_double[i] = _state->v_neginf;
+        state->workbndu.ptr.p_double[i] = _state->v_posinf;
+        state->havebndl.ptr.p_bool[i] = ae_false;
+        state->havebndu.ptr.p_bool[i] = ae_false;
+        state->startx.ptr.p_double[i] = 0.0;
+        state->xorigin.ptr.p_double[i] = 0.0;
+    }
+    state->havex = ae_false;
+    minqpsetalgocholesky(state, _state);
+}
 
-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.
+/*************************************************************************
+This function sets linear term for QP solver.
 
-4. User sets stopping conditions for outer iteration by calling
-   MinBLEICSetOuterCond() function.
-   This function controls handling of boundary and inequality constraints.
+By default, linear term is zero.
 
-5. User tunes barrier parameters:
-   * barrier width with MinBLEICSetBarrierWidth() call
-   * (optionally) dynamics of the barrier width with MinBLEICSetBarrierDecay() call
-   These functions control handling of boundary and inequality constraints.
+INPUT PARAMETERS:
+    State   -   structure which stores algorithm state
+    B       -   linear term, array[N].
 
-6. Additionally, user may set limit on number of internal iterations
-   by MinBLEICSetMaxIts() call.
-   This function allows to prevent algorithm from looping forever.
+  -- ALGLIB --
+     Copyright 11.01.2011 by Bochkanov Sergey
+*************************************************************************/
+void minqpsetlinearterm(minqpstate* state,
+     /* Real    */ ae_vector* b,
+     ae_state *_state)
+{
+    ae_int_t n;
 
-7. User calls MinBLEICOptimize() function which takes algorithm  state and
-   pointer (delegate, etc.) to callback function which calculates F/G.
 
-8. User calls MinBLEICResults() to get solution
+    n = state->n;
+    ae_assert(b->cnt>=n, "MinQPSetLinearTerm: Length(B)<N", _state);
+    ae_assert(isfinitevector(b, n, _state), "MinQPSetLinearTerm: B contains infinite or NaN elements", _state);
+    minqpsetlineartermfast(state, b, _state);
+}
+
 
-9. Optionally user may call MinBLEICRestartFrom() to solve another problem
-   with same N but another starting point.
-   MinBLEICRestartFrom() allows to reuse already initialized structure.
+/*************************************************************************
+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:
-    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.
+    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.
+
+  -- ALGLIB --
+     Copyright 11.01.2011 by Bochkanov Sergey
+*************************************************************************/
+void minqpsetquadraticterm(minqpstate* state,
+     /* Real    */ ae_matrix* a,
+     ae_bool isupper,
+     ae_state *_state)
+{
+    ae_int_t n;
+
+
+    n = state->n;
+    ae_assert(a->rows>=n, "MinQPSetQuadraticTerm: Rows(A)<N", _state);
+    ae_assert(a->cols>=n, "MinQPSetQuadraticTerm: Cols(A)<N", _state);
+    ae_assert(isfinitertrmatrix(a, n, isupper, _state), "MinQPSetQuadraticTerm: A contains infinite or NaN elements", _state);
+    minqpsetquadratictermfast(state, a, isupper, 0.0, _state);
+}
 
-OUTPUT PARAMETERS:
-    State   -   structure stores algorithm state
+
+/*************************************************************************
+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].
 
   -- ALGLIB --
-     Copyright 28.11.2010 by Bochkanov Sergey
+     Copyright 11.01.2011 by Bochkanov Sergey
 *************************************************************************/
-void minbleiccreate(ae_int_t n,
+void minqpsetstartingpoint(minqpstate* state,
      /* Real    */ ae_vector* x,
-     minbleicstate* state,
      ae_state *_state)
 {
-    ae_frame _frame_block;
-    ae_int_t i;
-    ae_matrix c;
-    ae_vector ct;
+    ae_int_t n;
 
-    ae_frame_make(_state, &_frame_block);
-    _minbleicstate_clear(state);
-    ae_matrix_init(&c, 0, 0, DT_REAL, _state, ae_true);
-    ae_vector_init(&ct, 0, DT_INT, _state, ae_true);
 
-    ae_assert(n>=1, "MinBLEICCreate: N<1", _state);
-    ae_assert(x->cnt>=n, "MinBLEICCreate: Length(X)<N", _state);
-    ae_assert(isfinitevector(x, n, _state), "MinBLEICCreate: X contains infinite or NaN values!", _state);
+    n = state->n;
+    ae_assert(x->cnt>=n, "MinQPSetStartingPoint: Length(B)<N", _state);
+    ae_assert(isfinitevector(x, n, _state), "MinQPSetStartingPoint: X contains infinite or NaN elements", _state);
+    minqpsetstartingpointfast(state, x, _state);
+}
+
+
+/*************************************************************************
+This  function sets origin for QP solver. By default, following QP program
+is solved:
+
+    min(0.5*x'*A*x+b'*x)
     
-    /*
-     * Initialize.
-     */
-    state->n = n;
-    ae_vector_set_length(&state->x, n, _state);
-    ae_vector_set_length(&state->g, n, _state);
-    ae_vector_set_length(&state->bndl, n, _state);
-    ae_vector_set_length(&state->hasbndl, n, _state);
-    ae_vector_set_length(&state->bndu, n, _state);
-    ae_vector_set_length(&state->hasbndu, n, _state);
-    ae_vector_set_length(&state->xcur, n, _state);
-    ae_vector_set_length(&state->xprev, n, _state);
-    ae_vector_set_length(&state->xstart, n, _state);
-    ae_vector_set_length(&state->xe, n, _state);
-    for(i=0; i<=n-1; i++)
-    {
-        state->bndl.ptr.p_double[i] = _state->v_neginf;
-        state->hasbndl.ptr.p_bool[i] = ae_false;
-        state->bndu.ptr.p_double[i] = _state->v_posinf;
-        state->hasbndu.ptr.p_bool[i] = ae_false;
-    }
-    minbleicsetlc(state, &c, &ct, 0, _state);
-    minbleicsetinnercond(state, 0.0, 0.0, 0.0, _state);
-    minbleicsetoutercond(state, 1.0E-6, 1.0E-6, _state);
-    minbleicsetbarrierwidth(state, 1.0E-3, _state);
-    minbleicsetbarrierdecay(state, 1.0, _state);
-    minbleicsetmaxits(state, 0, _state);
-    minbleicsetxrep(state, ae_false, _state);
-    minbleicsetstpmax(state, 0.0, _state);
-    minbleicrestartfrom(state, x, _state);
-    mincgcreate(n, x, &state->cgstate, _state);
-    ae_frame_leave(_state);
+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].
+
+  -- ALGLIB --
+     Copyright 11.01.2011 by Bochkanov Sergey
+*************************************************************************/
+void minqpsetorigin(minqpstate* state,
+     /* Real    */ ae_vector* xorigin,
+     ae_state *_state)
+{
+    ae_int_t n;
+
+
+    n = state->n;
+    ae_assert(xorigin->cnt>=n, "MinQPSetOrigin: Length(B)<N", _state);
+    ae_assert(isfinitevector(xorigin, n, _state), "MinQPSetOrigin: B contains infinite or NaN elements", _state);
+    minqpsetoriginfast(state, xorigin, _state);
 }
 
 
 /*************************************************************************
-This function sets boundary constraints for BLEIC optimizer.
+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
+
+  -- ALGLIB --
+     Copyright 11.01.2011 by Bochkanov Sergey
+*************************************************************************/
+void minqpsetalgocholesky(minqpstate* state, ae_state *_state)
+{
+
+
+    state->algokind = 1;
+}
+
+
+/*************************************************************************
+This function sets boundary constraints for QP solver
 
 Boundary constraints are inactive by default (after initial creation).
-They are preserved after algorithm restart with MinBLEICRestartFrom().
+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.
+                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.
+                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].
 
   -- ALGLIB --
-     Copyright 28.11.2010 by Bochkanov Sergey
+     Copyright 11.01.2011 by Bochkanov Sergey
 *************************************************************************/
-void minbleicsetbc(minbleicstate* state,
+void minqpsetbc(minqpstate* state,
      /* Real    */ ae_vector* bndl,
      /* Real    */ ae_vector* bndu,
      ae_state *_state)
@@ -10096,951 +11694,4139 @@ void minbleicsetbc(minbleicstate* state,
 
 
     n = state->n;
-    ae_assert(bndl->cnt>=n, "MinBLEICSetBC: Length(BndL)<N", _state);
-    ae_assert(bndu->cnt>=n, "MinBLEICSetBC: Length(BndU)<N", _state);
+    ae_assert(bndl->cnt>=n, "MinQPSetBC: Length(BndL)<N", _state);
+    ae_assert(bndu->cnt>=n, "MinQPSetBC: Length(BndU)<N", _state);
     for(i=0; i<=n-1; i++)
     {
-        ae_assert(ae_isfinite(bndl->ptr.p_double[i], _state)||ae_isneginf(bndl->ptr.p_double[i], _state), "MinBLEICSetBC: BndL contains NAN or +INF", _state);
-        ae_assert(ae_isfinite(bndu->ptr.p_double[i], _state)||ae_isposinf(bndu->ptr.p_double[i], _state), "MinBLEICSetBC: BndL contains NAN or -INF", _state);
+        ae_assert(ae_isfinite(bndl->ptr.p_double[i], _state)||ae_isneginf(bndl->ptr.p_double[i], _state), "MinQPSetBC: BndL contains NAN or +INF", _state);
+        ae_assert(ae_isfinite(bndu->ptr.p_double[i], _state)||ae_isposinf(bndu->ptr.p_double[i], _state), "MinQPSetBC: BndU contains NAN or -INF", _state);
         state->bndl.ptr.p_double[i] = bndl->ptr.p_double[i];
-        state->hasbndl.ptr.p_bool[i] = ae_isfinite(bndl->ptr.p_double[i], _state);
+        state->havebndl.ptr.p_bool[i] = ae_isfinite(bndl->ptr.p_double[i], _state);
         state->bndu.ptr.p_double[i] = bndu->ptr.p_double[i];
-        state->hasbndu.ptr.p_bool[i] = ae_isfinite(bndu->ptr.p_double[i], _state);
+        state->havebndu.ptr.p_bool[i] = ae_isfinite(bndu->ptr.p_double[i], _state);
     }
 }
 
 
 /*************************************************************************
-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().
+This function solves quadratic programming problem.
+You should call it after setting solver options with MinQPSet...() calls.
 
 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
+    State   -   algorithm state
+
+You should use MinQPResults() function to access results after calls
+to this function.
 
   -- ALGLIB --
-     Copyright 28.11.2010 by Bochkanov Sergey
+     Copyright 11.01.2011 by Bochkanov Sergey
 *************************************************************************/
-void minbleicsetlc(minbleicstate* state,
-     /* Real    */ ae_matrix* c,
-     /* Integer */ ae_vector* ct,
-     ae_int_t k,
-     ae_state *_state)
+void minqpoptimize(minqpstate* state, ae_state *_state)
 {
     ae_int_t n;
-    ae_int_t m;
     ae_int_t i;
-    ae_int_t idx;
-    ae_bool b;
+    ae_int_t j;
+    ae_int_t k;
+    ae_int_t nbc;
+    ae_int_t nlc;
+    ae_int_t nactive;
+    ae_int_t nfree;
+    double f;
+    double fprev;
     double v;
+    ae_bool b;
 
 
     n = state->n;
+    state->repterminationtype = -5;
+    state->repinneriterationscount = 0;
+    state->repouteriterationscount = 0;
+    state->repncholesky = 0;
+    state->repnmv = 0;
     
     /*
-     * First, check for errors in the inputs
-     */
-    ae_assert(k>=0, "MinBLEICSetLC: K<0", _state);
-    ae_assert(c->cols>=n+1||k==0, "MinBLEICSetLC: Cols(C)<N+1", _state);
-    ae_assert(c->rows>=k, "MinBLEICSetLC: Rows(C)<K", _state);
-    ae_assert(ct->cnt>=k, "MinBLEICSetLC: Length(CT)<K", _state);
-    ae_assert(apservisfinitematrix(c, k, n+1, _state), "MinBLEICSetLC: C contains infinite or NaN values!", _state);
-    
-    /*
-     * Determine number of constraints,
-     * allocate space and copy
+     * check correctness of constraints
      */
-    state->cecnt = 0;
-    state->cicnt = 0;
-    for(i=0; i<=k-1; i++)
-    {
-        if( ct->ptr.p_int[i]!=0 )
-        {
-            state->cicnt = state->cicnt+1;
-        }
-        else
-        {
-            state->cecnt = state->cecnt+1;
-        }
-    }
-    rmatrixsetlengthatleast(&state->ci, state->cicnt, n+1, _state);
-    rmatrixsetlengthatleast(&state->ce, state->cecnt, n+1, _state);
-    idx = 0;
-    for(i=0; i<=k-1; i++)
+    for(i=0; i<=n-1; i++)
     {
-        if( ct->ptr.p_int[i]!=0 )
+        if( state->havebndl.ptr.p_bool[i]&&state->havebndu.ptr.p_bool[i] )
         {
-            ae_v_move(&state->ci.ptr.pp_double[idx][0], 1, &c->ptr.pp_double[i][0], 1, ae_v_len(0,n));
-            if( ct->ptr.p_int[i]<0 )
+            if( ae_fp_greater(state->bndl.ptr.p_double[i],state->bndu.ptr.p_double[i]) )
             {
-                ae_v_muld(&state->ci.ptr.pp_double[idx][0], 1, ae_v_len(0,n), -1);
+                state->repterminationtype = -3;
+                return;
             }
-            idx = idx+1;
         }
     }
-    idx = 0;
-    for(i=0; i<=k-1; i++)
+    
+    /*
+     * count number of bound and linear constraints
+     */
+    nbc = 0;
+    nlc = 0;
+    for(i=0; i<=n-1; i++)
     {
-        if( ct->ptr.p_int[i]==0 )
+        if( state->havebndl.ptr.p_bool[i] )
         {
-            ae_v_move(&state->ce.ptr.pp_double[idx][0], 1, &c->ptr.pp_double[i][0], 1, ae_v_len(0,n));
-            idx = idx+1;
+            nbc = nbc+1;
         }
-    }
-    
-    /*
-     * Calculate ortohognal basis of row space of CE.
-     * Determine actual basis size, drop vectors corresponding to
-     * small singular values.
-     *
-     * NOTE: it is important to use "W[I]>W[0]*Tol" form (strict
-     * inequality instead of non-strict) because it allows us to
-     * handle situations with zero CE in a natural and elegant way:
-     * all singular values are zero, and even W[0] itself is not
-     * greater than W[0]*tol.
-     */
-    if( state->cecnt>0 )
-    {
-        b = rmatrixsvd(&state->ce, state->cecnt, n, 1, 1, 2, &state->w, &state->cesvl, &state->cebasis, _state);
-        ae_assert(b, "MinBLEIC: inconvergence of internal SVD", _state);
-        state->cedim = 0;
-        m = ae_minint(state->cecnt, n, _state);
-        for(i=0; i<=m-1; i++)
+        if( state->havebndu.ptr.p_bool[i] )
         {
-            if( ae_fp_greater(state->w.ptr.p_double[i],state->w.ptr.p_double[0]*minbleic_svdtol*ae_machineepsilon) )
-            {
-                state->cedim = state->cedim+1;
-            }
+            nbc = nbc+1;
         }
     }
-    else
-    {
-        state->cedim = 0;
-    }
     
     /*
-     * Calculate XE: solution of CE*x = b.
-     * Fill it with zeros if CEDim=0
+     * Our formulation of quadratic problem includes origin point,
+     * i.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.
      */
-    if( state->cedim>0 )
+    for(i=0; i<=n-1; i++)
     {
-        rvectorsetlengthatleast(&state->tmp0, state->cedim, _state);
-        for(i=0; i<=state->cedim-1; i++)
-        {
-            state->tmp0.ptr.p_double[i] = 0;
-        }
-        for(i=0; i<=state->cecnt-1; i++)
-        {
-            v = state->ce.ptr.pp_double[i][n];
-            ae_v_addd(&state->tmp0.ptr.p_double[0], 1, &state->cesvl.ptr.pp_double[i][0], 1, ae_v_len(0,state->cedim-1), v);
-        }
-        for(i=0; i<=state->cedim-1; i++)
+        state->xc.ptr.p_double[i] = state->startx.ptr.p_double[i]-state->xorigin.ptr.p_double[i];
+        if( state->havebndl.ptr.p_bool[i] )
         {
-            state->tmp0.ptr.p_double[i] = state->tmp0.ptr.p_double[i]/state->w.ptr.p_double[i];
+            state->workbndl.ptr.p_double[i] = state->bndl.ptr.p_double[i]-state->xorigin.ptr.p_double[i];
         }
-        for(i=0; i<=n-1; i++)
-        {
-            state->xe.ptr.p_double[i] = 0;
-        }
-        for(i=0; i<=state->cedim-1; i++)
+        if( state->havebndu.ptr.p_bool[i] )
         {
-            v = state->tmp0.ptr.p_double[i];
-            ae_v_addd(&state->xe.ptr.p_double[0], 1, &state->cebasis.ptr.pp_double[i][0], 1, ae_v_len(0,n-1), v);
+            state->workbndu.ptr.p_double[i] = state->bndu.ptr.p_double[i]-state->xorigin.ptr.p_double[i];
         }
     }
-    else
+    
+    /*
+     * modify starting point XC according to boundary constraints
+     */
+    if( state->havex )
     {
         
         /*
-         * no constraints, fill with zeros
+         * We have starting point in XC, so we just have to bound it
          */
         for(i=0; i<=n-1; i++)
         {
-            state->xe.ptr.p_double[i] = 0;
-        }
+            if( state->havebndl.ptr.p_bool[i] )
+            {
+                if( ae_fp_less(state->xc.ptr.p_double[i],state->workbndl.ptr.p_double[i]) )
+                {
+                    state->xc.ptr.p_double[i] = state->workbndl.ptr.p_double[i];
+                }
+            }
+            if( state->havebndu.ptr.p_bool[i] )
+            {
+                if( ae_fp_greater(state->xc.ptr.p_double[i],state->workbndu.ptr.p_double[i]) )
+                {
+                    state->xc.ptr.p_double[i] = state->workbndu.ptr.p_double[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++)
+        {
+            if( state->havebndl.ptr.p_bool[i]&&state->havebndu.ptr.p_bool[i] )
+            {
+                state->xc.ptr.p_double[i] = 0.5*(state->workbndl.ptr.p_double[i]+state->workbndu.ptr.p_double[i]);
+                if( ae_fp_less(state->xc.ptr.p_double[i],state->workbndl.ptr.p_double[i]) )
+                {
+                    state->xc.ptr.p_double[i] = state->workbndl.ptr.p_double[i];
+                }
+                if( ae_fp_greater(state->xc.ptr.p_double[i],state->workbndu.ptr.p_double[i]) )
+                {
+                    state->xc.ptr.p_double[i] = state->workbndu.ptr.p_double[i];
+                }
+                continue;
+            }
+            if( state->havebndl.ptr.p_bool[i] )
+            {
+                state->xc.ptr.p_double[i] = state->workbndl.ptr.p_double[i];
+                continue;
+            }
+            if( state->havebndu.ptr.p_bool[i] )
+            {
+                state->xc.ptr.p_double[i] = state->workbndu.ptr.p_double[i];
+                continue;
+            }
+            state->xc.ptr.p_double[i] = 0;
+        }
+    }
+    
+    /*
+     * Select algo
+     */
+    if( state->algokind==1&&state->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
+             */
+            rvectorsetlengthatleast(&state->tmp0, n, _state);
+            rvectorsetlengthatleast(&state->bufb, n, _state);
+            state->densea.ptr.pp_double[0][0] = state->diaga.ptr.p_double[0];
+            for(k=1; k<=n-1; k++)
+            {
+                ae_v_move(&state->densea.ptr.pp_double[0][k], state->densea.stride, &state->densea.ptr.pp_double[k][0], 1, ae_v_len(0,k-1));
+                state->densea.ptr.pp_double[k][k] = state->diaga.ptr.p_double[k];
+            }
+            ae_v_move(&state->bufb.ptr.p_double[0], 1, &state->b.ptr.p_double[0], 1, ae_v_len(0,n-1));
+            state->repncholesky = 1;
+            if( !spdmatrixcholeskyrec(&state->densea, 0, n, ae_true, &state->tmp0, _state) )
+            {
+                state->repterminationtype = -5;
+                return;
+            }
+            fblscholeskysolve(&state->densea, 1.0, n, ae_true, &state->bufb, &state->tmp0, _state);
+            ae_v_moveneg(&state->xc.ptr.p_double[0], 1, &state->bufb.ptr.p_double[0], 1, ae_v_len(0,n-1));
+            ae_v_add(&state->xc.ptr.p_double[0], 1, &state->xorigin.ptr.p_double[0], 1, ae_v_len(0,n-1));
+            state->repouteriterationscount = 1;
+            state->repterminationtype = 4;
+            return;
+        }
+        
+        /*
+         * General bound constrained algo
+         */
+        rmatrixsetlengthatleast(&state->bufa, n, n, _state);
+        rvectorsetlengthatleast(&state->bufb, n, _state);
+        rvectorsetlengthatleast(&state->bufx, n, _state);
+        ivectorsetlengthatleast(&state->activeconstraints, n, _state);
+        ivectorsetlengthatleast(&state->prevactiveconstraints, n, _state);
+        rvectorsetlengthatleast(&state->tmp0, n, _state);
+        
+        /*
+         * 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->prevactiveconstraints.ptr.p_int[i] = -1;
+        }
+        
+        /*
+         * Main cycle
+         */
+        fprev = ae_maxrealnumber;
+        for(;;)
+        {
+            
+            /*
+             * * 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
+             */
+            minqp_minqpgrad(state, _state);
+            nactive = 0;
+            for(i=0; i<=n-1; i++)
+            {
+                state->activeconstraints.ptr.p_int[i] = 0;
+                if( state->havebndl.ptr.p_bool[i] )
+                {
+                    if( ae_fp_less_eq(state->xc.ptr.p_double[i],state->workbndl.ptr.p_double[i])&&ae_fp_greater_eq(state->gc.ptr.p_double[i],0) )
+                    {
+                        state->activeconstraints.ptr.p_int[i] = 1;
+                    }
+                }
+                if( state->havebndu.ptr.p_bool[i] )
+                {
+                    if( ae_fp_greater_eq(state->xc.ptr.p_double[i],state->workbndu.ptr.p_double[i])&&ae_fp_less_eq(state->gc.ptr.p_double[i],0) )
+                    {
+                        state->activeconstraints.ptr.p_int[i] = 1;
+                    }
+                }
+                if( state->havebndl.ptr.p_bool[i]&&state->havebndu.ptr.p_bool[i] )
+                {
+                    if( ae_fp_eq(state->workbndl.ptr.p_double[i],state->workbndu.ptr.p_double[i]) )
+                    {
+                        state->activeconstraints.ptr.p_int[i] = 1;
+                    }
+                }
+                if( state->activeconstraints.ptr.p_int[i]>0 )
+                {
+                    nactive = nactive+1;
+                }
+            }
+            nfree = n-nactive;
+            if( nfree==0 )
+            {
+                break;
+            }
+            b = ae_false;
+            for(i=0; i<=n-1; i++)
+            {
+                if( state->activeconstraints.ptr.p_int[i]!=state->prevactiveconstraints.ptr.p_int[i] )
+                {
+                    b = ae_true;
+                }
+            }
+            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->bufa.ptr.pp_double[0][0] = state->diaga.ptr.p_double[0];
+            for(k=1; k<=n-1; k++)
+            {
+                ae_v_move(&state->bufa.ptr.pp_double[k][0], 1, &state->densea.ptr.pp_double[k][0], 1, ae_v_len(0,k-1));
+                ae_v_move(&state->bufa.ptr.pp_double[0][k], state->bufa.stride, &state->densea.ptr.pp_double[k][0], 1, ae_v_len(0,k-1));
+                state->bufa.ptr.pp_double[k][k] = state->diaga.ptr.p_double[k];
+            }
+            ae_v_move(&state->bufb.ptr.p_double[0], 1, &state->b.ptr.p_double[0], 1, ae_v_len(0,n-1));
+            ae_v_move(&state->bufx.ptr.p_double[0], 1, &state->xc.ptr.p_double[0], 1, ae_v_len(0,n-1));
+            for(i=0; i<=n-1; i++)
+            {
+                state->tmp0.ptr.p_double[i] = state->activeconstraints.ptr.p_int[i];
+            }
+            tagsortbuf(&state->tmp0, n, &state->itmp0, &state->p2, &state->buf, _state);
+            for(k=0; k<=n-1; k++)
+            {
+                if( state->p2.ptr.p_int[k]!=k )
+                {
+                    v = state->bufb.ptr.p_double[k];
+                    state->bufb.ptr.p_double[k] = state->bufb.ptr.p_double[state->p2.ptr.p_int[k]];
+                    state->bufb.ptr.p_double[state->p2.ptr.p_int[k]] = v;
+                    v = state->bufx.ptr.p_double[k];
+                    state->bufx.ptr.p_double[k] = state->bufx.ptr.p_double[state->p2.ptr.p_int[k]];
+                    state->bufx.ptr.p_double[state->p2.ptr.p_int[k]] = v;
+                }
+            }
+            for(i=0; i<=n-1; i++)
+            {
+                ae_v_move(&state->tmp0.ptr.p_double[0], 1, &state->bufa.ptr.pp_double[i][0], 1, ae_v_len(0,n-1));
+                for(k=0; k<=n-1; k++)
+                {
+                    if( state->p2.ptr.p_int[k]!=k )
+                    {
+                        v = state->tmp0.ptr.p_double[k];
+                        state->tmp0.ptr.p_double[k] = state->tmp0.ptr.p_double[state->p2.ptr.p_int[k]];
+                        state->tmp0.ptr.p_double[state->p2.ptr.p_int[k]] = v;
+                    }
+                }
+                ae_v_move(&state->bufa.ptr.pp_double[i][0], 1, &state->tmp0.ptr.p_double[0], 1, ae_v_len(0,n-1));
+            }
+            for(i=0; i<=n-1; i++)
+            {
+                if( state->p2.ptr.p_int[i]!=i )
+                {
+                    ae_v_move(&state->tmp0.ptr.p_double[0], 1, &state->bufa.ptr.pp_double[i][0], 1, ae_v_len(0,n-1));
+                    ae_v_move(&state->bufa.ptr.pp_double[i][0], 1, &state->bufa.ptr.pp_double[state->p2.ptr.p_int[i]][0], 1, ae_v_len(0,n-1));
+                    ae_v_move(&state->bufa.ptr.pp_double[state->p2.ptr.p_int[i]][0], 1, &state->tmp0.ptr.p_double[0], 1, ae_v_len(0,n-1));
+                }
+            }
+            
+            /*
+             * 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.
+             */
+            rmatrixmv(nfree, nactive, &state->bufa, 0, nfree, 0, &state->bufx, nfree, &state->tmp0, 0, _state);
+            ae_v_add(&state->bufb.ptr.p_double[0], 1, &state->tmp0.ptr.p_double[0], 1, ae_v_len(0,nfree-1));
+            state->constterm = 0.0;
+            for(i=nfree; i<=n-1; i++)
+            {
+                state->constterm = state->constterm+0.5*state->bufx.ptr.p_double[i]*state->bufa.ptr.pp_double[i][i]*state->bufx.ptr.p_double[i];
+                for(j=i+1; j<=n-1; j++)
+                {
+                    state->constterm = state->constterm+state->bufx.ptr.p_double[i]*state->bufa.ptr.pp_double[i][j]*state->bufx.ptr.p_double[j];
+                }
+            }
+            
+            /*
+             * Now we are ready to minimize F(Xf)...
+             */
+            state->repncholesky = state->repncholesky+1;
+            if( !spdmatrixcholeskyrec(&state->bufa, 0, nfree, ae_true, &state->tmp0, _state) )
+            {
+                state->repterminationtype = -5;
+                return;
+            }
+            fblscholeskysolve(&state->bufa, 1.0, nfree, ae_true, &state->bufb, &state->tmp0, _state);
+            ae_v_moveneg(&state->bufx.ptr.p_double[0], 1, &state->bufb.ptr.p_double[0], 1, ae_v_len(0,nfree-1));
+            
+            /*
+             * ...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--)
+            {
+                if( state->p2.ptr.p_int[k]!=k )
+                {
+                    v = state->bufx.ptr.p_double[k];
+                    state->bufx.ptr.p_double[k] = state->bufx.ptr.p_double[state->p2.ptr.p_int[k]];
+                    state->bufx.ptr.p_double[state->p2.ptr.p_int[k]] = v;
+                }
+            }
+            ae_v_move(&state->xc.ptr.p_double[0], 1, &state->bufx.ptr.p_double[0], 1, ae_v_len(0,n-1));
+            for(i=0; i<=n-1; i++)
+            {
+                if( state->havebndl.ptr.p_bool[i] )
+                {
+                    if( ae_fp_less(state->xc.ptr.p_double[i],state->workbndl.ptr.p_double[i]) )
+                    {
+                        state->xc.ptr.p_double[i] = state->workbndl.ptr.p_double[i];
+                    }
+                }
+                if( state->havebndu.ptr.p_bool[i] )
+                {
+                    if( ae_fp_greater(state->xc.ptr.p_double[i],state->workbndu.ptr.p_double[i]) )
+                    {
+                        state->xc.ptr.p_double[i] = state->workbndu.ptr.p_double[i];
+                    }
+                }
+            }
+            
+            /*
+             * Calculate F, compare it with FPrev.
+             *
+             * Break if F>=FPrev
+             * (sometimes possible at extremum due to numerical noise).
+             */
+            f = ae_v_dotproduct(&state->b.ptr.p_double[0], 1, &state->xc.ptr.p_double[0], 1, ae_v_len(0,n-1));
+            f = f+minqp_minqpxtax(state, &state->xc, _state);
+            if( ae_fp_greater_eq(f,fprev) )
+            {
+                break;
+            }
+            fprev = f;
+            
+            /*
+             * Update PrevActiveConstraints
+             */
+            for(i=0; i<=n-1; i++)
+            {
+                state->prevactiveconstraints.ptr.p_int[i] = state->activeconstraints.ptr.p_int[i];
+            }
+            
+            /*
+             * Update report-related fields
+             */
+            state->repouteriterationscount = state->repouteriterationscount+1;
+        }
+        state->repterminationtype = 4;
+        ae_v_add(&state->xc.ptr.p_double[0], 1, &state->xorigin.ptr.p_double[0], 1, ae_v_len(0,n-1));
+        return;
     }
 }
 
 
 /*************************************************************************
-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.
+QP solver results
 
 INPUT PARAMETERS:
-    State   -   structure which stores algorithm state
-    EpsG    -   >=0
-                Algorithm finishes its work if 2-norm of the Lagrangian
-                gradient is less than or equal to EpsG.
-    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 |X(k+1)-X(k)| <= EpsX is fulfilled.
-
-Passing EpsG=0, EpsF=0 and EpsX=0 (simultaneously) will lead to
-automatic stopping criterion selection.
+    State   -   algorithm state
 
-These conditions are used to terminate inner iterations. However, you
-need to tune termination conditions for outer iterations too.
+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.
 
   -- ALGLIB --
-     Copyright 28.11.2010 by Bochkanov Sergey
+     Copyright 11.01.2011 by Bochkanov Sergey
 *************************************************************************/
-void minbleicsetinnercond(minbleicstate* state,
-     double epsg,
-     double epsf,
-     double epsx,
+void minqpresults(minqpstate* state,
+     /* Real    */ ae_vector* x,
+     minqpreport* rep,
      ae_state *_state)
 {
 
+    ae_vector_clear(x);
+    _minqpreport_clear(rep);
 
-    ae_assert(ae_isfinite(epsg, _state), "MinBLEICSetInnerCond: EpsG is not finite number", _state);
-    ae_assert(ae_fp_greater_eq(epsg,0), "MinBLEICSetInnerCond: negative EpsG", _state);
-    ae_assert(ae_isfinite(epsf, _state), "MinBLEICSetInnerCond: EpsF is not finite number", _state);
-    ae_assert(ae_fp_greater_eq(epsf,0), "MinBLEICSetInnerCond: negative EpsF", _state);
-    ae_assert(ae_isfinite(epsx, _state), "MinBLEICSetInnerCond: EpsX is not finite number", _state);
-    ae_assert(ae_fp_greater_eq(epsx,0), "MinBLEICSetInnerCond: negative EpsX", _state);
-    state->innerepsg = epsg;
-    state->innerepsf = epsf;
-    state->innerepsx = epsx;
+    minqpresultsbuf(state, x, rep, _state);
 }
 
 
 /*************************************************************************
-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
+QP results
 
-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.
+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.
 
   -- ALGLIB --
-     Copyright 28.11.2010 by Bochkanov Sergey
+     Copyright 11.01.2011 by Bochkanov Sergey
 *************************************************************************/
-void minbleicsetoutercond(minbleicstate* state,
-     double epsx,
-     double epsi,
+void minqpresultsbuf(minqpstate* state,
+     /* Real    */ ae_vector* x,
+     minqpreport* rep,
      ae_state *_state)
 {
 
 
-    ae_assert(ae_isfinite(epsx, _state), "MinBLEICSetOuterCond: EpsX is not finite number", _state);
-    ae_assert(ae_fp_greater(epsx,0), "MinBLEICSetOuterCond: non-positive EpsX", _state);
-    ae_assert(ae_isfinite(epsi, _state), "MinBLEICSetOuterCond: EpsI is not finite number", _state);
-    ae_assert(ae_fp_greater(epsi,0), "MinBLEICSetOuterCond: non-positive EpsI", _state);
-    state->outerepsx = epsx;
-    state->outerepsi = epsi;
+    if( x->cnt<state->n )
+    {
+        ae_vector_set_length(x, state->n, _state);
+    }
+    ae_v_move(&x->ptr.p_double[0], 1, &state->xc.ptr.p_double[0], 1, ae_v_len(0,state->n-1));
+    rep->inneriterationscount = state->repinneriterationscount;
+    rep->outeriterationscount = state->repouteriterationscount;
+    rep->nmv = state->repnmv;
+    rep->terminationtype = state->repterminationtype;
 }
 
 
 /*************************************************************************
-This function sets initial barrier width.
-
-BLEIC optimizer uses  modified  barrier  functions  to  handle  inequality
-constraints. These functions are almost constant in the inner parts of the
-feasible  area,  but  grow rapidly to the infinity OUTSIDE of the feasible
-area. Barrier width is a distance from feasible area to  the  point  where
-modified barrier function becomes infinite.
-
-Barrier width must be:
-* small enough (below some problem-dependent value) in order for algorithm
-  to  converge.  Necessary  condition  is that the target function must be
-  well described by linear model in the areas as small as barrier width.
-* not VERY small (in order to avoid  difficulties  associated  with  rapid
-  changes in the modified function, ill-conditioning, round-off issues).
-
-Choosing  appropriate  barrier  width  is  very  important  for  efficient
-optimization, and it often requires error  and  trial.  You  can  use  two
-strategies when choosing barrier width:
-* set barrier width with MinBLEICSetBarrierWidth() call. In this case  you
-  should try different barrier widths and examine results.
-* set decreasing barrier width by combining  MinBLEICSetBarrierWidth() and
-  MinBLEICSetBarrierDecay()  calls.  In  this case algorithm will decrease
-  barrier  width  after  each  outer iteration until it encounters optimal
-  barrier width.
-
-INPUT PARAMETERS:
-    State   -   structure which stores algorithm state
-    Mu      -   >0, initial barrier width
+Fast version of MinQPSetLinearTerm(), which doesn't check its arguments.
+For internal use only.
 
   -- ALGLIB --
-     Copyright 28.11.2010 by Bochkanov Sergey
+     Copyright 11.01.2011 by Bochkanov Sergey
 *************************************************************************/
-void minbleicsetbarrierwidth(minbleicstate* state,
-     double mu,
+void minqpsetlineartermfast(minqpstate* state,
+     /* Real    */ ae_vector* b,
      ae_state *_state)
 {
+    ae_int_t n;
 
 
-    ae_assert(ae_isfinite(mu, _state), "MinBLEICSetBarrierWidth: Mu is not finite number", _state);
-    ae_assert(ae_fp_greater(mu,0), "MinBLEICSetBarrierWidth: non-positive Mu", _state);
-    state->mustart = mu;
+    n = state->n;
+    ae_v_move(&state->b.ptr.p_double[0], 1, &b->ptr.p_double[0], 1, ae_v_len(0,n-1));
 }
 
 
 /*************************************************************************
-This function sets decay coefficient for barrier width.
+Fast version of MinQPSetQuadraticTerm(), which doesn't check its arguments.
 
-By default, no barrier decay is used (Decay=1.0).
+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).
 
-BLEIC optimizer uses  modified  barrier  functions  to  handle  inequality
-constraints. These functions are almost constant in the inner parts of the
-feasible  area,  but  grow rapidly to the infinity OUTSIDE of the feasible
-area. Barrier width is a distance from feasible area to  the  point  where
-modified barrier function becomes infinite. Decay coefficient allows us to
-decrease  barrier  width  from  the  initial  (suboptimial)  value   until
-optimal value will be met.
-
-We recommend you either to set MuDecay=1.0 (no decay) or use some moderate
-value like 0.5-0.7
-
-INPUT PARAMETERS:
-    State   -   structure which stores algorithm state
-    MuDecay -   0<MuDecay<=1, decay coefficient
+For internal use only.
 
   -- ALGLIB --
-     Copyright 28.11.2010 by Bochkanov Sergey
+     Copyright 11.01.2011 by Bochkanov Sergey
 *************************************************************************/
-void minbleicsetbarrierdecay(minbleicstate* state,
-     double mudecay,
+void minqpsetquadratictermfast(minqpstate* state,
+     /* Real    */ ae_matrix* a,
+     ae_bool isupper,
+     double s,
      ae_state *_state)
 {
+    ae_int_t k;
+    ae_int_t n;
 
 
-    ae_assert(ae_isfinite(mudecay, _state), "MinBLEICSetBarrierDecay: MuDecay is not finite number", _state);
-    ae_assert(ae_fp_greater(mudecay,0), "MinBLEICSetBarrierDecay: non-positive MuDecay", _state);
-    ae_assert(ae_fp_less_eq(mudecay,1), "MinBLEICSetBarrierDecay: MuDecay>1", _state);
-    state->mudecay = mudecay;
-}
-
-
-/*************************************************************************
-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.
+    
+    /*
+     * 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->n;
+    state->akind = 0;
+    rmatrixsetlengthatleast(&state->densea, n, n, _state);
+    rvectorsetlengthatleast(&state->diaga, n, _state);
+    if( isupper )
+    {
+        for(k=0; k<=n-2; k++)
+        {
+            state->diaga.ptr.p_double[k] = a->ptr.pp_double[k][k]+s;
+            ae_v_move(&state->densea.ptr.pp_double[k+1][k], state->densea.stride, &a->ptr.pp_double[k][k+1], 1, ae_v_len(k+1,n-1));
+        }
+        state->diaga.ptr.p_double[n-1] = a->ptr.pp_double[n-1][n-1]+s;
+    }
+    else
+    {
+        state->diaga.ptr.p_double[0] = a->ptr.pp_double[0][0]+s;
+        for(k=1; k<=n-1; k++)
+        {
+            ae_v_move(&state->densea.ptr.pp_double[k][0], 1, &a->ptr.pp_double[k][0], 1, ae_v_len(0,k-1));
+            state->diaga.ptr.p_double[k] = a->ptr.pp_double[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.
 
   -- ALGLIB --
-     Copyright 28.11.2010 by Bochkanov Sergey
+     Copyright 16.01.2011 by Bochkanov Sergey
 *************************************************************************/
-void minbleicsetmaxits(minbleicstate* state,
-     ae_int_t maxits,
+void minqprewritediagonal(minqpstate* state,
+     /* Real    */ ae_vector* s,
      ae_state *_state)
 {
+    ae_int_t k;
+    ae_int_t n;
 
 
-    ae_assert(maxits>=0, "MinBLEICSetCond: negative MaxIts!", _state);
-    state->maxits = maxits;
+    ae_assert(state->akind==0, "MinQPRewriteDiagonal: internal error (AKind<>0)", _state);
+    n = state->n;
+    for(k=0; k<=n-1; k++)
+    {
+        state->diaga.ptr.p_double[k] = s->ptr.p_double[k];
+    }
 }
 
 
 /*************************************************************************
-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().
+Fast version of MinQPSetStartingPoint(), which doesn't check its arguments.
+For internal use only.
 
   -- ALGLIB --
-     Copyright 28.11.2010 by Bochkanov Sergey
+     Copyright 11.01.2011 by Bochkanov Sergey
 *************************************************************************/
-void minbleicsetxrep(minbleicstate* state,
-     ae_bool needxrep,
+void minqpsetstartingpointfast(minqpstate* state,
+     /* Real    */ ae_vector* x,
      ae_state *_state)
 {
+    ae_int_t n;
 
 
-    state->xrep = needxrep;
+    n = state->n;
+    ae_v_move(&state->startx.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,n-1));
+    state->havex = ae_true;
 }
 
 
 /*************************************************************************
-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  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.
+Fast version of MinQPSetOrigin(), which doesn't check its arguments.
+For internal use only.
 
   -- ALGLIB --
-     Copyright 02.04.2010 by Bochkanov Sergey
+     Copyright 11.01.2011 by Bochkanov Sergey
 *************************************************************************/
-void minbleicsetstpmax(minbleicstate* state,
-     double stpmax,
+void minqpsetoriginfast(minqpstate* state,
+     /* Real    */ ae_vector* xorigin,
      ae_state *_state)
 {
+    ae_int_t n;
 
 
-    ae_assert(ae_isfinite(stpmax, _state), "MinBLEICSetStpMax: StpMax is not finite!", _state);
-    ae_assert(ae_fp_greater_eq(stpmax,0), "MinBLEICSetStpMax: StpMax<0!", _state);
-    state->stpmax = stpmax;
+    n = state->n;
+    ae_v_move(&state->xorigin.ptr.p_double[0], 1, &xorigin->ptr.p_double[0], 1, ae_v_len(0,n-1));
 }
 
 
 /*************************************************************************
+This  function  calculates gradient of quadratic function at XC and stores
+it in the GC.
 
   -- ALGLIB --
-     Copyright 28.11.2010 by Bochkanov Sergey
+     Copyright 11.01.2011 by Bochkanov Sergey
 *************************************************************************/
-ae_bool minbleiciteration(minbleicstate* state, ae_state *_state)
+static void minqp_minqpgrad(minqpstate* state, ae_state *_state)
 {
     ae_int_t n;
-    ae_int_t m;
     ae_int_t i;
     double v;
-    double vv;
-    ae_bool b;
-    ae_bool result;
 
 
+    n = state->n;
+    ae_assert(state->akind==-1||state->akind==0, "MinQPGrad: internal error", _state);
+    
+    /*
+     * zero A
+     */
+    if( state->akind==-1 )
+    {
+        ae_v_move(&state->gc.ptr.p_double[0], 1, &state->b.ptr.p_double[0], 1, ae_v_len(0,n-1));
+        return;
+    }
+    
+    /*
+     * dense A
+     */
+    if( state->akind==0 )
+    {
+        ae_v_move(&state->gc.ptr.p_double[0], 1, &state->b.ptr.p_double[0], 1, ae_v_len(0,n-1));
+        state->gc.ptr.p_double[0] = state->gc.ptr.p_double[0]+state->diaga.ptr.p_double[0]*state->xc.ptr.p_double[0];
+        for(i=1; i<=n-1; i++)
+        {
+            v = ae_v_dotproduct(&state->densea.ptr.pp_double[i][0], 1, &state->xc.ptr.p_double[0], 1, ae_v_len(0,i-1));
+            state->gc.ptr.p_double[i] = state->gc.ptr.p_double[i]+v+state->diaga.ptr.p_double[i]*state->xc.ptr.p_double[i];
+            v = state->xc.ptr.p_double[i];
+            ae_v_addd(&state->gc.ptr.p_double[0], 1, &state->densea.ptr.pp_double[i][0], 1, ae_v_len(0,i-1), v);
+        }
+        return;
+    }
+}
+
+
+/*************************************************************************
+This  function  calculates x'*A*x for given X.
+
+  -- ALGLIB --
+     Copyright 11.01.2011 by Bochkanov Sergey
+*************************************************************************/
+static double minqp_minqpxtax(minqpstate* state,
+     /* Real    */ ae_vector* x,
+     ae_state *_state)
+{
+    ae_int_t n;
+    ae_int_t i;
+    ae_int_t j;
+    double result;
+
+
+    n = state->n;
+    ae_assert(state->akind==-1||state->akind==0, "MinQPXTAX: internal error", _state);
+    result = 0;
+    
+    /*
+     * zero A
+     */
+    if( state->akind==-1 )
+    {
+        result = 0.0;
+        return result;
+    }
+    
+    /*
+     * dense A
+     */
+    if( state->akind==0 )
+    {
+        result = 0;
+        for(i=0; i<=n-1; i++)
+        {
+            for(j=0; j<=i-1; j++)
+            {
+                result = result+state->densea.ptr.pp_double[i][j]*x->ptr.p_double[i]*x->ptr.p_double[j];
+            }
+            result = result+0.5*state->diaga.ptr.p_double[i]*ae_sqr(x->ptr.p_double[i], _state);
+        }
+        return result;
+    }
+    return result;
+}
+
+
+ae_bool _minqpstate_init(minqpstate* p, ae_state *_state, ae_bool make_automatic)
+{
+    if( !ae_matrix_init(&p->densea, 0, 0, DT_REAL, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init(&p->diaga, 0, DT_REAL, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init(&p->b, 0, DT_REAL, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init(&p->bndl, 0, DT_REAL, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init(&p->bndu, 0, DT_REAL, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init(&p->havebndl, 0, DT_BOOL, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init(&p->havebndu, 0, DT_BOOL, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init(&p->xorigin, 0, DT_REAL, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init(&p->startx, 0, DT_REAL, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init(&p->xc, 0, DT_REAL, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init(&p->gc, 0, DT_REAL, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init(&p->activeconstraints, 0, DT_INT, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init(&p->prevactiveconstraints, 0, DT_INT, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init(&p->workbndl, 0, DT_REAL, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init(&p->workbndu, 0, DT_REAL, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init(&p->tmp0, 0, DT_REAL, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init(&p->tmp1, 0, DT_REAL, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init(&p->itmp0, 0, DT_INT, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init(&p->p2, 0, DT_INT, _state, make_automatic) )
+        return ae_false;
+    if( !ae_matrix_init(&p->bufa, 0, 0, DT_REAL, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init(&p->bufb, 0, DT_REAL, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init(&p->bufx, 0, DT_REAL, _state, make_automatic) )
+        return ae_false;
+    if( !_apbuffers_init(&p->buf, _state, make_automatic) )
+        return ae_false;
+    return ae_true;
+}
+
+
+ae_bool _minqpstate_init_copy(minqpstate* dst, minqpstate* src, ae_state *_state, ae_bool make_automatic)
+{
+    dst->n = src->n;
+    dst->algokind = src->algokind;
+    dst->akind = src->akind;
+    if( !ae_matrix_init_copy(&dst->densea, &src->densea, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init_copy(&dst->diaga, &src->diaga, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init_copy(&dst->b, &src->b, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init_copy(&dst->bndl, &src->bndl, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init_copy(&dst->bndu, &src->bndu, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init_copy(&dst->havebndl, &src->havebndl, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init_copy(&dst->havebndu, &src->havebndu, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init_copy(&dst->xorigin, &src->xorigin, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init_copy(&dst->startx, &src->startx, _state, make_automatic) )
+        return ae_false;
+    dst->havex = src->havex;
+    if( !ae_vector_init_copy(&dst->xc, &src->xc, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init_copy(&dst->gc, &src->gc, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init_copy(&dst->activeconstraints, &src->activeconstraints, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init_copy(&dst->prevactiveconstraints, &src->prevactiveconstraints, _state, make_automatic) )
+        return ae_false;
+    dst->constterm = src->constterm;
+    if( !ae_vector_init_copy(&dst->workbndl, &src->workbndl, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init_copy(&dst->workbndu, &src->workbndu, _state, make_automatic) )
+        return ae_false;
+    dst->repinneriterationscount = src->repinneriterationscount;
+    dst->repouteriterationscount = src->repouteriterationscount;
+    dst->repncholesky = src->repncholesky;
+    dst->repnmv = src->repnmv;
+    dst->repterminationtype = src->repterminationtype;
+    if( !ae_vector_init_copy(&dst->tmp0, &src->tmp0, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init_copy(&dst->tmp1, &src->tmp1, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init_copy(&dst->itmp0, &src->itmp0, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init_copy(&dst->p2, &src->p2, _state, make_automatic) )
+        return ae_false;
+    if( !ae_matrix_init_copy(&dst->bufa, &src->bufa, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init_copy(&dst->bufb, &src->bufb, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init_copy(&dst->bufx, &src->bufx, _state, make_automatic) )
+        return ae_false;
+    if( !_apbuffers_init_copy(&dst->buf, &src->buf, _state, make_automatic) )
+        return ae_false;
+    return ae_true;
+}
+
+
+void _minqpstate_clear(minqpstate* p)
+{
+    ae_matrix_clear(&p->densea);
+    ae_vector_clear(&p->diaga);
+    ae_vector_clear(&p->b);
+    ae_vector_clear(&p->bndl);
+    ae_vector_clear(&p->bndu);
+    ae_vector_clear(&p->havebndl);
+    ae_vector_clear(&p->havebndu);
+    ae_vector_clear(&p->xorigin);
+    ae_vector_clear(&p->startx);
+    ae_vector_clear(&p->xc);
+    ae_vector_clear(&p->gc);
+    ae_vector_clear(&p->activeconstraints);
+    ae_vector_clear(&p->prevactiveconstraints);
+    ae_vector_clear(&p->workbndl);
+    ae_vector_clear(&p->workbndu);
+    ae_vector_clear(&p->tmp0);
+    ae_vector_clear(&p->tmp1);
+    ae_vector_clear(&p->itmp0);
+    ae_vector_clear(&p->p2);
+    ae_matrix_clear(&p->bufa);
+    ae_vector_clear(&p->bufb);
+    ae_vector_clear(&p->bufx);
+    _apbuffers_clear(&p->buf);
+}
+
+
+ae_bool _minqpreport_init(minqpreport* p, ae_state *_state, ae_bool make_automatic)
+{
+    return ae_true;
+}
+
+
+ae_bool _minqpreport_init_copy(minqpreport* dst, minqpreport* src, ae_state *_state, ae_bool make_automatic)
+{
+    dst->inneriterationscount = src->inneriterationscount;
+    dst->outeriterationscount = src->outeriterationscount;
+    dst->nmv = src->nmv;
+    dst->ncholesky = src->ncholesky;
+    dst->terminationtype = src->terminationtype;
+    return ae_true;
+}
+
+
+void _minqpreport_clear(minqpreport* p)
+{
+}
+
+
+
+
+/*************************************************************************
+                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.
+
+  -- ALGLIB --
+     Copyright 30.03.2009 by Bochkanov Sergey
+*************************************************************************/
+void minlmcreatevj(ae_int_t n,
+     ae_int_t m,
+     /* Real    */ ae_vector* x,
+     minlmstate* state,
+     ae_state *_state)
+{
+
+    _minlmstate_clear(state);
+
+    ae_assert(n>=1, "MinLMCreateVJ: N<1!", _state);
+    ae_assert(m>=1, "MinLMCreateVJ: M<1!", _state);
+    ae_assert(x->cnt>=n, "MinLMCreateVJ: Length(X)<N!", _state);
+    ae_assert(isfinitevector(x, n, _state), "MinLMCreateVJ: X contains infinite or NaN values!", _state);
+    
+    /*
+     * initialize, check parameters
+     */
+    state->n = n;
+    state->m = m;
+    state->algomode = 1;
+    state->hasf = ae_false;
+    state->hasfi = ae_true;
+    state->hasg = ae_false;
+    
+    /*
+     * second stage of initialization
+     */
+    minlm_lmprepare(n, m, ae_false, state, _state);
+    minlmsetacctype(state, 0, _state);
+    minlmsetcond(state, 0, 0, 0, 0, _state);
+    minlmsetxrep(state, ae_false, _state);
+    minlmsetstpmax(state, 0, _state);
+    minlmrestartfrom(state, x, _state);
+}
+
+
+/*************************************************************************
+                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.
+
+  -- ALGLIB --
+     Copyright 30.03.2009 by Bochkanov Sergey
+*************************************************************************/
+void minlmcreatev(ae_int_t n,
+     ae_int_t m,
+     /* Real    */ ae_vector* x,
+     double diffstep,
+     minlmstate* state,
+     ae_state *_state)
+{
+
+    _minlmstate_clear(state);
+
+    ae_assert(ae_isfinite(diffstep, _state), "MinLMCreateV: DiffStep is not finite!", _state);
+    ae_assert(ae_fp_greater(diffstep,0), "MinLMCreateV: DiffStep<=0!", _state);
+    ae_assert(n>=1, "MinLMCreateV: N<1!", _state);
+    ae_assert(m>=1, "MinLMCreateV: M<1!", _state);
+    ae_assert(x->cnt>=n, "MinLMCreateV: Length(X)<N!", _state);
+    ae_assert(isfinitevector(x, n, _state), "MinLMCreateV: X contains infinite or NaN values!", _state);
+    
+    /*
+     * initialize
+     */
+    state->n = n;
+    state->m = m;
+    state->algomode = 0;
+    state->hasf = ae_false;
+    state->hasfi = ae_true;
+    state->hasg = ae_false;
+    state->diffstep = diffstep;
+    
+    /*
+     * second stage of initialization
+     */
+    minlm_lmprepare(n, m, ae_false, state, _state);
+    minlmsetacctype(state, 1, _state);
+    minlmsetcond(state, 0, 0, 0, 0, _state);
+    minlmsetxrep(state, ae_false, _state);
+    minlmsetstpmax(state, 0, _state);
+    minlmrestartfrom(state, x, _state);
+}
+
+
+/*************************************************************************
+    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.
+
+  -- ALGLIB --
+     Copyright 30.03.2009 by Bochkanov Sergey
+*************************************************************************/
+void minlmcreatefgh(ae_int_t n,
+     /* Real    */ ae_vector* x,
+     minlmstate* state,
+     ae_state *_state)
+{
+
+    _minlmstate_clear(state);
+
+    ae_assert(n>=1, "MinLMCreateFGH: N<1!", _state);
+    ae_assert(x->cnt>=n, "MinLMCreateFGH: Length(X)<N!", _state);
+    ae_assert(isfinitevector(x, n, _state), "MinLMCreateFGH: X contains infinite or NaN values!", _state);
+    
+    /*
+     * initialize
+     */
+    state->n = n;
+    state->m = 0;
+    state->algomode = 2;
+    state->hasf = ae_true;
+    state->hasfi = ae_false;
+    state->hasg = ae_true;
+    
+    /*
+     * init2
+     */
+    minlm_lmprepare(n, 0, ae_true, state, _state);
+    minlmsetacctype(state, 2, _state);
+    minlmsetcond(state, 0, 0, 0, 0, _state);
+    minlmsetxrep(state, ae_false, _state);
+    minlmsetstpmax(state, 0, _state);
+    minlmrestartfrom(state, x, _state);
+}
+
+
+/*************************************************************************
+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).
+
+  -- ALGLIB --
+     Copyright 02.04.2010 by Bochkanov Sergey
+*************************************************************************/
+void minlmsetcond(minlmstate* state,
+     double epsg,
+     double epsf,
+     double epsx,
+     ae_int_t maxits,
+     ae_state *_state)
+{
+
+
+    ae_assert(ae_isfinite(epsg, _state), "MinLMSetCond: EpsG is not finite number!", _state);
+    ae_assert(ae_fp_greater_eq(epsg,0), "MinLMSetCond: negative EpsG!", _state);
+    ae_assert(ae_isfinite(epsf, _state), "MinLMSetCond: EpsF is not finite number!", _state);
+    ae_assert(ae_fp_greater_eq(epsf,0), "MinLMSetCond: negative EpsF!", _state);
+    ae_assert(ae_isfinite(epsx, _state), "MinLMSetCond: EpsX is not finite number!", _state);
+    ae_assert(ae_fp_greater_eq(epsx,0), "MinLMSetCond: negative EpsX!", _state);
+    ae_assert(maxits>=0, "MinLMSetCond: negative MaxIts!", _state);
+    if( ((ae_fp_eq(epsg,0)&&ae_fp_eq(epsf,0))&&ae_fp_eq(epsx,0))&&maxits==0 )
+    {
+        epsx = 1.0E-6;
+    }
+    state->epsg = epsg;
+    state->epsf = epsf;
+    state->epsx = epsx;
+    state->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.
+
+  -- ALGLIB --
+     Copyright 02.04.2010 by Bochkanov Sergey
+*************************************************************************/
+void minlmsetxrep(minlmstate* state, ae_bool needxrep, ae_state *_state)
+{
+
+
+    state->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.
+
+  -- ALGLIB --
+     Copyright 02.04.2010 by Bochkanov Sergey
+*************************************************************************/
+void minlmsetstpmax(minlmstate* state, double stpmax, ae_state *_state)
+{
+
+
+    ae_assert(ae_isfinite(stpmax, _state), "MinLMSetStpMax: StpMax is not finite!", _state);
+    ae_assert(ae_fp_greater_eq(stpmax,0), "MinLMSetStpMax: StpMax<0!", _state);
+    state->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.
+
+  -- ALGLIB --
+     Copyright 14.01.2011 by Bochkanov Sergey
+*************************************************************************/
+void minlmsetscale(minlmstate* state,
+     /* Real    */ ae_vector* s,
+     ae_state *_state)
+{
+    ae_int_t i;
+
+
+    ae_assert(s->cnt>=state->n, "MinLMSetScale: Length(S)<N", _state);
+    for(i=0; i<=state->n-1; i++)
+    {
+        ae_assert(ae_isfinite(s->ptr.p_double[i], _state), "MinLMSetScale: S contains infinite or NAN elements", _state);
+        ae_assert(ae_fp_neq(s->ptr.p_double[i],0), "MinLMSetScale: S contains zero elements", _state);
+        state->s.ptr.p_double[i] = ae_fabs(s->ptr.p_double[i], _state);
+    }
+}
+
+
+/*************************************************************************
+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
+
+  -- ALGLIB --
+     Copyright 14.01.2011 by Bochkanov Sergey
+*************************************************************************/
+void minlmsetbc(minlmstate* state,
+     /* Real    */ ae_vector* bndl,
+     /* Real    */ ae_vector* bndu,
+     ae_state *_state)
+{
+    ae_int_t i;
+    ae_int_t n;
+
+
+    n = state->n;
+    ae_assert(bndl->cnt>=n, "MinLMSetBC: Length(BndL)<N", _state);
+    ae_assert(bndu->cnt>=n, "MinLMSetBC: Length(BndU)<N", _state);
+    for(i=0; i<=n-1; i++)
+    {
+        ae_assert(ae_isfinite(bndl->ptr.p_double[i], _state)||ae_isneginf(bndl->ptr.p_double[i], _state), "MinLMSetBC: BndL contains NAN or +INF", _state);
+        ae_assert(ae_isfinite(bndu->ptr.p_double[i], _state)||ae_isposinf(bndu->ptr.p_double[i], _state), "MinLMSetBC: BndU contains NAN or -INF", _state);
+        state->bndl.ptr.p_double[i] = bndl->ptr.p_double[i];
+        state->havebndl.ptr.p_bool[i] = ae_isfinite(bndl->ptr.p_double[i], _state);
+        state->bndu.ptr.p_double[i] = bndu->ptr.p_double[i];
+        state->havebndu.ptr.p_bool[i] = ae_isfinite(bndu->ptr.p_double[i], _state);
+    }
+}
+
+
+/*************************************************************************
+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.
+
+  -- ALGLIB --
+     Copyright 14.10.2010 by Bochkanov Sergey
+*************************************************************************/
+void minlmsetacctype(minlmstate* state,
+     ae_int_t acctype,
+     ae_state *_state)
+{
+
+
+    ae_assert((acctype==0||acctype==1)||acctype==2, "MinLMSetAccType: incorrect AccType!", _state);
+    if( acctype==2 )
+    {
+        acctype = 0;
+    }
+    if( acctype==0 )
+    {
+        state->maxmodelage = 0;
+        state->makeadditers = ae_false;
+        return;
+    }
+    if( acctype==1 )
+    {
+        ae_assert(state->hasfi, "MinLMSetAccType: AccType=1 is incompatible with current protocol!", _state);
+        if( state->algomode==0 )
+        {
+            state->maxmodelage = 2*state->n;
+        }
+        else
+        {
+            state->maxmodelage = minlm_smallmodelage;
+        }
+        state->makeadditers = ae_false;
+        return;
+    }
+}
+
+
+/*************************************************************************
+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.
+
+  -- ALGLIB --
+     Copyright 10.03.2009 by Bochkanov Sergey
+*************************************************************************/
+ae_bool minlmiteration(minlmstate* state, ae_state *_state)
+{
+    ae_int_t n;
+    ae_int_t m;
+    ae_bool bflag;
+    ae_int_t iflag;
+    double v;
+    double s;
+    double t;
+    ae_int_t i;
+    ae_int_t k;
+    ae_bool result;
+
+
+    
+    /*
+     * 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->rstate.stage>=0 )
+    {
+        n = state->rstate.ia.ptr.p_int[0];
+        m = state->rstate.ia.ptr.p_int[1];
+        iflag = state->rstate.ia.ptr.p_int[2];
+        i = state->rstate.ia.ptr.p_int[3];
+        k = state->rstate.ia.ptr.p_int[4];
+        bflag = state->rstate.ba.ptr.p_bool[0];
+        v = state->rstate.ra.ptr.p_double[0];
+        s = state->rstate.ra.ptr.p_double[1];
+        t = state->rstate.ra.ptr.p_double[2];
+    }
+    else
+    {
+        n = -983;
+        m = -989;
+        iflag = -834;
+        i = 900;
+        k = -287;
+        bflag = ae_false;
+        v = 214;
+        s = -338;
+        t = -686;
+    }
+    if( state->rstate.stage==0 )
+    {
+        goto lbl_0;
+    }
+    if( state->rstate.stage==1 )
+    {
+        goto lbl_1;
+    }
+    if( state->rstate.stage==2 )
+    {
+        goto lbl_2;
+    }
+    if( state->rstate.stage==3 )
+    {
+        goto lbl_3;
+    }
+    if( state->rstate.stage==4 )
+    {
+        goto lbl_4;
+    }
+    if( state->rstate.stage==5 )
+    {
+        goto lbl_5;
+    }
+    if( state->rstate.stage==6 )
+    {
+        goto lbl_6;
+    }
+    if( state->rstate.stage==7 )
+    {
+        goto lbl_7;
+    }
+    if( state->rstate.stage==8 )
+    {
+        goto lbl_8;
+    }
+    if( state->rstate.stage==9 )
+    {
+        goto lbl_9;
+    }
+    if( state->rstate.stage==10 )
+    {
+        goto lbl_10;
+    }
+    if( state->rstate.stage==11 )
+    {
+        goto lbl_11;
+    }
+    if( state->rstate.stage==12 )
+    {
+        goto lbl_12;
+    }
+    if( state->rstate.stage==13 )
+    {
+        goto lbl_13;
+    }
+    if( state->rstate.stage==14 )
+    {
+        goto lbl_14;
+    }
+    if( state->rstate.stage==15 )
+    {
+        goto lbl_15;
+    }
+    
+    /*
+     * Routine body
+     */
+    
+    /*
+     * prepare
+     */
+    n = state->n;
+    m = state->m;
+    state->repiterationscount = 0;
+    state->repterminationtype = 0;
+    state->repnfunc = 0;
+    state->repnjac = 0;
+    state->repngrad = 0;
+    state->repnhess = 0;
+    state->repncholesky = 0;
+    
+    /*
+     * check consistency of constraints
+     * set constraints
+     */
+    for(i=0; i<=n-1; i++)
+    {
+        if( state->havebndl.ptr.p_bool[i]&&state->havebndu.ptr.p_bool[i] )
+        {
+            if( ae_fp_greater(state->bndl.ptr.p_double[i],state->bndu.ptr.p_double[i]) )
+            {
+                state->repterminationtype = -3;
+                result = ae_false;
+                return result;
+            }
+        }
+    }
+    minqpsetbc(&state->qpstate, &state->bndl, &state->bndu, _state);
+    
+    /*
+     * 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->xrep )
+    {
+        goto lbl_16;
+    }
+    ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1));
+    minlm_clearrequestfields(state, _state);
+    if( !state->hasf )
+    {
+        goto lbl_18;
+    }
+    state->needf = ae_true;
+    state->rstate.stage = 0;
+    goto lbl_rcomm;
+lbl_0:
+    state->needf = ae_false;
+    goto lbl_19;
+lbl_18:
+    ae_assert(state->hasfi, "MinLM: internal error 2!", _state);
+    state->needfi = ae_true;
+    state->rstate.stage = 1;
+    goto lbl_rcomm;
+lbl_1:
+    state->needfi = ae_false;
+    v = ae_v_dotproduct(&state->fi.ptr.p_double[0], 1, &state->fi.ptr.p_double[0], 1, ae_v_len(0,m-1));
+    state->f = v;
+lbl_19:
+    state->repnfunc = state->repnfunc+1;
+    ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1));
+    minlm_clearrequestfields(state, _state);
+    state->xupdated = ae_true;
+    state->rstate.stage = 2;
+    goto lbl_rcomm;
+lbl_2:
+    state->xupdated = ae_false;
+lbl_16:
+    
+    /*
+     * Prepare control variables
+     */
+    state->nu = 1;
+    state->lambdav = -ae_maxrealnumber;
+    state->modelage = state->maxmodelage+1;
+    state->deltaxready = ae_false;
+    state->deltafready = ae_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
+     *
+     */
+lbl_20:
+    if( ae_false )
+    {
+        goto lbl_21;
+    }
+    
+    /*
+     * 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 = ae_false;
+    if( !(state->algomode==0||state->algomode==1) )
+    {
+        goto lbl_22;
+    }
+    
+    /*
+     * Calculate f[] and Jacobian
+     */
+    if( !(state->modelage>state->maxmodelage||!(state->deltaxready&&state->deltafready)) )
+    {
+        goto lbl_24;
+    }
+    
+    /*
+     * Refresh model (using either finite differences or analytic Jacobian)
+     */
+    if( state->algomode!=0 )
+    {
+        goto lbl_26;
+    }
+    
+    /*
+     * Optimization using F values only.
+     * Use finite differences to estimate Jacobian.
+     */
+    ae_assert(state->hasfi, "MinLMIteration: internal error when estimating Jacobian (no f[])", _state);
+    k = 0;
+lbl_28:
+    if( k>n-1 )
+    {
+        goto lbl_30;
+    }
+    
+    /*
+     * We guard X[k] from leaving [BndL,BndU].
+     * In case BndL=BndU, we assume that derivative in this direction is zero.
+     */
+    ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1));
+    state->x.ptr.p_double[k] = state->x.ptr.p_double[k]-state->s.ptr.p_double[k]*state->diffstep;
+    if( state->havebndl.ptr.p_bool[k] )
+    {
+        state->x.ptr.p_double[k] = ae_maxreal(state->x.ptr.p_double[k], state->bndl.ptr.p_double[k], _state);
+    }
+    if( state->havebndu.ptr.p_bool[k] )
+    {
+        state->x.ptr.p_double[k] = ae_minreal(state->x.ptr.p_double[k], state->bndu.ptr.p_double[k], _state);
+    }
+    state->xm1 = state->x.ptr.p_double[k];
+    minlm_clearrequestfields(state, _state);
+    state->needfi = ae_true;
+    state->rstate.stage = 3;
+    goto lbl_rcomm;
+lbl_3:
+    state->repnfunc = state->repnfunc+1;
+    ae_v_move(&state->fm1.ptr.p_double[0], 1, &state->fi.ptr.p_double[0], 1, ae_v_len(0,m-1));
+    ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1));
+    state->x.ptr.p_double[k] = state->x.ptr.p_double[k]+state->s.ptr.p_double[k]*state->diffstep;
+    if( state->havebndl.ptr.p_bool[k] )
+    {
+        state->x.ptr.p_double[k] = ae_maxreal(state->x.ptr.p_double[k], state->bndl.ptr.p_double[k], _state);
+    }
+    if( state->havebndu.ptr.p_bool[k] )
+    {
+        state->x.ptr.p_double[k] = ae_minreal(state->x.ptr.p_double[k], state->bndu.ptr.p_double[k], _state);
+    }
+    state->xp1 = state->x.ptr.p_double[k];
+    minlm_clearrequestfields(state, _state);
+    state->needfi = ae_true;
+    state->rstate.stage = 4;
+    goto lbl_rcomm;
+lbl_4:
+    state->repnfunc = state->repnfunc+1;
+    ae_v_move(&state->fp1.ptr.p_double[0], 1, &state->fi.ptr.p_double[0], 1, ae_v_len(0,m-1));
+    v = state->xp1-state->xm1;
+    if( ae_fp_neq(v,0) )
+    {
+        v = 1/v;
+        ae_v_moved(&state->j.ptr.pp_double[0][k], state->j.stride, &state->fp1.ptr.p_double[0], 1, ae_v_len(0,m-1), v);
+        ae_v_subd(&state->j.ptr.pp_double[0][k], state->j.stride, &state->fm1.ptr.p_double[0], 1, ae_v_len(0,m-1), v);
+    }
+    else
+    {
+        for(i=0; i<=m-1; i++)
+        {
+            state->j.ptr.pp_double[i][k] = 0;
+        }
+    }
+    k = k+1;
+    goto lbl_28;
+lbl_30:
+    
+    /*
+     * Calculate F(XBase)
+     */
+    ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1));
+    minlm_clearrequestfields(state, _state);
+    state->needfi = ae_true;
+    state->rstate.stage = 5;
+    goto lbl_rcomm;
+lbl_5:
+    state->needfi = ae_false;
+    state->repnfunc = state->repnfunc+1;
+    state->repnjac = state->repnjac+1;
+    
+    /*
+     * New model
+     */
+    state->modelage = 0;
+    goto lbl_27;
+lbl_26:
+    
+    /*
+     * Obtain f[] and Jacobian
+     */
+    ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1));
+    minlm_clearrequestfields(state, _state);
+    state->needfij = ae_true;
+    state->rstate.stage = 6;
+    goto lbl_rcomm;
+lbl_6:
+    state->needfij = ae_false;
+    state->repnfunc = state->repnfunc+1;
+    state->repnjac = state->repnjac+1;
+    
+    /*
+     * New model
+     */
+    state->modelage = 0;
+lbl_27:
+    goto lbl_25;
+lbl_24:
+    
+    /*
+     * 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.
+     */
+    ae_assert(state->deltaxready&&state->deltafready, "MinLMIteration: uninitialized DeltaX/DeltaF", _state);
+    t = ae_v_dotproduct(&state->deltax.ptr.p_double[0], 1, &state->deltax.ptr.p_double[0], 1, ae_v_len(0,n-1));
+    ae_assert(ae_fp_neq(t,0), "MinLM: internal error (T=0)", _state);
+    for(i=0; i<=m-1; i++)
+    {
+        v = ae_v_dotproduct(&state->j.ptr.pp_double[i][0], 1, &state->deltax.ptr.p_double[0], 1, ae_v_len(0,n-1));
+        v = (state->deltaf.ptr.p_double[i]-v)/t;
+        ae_v_addd(&state->j.ptr.pp_double[i][0], 1, &state->deltax.ptr.p_double[0], 1, ae_v_len(0,n-1), v);
+    }
+    ae_v_move(&state->fi.ptr.p_double[0], 1, &state->fibase.ptr.p_double[0], 1, ae_v_len(0,m-1));
+    ae_v_add(&state->fi.ptr.p_double[0], 1, &state->deltaf.ptr.p_double[0], 1, ae_v_len(0,m-1));
+    
+    /*
+     * Increase model age
+     */
+    state->modelage = state->modelage+1;
+lbl_25:
+    
+    /*
+     * 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.e. it has 0.5 before quadratic term.
+     */
+    rmatrixgemm(n, n, m, 2.0, &state->j, 0, 0, 1, &state->j, 0, 0, 0, 0.0, &state->quadraticmodel, 0, 0, _state);
+    rmatrixmv(n, m, &state->j, 0, 0, 1, &state->fi, 0, &state->gbase, 0, _state);
+    ae_v_muld(&state->gbase.ptr.p_double[0], 1, ae_v_len(0,n-1), 2);
+    v = ae_v_dotproduct(&state->fi.ptr.p_double[0], 1, &state->fi.ptr.p_double[0], 1, ae_v_len(0,m-1));
+    state->fbase = v;
+    ae_v_move(&state->fibase.ptr.p_double[0], 1, &state->fi.ptr.p_double[0], 1, ae_v_len(0,m-1));
+    
+    /*
+     * set control variables
+     */
+    bflag = ae_true;
+lbl_22:
+    if( state->algomode!=2 )
+    {
+        goto lbl_31;
+    }
+    ae_assert(!state->hasfi, "MinLMIteration: internal error (HasFI is True in Hessian-based mode)", _state);
+    
+    /*
+     * Obtain F, G, H
+     */
+    ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1));
+    minlm_clearrequestfields(state, _state);
+    state->needfgh = ae_true;
+    state->rstate.stage = 7;
+    goto lbl_rcomm;
+lbl_7:
+    state->needfgh = ae_false;
+    state->repnfunc = state->repnfunc+1;
+    state->repngrad = state->repngrad+1;
+    state->repnhess = state->repnhess+1;
+    rmatrixcopy(n, n, &state->h, 0, 0, &state->quadraticmodel, 0, 0, _state);
+    ae_v_move(&state->gbase.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1));
+    state->fbase = state->f;
+    
+    /*
+     * set control variables
+     */
+    bflag = ae_true;
+    state->modelage = 0;
+lbl_31:
+    ae_assert(bflag, "MinLM: internal integrity check failed!", _state);
+    state->deltaxready = ae_false;
+    state->deltafready = ae_false;
+    
+    /*
+     * If Lambda is not initialized, initialize it using quadratic model
+     */
+    if( ae_fp_less(state->lambdav,0) )
+    {
+        state->lambdav = 0;
+        for(i=0; i<=n-1; i++)
+        {
+            state->lambdav = ae_maxreal(state->lambdav, ae_fabs(state->quadraticmodel.ptr.pp_double[i][i], _state)*ae_sqr(state->s.ptr.p_double[i], _state), _state);
+        }
+        state->lambdav = 0.001*state->lambdav;
+        if( ae_fp_eq(state->lambdav,0) )
+        {
+            state->lambdav = 1;
+        }
+    }
+    
+    /*
+     * Test stopping conditions for function gradient
+     */
+    if( ae_fp_greater(minlm_boundedscaledantigradnorm(state, &state->xbase, &state->gbase, _state),state->epsg) )
+    {
+        goto lbl_33;
+    }
+    if( state->modelage!=0 )
+    {
+        goto lbl_35;
+    }
+    
+    /*
+     * Model is fresh, we can rely on it and terminate algorithm
+     */
+    state->repterminationtype = 4;
+    if( !state->xrep )
+    {
+        goto lbl_37;
+    }
+    ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1));
+    state->f = state->fbase;
+    minlm_clearrequestfields(state, _state);
+    state->xupdated = ae_true;
+    state->rstate.stage = 8;
+    goto lbl_rcomm;
+lbl_8:
+    state->xupdated = ae_false;
+lbl_37:
+    result = ae_false;
+    return result;
+    goto lbl_36;
+lbl_35:
+    
+    /*
+     * Model is not fresh, we should refresh it and test
+     * conditions once more
+     */
+    state->modelage = state->maxmodelage+1;
+    goto lbl_20;
+lbl_36:
+lbl_33:
+    
+    /*
+     * 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;
+lbl_39:
+    if( ae_false )
+    {
+        goto lbl_40;
+    }
+    
+    /*
+     * Do we need model update?
+     */
+    if( state->modelage>0&&ae_fp_greater_eq(state->nu,minlm_suspiciousnu) )
+    {
+        iflag = -2;
+        goto lbl_40;
+    }
+    
+    /*
+     * 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 = ae_true;
+    minqpsetstartingpointfast(&state->qpstate, &state->xbase, _state);
+    minqpsetoriginfast(&state->qpstate, &state->xbase, _state);
+    minqpsetlineartermfast(&state->qpstate, &state->gbase, _state);
+    minqpsetquadratictermfast(&state->qpstate, &state->quadraticmodel, ae_true, 0.0, _state);
+    for(i=0; i<=n-1; i++)
+    {
+        state->tmp0.ptr.p_double[i] = state->quadraticmodel.ptr.pp_double[i][i]+state->lambdav/ae_sqr(state->s.ptr.p_double[i], _state);
+    }
+    minqprewritediagonal(&state->qpstate, &state->tmp0, _state);
+    minqpoptimize(&state->qpstate, _state);
+    minqpresultsbuf(&state->qpstate, &state->xdir, &state->qprep, _state);
+    if( state->qprep.terminationtype>0 )
+    {
+        
+        /*
+         * successful solution of QP problem
+         */
+        ae_v_sub(&state->xdir.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1));
+        v = ae_v_dotproduct(&state->xdir.ptr.p_double[0], 1, &state->xdir.ptr.p_double[0], 1, ae_v_len(0,n-1));
+        if( ae_isfinite(v, _state) )
+        {
+            v = ae_sqrt(v, _state);
+            if( ae_fp_greater(state->stpmax,0)&&ae_fp_greater(v,state->stpmax) )
+            {
+                bflag = ae_false;
+            }
+        }
+        else
+        {
+            bflag = ae_false;
+        }
+    }
+    else
+    {
+        
+        /*
+         * Either problem is non-convex (increase LambdaV) or constraints are inconsistent
+         */
+        ae_assert(state->qprep.terminationtype==-3||state->qprep.terminationtype==-5, "MinLM: unexpected completion code from QP solver", _state);
+        if( state->qprep.terminationtype==-3 )
+        {
+            iflag = -3;
+            goto lbl_40;
+        }
+        bflag = ae_false;
+    }
+    if( !bflag )
+    {
+        
+        /*
+         * Solution failed:
+         * try to increase lambda to make matrix positive definite and continue.
+         */
+        if( !minlm_increaselambda(&state->lambdav, &state->nu, _state) )
+        {
+            iflag = -1;
+            goto lbl_40;
+        }
+        goto lbl_39;
+    }
+    
+    /*
+     * 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)
+     */
+    ae_v_move(&state->deltax.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1));
+    ae_v_add(&state->deltax.ptr.p_double[0], 1, &state->xdir.ptr.p_double[0], 1, ae_v_len(0,n-1));
+    ae_v_sub(&state->deltax.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1));
+    state->deltaxready = ae_true;
+    v = 0.0;
+    for(i=0; i<=n-1; i++)
+    {
+        v = v+ae_sqr(state->deltax.ptr.p_double[i]/state->s.ptr.p_double[i], _state);
+    }
+    v = ae_sqrt(v, _state);
+    if( ae_fp_greater(v,state->epsx) )
+    {
+        goto lbl_41;
+    }
+    if( state->modelage!=0 )
+    {
+        goto lbl_43;
+    }
+    
+    /*
+     * Step is too short, model is fresh and we can rely on it.
+     * Terminating.
+     */
+    state->repterminationtype = 2;
+    if( !state->xrep )
+    {
+        goto lbl_45;
+    }
+    ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1));
+    state->f = state->fbase;
+    minlm_clearrequestfields(state, _state);
+    state->xupdated = ae_true;
+    state->rstate.stage = 9;
+    goto lbl_rcomm;
+lbl_9:
+    state->xupdated = ae_false;
+lbl_45:
+    result = ae_false;
+    return result;
+    goto lbl_44;
+lbl_43:
+    
+    /*
+     * Step is suspiciously short, but model is not fresh
+     * and we can't rely on it.
+     */
+    iflag = -2;
+    goto lbl_40;
+lbl_44:
+lbl_41:
+    
+    /*
+     * 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
+     */
+    ae_assert(state->hasfi||state->hasf, "MinLM: internal error 2!", _state);
+    ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1));
+    ae_v_add(&state->x.ptr.p_double[0], 1, &state->xdir.ptr.p_double[0], 1, ae_v_len(0,n-1));
+    minlm_clearrequestfields(state, _state);
+    if( !state->hasfi )
+    {
+        goto lbl_47;
+    }
+    state->needfi = ae_true;
+    state->rstate.stage = 10;
+    goto lbl_rcomm;
+lbl_10:
+    state->needfi = ae_false;
+    v = ae_v_dotproduct(&state->fi.ptr.p_double[0], 1, &state->fi.ptr.p_double[0], 1, ae_v_len(0,m-1));
+    state->f = v;
+    ae_v_move(&state->deltaf.ptr.p_double[0], 1, &state->fi.ptr.p_double[0], 1, ae_v_len(0,m-1));
+    ae_v_sub(&state->deltaf.ptr.p_double[0], 1, &state->fibase.ptr.p_double[0], 1, ae_v_len(0,m-1));
+    state->deltafready = ae_true;
+    goto lbl_48;
+lbl_47:
+    state->needf = ae_true;
+    state->rstate.stage = 11;
+    goto lbl_rcomm;
+lbl_11:
+    state->needf = ae_false;
+lbl_48:
+    state->repnfunc = state->repnfunc+1;
+    if( ae_fp_greater_eq(state->f,state->fbase) )
+    {
+        
+        /*
+         * Increase lambda and continue
+         */
+        if( !minlm_increaselambda(&state->lambdav, &state->nu, _state) )
+        {
+            iflag = -1;
+            goto lbl_40;
+        }
+        goto lbl_39;
+    }
+    
+    /*
+     * We've found our step!
+     */
+    iflag = 0;
+    goto lbl_40;
+    goto lbl_39;
+lbl_40:
+    state->nu = 1;
+    ae_assert(iflag>=-3&&iflag<=0, "MinLM: internal integrity check failed!", _state);
+    if( iflag==-3 )
+    {
+        state->repterminationtype = -3;
+        result = ae_false;
+        return result;
+    }
+    if( iflag==-2 )
+    {
+        state->modelage = state->maxmodelage+1;
+        goto lbl_20;
+    }
+    if( iflag==-1 )
+    {
+        goto lbl_21;
+    }
+    
+    /*
+     * 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.
+     */
+    ae_assert(state->deltaxready, "MinLM: deltaX is not ready", _state);
+    t = 0;
+    for(i=0; i<=n-1; i++)
+    {
+        v = ae_v_dotproduct(&state->quadraticmodel.ptr.pp_double[i][0], 1, &state->deltax.ptr.p_double[0], 1, ae_v_len(0,n-1));
+        t = t+state->deltax.ptr.p_double[i]*state->gbase.ptr.p_double[i]+0.5*state->deltax.ptr.p_double[i]*v;
+    }
+    state->predicteddecrease = -t;
+    state->actualdecrease = -(state->f-state->fbase);
+    if( ae_fp_less_eq(state->predicteddecrease,0) )
+    {
+        goto lbl_21;
+    }
+    v = state->actualdecrease/state->predicteddecrease;
+    if( ae_fp_greater_eq(v,0.1) )
+    {
+        goto lbl_49;
+    }
+    if( minlm_increaselambda(&state->lambdav, &state->nu, _state) )
+    {
+        goto lbl_51;
+    }
+    
+    /*
+     * Lambda is too large, we have to break iterations.
+     */
+    state->repterminationtype = 7;
+    if( !state->xrep )
+    {
+        goto lbl_53;
+    }
+    ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1));
+    state->f = state->fbase;
+    minlm_clearrequestfields(state, _state);
+    state->xupdated = ae_true;
+    state->rstate.stage = 12;
+    goto lbl_rcomm;
+lbl_12:
+    state->xupdated = ae_false;
+lbl_53:
+    result = ae_false;
+    return result;
+lbl_51:
+lbl_49:
+    if( ae_fp_greater(v,0.5) )
+    {
+        minlm_decreaselambda(&state->lambdav, &state->nu, _state);
+    }
+    
+    /*
+     * 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.
+     */
+    ae_v_add(&state->xbase.ptr.p_double[0], 1, &state->deltax.ptr.p_double[0], 1, ae_v_len(0,n-1));
+    if( !state->xrep )
+    {
+        goto lbl_55;
+    }
+    ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1));
+    minlm_clearrequestfields(state, _state);
+    state->xupdated = ae_true;
+    state->rstate.stage = 13;
+    goto lbl_rcomm;
+lbl_13:
+    state->xupdated = ae_false;
+lbl_55:
+    state->repiterationscount = state->repiterationscount+1;
+    if( state->repiterationscount>=state->maxits&&state->maxits>0 )
+    {
+        state->repterminationtype = 5;
+    }
+    if( state->modelage==0 )
+    {
+        if( ae_fp_less_eq(ae_fabs(state->f-state->fbase, _state),state->epsf*ae_maxreal(1, ae_maxreal(ae_fabs(state->f, _state), ae_fabs(state->fbase, _state), _state), _state)) )
+        {
+            state->repterminationtype = 1;
+        }
+    }
+    if( state->repterminationtype<=0 )
+    {
+        goto lbl_57;
+    }
+    if( !state->xrep )
+    {
+        goto lbl_59;
+    }
+    
+    /*
+     * Report: XBase contains new point, F contains function value at new point
+     */
+    ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1));
+    minlm_clearrequestfields(state, _state);
+    state->xupdated = ae_true;
+    state->rstate.stage = 14;
+    goto lbl_rcomm;
+lbl_14:
+    state->xupdated = ae_false;
+lbl_59:
+    result = ae_false;
+    return result;
+lbl_57:
+    state->modelage = state->modelage+1;
+    goto lbl_20;
+lbl_21:
+    
+    /*
+     * Lambda is too large, we have to break iterations.
+     */
+    state->repterminationtype = 7;
+    if( !state->xrep )
+    {
+        goto lbl_61;
+    }
+    ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1));
+    state->f = state->fbase;
+    minlm_clearrequestfields(state, _state);
+    state->xupdated = ae_true;
+    state->rstate.stage = 15;
+    goto lbl_rcomm;
+lbl_15:
+    state->xupdated = ae_false;
+lbl_61:
+    result = ae_false;
+    return result;
+    
+    /*
+     * Saving state
+     */
+lbl_rcomm:
+    result = ae_true;
+    state->rstate.ia.ptr.p_int[0] = n;
+    state->rstate.ia.ptr.p_int[1] = m;
+    state->rstate.ia.ptr.p_int[2] = iflag;
+    state->rstate.ia.ptr.p_int[3] = i;
+    state->rstate.ia.ptr.p_int[4] = k;
+    state->rstate.ba.ptr.p_bool[0] = bflag;
+    state->rstate.ra.ptr.p_double[0] = v;
+    state->rstate.ra.ptr.p_double[1] = s;
+    state->rstate.ra.ptr.p_double[2] = t;
+    return result;
+}
+
+
+/*************************************************************************
+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.
+
+  -- ALGLIB --
+     Copyright 10.03.2009 by Bochkanov Sergey
+*************************************************************************/
+void minlmresults(minlmstate* state,
+     /* Real    */ ae_vector* x,
+     minlmreport* rep,
+     ae_state *_state)
+{
+
+    ae_vector_clear(x);
+    _minlmreport_clear(rep);
+
+    minlmresultsbuf(state, x, rep, _state);
+}
+
+
+/*************************************************************************
+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.
+
+  -- ALGLIB --
+     Copyright 10.03.2009 by Bochkanov Sergey
+*************************************************************************/
+void minlmresultsbuf(minlmstate* state,
+     /* Real    */ ae_vector* x,
+     minlmreport* rep,
+     ae_state *_state)
+{
+
+
+    if( x->cnt<state->n )
+    {
+        ae_vector_set_length(x, state->n, _state);
+    }
+    ae_v_move(&x->ptr.p_double[0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,state->n-1));
+    rep->iterationscount = state->repiterationscount;
+    rep->terminationtype = state->repterminationtype;
+    rep->nfunc = state->repnfunc;
+    rep->njac = state->repnjac;
+    rep->ngrad = state->repngrad;
+    rep->nhess = state->repnhess;
+    rep->ncholesky = state->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.
+
+  -- ALGLIB --
+     Copyright 30.07.2010 by Bochkanov Sergey
+*************************************************************************/
+void minlmrestartfrom(minlmstate* state,
+     /* Real    */ ae_vector* x,
+     ae_state *_state)
+{
+
+
+    ae_assert(x->cnt>=state->n, "MinLMRestartFrom: Length(X)<N!", _state);
+    ae_assert(isfinitevector(x, state->n, _state), "MinLMRestartFrom: X contains infinite or NaN values!", _state);
+    ae_v_move(&state->xbase.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,state->n-1));
+    ae_vector_set_length(&state->rstate.ia, 4+1, _state);
+    ae_vector_set_length(&state->rstate.ba, 0+1, _state);
+    ae_vector_set_length(&state->rstate.ra, 2+1, _state);
+    state->rstate.stage = -1;
+    minlm_clearrequestfields(state, _state);
+}
+
+
+/*************************************************************************
+This is obsolete function.
+
+Since ALGLIB 3.3 it is equivalent to MinLMCreateVJ().
+
+  -- ALGLIB --
+     Copyright 30.03.2009 by Bochkanov Sergey
+*************************************************************************/
+void minlmcreatevgj(ae_int_t n,
+     ae_int_t m,
+     /* Real    */ ae_vector* x,
+     minlmstate* state,
+     ae_state *_state)
+{
+
+    _minlmstate_clear(state);
+
+    minlmcreatevj(n, m, x, state, _state);
+}
+
+
+/*************************************************************************
+This is obsolete function.
+
+Since ALGLIB 3.3 it is equivalent to MinLMCreateFJ().
+
+  -- ALGLIB --
+     Copyright 30.03.2009 by Bochkanov Sergey
+*************************************************************************/
+void minlmcreatefgj(ae_int_t n,
+     ae_int_t m,
+     /* Real    */ ae_vector* x,
+     minlmstate* state,
+     ae_state *_state)
+{
+
+    _minlmstate_clear(state);
+
+    minlmcreatefj(n, m, x, state, _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.
+
+  -- ALGLIB --
+     Copyright 30.03.2009 by Bochkanov Sergey
+*************************************************************************/
+void minlmcreatefj(ae_int_t n,
+     ae_int_t m,
+     /* Real    */ ae_vector* x,
+     minlmstate* state,
+     ae_state *_state)
+{
+
+    _minlmstate_clear(state);
+
+    ae_assert(n>=1, "MinLMCreateFJ: N<1!", _state);
+    ae_assert(m>=1, "MinLMCreateFJ: M<1!", _state);
+    ae_assert(x->cnt>=n, "MinLMCreateFJ: Length(X)<N!", _state);
+    ae_assert(isfinitevector(x, n, _state), "MinLMCreateFJ: X contains infinite or NaN values!", _state);
+    
+    /*
+     * initialize
+     */
+    state->n = n;
+    state->m = m;
+    state->algomode = 1;
+    state->hasf = ae_true;
+    state->hasfi = ae_false;
+    state->hasg = ae_false;
+    
+    /*
+     * init 2
+     */
+    minlm_lmprepare(n, m, ae_true, state, _state);
+    minlmsetacctype(state, 0, _state);
+    minlmsetcond(state, 0, 0, 0, 0, _state);
+    minlmsetxrep(state, ae_false, _state);
+    minlmsetstpmax(state, 0, _state);
+    minlmrestartfrom(state, x, _state);
+}
+
+
+/*************************************************************************
+Prepare internal structures (except for RComm).
+
+Note: M must be zero for FGH mode, non-zero for V/VJ/FJ/FGJ mode.
+*************************************************************************/
+static void minlm_lmprepare(ae_int_t n,
+     ae_int_t m,
+     ae_bool havegrad,
+     minlmstate* state,
+     ae_state *_state)
+{
+    ae_int_t i;
+
+
+    if( n<=0||m<0 )
+    {
+        return;
+    }
+    if( havegrad )
+    {
+        ae_vector_set_length(&state->g, n, _state);
+    }
+    if( m!=0 )
+    {
+        ae_matrix_set_length(&state->j, m, n, _state);
+        ae_vector_set_length(&state->fi, m, _state);
+        ae_vector_set_length(&state->fibase, m, _state);
+        ae_vector_set_length(&state->deltaf, m, _state);
+        ae_vector_set_length(&state->fm1, m, _state);
+        ae_vector_set_length(&state->fp1, m, _state);
+    }
+    else
+    {
+        ae_matrix_set_length(&state->h, n, n, _state);
+    }
+    ae_vector_set_length(&state->x, n, _state);
+    ae_vector_set_length(&state->deltax, n, _state);
+    ae_matrix_set_length(&state->quadraticmodel, n, n, _state);
+    ae_vector_set_length(&state->xbase, n, _state);
+    ae_vector_set_length(&state->gbase, n, _state);
+    ae_vector_set_length(&state->xdir, n, _state);
+    ae_vector_set_length(&state->tmp0, n, _state);
+    
+    /*
+     * prepare internal L-BFGS
+     */
+    for(i=0; i<=n-1; i++)
+    {
+        state->x.ptr.p_double[i] = 0;
+    }
+    minlbfgscreate(n, ae_minint(minlm_additers, n, _state), &state->x, &state->internalstate, _state);
+    minlbfgssetcond(&state->internalstate, 0.0, 0.0, 0.0, ae_minint(minlm_additers, n, _state), _state);
+    
+    /*
+     * Prepare internal QP solver
+     */
+    minqpcreate(n, &state->qpstate, _state);
+    minqpsetalgocholesky(&state->qpstate, _state);
+    
+    /*
+     * Prepare boundary constraints
+     */
+    ae_vector_set_length(&state->bndl, n, _state);
+    ae_vector_set_length(&state->bndu, n, _state);
+    ae_vector_set_length(&state->havebndl, n, _state);
+    ae_vector_set_length(&state->havebndu, n, _state);
+    for(i=0; i<=n-1; i++)
+    {
+        state->bndl.ptr.p_double[i] = _state->v_neginf;
+        state->havebndl.ptr.p_bool[i] = ae_false;
+        state->bndu.ptr.p_double[i] = _state->v_posinf;
+        state->havebndu.ptr.p_bool[i] = ae_false;
+    }
+    
+    /*
+     * Prepare scaling matrix
+     */
+    ae_vector_set_length(&state->s, n, _state);
+    for(i=0; i<=n-1; i++)
+    {
+        state->s.ptr.p_double[i] = 1.0;
+    }
+}
+
+
+/*************************************************************************
+Clears request fileds (to be sure that we don't forgot to clear something)
+*************************************************************************/
+static void minlm_clearrequestfields(minlmstate* state, ae_state *_state)
+{
+
+
+    state->needf = ae_false;
+    state->needfg = ae_false;
+    state->needfgh = ae_false;
+    state->needfij = ae_false;
+    state->needfi = ae_false;
+    state->xupdated = ae_false;
+}
+
+
+/*************************************************************************
+Increases lambda, returns False when there is a danger of overflow
+*************************************************************************/
+static ae_bool minlm_increaselambda(double* lambdav,
+     double* nu,
+     ae_state *_state)
+{
+    double lnlambda;
+    double lnnu;
+    double lnlambdaup;
+    double lnmax;
+    ae_bool result;
+
+
+    result = ae_false;
+    lnlambda = ae_log(*lambdav, _state);
+    lnlambdaup = ae_log(minlm_lambdaup, _state);
+    lnnu = ae_log(*nu, _state);
+    lnmax = ae_log(ae_maxrealnumber, _state);
+    if( ae_fp_greater(lnlambda+lnlambdaup+lnnu,0.25*lnmax) )
+    {
+        return result;
+    }
+    if( ae_fp_greater(lnnu+ae_log(2, _state),lnmax) )
+    {
+        return result;
+    }
+    *lambdav = *lambdav*minlm_lambdaup*(*nu);
+    *nu = *nu*2;
+    result = ae_true;
+    return result;
+}
+
+
+/*************************************************************************
+Decreases lambda, but leaves it unchanged when there is danger of underflow.
+*************************************************************************/
+static void minlm_decreaselambda(double* lambdav,
+     double* nu,
+     ae_state *_state)
+{
+
+
+    *nu = 1;
+    if( ae_fp_less(ae_log(*lambdav, _state)+ae_log(minlm_lambdadown, _state),ae_log(ae_minrealnumber, _state)) )
+    {
+        *lambdav = ae_minrealnumber;
+    }
+    else
+    {
+        *lambdav = *lambdav*minlm_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.
+
+  -- ALGLIB --
+     Copyright 14.01.2011 by Bochkanov Sergey
+*************************************************************************/
+static double minlm_boundedscaledantigradnorm(minlmstate* state,
+     /* Real    */ ae_vector* x,
+     /* Real    */ ae_vector* g,
+     ae_state *_state)
+{
+    ae_int_t n;
+    ae_int_t i;
+    double v;
+    double result;
+
+
+    result = 0;
+    n = state->n;
+    for(i=0; i<=n-1; i++)
+    {
+        v = -g->ptr.p_double[i]*state->s.ptr.p_double[i];
+        if( state->havebndl.ptr.p_bool[i] )
+        {
+            if( ae_fp_less_eq(x->ptr.p_double[i],state->bndl.ptr.p_double[i])&&ae_fp_less(-g->ptr.p_double[i],0) )
+            {
+                v = 0;
+            }
+        }
+        if( state->havebndu.ptr.p_bool[i] )
+        {
+            if( ae_fp_greater_eq(x->ptr.p_double[i],state->bndu.ptr.p_double[i])&&ae_fp_greater(-g->ptr.p_double[i],0) )
+            {
+                v = 0;
+            }
+        }
+        result = result+ae_sqr(v, _state);
+    }
+    result = ae_sqrt(result, _state);
+    return result;
+}
+
+
+ae_bool _minlmstate_init(minlmstate* p, ae_state *_state, ae_bool make_automatic)
+{
+    if( !ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init(&p->fi, 0, DT_REAL, _state, make_automatic) )
+        return ae_false;
+    if( !ae_matrix_init(&p->j, 0, 0, DT_REAL, _state, make_automatic) )
+        return ae_false;
+    if( !ae_matrix_init(&p->h, 0, 0, DT_REAL, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init(&p->g, 0, DT_REAL, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init(&p->xbase, 0, DT_REAL, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init(&p->fibase, 0, DT_REAL, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init(&p->gbase, 0, DT_REAL, _state, make_automatic) )
+        return ae_false;
+    if( !ae_matrix_init(&p->quadraticmodel, 0, 0, DT_REAL, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init(&p->bndl, 0, DT_REAL, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init(&p->bndu, 0, DT_REAL, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init(&p->havebndl, 0, DT_BOOL, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init(&p->havebndu, 0, DT_BOOL, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init(&p->s, 0, DT_REAL, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init(&p->xdir, 0, DT_REAL, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init(&p->deltax, 0, DT_REAL, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init(&p->deltaf, 0, DT_REAL, _state, make_automatic) )
+        return ae_false;
+    if( !_rcommstate_init(&p->rstate, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init(&p->choleskybuf, 0, DT_REAL, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init(&p->tmp0, 0, DT_REAL, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init(&p->fm1, 0, DT_REAL, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init(&p->fp1, 0, DT_REAL, _state, make_automatic) )
+        return ae_false;
+    if( !_minlbfgsstate_init(&p->internalstate, _state, make_automatic) )
+        return ae_false;
+    if( !_minlbfgsreport_init(&p->internalrep, _state, make_automatic) )
+        return ae_false;
+    if( !_minqpstate_init(&p->qpstate, _state, make_automatic) )
+        return ae_false;
+    if( !_minqpreport_init(&p->qprep, _state, make_automatic) )
+        return ae_false;
+    return ae_true;
+}
+
+
+ae_bool _minlmstate_init_copy(minlmstate* dst, minlmstate* src, ae_state *_state, ae_bool make_automatic)
+{
+    dst->n = src->n;
+    dst->m = src->m;
+    dst->diffstep = src->diffstep;
+    dst->epsg = src->epsg;
+    dst->epsf = src->epsf;
+    dst->epsx = src->epsx;
+    dst->maxits = src->maxits;
+    dst->xrep = src->xrep;
+    dst->stpmax = src->stpmax;
+    dst->maxmodelage = src->maxmodelage;
+    dst->makeadditers = src->makeadditers;
+    if( !ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic) )
+        return ae_false;
+    dst->f = src->f;
+    if( !ae_vector_init_copy(&dst->fi, &src->fi, _state, make_automatic) )
+        return ae_false;
+    if( !ae_matrix_init_copy(&dst->j, &src->j, _state, make_automatic) )
+        return ae_false;
+    if( !ae_matrix_init_copy(&dst->h, &src->h, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init_copy(&dst->g, &src->g, _state, make_automatic) )
+        return ae_false;
+    dst->needf = src->needf;
+    dst->needfg = src->needfg;
+    dst->needfgh = src->needfgh;
+    dst->needfij = src->needfij;
+    dst->needfi = src->needfi;
+    dst->xupdated = src->xupdated;
+    dst->algomode = src->algomode;
+    dst->hasf = src->hasf;
+    dst->hasfi = src->hasfi;
+    dst->hasg = src->hasg;
+    if( !ae_vector_init_copy(&dst->xbase, &src->xbase, _state, make_automatic) )
+        return ae_false;
+    dst->fbase = src->fbase;
+    if( !ae_vector_init_copy(&dst->fibase, &src->fibase, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init_copy(&dst->gbase, &src->gbase, _state, make_automatic) )
+        return ae_false;
+    if( !ae_matrix_init_copy(&dst->quadraticmodel, &src->quadraticmodel, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init_copy(&dst->bndl, &src->bndl, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init_copy(&dst->bndu, &src->bndu, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init_copy(&dst->havebndl, &src->havebndl, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init_copy(&dst->havebndu, &src->havebndu, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init_copy(&dst->s, &src->s, _state, make_automatic) )
+        return ae_false;
+    dst->lambdav = src->lambdav;
+    dst->nu = src->nu;
+    dst->modelage = src->modelage;
+    if( !ae_vector_init_copy(&dst->xdir, &src->xdir, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init_copy(&dst->deltax, &src->deltax, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init_copy(&dst->deltaf, &src->deltaf, _state, make_automatic) )
+        return ae_false;
+    dst->deltaxready = src->deltaxready;
+    dst->deltafready = src->deltafready;
+    dst->repiterationscount = src->repiterationscount;
+    dst->repterminationtype = src->repterminationtype;
+    dst->repnfunc = src->repnfunc;
+    dst->repnjac = src->repnjac;
+    dst->repngrad = src->repngrad;
+    dst->repnhess = src->repnhess;
+    dst->repncholesky = src->repncholesky;
+    if( !_rcommstate_init_copy(&dst->rstate, &src->rstate, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init_copy(&dst->choleskybuf, &src->choleskybuf, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init_copy(&dst->tmp0, &src->tmp0, _state, make_automatic) )
+        return ae_false;
+    dst->actualdecrease = src->actualdecrease;
+    dst->predicteddecrease = src->predicteddecrease;
+    dst->xm1 = src->xm1;
+    dst->xp1 = src->xp1;
+    if( !ae_vector_init_copy(&dst->fm1, &src->fm1, _state, make_automatic) )
+        return ae_false;
+    if( !ae_vector_init_copy(&dst->fp1, &src->fp1, _state, make_automatic) )
+        return ae_false;
+    if( !_minlbfgsstate_init_copy(&dst->internalstate, &src->internalstate, _state, make_automatic) )
+        return ae_false;
+    if( !_minlbfgsreport_init_copy(&dst->internalrep, &src->internalrep, _state, make_automatic) )
+        return ae_false;
+    if( !_minqpstate_init_copy(&dst->qpstate, &src->qpstate, _state, make_automatic) )
+        return ae_false;
+    if( !_minqpreport_init_copy(&dst->qprep, &src->qprep, _state, make_automatic) )
+        return ae_false;
+    return ae_true;
+}
+
+
+void _minlmstate_clear(minlmstate* p)
+{
+    ae_vector_clear(&p->x);
+    ae_vector_clear(&p->fi);
+    ae_matrix_clear(&p->j);
+    ae_matrix_clear(&p->h);
+    ae_vector_clear(&p->g);
+    ae_vector_clear(&p->xbase);
+    ae_vector_clear(&p->fibase);
+    ae_vector_clear(&p->gbase);
+    ae_matrix_clear(&p->quadraticmodel);
+    ae_vector_clear(&p->bndl);
+    ae_vector_clear(&p->bndu);
+    ae_vector_clear(&p->havebndl);
+    ae_vector_clear(&p->havebndu);
+    ae_vector_clear(&p->s);
+    ae_vector_clear(&p->xdir);
+    ae_vector_clear(&p->deltax);
+    ae_vector_clear(&p->deltaf);
+    _rcommstate_clear(&p->rstate);
+    ae_vector_clear(&p->choleskybuf);
+    ae_vector_clear(&p->tmp0);
+    ae_vector_clear(&p->fm1);
+    ae_vector_clear(&p->fp1);
+    _minlbfgsstate_clear(&p->internalstate);
+    _minlbfgsreport_clear(&p->internalrep);
+    _minqpstate_clear(&p->qpstate);
+    _minqpreport_clear(&p->qprep);
+}
+
+
+ae_bool _minlmreport_init(minlmreport* p, ae_state *_state, ae_bool make_automatic)
+{
+    return ae_true;
+}
+
+
+ae_bool _minlmreport_init_copy(minlmreport* dst, minlmreport* src, ae_state *_state, ae_bool make_automatic)
+{
+    dst->iterationscount = src->iterationscount;
+    dst->terminationtype = src->terminationtype;
+    dst->nfunc = src->nfunc;
+    dst->njac = src->njac;
+    dst->ngrad = src->ngrad;
+    dst->nhess = src->nhess;
+    dst->ncholesky = src->ncholesky;
+    return ae_true;
+}
+
+
+void _minlmreport_clear(minlmreport* p)
+{
+}
+
+
+
+
+/*************************************************************************
+Obsolete function, use MinLBFGSSetPrecDefault() instead.
+
+  -- ALGLIB --
+     Copyright 13.10.2010 by Bochkanov Sergey
+*************************************************************************/
+void minlbfgssetdefaultpreconditioner(minlbfgsstate* state,
+     ae_state *_state)
+{
+
+
+    minlbfgssetprecdefault(state, _state);
+}
+
+
+/*************************************************************************
+Obsolete function, use MinLBFGSSetCholeskyPreconditioner() instead.
+
+  -- ALGLIB --
+     Copyright 13.10.2010 by Bochkanov Sergey
+*************************************************************************/
+void minlbfgssetcholeskypreconditioner(minlbfgsstate* state,
+     /* Real    */ ae_matrix* p,
+     ae_bool isupper,
+     ae_state *_state)
+{
+
+
+    minlbfgssetpreccholesky(state, p, isupper, _state);
+}
+
+
+/*************************************************************************
+This is obsolete function which was used by previous version of the  BLEIC
+optimizer. It does nothing in the current version of BLEIC.
+
+  -- ALGLIB --
+     Copyright 28.11.2010 by Bochkanov Sergey
+*************************************************************************/
+void minbleicsetbarrierwidth(minbleicstate* state,
+     double mu,
+     ae_state *_state)
+{
+
+
+}
+
+
+/*************************************************************************
+This is obsolete function which was used by previous version of the  BLEIC
+optimizer. It does nothing in the current version of BLEIC.
+
+  -- ALGLIB --
+     Copyright 28.11.2010 by Bochkanov Sergey
+*************************************************************************/
+void minbleicsetbarrierdecay(minbleicstate* state,
+     double mudecay,
+     ae_state *_state)
+{
+
+
+}
+
+
+/*************************************************************************
+Obsolete optimization algorithm.
+Was replaced by MinBLEIC subpackage.
+
+  -- ALGLIB --
+     Copyright 25.03.2010 by Bochkanov Sergey
+*************************************************************************/
+void minasacreate(ae_int_t n,
+     /* Real    */ ae_vector* x,
+     /* Real    */ ae_vector* bndl,
+     /* Real    */ ae_vector* bndu,
+     minasastate* state,
+     ae_state *_state)
+{
+    ae_int_t i;
+
+    _minasastate_clear(state);
+
+    ae_assert(n>=1, "MinASA: N too small!", _state);
+    ae_assert(x->cnt>=n, "MinCGCreate: Length(X)<N!", _state);
+    ae_assert(isfinitevector(x, n, _state), "MinCGCreate: X contains infinite or NaN values!", _state);
+    ae_assert(bndl->cnt>=n, "MinCGCreate: Length(BndL)<N!", _state);
+    ae_assert(isfinitevector(bndl, n, _state), "MinCGCreate: BndL contains infinite or NaN values!", _state);
+    ae_assert(bndu->cnt>=n, "MinCGCreate: Length(BndU)<N!", _state);
+    ae_assert(isfinitevector(bndu, n, _state), "MinCGCreate: BndU contains infinite or NaN values!", _state);
+    for(i=0; i<=n-1; i++)
+    {
+        ae_assert(ae_fp_less_eq(bndl->ptr.p_double[i],bndu->ptr.p_double[i]), "MinASA: inconsistent bounds!", _state);
+        ae_assert(ae_fp_less_eq(bndl->ptr.p_double[i],x->ptr.p_double[i]), "MinASA: infeasible X!", _state);
+        ae_assert(ae_fp_less_eq(x->ptr.p_double[i],bndu->ptr.p_double[i]), "MinASA: infeasible X!", _state);
+    }
+    
+    /*
+     * Initialize
+     */
+    state->n = n;
+    minasasetcond(state, 0, 0, 0, 0, _state);
+    minasasetxrep(state, ae_false, _state);
+    minasasetstpmax(state, 0, _state);
+    minasasetalgorithm(state, -1, _state);
+    ae_vector_set_length(&state->bndl, n, _state);
+    ae_vector_set_length(&state->bndu, n, _state);
+    ae_vector_set_length(&state->ak, n, _state);
+    ae_vector_set_length(&state->xk, n, _state);
+    ae_vector_set_length(&state->dk, n, _state);
+    ae_vector_set_length(&state->an, n, _state);
+    ae_vector_set_length(&state->xn, n, _state);
+    ae_vector_set_length(&state->dn, n, _state);
+    ae_vector_set_length(&state->x, n, _state);
+    ae_vector_set_length(&state->d, n, _state);
+    ae_vector_set_length(&state->g, n, _state);
+    ae_vector_set_length(&state->gc, n, _state);
+    ae_vector_set_length(&state->work, n, _state);
+    ae_vector_set_length(&state->yk, n, _state);
+    minasarestartfrom(state, x, bndl, bndu, _state);
+}
+
+
+/*************************************************************************
+Obsolete optimization algorithm.
+Was replaced by MinBLEIC subpackage.
+
+  -- ALGLIB --
+     Copyright 02.04.2010 by Bochkanov Sergey
+*************************************************************************/
+void minasasetcond(minasastate* state,
+     double epsg,
+     double epsf,
+     double epsx,
+     ae_int_t maxits,
+     ae_state *_state)
+{
+
+
+    ae_assert(ae_isfinite(epsg, _state), "MinASASetCond: EpsG is not finite number!", _state);
+    ae_assert(ae_fp_greater_eq(epsg,0), "MinASASetCond: negative EpsG!", _state);
+    ae_assert(ae_isfinite(epsf, _state), "MinASASetCond: EpsF is not finite number!", _state);
+    ae_assert(ae_fp_greater_eq(epsf,0), "MinASASetCond: negative EpsF!", _state);
+    ae_assert(ae_isfinite(epsx, _state), "MinASASetCond: EpsX is not finite number!", _state);
+    ae_assert(ae_fp_greater_eq(epsx,0), "MinASASetCond: negative EpsX!", _state);
+    ae_assert(maxits>=0, "MinASASetCond: negative MaxIts!", _state);
+    if( ((ae_fp_eq(epsg,0)&&ae_fp_eq(epsf,0))&&ae_fp_eq(epsx,0))&&maxits==0 )
+    {
+        epsx = 1.0E-6;
+    }
+    state->epsg = epsg;
+    state->epsf = epsf;
+    state->epsx = epsx;
+    state->maxits = maxits;
+}
+
+
+/*************************************************************************
+Obsolete optimization algorithm.
+Was replaced by MinBLEIC subpackage.
+
+  -- ALGLIB --
+     Copyright 02.04.2010 by Bochkanov Sergey
+*************************************************************************/
+void minasasetxrep(minasastate* state, ae_bool needxrep, ae_state *_state)
+{
+
+
+    state->xrep = needxrep;
+}
+
+
+/*************************************************************************
+Obsolete optimization algorithm.
+Was replaced by MinBLEIC subpackage.
+
+  -- ALGLIB --
+     Copyright 02.04.2010 by Bochkanov Sergey
+*************************************************************************/
+void minasasetalgorithm(minasastate* state,
+     ae_int_t algotype,
+     ae_state *_state)
+{
+
+
+    ae_assert(algotype>=-1&&algotype<=1, "MinASASetAlgorithm: incorrect AlgoType!", _state);
+    if( algotype==-1 )
+    {
+        algotype = 1;
+    }
+    state->cgtype = algotype;
+}
+
+
+/*************************************************************************
+Obsolete optimization algorithm.
+Was replaced by MinBLEIC subpackage.
+
+  -- ALGLIB --
+     Copyright 02.04.2010 by Bochkanov Sergey
+*************************************************************************/
+void minasasetstpmax(minasastate* state, double stpmax, ae_state *_state)
+{
+
+
+    ae_assert(ae_isfinite(stpmax, _state), "MinASASetStpMax: StpMax is not finite!", _state);
+    ae_assert(ae_fp_greater_eq(stpmax,0), "MinASASetStpMax: StpMax<0!", _state);
+    state->stpmax = stpmax;
+}
+
+
+/*************************************************************************
+
+  -- ALGLIB --
+     Copyright 20.03.2009 by Bochkanov Sergey
+*************************************************************************/
+ae_bool minasaiteration(minasastate* state, ae_state *_state)
+{
+    ae_int_t n;
+    ae_int_t i;
+    double betak;
+    double v;
+    double vv;
+    ae_int_t mcinfo;
+    ae_bool b;
+    ae_bool stepfound;
+    ae_int_t diffcnt;
+    ae_bool result;
+
+
+    
+    /*
+     * 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->rstate.stage>=0 )
+    {
+        n = state->rstate.ia.ptr.p_int[0];
+        i = state->rstate.ia.ptr.p_int[1];
+        mcinfo = state->rstate.ia.ptr.p_int[2];
+        diffcnt = state->rstate.ia.ptr.p_int[3];
+        b = state->rstate.ba.ptr.p_bool[0];
+        stepfound = state->rstate.ba.ptr.p_bool[1];
+        betak = state->rstate.ra.ptr.p_double[0];
+        v = state->rstate.ra.ptr.p_double[1];
+        vv = state->rstate.ra.ptr.p_double[2];
+    }
+    else
+    {
+        n = -983;
+        i = -989;
+        mcinfo = -834;
+        diffcnt = 900;
+        b = ae_true;
+        stepfound = ae_false;
+        betak = 214;
+        v = -338;
+        vv = -686;
+    }
+    if( state->rstate.stage==0 )
+    {
+        goto lbl_0;
+    }
+    if( state->rstate.stage==1 )
+    {
+        goto lbl_1;
+    }
+    if( state->rstate.stage==2 )
+    {
+        goto lbl_2;
+    }
+    if( state->rstate.stage==3 )
+    {
+        goto lbl_3;
+    }
+    if( state->rstate.stage==4 )
+    {
+        goto lbl_4;
+    }
+    if( state->rstate.stage==5 )
+    {
+        goto lbl_5;
+    }
+    if( state->rstate.stage==6 )
+    {
+        goto lbl_6;
+    }
+    if( state->rstate.stage==7 )
+    {
+        goto lbl_7;
+    }
+    if( state->rstate.stage==8 )
+    {
+        goto lbl_8;
+    }
+    if( state->rstate.stage==9 )
+    {
+        goto lbl_9;
+    }
+    if( state->rstate.stage==10 )
+    {
+        goto lbl_10;
+    }
+    if( state->rstate.stage==11 )
+    {
+        goto lbl_11;
+    }
+    if( state->rstate.stage==12 )
+    {
+        goto lbl_12;
+    }
+    if( state->rstate.stage==13 )
+    {
+        goto lbl_13;
+    }
+    if( state->rstate.stage==14 )
+    {
+        goto lbl_14;
+    }
+    
+    /*
+     * Routine body
+     */
+    
+    /*
+     * Prepare
+     */
+    n = state->n;
+    state->repterminationtype = 0;
+    state->repiterationscount = 0;
+    state->repnfev = 0;
+    state->debugrestartscount = 0;
+    state->cgtype = 1;
+    ae_v_move(&state->xk.ptr.p_double[0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,n-1));
+    for(i=0; i<=n-1; i++)
+    {
+        if( ae_fp_eq(state->xk.ptr.p_double[i],state->bndl.ptr.p_double[i])||ae_fp_eq(state->xk.ptr.p_double[i],state->bndu.ptr.p_double[i]) )
+        {
+            state->ak.ptr.p_double[i] = 0;
+        }
+        else
+        {
+            state->ak.ptr.p_double[i] = 1;
+        }
+    }
+    state->mu = 0.1;
+    state->curalgo = 0;
+    
+    /*
+     * Calculate F/G, initialize algorithm
+     */
+    mincomp_clearrequestfields(state, _state);
+    state->needfg = ae_true;
+    state->rstate.stage = 0;
+    goto lbl_rcomm;
+lbl_0:
+    state->needfg = ae_false;
+    if( !state->xrep )
+    {
+        goto lbl_15;
+    }
+    
+    /*
+     * progress report
+     */
+    mincomp_clearrequestfields(state, _state);
+    state->xupdated = ae_true;
+    state->rstate.stage = 1;
+    goto lbl_rcomm;
+lbl_1:
+    state->xupdated = ae_false;
+lbl_15:
+    if( ae_fp_less_eq(mincomp_asaboundedantigradnorm(state, _state),state->epsg) )
+    {
+        state->repterminationtype = 4;
+        result = ae_false;
+        return result;
+    }
+    state->repnfev = state->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
+     */
+lbl_17:
+    if( ae_false )
+    {
+        goto lbl_18;
+    }
+    
+    /*
+     * GPA algorithm
+     */
+    if( state->curalgo!=0 )
+    {
+        goto lbl_19;
+    }
+    state->k = 0;
+    state->acount = 0;
+lbl_21:
+    if( ae_false )
+    {
+        goto lbl_22;
+    }
+    
+    /*
+     * Determine Dk = proj(xk - gk)-xk
+     */
+    for(i=0; i<=n-1; i++)
+    {
+        state->d.ptr.p_double[i] = boundval(state->xk.ptr.p_double[i]-state->g.ptr.p_double[i], state->bndl.ptr.p_double[i], state->bndu.ptr.p_double[i], _state)-state->xk.ptr.p_double[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 = ae_v_dotproduct(&state->d.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1));
+    state->dginit = v;
+    state->finit = state->f;
+    if( !(ae_fp_less_eq(mincomp_asad1norm(state, _state),state->stpmax)||ae_fp_eq(state->stpmax,0)) )
+    {
+        goto lbl_23;
+    }
+    
+    /*
+     * Try alpha=1 step first
+     */
+    for(i=0; i<=n-1; i++)
+    {
+        state->x.ptr.p_double[i] = boundval(state->xk.ptr.p_double[i]-state->g.ptr.p_double[i], state->bndl.ptr.p_double[i], state->bndu.ptr.p_double[i], _state);
+    }
+    mincomp_clearrequestfields(state, _state);
+    state->needfg = ae_true;
+    state->rstate.stage = 2;
+    goto lbl_rcomm;
+lbl_2:
+    state->needfg = ae_false;
+    state->repnfev = state->repnfev+1;
+    stepfound = ae_fp_less_eq(state->f,state->finit+mincomp_gpaftol*state->dginit);
+    goto lbl_24;
+lbl_23:
+    stepfound = ae_false;
+lbl_24:
+    if( !stepfound )
+    {
+        goto lbl_25;
+    }
+    
+    /*
+     * we are at the boundary(ies)
+     */
+    ae_v_move(&state->xn.ptr.p_double[0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,n-1));
+    state->stp = 1;
+    goto lbl_26;
+lbl_25:
+    
+    /*
+     * alpha=1 is too large, try smaller values
+     */
+    state->stp = 1;
+    linminnormalized(&state->d, &state->stp, n, _state);
+    state->dginit = state->dginit/state->stp;
+    state->stp = mincomp_gpadecay*state->stp;
+    if( ae_fp_greater(state->stpmax,0) )
+    {
+        state->stp = ae_minreal(state->stp, state->stpmax, _state);
+    }
+lbl_27:
+    if( ae_false )
+    {
+        goto lbl_28;
+    }
+    v = state->stp;
+    ae_v_move(&state->x.ptr.p_double[0], 1, &state->xk.ptr.p_double[0], 1, ae_v_len(0,n-1));
+    ae_v_addd(&state->x.ptr.p_double[0], 1, &state->d.ptr.p_double[0], 1, ae_v_len(0,n-1), v);
+    mincomp_clearrequestfields(state, _state);
+    state->needfg = ae_true;
+    state->rstate.stage = 3;
+    goto lbl_rcomm;
+lbl_3:
+    state->needfg = ae_false;
+    state->repnfev = state->repnfev+1;
+    if( ae_fp_less_eq(state->stp,mincomp_stpmin) )
+    {
+        goto lbl_28;
+    }
+    if( ae_fp_less_eq(state->f,state->finit+state->stp*mincomp_gpaftol*state->dginit) )
+    {
+        goto lbl_28;
+    }
+    state->stp = state->stp*mincomp_gpadecay;
+    goto lbl_27;
+lbl_28:
+    ae_v_move(&state->xn.ptr.p_double[0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,n-1));
+lbl_26:
+    state->repiterationscount = state->repiterationscount+1;
+    if( !state->xrep )
+    {
+        goto lbl_29;
+    }
     
     /*
-     * 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
+     * progress report
      */
-    if( state->rstate.stage>=0 )
+    mincomp_clearrequestfields(state, _state);
+    state->xupdated = ae_true;
+    state->rstate.stage = 4;
+    goto lbl_rcomm;
+lbl_4:
+    state->xupdated = ae_false;
+lbl_29:
+    
+    /*
+     * 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++)
     {
-        n = state->rstate.ia.ptr.p_int[0];
-        m = state->rstate.ia.ptr.p_int[1];
-        i = state->rstate.ia.ptr.p_int[2];
-        b = state->rstate.ba.ptr.p_bool[0];
-        v = state->rstate.ra.ptr.p_double[0];
-        vv = state->rstate.ra.ptr.p_double[1];
+        if( ae_fp_eq(state->xn.ptr.p_double[i],state->bndl.ptr.p_double[i])||ae_fp_eq(state->xn.ptr.p_double[i],state->bndu.ptr.p_double[i]) )
+        {
+            state->an.ptr.p_double[i] = 0;
+        }
+        else
+        {
+            state->an.ptr.p_double[i] = 1;
+        }
     }
-    else
+    for(i=0; i<=n-1; i++)
     {
-        n = -983;
-        m = -989;
-        i = -834;
-        b = ae_false;
-        v = -287;
-        vv = 364;
+        if( ae_fp_neq(state->ak.ptr.p_double[i],state->an.ptr.p_double[i]) )
+        {
+            state->acount = -1;
+            break;
+        }
     }
-    if( state->rstate.stage==0 )
+    state->acount = state->acount+1;
+    ae_v_move(&state->xk.ptr.p_double[0], 1, &state->xn.ptr.p_double[0], 1, ae_v_len(0,n-1));
+    ae_v_move(&state->ak.ptr.p_double[0], 1, &state->an.ptr.p_double[0], 1, ae_v_len(0,n-1));
+    
+    /*
+     * Stopping conditions
+     */
+    if( !(state->repiterationscount>=state->maxits&&state->maxits>0) )
     {
-        goto lbl_0;
+        goto lbl_31;
     }
-    if( state->rstate.stage==1 )
+    
+    /*
+     * Too many iterations
+     */
+    state->repterminationtype = 5;
+    if( !state->xrep )
     {
-        goto lbl_1;
+        goto lbl_33;
     }
-    if( state->rstate.stage==2 )
+    mincomp_clearrequestfields(state, _state);
+    state->xupdated = ae_true;
+    state->rstate.stage = 5;
+    goto lbl_rcomm;
+lbl_5:
+    state->xupdated = ae_false;
+lbl_33:
+    result = ae_false;
+    return result;
+lbl_31:
+    if( ae_fp_greater(mincomp_asaboundedantigradnorm(state, _state),state->epsg) )
     {
-        goto lbl_2;
+        goto lbl_35;
     }
-    if( state->rstate.stage==3 )
+    
+    /*
+     * Gradient is small enough
+     */
+    state->repterminationtype = 4;
+    if( !state->xrep )
     {
-        goto lbl_3;
+        goto lbl_37;
     }
-    if( state->rstate.stage==4 )
+    mincomp_clearrequestfields(state, _state);
+    state->xupdated = ae_true;
+    state->rstate.stage = 6;
+    goto lbl_rcomm;
+lbl_6:
+    state->xupdated = ae_false;
+lbl_37:
+    result = ae_false;
+    return result;
+lbl_35:
+    v = ae_v_dotproduct(&state->d.ptr.p_double[0], 1, &state->d.ptr.p_double[0], 1, ae_v_len(0,n-1));
+    if( ae_fp_greater(ae_sqrt(v, _state)*state->stp,state->epsx) )
     {
-        goto lbl_4;
+        goto lbl_39;
     }
     
     /*
-     * Routine body
+     * Step size is too small, no further improvement is
+     * possible
      */
+    state->repterminationtype = 2;
+    if( !state->xrep )
+    {
+        goto lbl_41;
+    }
+    mincomp_clearrequestfields(state, _state);
+    state->xupdated = ae_true;
+    state->rstate.stage = 7;
+    goto lbl_rcomm;
+lbl_7:
+    state->xupdated = ae_false;
+lbl_41:
+    result = ae_false;
+    return result;
+lbl_39:
+    if( ae_fp_greater(state->finit-state->f,state->epsf*ae_maxreal(ae_fabs(state->finit, _state), ae_maxreal(ae_fabs(state->f, _state), 1.0, _state), _state)) )
+    {
+        goto lbl_43;
+    }
     
     /*
-     * Prepare.
+     * F(k+1)-F(k) is small enough
      */
-    n = state->n;
-    state->repterminationtype = 0;
-    state->repinneriterationscount = 0;
-    state->repouteriterationscount = 0;
-    state->repnfev = 0;
-    state->repdebugeqerr = 0.0;
-    state->repdebugfs = _state->v_nan;
-    state->repdebugff = _state->v_nan;
-    state->repdebugdx = _state->v_nan;
-    rvectorsetlengthatleast(&state->r, n, _state);
-    rvectorsetlengthatleast(&state->tmp1, n, _state);
+    state->repterminationtype = 1;
+    if( !state->xrep )
+    {
+        goto lbl_45;
+    }
+    mincomp_clearrequestfields(state, _state);
+    state->xupdated = ae_true;
+    state->rstate.stage = 8;
+    goto lbl_rcomm;
+lbl_8:
+    state->xupdated = ae_false;
+lbl_45:
+    result = ae_false;
+    return result;
+lbl_43:
     
     /*
-     * Check that equality constraints are consistent within EpsC.
-     * If not - premature termination.
+     * Decide - should we switch algorithm or not
      */
-    if( state->cedim>0 )
+    if( mincomp_asauisempty(state, _state) )
     {
-        state->repdebugeqerr = 0.0;
-        for(i=0; i<=state->cecnt-1; i++)
+        if( ae_fp_greater_eq(mincomp_asaginorm(state, _state),state->mu*mincomp_asad1norm(state, _state)) )
         {
-            v = ae_v_dotproduct(&state->ce.ptr.pp_double[i][0], 1, &state->xe.ptr.p_double[0], 1, ae_v_len(0,n-1));
-            state->repdebugeqerr = state->repdebugeqerr+ae_sqr(v-state->ce.ptr.pp_double[i][n], _state);
+            state->curalgo = 1;
+            goto lbl_22;
         }
-        state->repdebugeqerr = ae_sqrt(state->repdebugeqerr, _state);
-        if( ae_fp_greater(state->repdebugeqerr,state->outerepsi) )
+        else
         {
-            state->repterminationtype = -3;
-            result = ae_false;
-            return result;
+            state->mu = state->mu*mincomp_asarho;
+        }
+    }
+    else
+    {
+        if( state->acount==mincomp_n1 )
+        {
+            if( ae_fp_greater_eq(mincomp_asaginorm(state, _state),state->mu*mincomp_asad1norm(state, _state)) )
+            {
+                state->curalgo = 1;
+                goto lbl_22;
+            }
         }
     }
     
     /*
-     * Find feasible point.
-     *
-     * We make up to 16*N iterations of nonlinear CG trying to
-     * minimize penalty for violation of inequality constraints.
-     *
-     * if P is magnitude of violation, then penalty function has form:
-     * * P*P+P for non-zero violation (P>=0)
-     * * 0.0 for absence of violation (P<0)
-     * Such function is non-smooth at P=0.0, but its nonsmoothness
-     * allows us to rapidly converge to the feasible point.
+     * Next iteration
      */
-    minbleic_makeprojection(state, &state->xcur, &state->r, &vv, _state);
-    mincgrestartfrom(&state->cgstate, &state->xcur, _state);
-    mincgsetcond(&state->cgstate, 0.0, 0.0, 0.0, 16*n, _state);
-    mincgsetxrep(&state->cgstate, ae_false, _state);
-    while(mincgiteration(&state->cgstate, _state))
+    state->k = state->k+1;
+    goto lbl_21;
+lbl_22:
+lbl_19:
+    
+    /*
+     * CG algorithm
+     */
+    if( state->curalgo!=1 )
+    {
+        goto lbl_47;
+    }
+    
+    /*
+     * first, check that there are non-active constraints.
+     * move to GPA algorithm, if all constraints are active
+     */
+    b = ae_true;
+    for(i=0; i<=n-1; i++)
     {
-        if( state->cgstate.needfg )
+        if( ae_fp_neq(state->ak.ptr.p_double[i],0) )
         {
-            ae_v_move(&state->x.ptr.p_double[0], 1, &state->cgstate.x.ptr.p_double[0], 1, ae_v_len(0,n-1));
-            minbleic_penaltyfunction(state, &state->x, &state->cgstate.f, &state->cgstate.g, &state->r, &state->mba, &state->errfeas, _state);
-            continue;
+            b = ae_false;
+            break;
         }
     }
-    mincgresults(&state->cgstate, &state->xcur, &state->cgrep, _state);
-    ae_v_move(&state->tmp1.ptr.p_double[0], 1, &state->xcur.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    minbleic_penaltyfunction(state, &state->tmp1, &state->f, &state->g, &state->r, &state->mba, &state->errfeas, _state);
-    if( ae_fp_greater(state->errfeas,state->outerepsi) )
+    if( b )
     {
-        state->repterminationtype = -3;
-        result = ae_false;
-        return result;
+        state->curalgo = 0;
+        goto lbl_17;
     }
     
     /*
-     * Initialize RepDebugFS with function value at initial point
+     * CG iterations
      */
-    ae_v_move(&state->x.ptr.p_double[0], 1, &state->xcur.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    minbleic_clearrequestfields(state, _state);
-    state->needfg = ae_true;
-    state->rstate.stage = 0;
-    goto lbl_rcomm;
-lbl_0:
-    state->needfg = ae_false;
-    state->repnfev = state->repnfev+1;
-    state->repdebugfs = state->f;
+    state->fold = state->f;
+    ae_v_move(&state->xk.ptr.p_double[0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,n-1));
+    for(i=0; i<=n-1; i++)
+    {
+        state->dk.ptr.p_double[i] = -state->g.ptr.p_double[i]*state->ak.ptr.p_double[i];
+        state->gc.ptr.p_double[i] = state->g.ptr.p_double[i]*state->ak.ptr.p_double[i];
+    }
+lbl_49:
+    if( ae_false )
+    {
+        goto lbl_50;
+    }
     
     /*
-     * Calculate number of inequality constraints and allocate
-     * array for Lagrange multipliers.
-     *
-     * Initialize Lagrange multipliers and penalty term
+     * Store G[k] for later calculation of Y[k]
      */
-    state->lmcnt = state->cicnt;
     for(i=0; i<=n-1; i++)
     {
-        if( state->hasbndl.ptr.p_bool[i] )
-        {
-            state->lmcnt = state->lmcnt+1;
-        }
-        if( state->hasbndu.ptr.p_bool[i] )
-        {
-            state->lmcnt = state->lmcnt+1;
-        }
+        state->yk.ptr.p_double[i] = -state->gc.ptr.p_double[i];
     }
-    if( state->lmcnt>0 )
+    
+    /*
+     * 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.
+     */
+    ae_v_move(&state->d.ptr.p_double[0], 1, &state->dk.ptr.p_double[0], 1, ae_v_len(0,n-1));
+    ae_v_move(&state->xn.ptr.p_double[0], 1, &state->xk.ptr.p_double[0], 1, ae_v_len(0,n-1));
+    state->mcstage = 0;
+    state->stp = 1;
+    linminnormalized(&state->d, &state->stp, n, _state);
+    if( ae_fp_neq(state->laststep,0) )
     {
-        rvectorsetlengthatleast(&state->lm, state->lmcnt, _state);
+        state->stp = state->laststep;
     }
-    for(i=0; i<=state->lmcnt-1; i++)
+    mcsrch(n, &state->xn, &state->f, &state->gc, &state->d, &state->stp, state->stpmax, mincomp_gtol, &mcinfo, &state->nfev, &state->work, &state->lstate, &state->mcstage, _state);
+lbl_51:
+    if( state->mcstage==0 )
     {
-        state->lm.ptr.p_double[i] = 1.0;
+        goto lbl_52;
     }
-    state->mu = ae_maxreal(state->mustart, state->outerepsi, _state);
     
     /*
-     * BndMax is a maximum over right parts of inequality constraints.
-     * It is used later to bound Mu from below.
+     * preprocess data: bound State.XN so it belongs to the
+     * feasible set and store it in the State.X
      */
-    state->bndmax = 0.0;
     for(i=0; i<=n-1; i++)
     {
-        if( state->hasbndl.ptr.p_bool[i] )
-        {
-            state->bndmax = ae_maxreal(state->bndmax, ae_fabs(state->bndl.ptr.p_double[i], _state), _state);
-        }
-        if( state->hasbndu.ptr.p_bool[i] )
-        {
-            state->bndmax = ae_maxreal(state->bndmax, ae_fabs(state->bndu.ptr.p_double[i], _state), _state);
-        }
-    }
-    for(i=0; i<=state->cicnt-1; i++)
-    {
-        state->bndmax = ae_maxreal(state->bndmax, ae_fabs(state->ci.ptr.pp_double[i][n], _state), _state);
+        state->x.ptr.p_double[i] = boundval(state->xn.ptr.p_double[i], state->bndl.ptr.p_double[i], state->bndu.ptr.p_double[i], _state);
     }
     
     /*
-     * External cycle: optimization subject to current
-     * estimate of Lagrange multipliers and penalty term
+     * RComm
      */
-    state->itsleft = state->maxits;
-    state->mucounter = minbleic_mucountdownlen;
-    ae_v_move(&state->xprev.ptr.p_double[0], 1, &state->xcur.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    ae_v_move(&state->xstart.ptr.p_double[0], 1, &state->xcur.ptr.p_double[0], 1, ae_v_len(0,n-1));
-lbl_5:
-    if( ae_false )
-    {
-        goto lbl_6;
-    }
+    mincomp_clearrequestfields(state, _state);
+    state->needfg = ae_true;
+    state->rstate.stage = 9;
+    goto lbl_rcomm;
+lbl_9:
+    state->needfg = ae_false;
     
     /*
-     * Inner cycle: CG with projections and penalty functions
+     * postprocess data: zero components of G corresponding to
+     * the active constraints
      */
-    mincgrestartfrom(&state->cgstate, &state->xcur, _state);
-    mincgsetcond(&state->cgstate, state->innerepsg, state->innerepsf, state->innerepsx, state->itsleft, _state);
-    mincgsetxrep(&state->cgstate, state->xrep, _state);
-    mincgsetdrep(&state->cgstate, ae_true, _state);
-    mincgsetstpmax(&state->cgstate, state->stpmax, _state);
-lbl_7:
-    if( !mincgiteration(&state->cgstate, _state) )
+    for(i=0; i<=n-1; i++)
     {
-        goto lbl_8;
+        if( ae_fp_eq(state->x.ptr.p_double[i],state->bndl.ptr.p_double[i])||ae_fp_eq(state->x.ptr.p_double[i],state->bndu.ptr.p_double[i]) )
+        {
+            state->gc.ptr.p_double[i] = 0;
+        }
+        else
+        {
+            state->gc.ptr.p_double[i] = state->g.ptr.p_double[i];
+        }
     }
-    if( state->cgstate.lsstart )
+    mcsrch(n, &state->xn, &state->f, &state->gc, &state->d, &state->stp, state->stpmax, mincomp_gtol, &mcinfo, &state->nfev, &state->work, &state->lstate, &state->mcstage, _state);
+    goto lbl_51;
+lbl_52:
+    diffcnt = 0;
+    for(i=0; i<=n-1; i++)
     {
         
         /*
-         * Beginning of the line search: set upper limit on step size
-         * to prevent algo from leaving area where barrier function
-         * is defined.
-         *
-         * We calculate State.CGState.CurStpMax in two steps:
-         * * first, we calculate it as the distance from the current
-         *   point to the boundary where modified barrier function
-         *   overflows; distance is taken along State.CGState.D
-         * * then we multiply it by 0.999 to make sure that we won't
-         *   make step into the boundary due to the rounding noise
+         * XN contains unprojected result, project it,
+         * save copy to X (will be used for progress reporting)
          */
-        if( ae_fp_eq(state->cgstate.curstpmax,0) )
-        {
-            state->cgstate.curstpmax = 1.0E50;
-        }
-        state->boundary = -0.9*state->mu;
-        state->closetobarrier = ae_false;
-        for(i=0; i<=n-1; i++)
+        state->xn.ptr.p_double[i] = boundval(state->xn.ptr.p_double[i], state->bndl.ptr.p_double[i], state->bndu.ptr.p_double[i], _state);
+        
+        /*
+         * update active set
+         */
+        if( ae_fp_eq(state->xn.ptr.p_double[i],state->bndl.ptr.p_double[i])||ae_fp_eq(state->xn.ptr.p_double[i],state->bndu.ptr.p_double[i]) )
         {
-            if( state->hasbndl.ptr.p_bool[i] )
-            {
-                v = state->cgstate.x.ptr.p_double[i]-state->bndl.ptr.p_double[i];
-                if( ae_fp_less(state->cgstate.d.ptr.p_double[i],0) )
-                {
-                    state->cgstate.curstpmax = safeminposrv(v+state->mu, -state->cgstate.d.ptr.p_double[i], state->cgstate.curstpmax, _state);
-                }
-                if( ae_fp_greater(state->cgstate.d.ptr.p_double[i],0)&&ae_fp_less_eq(v,state->boundary) )
-                {
-                    state->cgstate.curstpmax = safeminposrv(-v, state->cgstate.d.ptr.p_double[i], state->cgstate.curstpmax, _state);
-                    state->closetobarrier = ae_true;
-                }
-            }
-            if( state->hasbndu.ptr.p_bool[i] )
-            {
-                v = state->bndu.ptr.p_double[i]-state->cgstate.x.ptr.p_double[i];
-                if( ae_fp_greater(state->cgstate.d.ptr.p_double[i],0) )
-                {
-                    state->cgstate.curstpmax = safeminposrv(v+state->mu, state->cgstate.d.ptr.p_double[i], state->cgstate.curstpmax, _state);
-                }
-                if( ae_fp_less(state->cgstate.d.ptr.p_double[i],0)&&ae_fp_less_eq(v,state->boundary) )
-                {
-                    state->cgstate.curstpmax = safeminposrv(-v, -state->cgstate.d.ptr.p_double[i], state->cgstate.curstpmax, _state);
-                    state->closetobarrier = ae_true;
-                }
-            }
+            state->an.ptr.p_double[i] = 0;
         }
-        for(i=0; i<=state->cicnt-1; i++)
+        else
         {
-            v = ae_v_dotproduct(&state->ci.ptr.pp_double[i][0], 1, &state->cgstate.d.ptr.p_double[0], 1, ae_v_len(0,n-1));
-            vv = ae_v_dotproduct(&state->ci.ptr.pp_double[i][0], 1, &state->cgstate.x.ptr.p_double[0], 1, ae_v_len(0,n-1));
-            vv = vv-state->ci.ptr.pp_double[i][n];
-            if( ae_fp_less(v,0) )
-            {
-                state->cgstate.curstpmax = safeminposrv(vv+state->mu, -v, state->cgstate.curstpmax, _state);
-            }
-            if( ae_fp_greater(v,0)&&ae_fp_less_eq(vv,state->boundary) )
-            {
-                state->cgstate.curstpmax = safeminposrv(-vv, v, state->cgstate.curstpmax, _state);
-                state->closetobarrier = ae_true;
-            }
+            state->an.ptr.p_double[i] = 1;
         }
-        state->cgstate.curstpmax = 0.999*state->cgstate.curstpmax;
-        if( state->closetobarrier )
+        if( ae_fp_neq(state->an.ptr.p_double[i],state->ak.ptr.p_double[i]) )
         {
-            state->cgstate.stp = 0.5*state->cgstate.curstpmax;
+            diffcnt = diffcnt+1;
         }
-        goto lbl_7;
-    }
-    if( !state->cgstate.needfg )
-    {
-        goto lbl_9;
+        state->ak.ptr.p_double[i] = state->an.ptr.p_double[i];
     }
-    
-    /*
-     * * get X from CG
-     * * project X into equality constrained subspace
-     * * RComm (note: X is stored in Tmp1 to prevent accidental corruption by user)
-     * * modify target function with barriers and penalties
-     * * pass F/G back to nonlinear CG
-     */
-    ae_v_move(&state->x.ptr.p_double[0], 1, &state->cgstate.x.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    minbleic_makeprojection(state, &state->x, &state->r, &vv, _state);
-    ae_v_move(&state->tmp1.ptr.p_double[0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    minbleic_clearrequestfields(state, _state);
-    state->needfg = ae_true;
-    state->rstate.stage = 1;
-    goto lbl_rcomm;
-lbl_1:
-    state->needfg = ae_false;
-    ae_v_move(&state->x.ptr.p_double[0], 1, &state->tmp1.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    minbleic_modifytargetfunction(state, &state->x, &state->r, vv, &state->f, &state->g, &state->gnorm, &state->mpgnorm, &state->mba, &state->errfeas, &state->errslack, _state);
-    state->cgstate.f = state->f;
-    ae_v_move(&state->cgstate.g.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    goto lbl_7;
-lbl_9:
-    if( !state->cgstate.xupdated )
+    ae_v_move(&state->xk.ptr.p_double[0], 1, &state->xn.ptr.p_double[0], 1, ae_v_len(0,n-1));
+    state->repnfev = state->repnfev+state->nfev;
+    state->repiterationscount = state->repiterationscount+1;
+    if( !state->xrep )
     {
-        goto lbl_11;
+        goto lbl_53;
     }
     
     /*
-     * Report
+     * progress report
      */
-    ae_v_move(&state->x.ptr.p_double[0], 1, &state->cgstate.x.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    state->f = state->cgstate.f;
-    minbleic_clearrequestfields(state, _state);
+    mincomp_clearrequestfields(state, _state);
     state->xupdated = ae_true;
-    state->rstate.stage = 2;
+    state->rstate.stage = 10;
     goto lbl_rcomm;
-lbl_2:
+lbl_10:
     state->xupdated = ae_false;
-    goto lbl_7;
-lbl_11:
-    goto lbl_7;
-lbl_8:
-    mincgresults(&state->cgstate, &state->xcur, &state->cgrep, _state);
-    state->repinneriterationscount = state->repinneriterationscount+state->cgrep.iterationscount;
-    state->repouteriterationscount = state->repouteriterationscount+1;
-    state->repnfev = state->repnfev+state->cgrep.nfev;
+lbl_53:
     
     /*
-     * Update RepDebugFF with function value at current point
+     * Update info about step length
      */
-    ae_v_move(&state->x.ptr.p_double[0], 1, &state->xcur.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    minbleic_clearrequestfields(state, _state);
-    state->needfg = ae_true;
-    state->rstate.stage = 3;
-    goto lbl_rcomm;
-lbl_3:
-    state->needfg = ae_false;
-    state->repnfev = state->repnfev+1;
-    state->repdebugff = state->f;
+    v = ae_v_dotproduct(&state->d.ptr.p_double[0], 1, &state->d.ptr.p_double[0], 1, ae_v_len(0,n-1));
+    state->laststep = ae_sqrt(v, _state)*state->stp;
     
     /*
-     * Update Lagrange multipliers and Mu
-     *
-     * We calculate three values during update:
-     * * LMDif      -   absolute differense between new and old multipliers
-     * * LMNorm     -   inf-norm of Lagrange vector
-     * * LMGrowth   -   maximum componentwise relative growth of Lagrange vector
-     *
-     * We limit growth of Lagrange multipliers by MaxLMGrowth,
-     * it allows us to stabilize algorithm when it moves deep into
-     * the infeasible area.
-     *
-     * We calculate modified target function at XCur in order to get
-     * information about overall problem properties. Some values
-     * calculated here will be used later:
-     * * ErrFeas  - feasibility error
-     * * ErrSlack - complementary slackness error
-     */
-    ae_v_move(&state->x.ptr.p_double[0], 1, &state->xcur.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    minbleic_makeprojection(state, &state->x, &state->r, &vv, _state);
-    ae_v_move(&state->tmp1.ptr.p_double[0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    minbleic_clearrequestfields(state, _state);
-    state->needfg = ae_true;
-    state->rstate.stage = 4;
-    goto lbl_rcomm;
-lbl_4:
-    state->needfg = ae_false;
-    ae_v_move(&state->x.ptr.p_double[0], 1, &state->tmp1.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    minbleic_modifytargetfunction(state, &state->x, &state->r, vv, &state->f, &state->g, &state->gnorm, &state->mpgnorm, &state->mba, &state->errfeas, &state->errslack, _state);
-    m = 0;
-    state->lmdif = 0;
-    state->lmnorm = 0;
-    state->lmgrowth = 0;
-    for(i=0; i<=n-1; i++)
-    {
-        if( state->hasbndl.ptr.p_bool[i] )
-        {
-            barrierfunc(state->xcur.ptr.p_double[i]-state->bndl.ptr.p_double[i], state->mu, &state->v0, &state->v1, &state->v2, _state);
-            v = state->lm.ptr.p_double[m];
-            vv = ae_minreal(minbleic_maxlmgrowth, -state->mu*state->v1, _state);
-            state->lm.ptr.p_double[m] = vv*state->lm.ptr.p_double[m];
-            state->lmnorm = ae_maxreal(state->lmnorm, ae_fabs(v, _state), _state);
-            state->lmdif = ae_maxreal(state->lmdif, ae_fabs(state->lm.ptr.p_double[m]-v, _state), _state);
-            state->lmgrowth = ae_maxreal(state->lmgrowth, vv, _state);
-            m = m+1;
-        }
-        if( state->hasbndu.ptr.p_bool[i] )
-        {
-            barrierfunc(state->bndu.ptr.p_double[i]-state->xcur.ptr.p_double[i], state->mu, &state->v0, &state->v1, &state->v2, _state);
-            v = state->lm.ptr.p_double[m];
-            vv = ae_minreal(minbleic_maxlmgrowth, -state->mu*state->v1, _state);
-            state->lm.ptr.p_double[m] = vv*state->lm.ptr.p_double[m];
-            state->lmnorm = ae_maxreal(state->lmnorm, ae_fabs(v, _state), _state);
-            state->lmdif = ae_maxreal(state->lmdif, ae_fabs(state->lm.ptr.p_double[m]-v, _state), _state);
-            state->lmgrowth = ae_maxreal(state->lmgrowth, vv, _state);
-            m = m+1;
-        }
-    }
-    for(i=0; i<=state->cicnt-1; i++)
+     * Check stopping conditions.
+     */
+    if( ae_fp_greater(mincomp_asaboundedantigradnorm(state, _state),state->epsg) )
     {
-        v = ae_v_dotproduct(&state->ci.ptr.pp_double[i][0], 1, &state->xcur.ptr.p_double[0], 1, ae_v_len(0,n-1));
-        v = v-state->ci.ptr.pp_double[i][n];
-        barrierfunc(v, state->mu, &state->v0, &state->v1, &state->v2, _state);
-        v = state->lm.ptr.p_double[m];
-        vv = ae_minreal(minbleic_maxlmgrowth, -state->mu*state->v1, _state);
-        state->lm.ptr.p_double[m] = vv*state->lm.ptr.p_double[m];
-        state->lmnorm = ae_maxreal(state->lmnorm, ae_fabs(v, _state), _state);
-        state->lmdif = ae_maxreal(state->lmdif, ae_fabs(state->lm.ptr.p_double[m]-v, _state), _state);
-        state->lmgrowth = ae_maxreal(state->lmgrowth, vv, _state);
-        m = m+1;
+        goto lbl_55;
     }
-    if( ae_fp_greater(state->mba,-0.2*state->mudecay*state->mu) )
+    
+    /*
+     * Gradient is small enough
+     */
+    state->repterminationtype = 4;
+    if( !state->xrep )
     {
-        state->mu = ae_maxreal(state->mudecay*state->mu, 1.0E6*ae_machineepsilon*state->bndmax, _state);
+        goto lbl_57;
     }
-    if( ae_fp_less(state->mu,state->outerepsi) )
+    mincomp_clearrequestfields(state, _state);
+    state->xupdated = ae_true;
+    state->rstate.stage = 11;
+    goto lbl_rcomm;
+lbl_11:
+    state->xupdated = ae_false;
+lbl_57:
+    result = ae_false;
+    return result;
+lbl_55:
+    if( !(state->repiterationscount>=state->maxits&&state->maxits>0) )
     {
-        state->mucounter = state->mucounter-1;
-        state->mu = state->outerepsi;
+        goto lbl_59;
     }
     
     /*
-     * 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
+     * Too many iterations
      */
-    v = 0;
-    for(i=0; i<=n-1; i++)
-    {
-        v = v+ae_sqr(state->xcur.ptr.p_double[i]-state->xprev.ptr.p_double[i], _state);
-    }
-    v = ae_sqrt(v, _state);
-    if( ae_fp_less_eq(state->errfeas,state->outerepsi)&&ae_fp_less_eq(v,state->outerepsx) )
+    state->repterminationtype = 5;
+    if( !state->xrep )
     {
-        state->repterminationtype = 4;
-        goto lbl_6;
+        goto lbl_61;
     }
-    if( state->maxits>0 )
+    mincomp_clearrequestfields(state, _state);
+    state->xupdated = ae_true;
+    state->rstate.stage = 12;
+    goto lbl_rcomm;
+lbl_12:
+    state->xupdated = ae_false;
+lbl_61:
+    result = ae_false;
+    return result;
+lbl_59:
+    if( !(ae_fp_greater_eq(mincomp_asaginorm(state, _state),state->mu*mincomp_asad1norm(state, _state))&&diffcnt==0) )
     {
-        state->itsleft = state->itsleft-state->cgrep.iterationscount;
-        if( state->itsleft<=0 )
-        {
-            state->repterminationtype = 5;
-            goto lbl_6;
-        }
+        goto lbl_63;
     }
-    if( ae_fp_greater_eq(state->repouteriterationscount,minbleic_maxouterits) )
+    
+    /*
+     * 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( ae_fp_greater(state->fold-state->f,state->epsf*ae_maxreal(ae_fabs(state->fold, _state), ae_maxreal(ae_fabs(state->f, _state), 1.0, _state), _state)) )
     {
-        state->repterminationtype = 5;
-        goto lbl_6;
+        goto lbl_65;
     }
-    if( ae_fp_less(state->lmdif,minbleic_lmtol*ae_machineepsilon*state->lmnorm)||ae_fp_less(state->lmnorm,minbleic_minlagrangemul) )
+    
+    /*
+     * F(k+1)-F(k) is small enough
+     */
+    state->repterminationtype = 1;
+    if( !state->xrep )
     {
-        state->repterminationtype = 7;
-        goto lbl_6;
+        goto lbl_67;
     }
-    if( state->mucounter<=0 )
+    mincomp_clearrequestfields(state, _state);
+    state->xupdated = ae_true;
+    state->rstate.stage = 13;
+    goto lbl_rcomm;
+lbl_13:
+    state->xupdated = ae_false;
+lbl_67:
+    result = ae_false;
+    return result;
+lbl_65:
+    if( ae_fp_greater(state->laststep,state->epsx) )
     {
-        state->repterminationtype = 7;
-        goto lbl_6;
+        goto lbl_69;
     }
-    if( ae_fp_greater(state->lmnorm,minbleic_maxlagrangemul) )
+    
+    /*
+     * X(k+1)-X(k) is small enough
+     */
+    state->repterminationtype = 2;
+    if( !state->xrep )
     {
-        state->repterminationtype = -3;
-        goto lbl_6;
+        goto lbl_71;
     }
+    mincomp_clearrequestfields(state, _state);
+    state->xupdated = ae_true;
+    state->rstate.stage = 14;
+    goto lbl_rcomm;
+lbl_14:
+    state->xupdated = ae_false;
+lbl_71:
+    result = ae_false;
+    return result;
+lbl_69:
+lbl_63:
     
     /*
-     * Next iteration
+     * Check conditions for switching
      */
-    ae_v_move(&state->xprev.ptr.p_double[0], 1, &state->xcur.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    goto lbl_5;
-lbl_6:
+    if( ae_fp_less(mincomp_asaginorm(state, _state),state->mu*mincomp_asad1norm(state, _state)) )
+    {
+        state->curalgo = 0;
+        goto lbl_50;
+    }
+    if( diffcnt>0 )
+    {
+        if( mincomp_asauisempty(state, _state)||diffcnt>=mincomp_n2 )
+        {
+            state->curalgo = 1;
+        }
+        else
+        {
+            state->curalgo = 0;
+        }
+        goto lbl_50;
+    }
     
     /*
-     * We've stopped, fill debug information
+     * 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)
      */
-    state->repdebugeqerr = 0.0;
-    for(i=0; i<=state->cecnt-1; i++)
+    if( mcinfo==1 )
     {
-        v = ae_v_dotproduct(&state->ce.ptr.pp_double[i][0], 1, &state->xe.ptr.p_double[0], 1, ae_v_len(0,n-1));
-        state->repdebugeqerr = state->repdebugeqerr+ae_sqr(v-state->ce.ptr.pp_double[i][n], _state);
+        
+        /*
+         * Standard Wolfe conditions are satisfied:
+         * * calculate Y[K] and BetaK
+         */
+        ae_v_add(&state->yk.ptr.p_double[0], 1, &state->gc.ptr.p_double[0], 1, ae_v_len(0,n-1));
+        vv = ae_v_dotproduct(&state->yk.ptr.p_double[0], 1, &state->dk.ptr.p_double[0], 1, ae_v_len(0,n-1));
+        v = ae_v_dotproduct(&state->gc.ptr.p_double[0], 1, &state->gc.ptr.p_double[0], 1, ae_v_len(0,n-1));
+        state->betady = v/vv;
+        v = ae_v_dotproduct(&state->gc.ptr.p_double[0], 1, &state->yk.ptr.p_double[0], 1, ae_v_len(0,n-1));
+        state->betahs = v/vv;
+        if( state->cgtype==0 )
+        {
+            betak = state->betady;
+        }
+        if( state->cgtype==1 )
+        {
+            betak = ae_maxreal(0, ae_minreal(state->betady, state->betahs, _state), _state);
+        }
     }
-    state->repdebugeqerr = ae_sqrt(state->repdebugeqerr, _state);
-    state->repdebugdx = 0;
-    for(i=0; i<=n-1; i++)
+    else
     {
-        state->repdebugdx = state->repdebugdx+ae_sqr(state->xcur.ptr.p_double[i]-state->xstart.ptr.p_double[i], _state);
+        
+        /*
+         * 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->debugrestartscount = state->debugrestartscount+1;
     }
-    state->repdebugdx = ae_sqrt(state->repdebugdx, _state);
+    ae_v_moveneg(&state->dn.ptr.p_double[0], 1, &state->gc.ptr.p_double[0], 1, ae_v_len(0,n-1));
+    ae_v_addd(&state->dn.ptr.p_double[0], 1, &state->dk.ptr.p_double[0], 1, ae_v_len(0,n-1), betak);
+    ae_v_move(&state->dk.ptr.p_double[0], 1, &state->dn.ptr.p_double[0], 1, ae_v_len(0,n-1));
+    
+    /*
+     * update other information
+     */
+    state->fold = state->f;
+    state->k = state->k+1;
+    goto lbl_49;
+lbl_50:
+lbl_47:
+    goto lbl_17;
+lbl_18:
     result = ae_false;
     return result;
     
@@ -11050,774 +15836,397 @@ lbl_6:
 lbl_rcomm:
     result = ae_true;
     state->rstate.ia.ptr.p_int[0] = n;
-    state->rstate.ia.ptr.p_int[1] = m;
-    state->rstate.ia.ptr.p_int[2] = i;
+    state->rstate.ia.ptr.p_int[1] = i;
+    state->rstate.ia.ptr.p_int[2] = mcinfo;
+    state->rstate.ia.ptr.p_int[3] = diffcnt;
     state->rstate.ba.ptr.p_bool[0] = b;
-    state->rstate.ra.ptr.p_double[0] = v;
-    state->rstate.ra.ptr.p_double[1] = vv;
+    state->rstate.ba.ptr.p_bool[1] = stepfound;
+    state->rstate.ra.ptr.p_double[0] = betak;
+    state->rstate.ra.ptr.p_double[1] = v;
+    state->rstate.ra.ptr.p_double[2] = vv;
     return result;
 }
 
 
 /*************************************************************************
-BLEIC results
-
-INPUT PARAMETERS:
-    State   -   algorithm state
-
-OUTPUT PARAMETERS:
-    X       -   array[0..N-1], solution
-    Rep     -   optimization report:
-                * Rep.TerminationType completetion code:
-                    * -3    inconsistent constraints. Feasible point is
-                            either nonexistent or too hard to find. Try to
-                            restart optimizer with better initial
-                            approximation
-                    * -2    rounding errors prevent further improvement.
-                            X contains best point found.
-                    *  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.
-                * Rep.IterationsCount contains iterations count
-                * NFEV countains number of function calculations
+Obsolete optimization algorithm.
+Was replaced by MinBLEIC subpackage.
 
   -- ALGLIB --
-     Copyright 28.11.2010 by Bochkanov Sergey
+     Copyright 20.03.2009 by Bochkanov Sergey
 *************************************************************************/
-void minbleicresults(minbleicstate* state,
+void minasaresults(minasastate* state,
      /* Real    */ ae_vector* x,
-     minbleicreport* rep,
+     minasareport* rep,
      ae_state *_state)
 {
 
     ae_vector_clear(x);
-    _minbleicreport_clear(rep);
-
-    minbleicresultsbuf(state, x, rep, _state);
-}
-
-
-/*************************************************************************
-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.
-
-  -- ALGLIB --
-     Copyright 28.11.2010 by Bochkanov Sergey
-*************************************************************************/
-void minbleicresultsbuf(minbleicstate* state,
-     /* Real    */ ae_vector* x,
-     minbleicreport* rep,
-     ae_state *_state)
-{
-
-
-    if( x->cnt<state->n )
-    {
-        ae_vector_set_length(x, state->n, _state);
-    }
-    ae_v_move(&x->ptr.p_double[0], 1, &state->xcur.ptr.p_double[0], 1, ae_v_len(0,state->n-1));
-    rep->inneriterationscount = state->repinneriterationscount;
-    rep->outeriterationscount = state->repouteriterationscount;
-    rep->nfev = state->repnfev;
-    rep->terminationtype = state->repterminationtype;
-    rep->debugeqerr = state->repdebugeqerr;
-    rep->debugfs = state->repdebugfs;
-    rep->debugff = state->repdebugff;
-    rep->debugdx = state->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.
-
-  -- ALGLIB --
-     Copyright 28.11.2010 by Bochkanov Sergey
-*************************************************************************/
-void minbleicrestartfrom(minbleicstate* state,
-     /* Real    */ ae_vector* x,
-     ae_state *_state)
-{
-    ae_int_t n;
-
-
-    n = state->n;
-    
-    /*
-     * First, check for errors in the inputs
-     */
-    ae_assert(x->cnt>=n, "MinBLEICRestartFrom: Length(X)<N", _state);
-    ae_assert(isfinitevector(x, n, _state), "MinBLEICRestartFrom: X contains infinite or NaN values!", _state);
-    
-    /*
-     * Set XC
-     */
-    ae_v_move(&state->xcur.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,n-1));
-    
-    /*
-     * prepare RComm facilities
-     */
-    ae_vector_set_length(&state->rstate.ia, 2+1, _state);
-    ae_vector_set_length(&state->rstate.ba, 0+1, _state);
-    ae_vector_set_length(&state->rstate.ra, 1+1, _state);
-    state->rstate.stage = -1;
-    minbleic_clearrequestfields(state, _state);
-}
-
-
-/*************************************************************************
-Modified barrier function calculated at point X with respect to the
-barrier parameter Mu.
-
-Functions, its first and second derivatives are calculated.
-*************************************************************************/
-void barrierfunc(double x,
-     double mu,
-     double* f,
-     double* df,
-     double* d2f,
-     ae_state *_state)
-{
-    double c0;
-    double c1;
-    double c2;
-    double xpmu;
-
-    *f = 0;
-    *df = 0;
-    *d2f = 0;
-
-    xpmu = x+mu;
-    if( ae_fp_greater(xpmu,0.5*mu) )
-    {
-        *f = -ae_log(x/mu+1, _state);
-        *df = -1/(x+mu);
-        *d2f = 1/(xpmu*xpmu);
-        return;
-    }
-    if( ae_fp_greater(xpmu,0) )
-    {
-        c0 = -ae_log(0.5, _state)-0.5;
-        c1 = -1/mu;
-        c2 = mu/4;
-        *f = c0+c1*(x+0.5*mu)+c2/xpmu;
-        *df = c1-c2/((x+mu)*(x+mu));
-        *d2f = 2*c2/((x+mu)*(x+mu)*(x+mu));
-        return;
-    }
-    *f = ae_maxrealnumber;
-    *df = 0;
-    *d2f = 0;
-}
-
-
-/*************************************************************************
-Clears request fileds (to be sure that we don't forget to clear something)
-*************************************************************************/
-static void minbleic_clearrequestfields(minbleicstate* state,
-     ae_state *_state)
-{
-
-
-    state->needfg = ae_false;
-    state->xupdated = ae_false;
-}
-
-
-/*************************************************************************
-This function makes projection of X into equality constrained subspace.
-It calculates set of additional values which are used later for
-modification of the target function F.
+    _minasareport_clear(rep);
 
-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
+    minasaresultsbuf(state, x, rep, _state);
+}
 
-OUTPUT PARAMETERS:
-    X       -   projection of input X
-    R       -   residual
-    RNorm   -   residual norm squared, used later to modify target function
+
+/*************************************************************************
+Obsolete optimization algorithm.
+Was replaced by MinBLEIC subpackage.
+
+  -- ALGLIB --
+     Copyright 20.03.2009 by Bochkanov Sergey
 *************************************************************************/
-static void minbleic_makeprojection(minbleicstate* state,
+void minasaresultsbuf(minasastate* state,
      /* Real    */ ae_vector* x,
-     /* Real    */ ae_vector* r,
-     double* rnorm2,
+     minasareport* rep,
      ae_state *_state)
 {
-    double v;
     ae_int_t i;
-    ae_int_t n;
 
-    *rnorm2 = 0;
 
-    n = state->n;
-    
-    /*
-     * * subtract XE from X
-     * * project X
-     * * calculate norm of deviation from null space, store it in VV
-     * * calculate residual from projection, store it in R
-     * * add XE to X
-     */
-    ae_v_sub(&x->ptr.p_double[0], 1, &state->xe.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    *rnorm2 = 0;
-    for(i=0; i<=n-1; i++)
+    if( x->cnt<state->n )
     {
-        r->ptr.p_double[i] = 0;
+        ae_vector_set_length(x, state->n, _state);
     }
-    for(i=0; i<=state->cedim-1; i++)
+    ae_v_move(&x->ptr.p_double[0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,state->n-1));
+    rep->iterationscount = state->repiterationscount;
+    rep->nfev = state->repnfev;
+    rep->terminationtype = state->repterminationtype;
+    rep->activeconstraints = 0;
+    for(i=0; i<=state->n-1; i++)
     {
-        v = ae_v_dotproduct(&x->ptr.p_double[0], 1, &state->cebasis.ptr.pp_double[i][0], 1, ae_v_len(0,n-1));
-        ae_v_subd(&x->ptr.p_double[0], 1, &state->cebasis.ptr.pp_double[i][0], 1, ae_v_len(0,n-1), v);
-        ae_v_addd(&r->ptr.p_double[0], 1, &state->cebasis.ptr.pp_double[i][0], 1, ae_v_len(0,n-1), v);
-        *rnorm2 = *rnorm2+ae_sqr(v, _state);
+        if( ae_fp_eq(state->ak.ptr.p_double[i],0) )
+        {
+            rep->activeconstraints = rep->activeconstraints+1;
+        }
     }
-    ae_v_add(&x->ptr.p_double[0], 1, &state->xe.ptr.p_double[0], 1, ae_v_len(0,n-1));
 }
 
 
 /*************************************************************************
-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.
+Obsolete optimization algorithm.
+Was replaced by MinBLEIC subpackage.
 
-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)
+  -- ALGLIB --
+     Copyright 30.07.2010 by Bochkanov Sergey
+*************************************************************************/
+void minasarestartfrom(minasastate* state,
+     /* Real    */ ae_vector* x,
+     /* Real    */ ae_vector* bndl,
+     /* Real    */ ae_vector* bndu,
+     ae_state *_state)
+{
 
-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
+    ae_assert(x->cnt>=state->n, "MinASARestartFrom: Length(X)<N!", _state);
+    ae_assert(isfinitevector(x, state->n, _state), "MinASARestartFrom: X contains infinite or NaN values!", _state);
+    ae_assert(bndl->cnt>=state->n, "MinASARestartFrom: Length(BndL)<N!", _state);
+    ae_assert(isfinitevector(bndl, state->n, _state), "MinASARestartFrom: BndL contains infinite or NaN values!", _state);
+    ae_assert(bndu->cnt>=state->n, "MinASARestartFrom: Length(BndU)<N!", _state);
+    ae_assert(isfinitevector(bndu, state->n, _state), "MinASARestartFrom: BndU contains infinite or NaN values!", _state);
+    ae_v_move(&state->x.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,state->n-1));
+    ae_v_move(&state->bndl.ptr.p_double[0], 1, &bndl->ptr.p_double[0], 1, ae_v_len(0,state->n-1));
+    ae_v_move(&state->bndu.ptr.p_double[0], 1, &bndu->ptr.p_double[0], 1, ae_v_len(0,state->n-1));
+    state->laststep = 0;
+    ae_vector_set_length(&state->rstate.ia, 3+1, _state);
+    ae_vector_set_length(&state->rstate.ba, 1+1, _state);
+    ae_vector_set_length(&state->rstate.ra, 2+1, _state);
+    state->rstate.stage = -1;
+    mincomp_clearrequestfields(state, _state);
+}
 
-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
+
+/*************************************************************************
+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.
+
+  -- ALGLIB --
+     Copyright 20.03.2009 by Bochkanov Sergey
 *************************************************************************/
-static void minbleic_modifytargetfunction(minbleicstate* state,
-     /* Real    */ ae_vector* x,
-     /* Real    */ ae_vector* r,
-     double rnorm2,
-     double* f,
-     /* Real    */ ae_vector* g,
-     double* gnorm,
-     double* mpgnorm,
-     double* mba,
-     double* fierr,
-     double* cserr,
+static double mincomp_asaboundedantigradnorm(minasastate* state,
      ae_state *_state)
 {
-    double v;
-    double vv;
-    double t;
     ae_int_t i;
-    ae_int_t n;
-    ae_int_t m;
-    double v0;
-    double v1;
-    double v2;
-    ae_bool hasconstraints;
+    double v;
+    double result;
 
-    *gnorm = 0;
-    *mpgnorm = 0;
-    *mba = 0;
-    *fierr = 0;
-    *cserr = 0;
 
-    n = state->n;
-    *mba = ae_maxrealnumber;
-    hasconstraints = ae_false;
-    
-    /*
-     * GNorm
-     */
-    v = ae_v_dotproduct(&g->ptr.p_double[0], 1, &g->ptr.p_double[0], 1, ae_v_len(0,n-1));
-    *gnorm = ae_sqrt(v, _state);
-    
-    /*
-     * Process bound and inequality constraints.
-     * Bound constraints with +-INF are ignored.
-     * Here M is used to store number of constraints processed.
-     */
-    m = 0;
-    *fierr = 0;
-    *cserr = 0;
-    for(i=0; i<=n-1; i++)
+    result = 0;
+    for(i=0; i<=state->n-1; i++)
     {
-        if( state->hasbndl.ptr.p_bool[i] )
-        {
-            v = x->ptr.p_double[i]-state->bndl.ptr.p_double[i];
-            *mba = ae_minreal(v, *mba, _state);
-            barrierfunc(v, state->mu, &v0, &v1, &v2, _state);
-            *f = *f+state->mu*state->lm.ptr.p_double[m]*v0;
-            g->ptr.p_double[i] = g->ptr.p_double[i]+state->mu*state->lm.ptr.p_double[m]*v1;
-            if( ae_fp_less(v,0) )
-            {
-                *fierr = *fierr+v*v;
-            }
-            t = -state->lm.ptr.p_double[m]*v;
-            *cserr = *cserr+t*t;
-            m = m+1;
-            hasconstraints = ae_true;
-        }
-        if( state->hasbndu.ptr.p_bool[i] )
+        v = -state->g.ptr.p_double[i];
+        if( ae_fp_eq(state->x.ptr.p_double[i],state->bndl.ptr.p_double[i])&&ae_fp_less(-state->g.ptr.p_double[i],0) )
         {
-            v = state->bndu.ptr.p_double[i]-x->ptr.p_double[i];
-            *mba = ae_minreal(v, *mba, _state);
-            barrierfunc(v, state->mu, &v0, &v1, &v2, _state);
-            *f = *f+state->mu*state->lm.ptr.p_double[m]*v0;
-            g->ptr.p_double[i] = g->ptr.p_double[i]-state->mu*state->lm.ptr.p_double[m]*v1;
-            if( ae_fp_less(v,0) )
-            {
-                *fierr = *fierr+v*v;
-            }
-            t = -state->lm.ptr.p_double[m]*v;
-            *cserr = *cserr+t*t;
-            m = m+1;
-            hasconstraints = ae_true;
+            v = 0;
         }
-    }
-    for(i=0; i<=state->cicnt-1; i++)
-    {
-        v = ae_v_dotproduct(&state->ci.ptr.pp_double[i][0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,n-1));
-        v = v-state->ci.ptr.pp_double[i][n];
-        *mba = ae_minreal(v, *mba, _state);
-        barrierfunc(v, state->mu, &v0, &v1, &v2, _state);
-        *f = *f+state->mu*state->lm.ptr.p_double[m]*v0;
-        vv = state->mu*state->lm.ptr.p_double[m]*v1;
-        ae_v_addd(&g->ptr.p_double[0], 1, &state->ci.ptr.pp_double[i][0], 1, ae_v_len(0,n-1), vv);
-        if( ae_fp_less(v,0) )
+        if( ae_fp_eq(state->x.ptr.p_double[i],state->bndu.ptr.p_double[i])&&ae_fp_greater(-state->g.ptr.p_double[i],0) )
         {
-            *fierr = *fierr+v*v;
+            v = 0;
         }
-        t = -state->lm.ptr.p_double[m]*v;
-        *cserr = *cserr+t*t;
-        m = m+1;
-        hasconstraints = ae_true;
-    }
-    *fierr = ae_sqrt(*fierr, _state);
-    *cserr = ae_sqrt(*cserr, _state);
-    if( !hasconstraints )
-    {
-        *mba = 0.0;
-    }
-    
-    /*
-     * 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<=state->cedim-1; i++)
-    {
-        v = ae_v_dotproduct(&g->ptr.p_double[0], 1, &state->cebasis.ptr.pp_double[i][0], 1, ae_v_len(0,n-1));
-        ae_v_subd(&g->ptr.p_double[0], 1, &state->cebasis.ptr.pp_double[i][0], 1, ae_v_len(0,n-1), v);
+        result = result+ae_sqr(v, _state);
     }
-    ae_v_addd(&g->ptr.p_double[0], 1, &r->ptr.p_double[0], 1, ae_v_len(0,n-1), 2);
-    
-    /*
-     * MPGNorm
-     */
-    v = ae_v_dotproduct(&g->ptr.p_double[0], 1, &g->ptr.p_double[0], 1, ae_v_len(0,n-1));
-    *mpgnorm = ae_sqrt(v, _state);
+    result = ae_sqrt(result, _state);
+    return result;
 }
 
 
 /*************************************************************************
-This subroutine calculates penalty for violation of equality/inequality
-constraints. It is used to find feasible point.
-
-Following modifications are applied:
-* quadratic penalty for deviations from inequality constrained subspace
-  (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)
+Returns norm of GI(x).
 
-INPUT PARAMETERS:
-    State   -   optimizer state (we use its fields to get information
-                about constraints)
-    X       -   point (modified by function)
-    G       -   preallocated array[N]
-    R       -   preallocated array[N]
+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.
 
-OUTPUT PARAMETERS:
-    X       -   projection of X into equality constrained subspace
-    F       -   modified function value at X
-    G       -   modified function gradient at X
-    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
+  -- ALGLIB --
+     Copyright 20.03.2009 by Bochkanov Sergey
 *************************************************************************/
-static void minbleic_penaltyfunction(minbleicstate* state,
-     /* Real    */ ae_vector* x,
-     double* f,
-     /* Real    */ ae_vector* g,
-     /* Real    */ ae_vector* r,
-     double* mba,
-     double* fierr,
-     ae_state *_state)
+static double mincomp_asaginorm(minasastate* state, ae_state *_state)
 {
-    double v;
-    double vv;
     ae_int_t i;
-    ae_int_t m;
-    ae_int_t n;
-    double rnorm2;
-    ae_bool hasconstraints;
+    double result;
 
-    *mba = 0;
-    *fierr = 0;
 
-    n = state->n;
-    *mba = ae_maxrealnumber;
-    hasconstraints = ae_false;
-    
-    /*
-     * Initialize F/G
-     */
-    *f = 0.0;
-    for(i=0; i<=n-1; i++)
-    {
-        g->ptr.p_double[i] = 0.0;
-    }
-    
-    /*
-     * Calculate projection of X:
-     * * subtract XE from X
-     * * project X
-     * * calculate norm of deviation from null space, store it in VV
-     * * calculate residual from projection, store it in R
-     * * add XE to X
-     */
-    ae_v_sub(&x->ptr.p_double[0], 1, &state->xe.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    rnorm2 = 0;
-    for(i=0; i<=n-1; i++)
-    {
-        r->ptr.p_double[i] = 0;
-    }
-    for(i=0; i<=state->cedim-1; i++)
-    {
-        v = ae_v_dotproduct(&x->ptr.p_double[0], 1, &state->cebasis.ptr.pp_double[i][0], 1, ae_v_len(0,n-1));
-        ae_v_subd(&x->ptr.p_double[0], 1, &state->cebasis.ptr.pp_double[i][0], 1, ae_v_len(0,n-1), v);
-        ae_v_addd(&r->ptr.p_double[0], 1, &state->cebasis.ptr.pp_double[i][0], 1, ae_v_len(0,n-1), v);
-        rnorm2 = rnorm2+ae_sqr(v, _state);
-    }
-    ae_v_add(&x->ptr.p_double[0], 1, &state->xe.ptr.p_double[0], 1, ae_v_len(0,n-1));
-    
-    /*
-     * Process bound and inequality constraints.
-     * Bound constraints with +-INF are ignored.
-     * Here M is used to store number of constraints processed.
-     */
-    m = 0;
-    *fierr = 0;
-    for(i=0; i<=n-1; i++)
-    {
-        if( state->hasbndl.ptr.p_bool[i] )
-        {
-            v = x->ptr.p_double[i]-state->bndl.ptr.p_double[i];
-            *mba = ae_minreal(v, *mba, _state);
-            if( ae_fp_less(v,0) )
-            {
-                *f = *f+v*v;
-                g->ptr.p_double[i] = g->ptr.p_double[i]+2*v;
-                *fierr = *fierr+v*v;
-            }
-            m = m+1;
-            hasconstraints = ae_true;
-        }
-        if( state->hasbndu.ptr.p_bool[i] )
-        {
-            v = state->bndu.ptr.p_double[i]-x->ptr.p_double[i];
-            *mba = ae_minreal(v, *mba, _state);
-            if( ae_fp_less(v,0) )
-            {
-                *f = *f+v*v;
-                g->ptr.p_double[i] = g->ptr.p_double[i]-2*v;
-                *fierr = *fierr+v*v;
-            }
-            m = m+1;
-            hasconstraints = ae_true;
-        }
-    }
-    for(i=0; i<=state->cicnt-1; i++)
+    result = 0;
+    for(i=0; i<=state->n-1; i++)
     {
-        v = ae_v_dotproduct(&state->ci.ptr.pp_double[i][0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,n-1));
-        v = v-state->ci.ptr.pp_double[i][n];
-        *mba = ae_minreal(v, *mba, _state);
-        if( ae_fp_less(v,0) )
+        if( ae_fp_neq(state->x.ptr.p_double[i],state->bndl.ptr.p_double[i])&&ae_fp_neq(state->x.ptr.p_double[i],state->bndu.ptr.p_double[i]) )
         {
-            *f = *f+v*v;
-            vv = 2*v;
-            ae_v_addd(&g->ptr.p_double[0], 1, &state->ci.ptr.pp_double[i][0], 1, ae_v_len(0,n-1), vv);
-            *fierr = *fierr+v*v;
+            result = result+ae_sqr(state->g.ptr.p_double[i], _state);
         }
-        m = m+1;
-        hasconstraints = ae_true;
     }
-    *fierr = ae_sqrt(*fierr, _state);
-    if( !hasconstraints )
+    result = ae_sqrt(result, _state);
+    return 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.
+
+  -- ALGLIB --
+     Copyright 20.03.2009 by Bochkanov Sergey
+*************************************************************************/
+static double mincomp_asad1norm(minasastate* state, ae_state *_state)
+{
+    ae_int_t i;
+    double result;
+
+
+    result = 0;
+    for(i=0; i<=state->n-1; i++)
     {
-        *mba = 0.0;
+        result = result+ae_sqr(boundval(state->x.ptr.p_double[i]-state->g.ptr.p_double[i], state->bndl.ptr.p_double[i], state->bndu.ptr.p_double[i], _state)-state->x.ptr.p_double[i], _state);
     }
-    
-    /*
-     * 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<=state->cedim-1; i++)
+    result = ae_sqrt(result, _state);
+    return 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.
+
+  -- ALGLIB --
+     Copyright 20.03.2009 by Bochkanov Sergey
+*************************************************************************/
+static ae_bool mincomp_asauisempty(minasastate* state, ae_state *_state)
+{
+    ae_int_t i;
+    double d;
+    double d2;
+    double d32;
+    ae_bool result;
+
+
+    d = mincomp_asad1norm(state, _state);
+    d2 = ae_sqrt(d, _state);
+    d32 = d*d2;
+    result = ae_true;
+    for(i=0; i<=state->n-1; i++)
     {
-        v = ae_v_dotproduct(&g->ptr.p_double[0], 1, &state->cebasis.ptr.pp_double[i][0], 1, ae_v_len(0,n-1));
-        ae_v_subd(&g->ptr.p_double[0], 1, &state->cebasis.ptr.pp_double[i][0], 1, ae_v_len(0,n-1), v);
+        if( ae_fp_greater_eq(ae_fabs(state->g.ptr.p_double[i], _state),d2)&&ae_fp_greater_eq(ae_minreal(state->x.ptr.p_double[i]-state->bndl.ptr.p_double[i], state->bndu.ptr.p_double[i]-state->x.ptr.p_double[i], _state),d32) )
+        {
+            result = ae_false;
+            return result;
+        }
     }
-    ae_v_addd(&g->ptr.p_double[0], 1, &r->ptr.p_double[0], 1, ae_v_len(0,n-1), 2);
+    return result;
 }
 
 
-ae_bool _minbleicstate_init(minbleicstate* p, ae_state *_state, ae_bool make_automatic)
+/*************************************************************************
+Clears request fileds (to be sure that we don't forgot to clear something)
+*************************************************************************/
+static void mincomp_clearrequestfields(minasastate* state,
+     ae_state *_state)
 {
-    if( !ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic) )
-        return ae_false;
-    if( !ae_vector_init(&p->g, 0, DT_REAL, _state, make_automatic) )
-        return ae_false;
-    if( !_rcommstate_init(&p->rstate, _state, make_automatic) )
-        return ae_false;
-    if( !ae_vector_init(&p->xcur, 0, DT_REAL, _state, make_automatic) )
-        return ae_false;
-    if( !ae_vector_init(&p->xprev, 0, DT_REAL, _state, make_automatic) )
-        return ae_false;
-    if( !ae_vector_init(&p->xstart, 0, DT_REAL, _state, make_automatic) )
+
+
+    state->needfg = ae_false;
+    state->xupdated = ae_false;
+}
+
+
+ae_bool _minasastate_init(minasastate* p, ae_state *_state, ae_bool make_automatic)
+{
+    if( !ae_vector_init(&p->bndl, 0, DT_REAL, _state, make_automatic) )
         return ae_false;
-    if( !ae_matrix_init(&p->ce, 0, 0, DT_REAL, _state, make_automatic) )
+    if( !ae_vector_init(&p->bndu, 0, DT_REAL, _state, make_automatic) )
         return ae_false;
-    if( !ae_matrix_init(&p->ci, 0, 0, DT_REAL, _state, make_automatic) )
+    if( !ae_vector_init(&p->ak, 0, DT_REAL, _state, make_automatic) )
         return ae_false;
-    if( !ae_matrix_init(&p->cebasis, 0, 0, DT_REAL, _state, make_automatic) )
+    if( !ae_vector_init(&p->xk, 0, DT_REAL, _state, make_automatic) )
         return ae_false;
-    if( !ae_matrix_init(&p->cesvl, 0, 0, DT_REAL, _state, make_automatic) )
+    if( !ae_vector_init(&p->dk, 0, DT_REAL, _state, make_automatic) )
         return ae_false;
-    if( !ae_vector_init(&p->xe, 0, DT_REAL, _state, make_automatic) )
+    if( !ae_vector_init(&p->an, 0, DT_REAL, _state, make_automatic) )
         return ae_false;
-    if( !ae_vector_init(&p->bndl, 0, DT_REAL, _state, make_automatic) )
+    if( !ae_vector_init(&p->xn, 0, DT_REAL, _state, make_automatic) )
         return ae_false;
-    if( !ae_vector_init(&p->hasbndl, 0, DT_BOOL, _state, make_automatic) )
+    if( !ae_vector_init(&p->dn, 0, DT_REAL, _state, make_automatic) )
         return ae_false;
-    if( !ae_vector_init(&p->bndu, 0, DT_REAL, _state, make_automatic) )
+    if( !ae_vector_init(&p->d, 0, DT_REAL, _state, make_automatic) )
         return ae_false;
-    if( !ae_vector_init(&p->hasbndu, 0, DT_BOOL, _state, make_automatic) )
+    if( !ae_vector_init(&p->work, 0, DT_REAL, _state, make_automatic) )
         return ae_false;
-    if( !ae_vector_init(&p->lm, 0, DT_REAL, _state, make_automatic) )
+    if( !ae_vector_init(&p->yk, 0, DT_REAL, _state, make_automatic) )
         return ae_false;
-    if( !ae_vector_init(&p->w, 0, DT_REAL, _state, make_automatic) )
+    if( !ae_vector_init(&p->gc, 0, DT_REAL, _state, make_automatic) )
         return ae_false;
-    if( !ae_vector_init(&p->tmp0, 0, DT_REAL, _state, make_automatic) )
+    if( !ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic) )
         return ae_false;
-    if( !ae_vector_init(&p->tmp1, 0, DT_REAL, _state, make_automatic) )
+    if( !ae_vector_init(&p->g, 0, DT_REAL, _state, make_automatic) )
         return ae_false;
-    if( !ae_vector_init(&p->r, 0, DT_REAL, _state, make_automatic) )
+    if( !_rcommstate_init(&p->rstate, _state, make_automatic) )
         return ae_false;
     if( !_linminstate_init(&p->lstate, _state, make_automatic) )
         return ae_false;
-    if( !_mincgstate_init(&p->cgstate, _state, make_automatic) )
-        return ae_false;
-    if( !_mincgreport_init(&p->cgrep, _state, make_automatic) )
-        return ae_false;
     return ae_true;
 }
 
 
-ae_bool _minbleicstate_init_copy(minbleicstate* dst, minbleicstate* src, ae_state *_state, ae_bool make_automatic)
+ae_bool _minasastate_init_copy(minasastate* dst, minasastate* src, ae_state *_state, ae_bool make_automatic)
 {
     dst->n = src->n;
-    dst->innerepsg = src->innerepsg;
-    dst->innerepsf = src->innerepsf;
-    dst->innerepsx = src->innerepsx;
-    dst->outerepsx = src->outerepsx;
-    dst->outerepsi = src->outerepsi;
+    dst->epsg = src->epsg;
+    dst->epsf = src->epsf;
+    dst->epsx = src->epsx;
     dst->maxits = src->maxits;
     dst->xrep = src->xrep;
     dst->stpmax = src->stpmax;
     dst->cgtype = src->cgtype;
-    dst->mustart = src->mustart;
-    dst->mudecay = src->mudecay;
-    if( !ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic) )
-        return ae_false;
-    dst->f = src->f;
-    if( !ae_vector_init_copy(&dst->g, &src->g, _state, make_automatic) )
-        return ae_false;
-    dst->needfg = src->needfg;
-    dst->xupdated = src->xupdated;
-    if( !_rcommstate_init_copy(&dst->rstate, &src->rstate, _state, make_automatic) )
-        return ae_false;
-    dst->repinneriterationscount = src->repinneriterationscount;
-    dst->repouteriterationscount = src->repouteriterationscount;
-    dst->repnfev = src->repnfev;
-    dst->repterminationtype = src->repterminationtype;
-    dst->repdebugeqerr = src->repdebugeqerr;
-    dst->repdebugfs = src->repdebugfs;
-    dst->repdebugff = src->repdebugff;
-    dst->repdebugdx = src->repdebugdx;
-    if( !ae_vector_init_copy(&dst->xcur, &src->xcur, _state, make_automatic) )
-        return ae_false;
-    if( !ae_vector_init_copy(&dst->xprev, &src->xprev, _state, make_automatic) )
-        return ae_false;
-    if( !ae_vector_init_copy(&dst->xstart, &src->xstart, _state, make_automatic) )
+    dst->k = src->k;
+    dst->nfev = src->nfev;
+    dst->mcstage = src->mcstage;
+    if( !ae_vector_init_copy(&dst->bndl, &src->bndl, _state, make_automatic) )
         return ae_false;
-    dst->itsleft = src->itsleft;
-    dst->mucounter = src->mucounter;
-    if( !ae_matrix_init_copy(&dst->ce, &src->ce, _state, make_automatic) )
+    if( !ae_vector_init_copy(&dst->bndu, &src->bndu, _state, make_automatic) )
         return ae_false;
-    if( !ae_matrix_init_copy(&dst->ci, &src->ci, _state, make_automatic) )
+    dst->curalgo = src->curalgo;
+    dst->acount = src->acount;
+    dst->mu = src->mu;
+    dst->finit = src->finit;
+    dst->dginit = src->dginit;
+    if( !ae_vector_init_copy(&dst->ak, &src->ak, _state, make_automatic) )
         return ae_false;
-    if( !ae_matrix_init_copy(&dst->cebasis, &src->cebasis, _state, make_automatic) )
+    if( !ae_vector_init_copy(&dst->xk, &src->xk, _state, make_automatic) )
         return ae_false;
-    if( !ae_matrix_init_copy(&dst->cesvl, &src->cesvl, _state, make_automatic) )
+    if( !ae_vector_init_copy(&dst->dk, &src->dk, _state, make_automatic) )
         return ae_false;
-    if( !ae_vector_init_copy(&dst->xe, &src->xe, _state, make_automatic) )
+    if( !ae_vector_init_copy(&dst->an, &src->an, _state, make_automatic) )
         return ae_false;
-    dst->cecnt = src->cecnt;
-    dst->cicnt = src->cicnt;
-    dst->cedim = src->cedim;
-    if( !ae_vector_init_copy(&dst->bndl, &src->bndl, _state, make_automatic) )
+    if( !ae_vector_init_copy(&dst->xn, &src->xn, _state, make_automatic) )
         return ae_false;
-    if( !ae_vector_init_copy(&dst->hasbndl, &src->hasbndl, _state, make_automatic) )
+    if( !ae_vector_init_copy(&dst->dn, &src->dn, _state, make_automatic) )
         return ae_false;
-    if( !ae_vector_init_copy(&dst->bndu, &src->bndu, _state, make_automatic) )
+    if( !ae_vector_init_copy(&dst->d, &src->d, _state, make_automatic) )
         return ae_false;
-    if( !ae_vector_init_copy(&dst->hasbndu, &src->hasbndu, _state, make_automatic) )
+    dst->fold = src->fold;
+    dst->stp = src->stp;
+    if( !ae_vector_init_copy(&dst->work, &src->work, _state, make_automatic) )
         return ae_false;
-    if( !ae_vector_init_copy(&dst->lm, &src->lm, _state, make_automatic) )
+    if( !ae_vector_init_copy(&dst->yk, &src->yk, _state, make_automatic) )
         return ae_false;
-    dst->lmcnt = src->lmcnt;
-    dst->mu = src->mu;
-    if( !ae_vector_init_copy(&dst->w, &src->w, _state, make_automatic) )
+    if( !ae_vector_init_copy(&dst->gc, &src->gc, _state, make_automatic) )
         return ae_false;
-    if( !ae_vector_init_copy(&dst->tmp0, &src->tmp0, _state, make_automatic) )
+    dst->laststep = src->laststep;
+    if( !ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic) )
         return ae_false;
-    if( !ae_vector_init_copy(&dst->tmp1, &src->tmp1, _state, make_automatic) )
+    dst->f = src->f;
+    if( !ae_vector_init_copy(&dst->g, &src->g, _state, make_automatic) )
         return ae_false;
-    if( !ae_vector_init_copy(&dst->r, &src->r, _state, make_automatic) )
+    dst->needfg = src->needfg;
+    dst->xupdated = src->xupdated;
+    if( !_rcommstate_init_copy(&dst->rstate, &src->rstate, _state, make_automatic) )
         return ae_false;
-    dst->v0 = src->v0;
-    dst->v1 = src->v1;
-    dst->v2 = src->v2;
-    dst->t = src->t;
-    dst->errfeas = src->errfeas;
-    dst->errslack = src->errslack;
-    dst->gnorm = src->gnorm;
-    dst->mpgnorm = src->mpgnorm;
-    dst->lmdif = src->lmdif;
-    dst->lmnorm = src->lmnorm;
-    dst->lmgrowth = src->lmgrowth;
-    dst->mba = src->mba;
-    dst->boundary = src->boundary;
-    dst->closetobarrier = src->closetobarrier;
-    dst->bndmax = src->bndmax;
+    dst->repiterationscount = src->repiterationscount;
+    dst->repnfev = src->repnfev;
+    dst->repterminationtype = src->repterminationtype;
+    dst->debugrestartscount = src->debugrestartscount;
     if( !_linminstate_init_copy(&dst->lstate, &src->lstate, _state, make_automatic) )
         return ae_false;
-    if( !_mincgstate_init_copy(&dst->cgstate, &src->cgstate, _state, make_automatic) )
-        return ae_false;
-    if( !_mincgreport_init_copy(&dst->cgrep, &src->cgrep, _state, make_automatic) )
-        return ae_false;
+    dst->betahs = src->betahs;
+    dst->betady = src->betady;
     return ae_true;
 }
 
 
-void _minbleicstate_clear(minbleicstate* p)
+void _minasastate_clear(minasastate* p)
 {
+    ae_vector_clear(&p->bndl);
+    ae_vector_clear(&p->bndu);
+    ae_vector_clear(&p->ak);
+    ae_vector_clear(&p->xk);
+    ae_vector_clear(&p->dk);
+    ae_vector_clear(&p->an);
+    ae_vector_clear(&p->xn);
+    ae_vector_clear(&p->dn);
+    ae_vector_clear(&p->d);
+    ae_vector_clear(&p->work);
+    ae_vector_clear(&p->yk);
+    ae_vector_clear(&p->gc);
     ae_vector_clear(&p->x);
     ae_vector_clear(&p->g);
     _rcommstate_clear(&p->rstate);
-    ae_vector_clear(&p->xcur);
-    ae_vector_clear(&p->xprev);
-    ae_vector_clear(&p->xstart);
-    ae_matrix_clear(&p->ce);
-    ae_matrix_clear(&p->ci);
-    ae_matrix_clear(&p->cebasis);
-    ae_matrix_clear(&p->cesvl);
-    ae_vector_clear(&p->xe);
-    ae_vector_clear(&p->bndl);
-    ae_vector_clear(&p->hasbndl);
-    ae_vector_clear(&p->bndu);
-    ae_vector_clear(&p->hasbndu);
-    ae_vector_clear(&p->lm);
-    ae_vector_clear(&p->w);
-    ae_vector_clear(&p->tmp0);
-    ae_vector_clear(&p->tmp1);
-    ae_vector_clear(&p->r);
     _linminstate_clear(&p->lstate);
-    _mincgstate_clear(&p->cgstate);
-    _mincgreport_clear(&p->cgrep);
 }
 
 
-ae_bool _minbleicreport_init(minbleicreport* p, ae_state *_state, ae_bool make_automatic)
+ae_bool _minasareport_init(minasareport* p, ae_state *_state, ae_bool make_automatic)
 {
     return ae_true;
 }
 
 
-ae_bool _minbleicreport_init_copy(minbleicreport* dst, minbleicreport* src, ae_state *_state, ae_bool make_automatic)
+ae_bool _minasareport_init_copy(minasareport* dst, minasareport* src, ae_state *_state, ae_bool make_automatic)
 {
-    dst->inneriterationscount = src->inneriterationscount;
-    dst->outeriterationscount = src->outeriterationscount;
+    dst->iterationscount = src->iterationscount;
     dst->nfev = src->nfev;
     dst->terminationtype = src->terminationtype;
-    dst->debugeqerr = src->debugeqerr;
-    dst->debugfs = src->debugfs;
-    dst->debugff = src->debugff;
-    dst->debugdx = src->debugdx;
+    dst->activeconstraints = src->activeconstraints;
     return ae_true;
 }
 
 
-void _minbleicreport_clear(minbleicreport* p)
+void _minasareport_clear(minasareport* p)
 {
 }
 
diff --git a/contrib/lbfgs/optimization.h b/contrib/lbfgs/optimization.h
index 86a6c0a0adf848ccf1b6793f4c117ec0af8dbc2d..22be76b82c332c06ed5ff8825a113ef929b328d1 100755
--- a/contrib/lbfgs/optimization.h
+++ b/contrib/lbfgs/optimization.h
@@ -20,8 +20,9 @@ http://www.fsf.org/licensing/licenses
 #define _optimization_pkg_h
 #include "ap.h"
 #include "alglibinternal.h"
-#include "linalg.h"
 #include "alglibmisc.h"
+#include "linalg.h"
+#include "solvers.h"
 
 /////////////////////////////////////////////////////////////////////////
 //
@@ -31,6 +32,169 @@ http://www.fsf.org/licensing/licenses
 namespace alglib_impl
 {
 typedef struct
+{
+    ae_int_t n;
+    double epsg;
+    double epsf;
+    double epsx;
+    ae_int_t maxits;
+    double stpmax;
+    double suggestedstep;
+    ae_bool xrep;
+    ae_bool drep;
+    ae_int_t cgtype;
+    ae_int_t prectype;
+    ae_vector diagh;
+    ae_vector diaghl2;
+    ae_matrix vcorr;
+    ae_int_t vcnt;
+    ae_vector s;
+    double diffstep;
+    ae_int_t nfev;
+    ae_int_t mcstage;
+    ae_int_t k;
+    ae_vector xk;
+    ae_vector dk;
+    ae_vector xn;
+    ae_vector dn;
+    ae_vector d;
+    double fold;
+    double stp;
+    double curstpmax;
+    ae_vector yk;
+    double laststep;
+    double lastscaledstep;
+    ae_int_t mcinfo;
+    ae_bool innerresetneeded;
+    ae_bool terminationneeded;
+    double trimthreshold;
+    ae_int_t rstimer;
+    ae_vector x;
+    double f;
+    ae_vector g;
+    ae_bool needf;
+    ae_bool needfg;
+    ae_bool xupdated;
+    ae_bool algpowerup;
+    ae_bool lsstart;
+    ae_bool lsend;
+    rcommstate rstate;
+    ae_int_t repiterationscount;
+    ae_int_t repnfev;
+    ae_int_t repterminationtype;
+    ae_int_t debugrestartscount;
+    linminstate lstate;
+    double fbase;
+    double fm2;
+    double fm1;
+    double fp1;
+    double fp2;
+    double betahs;
+    double betady;
+    ae_vector work0;
+    ae_vector work1;
+} mincgstate;
+typedef struct
+{
+    ae_int_t iterationscount;
+    ae_int_t nfev;
+    ae_int_t terminationtype;
+} mincgreport;
+typedef struct
+{
+    ae_int_t nmain;
+    ae_int_t nslack;
+    double innerepsg;
+    double innerepsf;
+    double innerepsx;
+    double outerepsx;
+    double outerepsi;
+    ae_int_t maxits;
+    ae_bool xrep;
+    double stpmax;
+    double diffstep;
+    ae_int_t prectype;
+    ae_vector diaghoriginal;
+    ae_vector diagh;
+    ae_vector x;
+    double f;
+    ae_vector g;
+    ae_bool needf;
+    ae_bool needfg;
+    ae_bool xupdated;
+    rcommstate rstate;
+    ae_int_t repinneriterationscount;
+    ae_int_t repouteriterationscount;
+    ae_int_t repnfev;
+    ae_int_t repterminationtype;
+    double repdebugeqerr;
+    double repdebugfs;
+    double repdebugff;
+    double repdebugdx;
+    ae_vector xcur;
+    ae_vector xprev;
+    ae_vector xstart;
+    ae_int_t itsleft;
+    ae_vector xend;
+    ae_vector lastg;
+    double trimthreshold;
+    ae_matrix ceoriginal;
+    ae_matrix ceeffective;
+    ae_matrix cecurrent;
+    ae_vector ct;
+    ae_int_t cecnt;
+    ae_int_t cedim;
+    ae_vector xe;
+    ae_vector hasbndl;
+    ae_vector hasbndu;
+    ae_vector bndloriginal;
+    ae_vector bnduoriginal;
+    ae_vector bndleffective;
+    ae_vector bndueffective;
+    ae_vector activeconstraints;
+    ae_vector constrainedvalues;
+    ae_vector transforms;
+    ae_vector seffective;
+    ae_vector soriginal;
+    ae_vector w;
+    ae_vector tmp0;
+    ae_vector tmp1;
+    ae_vector tmp2;
+    ae_vector r;
+    ae_matrix lmmatrix;
+    double v0;
+    double v1;
+    double v2;
+    double t;
+    double errfeas;
+    double gnorm;
+    double mpgnorm;
+    double mba;
+    ae_int_t variabletofreeze;
+    double valuetofreeze;
+    double fbase;
+    double fm2;
+    double fm1;
+    double fp1;
+    double fp2;
+    double xm1;
+    double xp1;
+    mincgstate cgstate;
+    mincgreport cgrep;
+    ae_int_t optdim;
+} minbleicstate;
+typedef struct
+{
+    ae_int_t inneriterationscount;
+    ae_int_t outeriterationscount;
+    ae_int_t nfev;
+    ae_int_t terminationtype;
+    double debugeqerr;
+    double debugfs;
+    double debugff;
+    double debugdx;
+} minbleicreport;
+typedef struct
 {
     ae_int_t n;
     ae_int_t m;
@@ -38,29 +202,38 @@ typedef struct
     double epsf;
     double epsx;
     ae_int_t maxits;
-    ae_int_t flags;
     ae_bool xrep;
     double stpmax;
+    ae_vector s;
+    double diffstep;
     ae_int_t nfev;
     ae_int_t mcstage;
     ae_int_t k;
     ae_int_t q;
     ae_int_t p;
     ae_vector rho;
-    ae_matrix y;
-    ae_matrix s;
+    ae_matrix yk;
+    ae_matrix sk;
     ae_vector theta;
     ae_vector d;
     double stp;
     ae_vector work;
     double fold;
+    double trimthreshold;
     ae_int_t prectype;
     double gammak;
     ae_matrix denseh;
+    ae_vector diagh;
+    double fbase;
+    double fm2;
+    double fm1;
+    double fp1;
+    double fp2;
     ae_vector autobuf;
     ae_vector x;
     double f;
     ae_vector g;
+    ae_bool needf;
     ae_bool needfg;
     ae_bool xupdated;
     rcommstate rstate;
@@ -76,6 +249,50 @@ typedef struct
     ae_int_t terminationtype;
 } minlbfgsreport;
 typedef struct
+{
+    ae_int_t n;
+    ae_int_t algokind;
+    ae_int_t akind;
+    ae_matrix densea;
+    ae_vector diaga;
+    ae_vector b;
+    ae_vector bndl;
+    ae_vector bndu;
+    ae_vector havebndl;
+    ae_vector havebndu;
+    ae_vector xorigin;
+    ae_vector startx;
+    ae_bool havex;
+    ae_vector xc;
+    ae_vector gc;
+    ae_vector activeconstraints;
+    ae_vector prevactiveconstraints;
+    double constterm;
+    ae_vector workbndl;
+    ae_vector workbndu;
+    ae_int_t repinneriterationscount;
+    ae_int_t repouteriterationscount;
+    ae_int_t repncholesky;
+    ae_int_t repnmv;
+    ae_int_t repterminationtype;
+    ae_vector tmp0;
+    ae_vector tmp1;
+    ae_vector itmp0;
+    ae_vector p2;
+    ae_matrix bufa;
+    ae_vector bufb;
+    ae_vector bufx;
+    apbuffers buf;
+} minqpstate;
+typedef struct
+{
+    ae_int_t inneriterationscount;
+    ae_int_t outeriterationscount;
+    ae_int_t nmv;
+    ae_int_t ncholesky;
+    ae_int_t terminationtype;
+} minqpreport;
+typedef struct
 {
     ae_int_t n;
     ae_int_t m;
@@ -109,9 +326,13 @@ typedef struct
     ae_vector fibase;
     ae_vector gbase;
     ae_matrix quadraticmodel;
+    ae_vector bndl;
+    ae_vector bndu;
+    ae_vector havebndl;
+    ae_vector havebndu;
+    ae_vector s;
     double lambdav;
     double nu;
-    ae_matrix dampedmodel;
     ae_int_t modelage;
     ae_vector xdir;
     ae_vector deltax;
@@ -127,14 +348,17 @@ typedef struct
     ae_int_t repncholesky;
     rcommstate rstate;
     ae_vector choleskybuf;
+    ae_vector tmp0;
     double actualdecrease;
     double predicteddecrease;
-    ae_vector fm2;
+    double xm1;
+    double xp1;
     ae_vector fm1;
-    ae_vector fp2;
     ae_vector fp1;
     minlbfgsstate internalstate;
     minlbfgsreport internalrep;
+    minqpstate qpstate;
+    minqpreport qprep;
 } minlmstate;
 typedef struct
 {
@@ -200,137 +424,6 @@ typedef struct
     ae_int_t terminationtype;
     ae_int_t activeconstraints;
 } minasareport;
-typedef struct
-{
-    ae_int_t n;
-    double epsg;
-    double epsf;
-    double epsx;
-    ae_int_t maxits;
-    double stpmax;
-    double suggestedstep;
-    ae_bool xrep;
-    ae_bool drep;
-    ae_int_t cgtype;
-    ae_int_t nfev;
-    ae_int_t mcstage;
-    ae_int_t k;
-    ae_vector xk;
-    ae_vector dk;
-    ae_vector xn;
-    ae_vector dn;
-    ae_vector d;
-    double fold;
-    double stp;
-    double curstpmax;
-    ae_vector work;
-    ae_vector yk;
-    double laststep;
-    ae_int_t rstimer;
-    ae_vector x;
-    double f;
-    ae_vector g;
-    ae_bool needfg;
-    ae_bool xupdated;
-    ae_bool lsstart;
-    ae_bool lsend;
-    rcommstate rstate;
-    ae_int_t repiterationscount;
-    ae_int_t repnfev;
-    ae_int_t repterminationtype;
-    ae_int_t debugrestartscount;
-    linminstate lstate;
-    double betahs;
-    double betady;
-} mincgstate;
-typedef struct
-{
-    ae_int_t iterationscount;
-    ae_int_t nfev;
-    ae_int_t terminationtype;
-} mincgreport;
-typedef struct
-{
-    ae_int_t n;
-    double innerepsg;
-    double innerepsf;
-    double innerepsx;
-    double outerepsx;
-    double outerepsi;
-    ae_int_t maxits;
-    ae_bool xrep;
-    double stpmax;
-    ae_int_t cgtype;
-    double mustart;
-    double mudecay;
-    ae_vector x;
-    double f;
-    ae_vector g;
-    ae_bool needfg;
-    ae_bool xupdated;
-    rcommstate rstate;
-    ae_int_t repinneriterationscount;
-    ae_int_t repouteriterationscount;
-    ae_int_t repnfev;
-    ae_int_t repterminationtype;
-    double repdebugeqerr;
-    double repdebugfs;
-    double repdebugff;
-    double repdebugdx;
-    ae_vector xcur;
-    ae_vector xprev;
-    ae_vector xstart;
-    ae_int_t itsleft;
-    ae_int_t mucounter;
-    ae_matrix ce;
-    ae_matrix ci;
-    ae_matrix cebasis;
-    ae_matrix cesvl;
-    ae_vector xe;
-    ae_int_t cecnt;
-    ae_int_t cicnt;
-    ae_int_t cedim;
-    ae_vector bndl;
-    ae_vector hasbndl;
-    ae_vector bndu;
-    ae_vector hasbndu;
-    ae_vector lm;
-    ae_int_t lmcnt;
-    double mu;
-    ae_vector w;
-    ae_vector tmp0;
-    ae_vector tmp1;
-    ae_vector r;
-    double v0;
-    double v1;
-    double v2;
-    double t;
-    double errfeas;
-    double errslack;
-    double gnorm;
-    double mpgnorm;
-    double lmdif;
-    double lmnorm;
-    double lmgrowth;
-    double mba;
-    double boundary;
-    ae_bool closetobarrier;
-    double bndmax;
-    linminstate lstate;
-    mincgstate cgstate;
-    mincgreport cgrep;
-} minbleicstate;
-typedef struct
-{
-    ae_int_t inneriterationscount;
-    ae_int_t outeriterationscount;
-    ae_int_t nfev;
-    ae_int_t terminationtype;
-    double debugeqerr;
-    double debugfs;
-    double debugff;
-    double debugdx;
-} minbleicreport;
 
 }
 
@@ -342,6 +435,168 @@ typedef struct
 namespace alglib
 {
 
+/*************************************************************************
+This object stores state of the nonlinear CG optimizer.
+
+You should use ALGLIB functions to work with this object.
+*************************************************************************/
+class _mincgstate_owner
+{
+public:
+    _mincgstate_owner();
+    _mincgstate_owner(const _mincgstate_owner &rhs);
+    _mincgstate_owner& operator=(const _mincgstate_owner &rhs);
+    virtual ~_mincgstate_owner();
+    alglib_impl::mincgstate* c_ptr();
+    alglib_impl::mincgstate* c_ptr() const;
+protected:
+    alglib_impl::mincgstate *p_struct;
+};
+class mincgstate : public _mincgstate_owner
+{
+public:
+    mincgstate();
+    mincgstate(const mincgstate &rhs);
+    mincgstate& operator=(const mincgstate &rhs);
+    virtual ~mincgstate();
+    ae_bool &needf;
+    ae_bool &needfg;
+    ae_bool &xupdated;
+    double &f;
+    real_1d_array g;
+    real_1d_array x;
+
+};
+
+
+/*************************************************************************
+
+*************************************************************************/
+class _mincgreport_owner
+{
+public:
+    _mincgreport_owner();
+    _mincgreport_owner(const _mincgreport_owner &rhs);
+    _mincgreport_owner& operator=(const _mincgreport_owner &rhs);
+    virtual ~_mincgreport_owner();
+    alglib_impl::mincgreport* c_ptr();
+    alglib_impl::mincgreport* c_ptr() const;
+protected:
+    alglib_impl::mincgreport *p_struct;
+};
+class mincgreport : public _mincgreport_owner
+{
+public:
+    mincgreport();
+    mincgreport(const mincgreport &rhs);
+    mincgreport& operator=(const mincgreport &rhs);
+    virtual ~mincgreport();
+    ae_int_t &iterationscount;
+    ae_int_t &nfev;
+    ae_int_t &terminationtype;
+
+};
+
+/*************************************************************************
+This object stores nonlinear optimizer state.
+You should use functions provided by MinBLEIC subpackage to work with this
+object
+*************************************************************************/
+class _minbleicstate_owner
+{
+public:
+    _minbleicstate_owner();
+    _minbleicstate_owner(const _minbleicstate_owner &rhs);
+    _minbleicstate_owner& operator=(const _minbleicstate_owner &rhs);
+    virtual ~_minbleicstate_owner();
+    alglib_impl::minbleicstate* c_ptr();
+    alglib_impl::minbleicstate* c_ptr() const;
+protected:
+    alglib_impl::minbleicstate *p_struct;
+};
+class minbleicstate : public _minbleicstate_owner
+{
+public:
+    minbleicstate();
+    minbleicstate(const minbleicstate &rhs);
+    minbleicstate& operator=(const minbleicstate &rhs);
+    virtual ~minbleicstate();
+    ae_bool &needf;
+    ae_bool &needfg;
+    ae_bool &xupdated;
+    double &f;
+    real_1d_array g;
+    real_1d_array x;
+
+};
+
+
+/*************************************************************************
+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 _minbleicreport_owner
+{
+public:
+    _minbleicreport_owner();
+    _minbleicreport_owner(const _minbleicreport_owner &rhs);
+    _minbleicreport_owner& operator=(const _minbleicreport_owner &rhs);
+    virtual ~_minbleicreport_owner();
+    alglib_impl::minbleicreport* c_ptr();
+    alglib_impl::minbleicreport* c_ptr() const;
+protected:
+    alglib_impl::minbleicreport *p_struct;
+};
+class minbleicreport : public _minbleicreport_owner
+{
+public:
+    minbleicreport();
+    minbleicreport(const minbleicreport &rhs);
+    minbleicreport& operator=(const minbleicreport &rhs);
+    virtual ~minbleicreport();
+    ae_int_t &inneriterationscount;
+    ae_int_t &outeriterationscount;
+    ae_int_t &nfev;
+    ae_int_t &terminationtype;
+    double &debugeqerr;
+    double &debugfs;
+    double &debugff;
+    double &debugdx;
+
+};
+
 /*************************************************************************
 
 *************************************************************************/
@@ -364,6 +619,7 @@ public:
     minlbfgsstate(const minlbfgsstate &rhs);
     minlbfgsstate& operator=(const minlbfgsstate &rhs);
     virtual ~minlbfgsstate();
+    ae_bool &needf;
     ae_bool &needfg;
     ae_bool &xupdated;
     double &f;
@@ -401,6 +657,84 @@ public:
 
 };
 
+/*************************************************************************
+This object stores nonlinear optimizer state.
+You should use functions provided by MinQP subpackage to work with this
+object
+*************************************************************************/
+class _minqpstate_owner
+{
+public:
+    _minqpstate_owner();
+    _minqpstate_owner(const _minqpstate_owner &rhs);
+    _minqpstate_owner& operator=(const _minqpstate_owner &rhs);
+    virtual ~_minqpstate_owner();
+    alglib_impl::minqpstate* c_ptr();
+    alglib_impl::minqpstate* c_ptr() const;
+protected:
+    alglib_impl::minqpstate *p_struct;
+};
+class minqpstate : public _minqpstate_owner
+{
+public:
+    minqpstate();
+    minqpstate(const minqpstate &rhs);
+    minqpstate& operator=(const minqpstate &rhs);
+    virtual ~minqpstate();
+
+};
+
+
+/*************************************************************************
+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 _minqpreport_owner
+{
+public:
+    _minqpreport_owner();
+    _minqpreport_owner(const _minqpreport_owner &rhs);
+    _minqpreport_owner& operator=(const _minqpreport_owner &rhs);
+    virtual ~_minqpreport_owner();
+    alglib_impl::minqpreport* c_ptr();
+    alglib_impl::minqpreport* c_ptr() const;
+protected:
+    alglib_impl::minqpreport *p_struct;
+};
+class minqpreport : public _minqpreport_owner
+{
+public:
+    minqpreport();
+    minqpreport(const minqpreport &rhs);
+    minqpreport& operator=(const minqpreport &rhs);
+    virtual ~minqpreport();
+    ae_int_t &inneriterationscount;
+    ae_int_t &outeriterationscount;
+    ae_int_t &nmv;
+    ae_int_t &ncholesky;
+    ae_int_t &terminationtype;
+
+};
+
 /*************************************************************************
 Levenberg-Marquardt optimizer.
 
@@ -555,217 +889,119 @@ public:
 };
 
 /*************************************************************************
-This object stores state of the nonlinear CG optimizer.
+        NONLINEAR CONJUGATE GRADIENT METHOD
 
-You should use ALGLIB functions to work with this object.
-*************************************************************************/
-class _mincgstate_owner
-{
-public:
-    _mincgstate_owner();
-    _mincgstate_owner(const _mincgstate_owner &rhs);
-    _mincgstate_owner& operator=(const _mincgstate_owner &rhs);
-    virtual ~_mincgstate_owner();
-    alglib_impl::mincgstate* c_ptr();
-    alglib_impl::mincgstate* c_ptr() const;
-protected:
-    alglib_impl::mincgstate *p_struct;
-};
-class mincgstate : public _mincgstate_owner
-{
-public:
-    mincgstate();
-    mincgstate(const mincgstate &rhs);
-    mincgstate& operator=(const mincgstate &rhs);
-    virtual ~mincgstate();
-    ae_bool &needfg;
-    ae_bool &xupdated;
-    double &f;
-    real_1d_array g;
-    real_1d_array x;
+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
 
-*************************************************************************/
-class _mincgreport_owner
-{
-public:
-    _mincgreport_owner();
-    _mincgreport_owner(const _mincgreport_owner &rhs);
-    _mincgreport_owner& operator=(const _mincgreport_owner &rhs);
-    virtual ~_mincgreport_owner();
-    alglib_impl::mincgreport* c_ptr();
-    alglib_impl::mincgreport* c_ptr() const;
-protected:
-    alglib_impl::mincgreport *p_struct;
-};
-class mincgreport : public _mincgreport_owner
-{
-public:
-    mincgreport();
-    mincgreport(const mincgreport &rhs);
-    mincgreport& operator=(const mincgreport &rhs);
-    virtual ~mincgreport();
-    ae_int_t &iterationscount;
-    ae_int_t &nfev;
-    ae_int_t &terminationtype;
 
-};
+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.
 
-/*************************************************************************
-This object stores nonlinear optimizer state.
-You should use functions provided by MinBLEIC subpackage to work with this
-object
-*************************************************************************/
-class _minbleicstate_owner
-{
-public:
-    _minbleicstate_owner();
-    _minbleicstate_owner(const _minbleicstate_owner &rhs);
-    _minbleicstate_owner& operator=(const _minbleicstate_owner &rhs);
-    virtual ~_minbleicstate_owner();
-    alglib_impl::minbleicstate* c_ptr();
-    alglib_impl::minbleicstate* c_ptr() const;
-protected:
-    alglib_impl::minbleicstate *p_struct;
-};
-class minbleicstate : public _minbleicstate_owner
-{
-public:
-    minbleicstate();
-    minbleicstate(const minbleicstate &rhs);
-    minbleicstate& operator=(const minbleicstate &rhs);
-    virtual ~minbleicstate();
-    ae_bool &needfg;
-    ae_bool &xupdated;
-    double &f;
-    real_1d_array g;
-    real_1d_array x;
-
-};
 
+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].
 
-/*************************************************************************
-This structure stores optimization report:
-* InnerIterationsCount      number of inner iterations
-* OuterIterationsCount      number of outer iterations
-* NFEV                      number of gradient evaluations
+OUTPUT PARAMETERS:
+    State   -   structure which stores algorithm state
 
-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|
+  -- ALGLIB --
+     Copyright 25.03.2010 by Bochkanov Sergey
 *************************************************************************/
-class _minbleicreport_owner
-{
-public:
-    _minbleicreport_owner();
-    _minbleicreport_owner(const _minbleicreport_owner &rhs);
-    _minbleicreport_owner& operator=(const _minbleicreport_owner &rhs);
-    virtual ~_minbleicreport_owner();
-    alglib_impl::minbleicreport* c_ptr();
-    alglib_impl::minbleicreport* c_ptr() const;
-protected:
-    alglib_impl::minbleicreport *p_struct;
-};
-class minbleicreport : public _minbleicreport_owner
-{
-public:
-    minbleicreport();
-    minbleicreport(const minbleicreport &rhs);
-    minbleicreport& operator=(const minbleicreport &rhs);
-    virtual ~minbleicreport();
-    ae_int_t &inneriterationscount;
-    ae_int_t &outeriterationscount;
-    ae_int_t &nfev;
-    ae_int_t &terminationtype;
-    double &debugeqerr;
-    double &debugfs;
-    double &debugff;
-    double &debugdx;
+void mincgcreate(const ae_int_t n, const real_1d_array &x, mincgstate &state);
+void mincgcreate(const real_1d_array &x, mincgstate &state);
 
-};
 
 /*************************************************************************
-        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.
+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
-    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].
-
+    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. 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.
-
+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.
 
   -- ALGLIB --
-     Copyright 02.04.2010 by Bochkanov Sergey
+     Copyright 16.05.2011 by Bochkanov Sergey
 *************************************************************************/
-void minlbfgscreate(const ae_int_t n, const ae_int_t m, const real_1d_array &x, minlbfgsstate &state);
-void minlbfgscreate(const ae_int_t m, const real_1d_array &x, minlbfgsstate &state);
+void mincgcreatef(const ae_int_t n, const real_1d_array &x, const double diffstep, mincgstate &state);
+void mincgcreatef(const real_1d_array &x, const double diffstep, mincgstate &state);
 
 
 /*************************************************************************
-This function sets stopping conditions for L-BFGS optimization algorithm.
+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
-                ||G||<EpsG is satisfied, where ||.|| means Euclidian norm,
-                G - gradient.
+                |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 |X(k+1)-X(k)| <= EpsX is fulfilled.
+                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.
 
@@ -775,7 +1011,40 @@ automatic stopping criterion selection (small EpsX).
   -- ALGLIB --
      Copyright 02.04.2010 by Bochkanov Sergey
 *************************************************************************/
-void minlbfgssetcond(const minlbfgsstate &state, const double epsg, const double epsf, const double epsx, const ae_int_t maxits);
+void mincgsetcond(const mincgstate &state, const double epsg, const double epsf, const double epsx, const ae_int_t 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.
+
+  -- ALGLIB --
+     Copyright 14.01.2011 by Bochkanov Sergey
+*************************************************************************/
+void mincgsetscale(const mincgstate &state, const real_1d_array &s);
 
 
 /*************************************************************************
@@ -786,13 +1055,28 @@ INPUT PARAMETERS:
     NeedXRep-   whether iteration reports are needed or not
 
 If NeedXRep is True, algorithm will call rep() callback function if  it is
-provided to MinLBFGSOptimize().
+provided to MinCGOptimize().
+
+  -- ALGLIB --
+     Copyright 02.04.2010 by Bochkanov Sergey
+*************************************************************************/
+void mincgsetxrep(const mincgstate &state, const bool needxrep);
+
+
+/*************************************************************************
+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
 
   -- ALGLIB --
      Copyright 02.04.2010 by Bochkanov Sergey
 *************************************************************************/
-void minlbfgssetxrep(const minlbfgsstate &state, const bool needxrep);
+void mincgsetcgtype(const mincgstate &state, const ae_int_t cgtype);
 
 
 /*************************************************************************
@@ -800,8 +1084,8 @@ 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.
+    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
@@ -812,17 +1096,50 @@ overflow) without actually calculating function value at the x+stp*d.
   -- ALGLIB --
      Copyright 02.04.2010 by Bochkanov Sergey
 *************************************************************************/
-void minlbfgssetstpmax(const minlbfgsstate &state, const double stpmax);
+void mincgsetstpmax(const mincgstate &state, const double stpmax);
 
 
 /*************************************************************************
-Modification of the preconditioner:
-default preconditioner (simple scaling) is used.
+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 which stores algorithm state
+    State   -   structure used to store algorithm state.
+    Stp     -   initial estimate of the step length.
+                Can be zero (no estimate).
+
+  -- ALGLIB --
+     Copyright 30.07.2010 by Bochkanov Sergey
+*************************************************************************/
+void mincgsuggeststep(const mincgstate &state, const double stp);
+
+
+/*************************************************************************
+Modification of the preconditioner: preconditioning is turned off.
 
-After call to this function preconditioner is changed to the default one.
+INPUT PARAMETERS:
+    State   -   structure which stores algorithm state
 
 NOTE:  you  can  change  preconditioner  "on  the  fly",  during algorithm
 iterations.
@@ -830,35 +1147,56 @@ iterations.
   -- ALGLIB --
      Copyright 13.10.2010 by Bochkanov Sergey
 *************************************************************************/
-void minlbfgssetdefaultpreconditioner(const minlbfgsstate &state);
+void mincgsetprecdefault(const mincgstate &state);
 
 
 /*************************************************************************
-Modification of the preconditioner:
-Cholesky factorization of approximate Hessian is used.
+Modification  of  the  preconditioner:  diagonal 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],
+    D       -   diagonal of the approximate Hessian, array[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. It
-also should be well conditioned, although only strict  non-singularity  is
-tested.
+NOTE 2: D[i] should be positive. Exception will be thrown otherwise.
+
+NOTE 3: you should pass diagonal of approximate Hessian - NOT ITS INVERSE.
 
   -- ALGLIB --
      Copyright 13.10.2010 by Bochkanov Sergey
 *************************************************************************/
-void minlbfgssetcholeskypreconditioner(const minlbfgsstate &state, const real_2d_array &p, const bool isupper);
+void mincgsetprecdiag(const mincgstate &state, const real_1d_array &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.
+
+  -- ALGLIB --
+     Copyright 13.10.2010 by Bochkanov Sergey
+*************************************************************************/
+void mincgsetprecscale(const mincgstate &state);
 
 
 /*************************************************************************
@@ -866,7 +1204,7 @@ This function provides reverse communication interface
 Reverse communication interface is not documented or recommended to use.
 See below for functions which provide better documented API
 *************************************************************************/
-bool minlbfgsiteration(const minlbfgsstate &state);
+bool mincgiteration(const mincgstate &state);
 
 
 /*************************************************************************
@@ -874,6 +1212,8 @@ This family of functions is used to launcn iterations of nonlinear optimizer
 
 These functions accept following parameters:
     state   -   algorithm state
+    func    -   callback which calculates function (or merit function)
+                value func at given point x
     grad    -   callback which calculates function (or merit function)
                 value func and gradient grad at given point x
     rep     -   optional callback which is called after each iteration
@@ -881,19 +1221,54 @@ These functions accept following parameters:
     ptr     -   optional pointer which is passed to func/grad/hess/jac/rep
                 can be NULL
 
+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.
 
   -- ALGLIB --
-     Copyright 20.03.2009 by Bochkanov Sergey
+     Copyright 20.04.2009 by Bochkanov Sergey
 
 *************************************************************************/
-void minlbfgsoptimize(minlbfgsstate &state,
+void mincgoptimize(mincgstate &state,
+    void (*func)(const real_1d_array &x, double &func, void *ptr),
+    void  (*rep)(const real_1d_array &x, double func, void *ptr) = NULL,
+    void *ptr = NULL);
+void mincgoptimize(mincgstate &state,
     void (*grad)(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr),
     void  (*rep)(const real_1d_array &x, double func, void *ptr) = NULL,
     void *ptr = NULL);
 
 
 /*************************************************************************
-L-BFGS algorithm results
+Conjugate gradient results
 
 INPUT PARAMETERS:
     State   -   algorithm state
@@ -902,391 +1277,714 @@ 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
+                            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
 
   -- ALGLIB --
-     Copyright 02.04.2010 by Bochkanov Sergey
+     Copyright 20.04.2009 by Bochkanov Sergey
 *************************************************************************/
-void minlbfgsresults(const minlbfgsstate &state, real_1d_array &x, minlbfgsreport &rep);
+void mincgresults(const mincgstate &state, real_1d_array &x, mincgreport &rep);
 
 
 /*************************************************************************
-L-BFGS algorithm results
+Conjugate gradient results
 
-Buffered implementation of MinLBFGSResults which uses pre-allocated buffer
+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.
 
   -- ALGLIB --
-     Copyright 20.08.2010 by Bochkanov Sergey
+     Copyright 20.04.2009 by Bochkanov Sergey
 *************************************************************************/
-void minlbfgsresultsbuf(const minlbfgsstate &state, real_1d_array &x, minlbfgsreport &rep);
+void mincgresultsbuf(const mincgstate &state, real_1d_array &x, mincgreport &rep);
 
 
 /*************************************************************************
-This  subroutine restarts LBFGS algorithm from new point. All optimization
+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
+    State   -   structure used to store algorithm state.
     X       -   new starting point.
 
   -- ALGLIB --
      Copyright 30.07.2010 by Bochkanov Sergey
 *************************************************************************/
-void minlbfgsrestartfrom(const minlbfgsstate &state, const real_1d_array &x);
+void mincgrestartfrom(const mincgstate &state, const real_1d_array &x);
 
 /*************************************************************************
-                IMPROVED LEVENBERG-MARQUARDT METHOD FOR
-                 NON-LINEAR LEAST SQUARES OPTIMIZATION
+                     BOUND CONSTRAINED OPTIMIZATION
+       WITH ADDITIONAL LINEAR EQUALITY AND INEQUALITY CONSTRAINTS
 
 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[].
-
+The  subroutine  minimizes  function   F(x)  of N arguments subject to any
+combination of:
+* bound constraints
+* linear inequality constraints
+* linear equality constraints
 
 REQUIREMENTS:
-This algorithm will request following information during its operation:
+* 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
 
-* function vector f[] at given point X
-* function vector f[] and Jacobian of f[] (simultaneously) at given point
+USAGE:
 
-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].
+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/
 
-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.
+1. User initializes algorithm state with MinBLEICCreate() call
 
+2. USer adds boundary and/or linear constraints by calling
+   MinBLEICSetBC() and MinBLEICSetLC() functions.
 
-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.
+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       -   dimension, N>1
+    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 functions f[i]
-    X       -   initial solution, array[0..N-1]
+                * 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 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.
+    State   -   structure stores algorithm state
 
   -- ALGLIB --
-     Copyright 30.03.2009 by Bochkanov Sergey
+     Copyright 28.11.2010 by Bochkanov Sergey
 *************************************************************************/
-void minlmcreatevj(const ae_int_t n, const ae_int_t m, const real_1d_array &x, minlmstate &state);
-void minlmcreatevj(const ae_int_t m, const real_1d_array &x, minlmstate &state);
+void minbleiccreate(const ae_int_t n, const real_1d_array &x, minbleicstate &state);
+void minbleiccreate(const real_1d_array &x, minbleicstate &state);
 
 
 /*************************************************************************
-                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.
+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       -   dimension, N>1
+    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 functions f[i]
-    X       -   initial solution, array[0..N-1]
+    X       -   starting point, 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.
+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.
 
   -- ALGLIB --
-     Copyright 30.03.2009 by Bochkanov Sergey
+     Copyright 16.05.2011 by Bochkanov Sergey
 *************************************************************************/
-void minlmcreatev(const ae_int_t n, const ae_int_t m, const real_1d_array &x, const double diffstep, minlmstate &state);
-void minlmcreatev(const ae_int_t m, const real_1d_array &x, const double diffstep, minlmstate &state);
+void minbleiccreatef(const ae_int_t n, const real_1d_array &x, const double diffstep, minbleicstate &state);
+void minbleiccreatef(const real_1d_array &x, const double diffstep, minbleicstate &state);
 
 
 /*************************************************************************
-    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.
+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().
 
-REQUIREMENTS:
-This algorithm will request following information during its operation:
+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.
 
-* 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
+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].
 
-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).
+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)
 
-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.
+  -- ALGLIB --
+     Copyright 28.11.2010 by Bochkanov Sergey
+*************************************************************************/
+void minbleicsetbc(const minbleicstate &state, const real_1d_array &bndl, const real_1d_array &bndu);
 
 
-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.
+/*************************************************************************
+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:
-    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
+    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
 
-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.
+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).
 
   -- ALGLIB --
-     Copyright 30.03.2009 by Bochkanov Sergey
+     Copyright 28.11.2010 by Bochkanov Sergey
 *************************************************************************/
-void minlmcreatefgh(const ae_int_t n, const real_1d_array &x, minlmstate &state);
-void minlmcreatefgh(const real_1d_array &x, minlmstate &state);
+void minbleicsetlc(const minbleicstate &state, const real_2d_array &c, const integer_1d_array &ct, const ae_int_t k);
+void minbleicsetlc(const minbleicstate &state, const real_2d_array &c, const integer_1d_array &ct);
 
 
 /*************************************************************************
-                IMPROVED LEVENBERG-MARQUARDT METHOD FOR
-                 NON-LINEAR LEAST SQUARES OPTIMIZATION
+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.
 
-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[]
-* value of Jacobian of f[]
-* gradient of merit function F(x)
+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()
 
-This function creates optimizer which uses acceleration strategy 2.  Cheap
-gradient of merit function (which is twice the product of function  vector
-and Jacobian) is used for accelerated iterations (see User Guide for  more
-info on this subject).
+Passing EpsG=0, EpsF=0 and EpsX=0 (simultaneously) will lead to
+automatic stopping criterion selection.
 
-REQUIREMENTS:
-This algorithm will request following information during its operation:
+These conditions are used to terminate inner iterations. However, you
+need to tune termination conditions for outer iterations too.
 
-* function vector f[] at given point X
-* function vector f[] and Jacobian of f[] (simultaneously) at given point
-* gradient of
+  -- ALGLIB --
+     Copyright 28.11.2010 by Bochkanov Sergey
+*************************************************************************/
+void minbleicsetinnercond(const minbleicstate &state, const double epsg, const double epsf, const double epsx);
 
-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(),  jac()  and  grad()
-callbacks. First one is used to calculate f[] at given point,  second  one
-calculates f[] and Jacobian df[i]/dx[j], last one calculates  gradient  of
-merit function F(x).
 
-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.
+/*************************************************************************
+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.
 
-USAGE:
-1. User initializes algorithm state with MinLMCreateVGJ() 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:
+    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.
+
+  -- ALGLIB --
+     Copyright 28.11.2010 by Bochkanov Sergey
+*************************************************************************/
+void minbleicsetoutercond(const minbleicstate &state, const double epsx, const double 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:
-    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]
+    State   -   structure stores algorithm state
+    S       -   array[N], non-zero scaling coefficients
+                S[i] may be negative, sign doesn't matter.
 
-OUTPUT PARAMETERS:
+  -- ALGLIB --
+     Copyright 14.01.2011 by Bochkanov Sergey
+*************************************************************************/
+void minbleicsetscale(const minbleicstate &state, const real_1d_array &s);
+
+
+/*************************************************************************
+Modification of the preconditioner: preconditioning is turned off.
+
+INPUT PARAMETERS:
     State   -   structure which stores algorithm state
 
+  -- ALGLIB --
+     Copyright 13.10.2010 by Bochkanov Sergey
+*************************************************************************/
+void minbleicsetprecdefault(const minbleicstate &state);
+
+
+/*************************************************************************
+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.
+
+  -- ALGLIB --
+     Copyright 13.10.2010 by Bochkanov Sergey
+*************************************************************************/
+void minbleicsetprecdiag(const minbleicstate &state, const real_1d_array &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  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
+
+  -- ALGLIB --
+     Copyright 13.10.2010 by Bochkanov Sergey
+*************************************************************************/
+void minbleicsetprecscale(const minbleicstate &state);
+
+
+/*************************************************************************
+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.
+
+  -- ALGLIB --
+     Copyright 28.11.2010 by Bochkanov Sergey
+*************************************************************************/
+void minbleicsetmaxits(const minbleicstate &state, const ae_int_t 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().
+
+  -- ALGLIB --
+     Copyright 28.11.2010 by Bochkanov Sergey
+*************************************************************************/
+void minbleicsetxrep(const minbleicstate &state, const bool 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.
+
+  -- ALGLIB --
+     Copyright 02.04.2010 by Bochkanov Sergey
+*************************************************************************/
+void minbleicsetstpmax(const minbleicstate &state, const double stpmax);
+
+
+/*************************************************************************
+This function provides reverse communication interface
+Reverse communication interface is not documented or recommended to use.
+See below for functions which provide better documented API
+*************************************************************************/
+bool minbleiciteration(const minbleicstate &state);
+
+
+/*************************************************************************
+This family of functions is used to launcn iterations of nonlinear optimizer
+
+These functions accept following parameters:
+    state   -   algorithm state
+    func    -   callback which calculates function (or merit function)
+                value func at given point x
+    grad    -   callback which calculates function (or merit function)
+                value func and gradient grad at given point x
+    rep     -   optional callback which is called after each iteration
+                can be NULL
+    ptr     -   optional pointer which is passed to func/grad/hess/jac/rep
+                can be NULL
+
 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.
+
+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.
 
   -- ALGLIB --
-     Copyright 30.03.2009 by Bochkanov Sergey
+     Copyright 28.11.2010 by Bochkanov Sergey
+
 *************************************************************************/
-void minlmcreatevgj(const ae_int_t n, const ae_int_t m, const real_1d_array &x, minlmstate &state);
-void minlmcreatevgj(const ae_int_t m, const real_1d_array &x, minlmstate &state);
+void minbleicoptimize(minbleicstate &state,
+    void (*func)(const real_1d_array &x, double &func, void *ptr),
+    void  (*rep)(const real_1d_array &x, double func, void *ptr) = NULL,
+    void *ptr = NULL);
+void minbleicoptimize(minbleicstate &state,
+    void (*grad)(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr),
+    void  (*rep)(const real_1d_array &x, double func, void *ptr) = NULL,
+    void *ptr = NULL);
+
+
+/*************************************************************************
+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.
+
+  -- ALGLIB --
+     Copyright 28.11.2010 by Bochkanov Sergey
+*************************************************************************/
+void minbleicresults(const minbleicstate &state, real_1d_array &x, minbleicreport &rep);
 
 
 /*************************************************************************
-                   LEVENBERG-MARQUARDT-LIKE METHOD FOR
-                  NON-LINEAR LEAST SQUARES OPTIMIZATION
+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.
+
+  -- ALGLIB --
+     Copyright 28.11.2010 by Bochkanov Sergey
+*************************************************************************/
+void minbleicresultsbuf(const minbleicstate &state, real_1d_array &x, minbleicreport &rep);
+
+
+/*************************************************************************
+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.
+
+  -- ALGLIB --
+     Copyright 28.11.2010 by Bochkanov Sergey
+*************************************************************************/
+void minbleicrestartfrom(const minbleicstate &state, const real_1d_array &x);
+
+/*************************************************************************
+        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.
 
-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 F(), gradient of F(), function vector f[]  and  Jacobian of
-f[].
 
-This function is considered obsolete since ALGLIB 3.1.0 and is present for
-backward  compatibility  only.  We  recommend to use MinLMCreateVGJ, which
-provides similar, but more consistent interface.
+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.
+
 
   -- ALGLIB --
-     Copyright 30.03.2009 by Bochkanov Sergey
+     Copyright 02.04.2010 by Bochkanov Sergey
 *************************************************************************/
-void minlmcreatefgj(const ae_int_t n, const ae_int_t m, const real_1d_array &x, minlmstate &state);
-void minlmcreatefgj(const ae_int_t m, const real_1d_array &x, minlmstate &state);
+void minlbfgscreate(const ae_int_t n, const ae_int_t m, const real_1d_array &x, minlbfgsstate &state);
+void minlbfgscreate(const ae_int_t m, const real_1d_array &x, minlbfgsstate &state);
 
 
 /*************************************************************************
-    CLASSIC LEVENBERG-MARQUARDT METHOD FOR NON-LINEAR OPTIMIZATION
+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
 
-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  F(),  function  vector  f[] and Jacobian of f[]. Classic
-Levenberg-Marquardt method is used.
+OUTPUT PARAMETERS:
+    State   -   structure which stores algorithm 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.
+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.
 
   -- ALGLIB --
-     Copyright 30.03.2009 by Bochkanov Sergey
+     Copyright 16.05.2011 by Bochkanov Sergey
 *************************************************************************/
-void minlmcreatefj(const ae_int_t n, const ae_int_t m, const real_1d_array &x, minlmstate &state);
-void minlmcreatefj(const ae_int_t m, const real_1d_array &x, minlmstate &state);
+void minlbfgscreatef(const ae_int_t n, const ae_int_t m, const real_1d_array &x, const double diffstep, minlbfgsstate &state);
+void minlbfgscreatef(const ae_int_t m, const real_1d_array &x, const double diffstep, minlbfgsstate &state);
 
 
 /*************************************************************************
-This function sets stopping conditions for Levenberg-Marquardt optimization
-algorithm.
+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
-                ||G||<EpsG is satisfied, where ||.|| means Euclidian norm,
-                G - gradient.
+                |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 |X(k+1)-X(k)| <= EpsX is fulfilled.
+                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.   Only   Levenberg-Marquardt
-                iterations  are  counted  (L-BFGS/CG  iterations  are  NOT
-                counted because their cost is very low compared to that of
-                LM).
+                iterations is unlimited.
 
 Passing EpsG=0, EpsF=0, EpsX=0 and MaxIts=0 (simultaneously) will lead to
 automatic stopping criterion selection (small EpsX).
@@ -1294,7 +1992,7 @@ automatic stopping criterion selection (small EpsX).
   -- ALGLIB --
      Copyright 02.04.2010 by Bochkanov Sergey
 *************************************************************************/
-void minlmsetcond(const minlmstate &state, const double epsg, const double epsf, const double epsx, const ae_int_t maxits);
+void minlbfgssetcond(const minlbfgsstate &state, const double epsg, const double epsf, const double epsx, const ae_int_t maxits);
 
 
 /*************************************************************************
@@ -1305,13 +2003,13 @@ INPUT PARAMETERS:
     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.
+provided to MinLBFGSOptimize().
+
 
   -- ALGLIB --
      Copyright 02.04.2010 by Bochkanov Sergey
 *************************************************************************/
-void minlmsetxrep(const minlmstate &state, const bool needxrep);
+void minlbfgssetxrep(const minlbfgsstate &state, const bool needxrep);
 
 
 /*************************************************************************
@@ -1319,8 +2017,8 @@ 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.
+    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
@@ -1328,74 +2026,133 @@ 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.
-
   -- ALGLIB --
      Copyright 02.04.2010 by Bochkanov Sergey
 *************************************************************************/
-void minlmsetstpmax(const minlmstate &state, const double stpmax);
+void minlbfgssetstpmax(const minlbfgsstate &state, const double stpmax);
 
 
 /*************************************************************************
-This function is used to change acceleration settings
+This function sets scaling coefficients for LBFGS optimizer.
 
-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=2, after quadratic model is built and LM step is made, we use it
-  as preconditioner for several (5-10) iterations of L-BFGS algorithm.
+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
 
-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.
+Scaling is also used by finite difference variant of the optimizer  - step
+along I-th axis is equal to DiffStep*S[I].
 
-AccType=2 is recommended when Jacobian is cheap - much more  cheaper  than
-one  Cholesky  factorization.   We   can   reduce   number   of   Cholesky
-factorizations at the cost of increased number of  Jacobian  calculations.
-Sometimes it helps.
+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.
 
-Table below list  optimization  protocols  (XYZ  protocol  corresponds  to
-MinLMCreateXYZ) and acceleration types they support (and use by  default).
+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.
 
-ACCELERATION TYPES SUPPORTED BY OPTIMIZATION PROTOCOLS:
+INPUT PARAMETERS:
+    State   -   structure stores algorithm state
+    S       -   array[N], non-zero scaling coefficients
+                S[i] may be negative, sign doesn't matter.
 
-protocol    0   1   2   comment
-V           +   +
-VJ          +   +   +
-FGH         +       +
-VGJ         +   +   +   special protocol, not for widespread use
-FJ          +       +   obsolete protocol, not recommended
-FGJ         +       +   obsolete protocol, not recommended
+  -- ALGLIB --
+     Copyright 14.01.2011 by Bochkanov Sergey
+*************************************************************************/
+void minlbfgssetscale(const minlbfgsstate &state, const real_1d_array &s);
 
-DAFAULT VALUES:
 
-protocol    0   1   2   comment
-V               x       without acceleration it is so slooooooooow
-VJ          x
-FGH         x
-VGJ                 x   we've implicitly turned (2) by passing gradient
-FJ          x           obsolete protocol, not recommended
-FGJ                 x   obsolete protocol, not recommended
+/*************************************************************************
+Modification  of  the  preconditioner:  default  preconditioner    (simple
+scaling, same for all elements of X) is used.
 
-NOTE: this  function should be called before optimization. Attempt to call
-it during algorithm iterations may result in unexpected behavior.
+INPUT PARAMETERS:
+    State   -   structure which stores algorithm state
 
-NOTE: attempt to call this function with unsupported protocol/acceleration
-combination will result in exception being thrown.
+NOTE:  you  can  change  preconditioner  "on  the  fly",  during algorithm
+iterations.
 
   -- ALGLIB --
-     Copyright 14.10.2010 by Bochkanov Sergey
+     Copyright 13.10.2010 by Bochkanov Sergey
 *************************************************************************/
-void minlmsetacctype(const minlmstate &state, const ae_int_t acctype);
+void minlbfgssetprecdefault(const minlbfgsstate &state);
+
+
+/*************************************************************************
+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.
+
+  -- ALGLIB --
+     Copyright 13.10.2010 by Bochkanov Sergey
+*************************************************************************/
+void minlbfgssetpreccholesky(const minlbfgsstate &state, const real_2d_array &p, const bool isupper);
+
+
+/*************************************************************************
+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.
+
+  -- ALGLIB --
+     Copyright 13.10.2010 by Bochkanov Sergey
+*************************************************************************/
+void minlbfgssetprecdiag(const minlbfgsstate &state, const real_1d_array &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  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
+
+  -- ALGLIB --
+     Copyright 13.10.2010 by Bochkanov Sergey
+*************************************************************************/
+void minlbfgssetprecscale(const minlbfgsstate &state);
 
 
 /*************************************************************************
@@ -1403,7 +2160,7 @@ This function provides reverse communication interface
 Reverse communication interface is not documented or recommended to use.
 See below for functions which provide better documented API
 *************************************************************************/
-bool minlmiteration(const minlmstate &state);
+bool minlbfgsiteration(const minlbfgsstate &state);
 
 
 /*************************************************************************
@@ -1415,12 +2172,6 @@ These functions accept following parameters:
                 value func at given point x
     grad    -   callback which calculates function (or merit function)
                 value func and gradient grad at given point x
-    hess    -   callback which calculates function (or merit function)
-                value func, gradient grad and Hessian hess at given point x
-    fvec    -   callback which calculates function vector fi[]
-                at given point x
-    jac     -   callback which calculates function vector fi[]
-                and Jacobian jac at given point x
     rep     -   optional callback which is called after each iteration
                 can be NULL
     ptr     -   optional pointer which is passed to func/grad/hess/jac/rep
@@ -1428,400 +2179,531 @@ These functions accept following parameters:
 
 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.
+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.
 
-   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.
+   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 avoid such errors because there is no way to find them at
-   compile time - you can see them at runtime 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.
 
   -- ALGLIB --
-     Copyright 10.03.2009 by Bochkanov Sergey
+     Copyright 20.03.2009 by Bochkanov Sergey
 
 *************************************************************************/
-void minlmoptimize(minlmstate &state,
-    void (*fvec)(const real_1d_array &x, real_1d_array &fi, void *ptr),
-    void  (*rep)(const real_1d_array &x, double func, void *ptr) = NULL,
-    void *ptr = NULL);
-void minlmoptimize(minlmstate &state,
-    void (*fvec)(const real_1d_array &x, real_1d_array &fi, void *ptr),
-    void  (*jac)(const real_1d_array &x, real_1d_array &fi, real_2d_array &jac, void *ptr),
-    void  (*rep)(const real_1d_array &x, double func, void *ptr) = NULL,
-    void *ptr = NULL);
-void minlmoptimize(minlmstate &state,
-    void (*func)(const real_1d_array &x, double &func, void *ptr),
-    void (*grad)(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr),
-    void (*hess)(const real_1d_array &x, double &func, real_1d_array &grad, real_2d_array &hess, void *ptr),
-    void  (*rep)(const real_1d_array &x, double func, void *ptr) = NULL,
-    void *ptr = NULL);
-void minlmoptimize(minlmstate &state,
+void minlbfgsoptimize(minlbfgsstate &state,
     void (*func)(const real_1d_array &x, double &func, void *ptr),
-    void  (*jac)(const real_1d_array &x, real_1d_array &fi, real_2d_array &jac, void *ptr),
     void  (*rep)(const real_1d_array &x, double func, void *ptr) = NULL,
     void *ptr = NULL);
-void minlmoptimize(minlmstate &state,
-    void (*func)(const real_1d_array &x, double &func, void *ptr),
+void minlbfgsoptimize(minlbfgsstate &state,
     void (*grad)(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr),
-    void  (*jac)(const real_1d_array &x, real_1d_array &fi, real_2d_array &jac, void *ptr),
     void  (*rep)(const real_1d_array &x, double func, void *ptr) = NULL,
     void *ptr = NULL);
 
 
 /*************************************************************************
-Levenberg-Marquardt algorithm results
+L-BFGS 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.
+    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
 
   -- ALGLIB --
-     Copyright 10.03.2009 by Bochkanov Sergey
+     Copyright 02.04.2010 by Bochkanov Sergey
 *************************************************************************/
-void minlmresults(const minlmstate &state, real_1d_array &x, minlmreport &rep);
+void minlbfgsresults(const minlbfgsstate &state, real_1d_array &x, minlbfgsreport &rep);
 
 
 /*************************************************************************
-Levenberg-Marquardt algorithm results
+L-BFGS algorithm results
 
-Buffered implementation of MinLMResults(), which uses pre-allocated buffer
+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.
 
   -- ALGLIB --
-     Copyright 10.03.2009 by Bochkanov Sergey
+     Copyright 20.08.2010 by Bochkanov Sergey
 *************************************************************************/
-void minlmresultsbuf(const minlmstate &state, real_1d_array &x, minlmreport &rep);
+void minlbfgsresultsbuf(const minlbfgsstate &state, real_1d_array &x, minlbfgsreport &rep);
 
 
 /*************************************************************************
-This  subroutine  restarts  LM  algorithm from new point. All optimization
+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 for reverse communication previously
-                allocated with MinLMCreateXXX call.
+    State   -   structure used to store algorithm state
     X       -   new starting point.
 
   -- ALGLIB --
      Copyright 30.07.2010 by Bochkanov Sergey
 *************************************************************************/
-void minlmrestartfrom(const minlmstate &state, const real_1d_array &x);
+void minlbfgsrestartfrom(const minlbfgsstate &state, const real_1d_array &x);
 
 /*************************************************************************
-              NONLINEAR BOUND CONSTRAINED OPTIMIZATION USING
-                      MODIFIED ACTIVE SET ALGORITHM
-                   WILLIAM W. HAGER AND HONGCHAO ZHANG
+                    CONSTRAINED QUADRATIC PROGRAMMING
 
-DESCRIPTION:
-The  subroutine  minimizes  function  F(x)  of  N  arguments  with   bound
-constraints: BndL[i] <= x[i] <= BndU[i]
+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.
 
-This method is  globally  convergent  as  long  as  grad(f)  is  Lipschitz
-continuous on a level set: L = { x : f(x)<=f(x0) }.
+INPUT PARAMETERS:
+    N       -   problem size
 
+OUTPUT PARAMETERS:
+    State   -   optimizer with zero quadratic/linear terms
+                and no constraints
 
-REQUIREMENTS:
-Algorithm will request following information during its operation:
-* function value F and its gradient G (simultaneously) at given point X
+  -- ALGLIB --
+     Copyright 11.01.2011 by Bochkanov Sergey
+*************************************************************************/
+void minqpcreate(const ae_int_t n, minqpstate &state);
 
 
-USAGE:
-1. User initializes algorithm state with MinASACreate() call
-2. User tunes solver parameters with MinASASetCond() MinASASetStpMax() and
-   other functions
-3. User calls MinASAOptimize() function which takes algorithm  state   and
-   pointer (delegate, etc.) to callback function which calculates F/G.
-4. User calls MinASAResults() to get solution
-5. Optionally, user may call MinASARestartFrom() to solve another  problem
-   with same N but another starting point and/or another function.
-   MinASARestartFrom() allows to reuse already initialized structure.
+/*************************************************************************
+This function sets linear term for QP solver.
 
+By default, linear term is zero.
 
 INPUT PARAMETERS:
-    N       -   problem dimension, N>0:
-                * if given, only leading N elements of X are used
-                * if not given, automatically determined from sizes of
-                  X/BndL/BndU.
-    X       -   starting point, array[0..N-1].
-    BndL    -   lower bounds, array[0..N-1].
-                all elements MUST be specified,  i.e.  all  variables  are
-                bounded. However, if some (all) variables  are  unbounded,
-                you may specify very small number as bound: -1000,  -1.0E6
-                or -1.0E300, or something like that.
-    BndU    -   upper bounds, array[0..N-1].
-                all elements MUST be specified,  i.e.  all  variables  are
-                bounded. However, if some (all) variables  are  unbounded,
-                you may specify very large number as bound: +1000,  +1.0E6
-                or +1.0E300, or something like that.
-
-OUTPUT PARAMETERS:
-    State   -   structure stores algorithm state
-
-NOTES:
-
-1. you may tune stopping conditions with MinASASetCond() function
-2. if target function contains exp() or other fast growing functions,  and
-   optimization algorithm makes too large steps which leads  to  overflow,
-   use MinASASetStpMax() function to bound algorithm's steps.
-3. this function does NOT support infinite/NaN values in X, BndL, BndU.
+    State   -   structure which stores algorithm state
+    B       -   linear term, array[N].
 
   -- ALGLIB --
-     Copyright 25.03.2010 by Bochkanov Sergey
+     Copyright 11.01.2011 by Bochkanov Sergey
 *************************************************************************/
-void minasacreate(const ae_int_t n, const real_1d_array &x, const real_1d_array &bndl, const real_1d_array &bndu, minasastate &state);
-void minasacreate(const real_1d_array &x, const real_1d_array &bndl, const real_1d_array &bndu, minasastate &state);
+void minqpsetlinearterm(const minqpstate &state, const real_1d_array &b);
 
 
 /*************************************************************************
-This function sets stopping conditions for the ASA optimization algorithm.
+This function sets quadratic term for QP solver.
 
-INPUT PARAMETERS:
-    State   -   structure which stores algorithm state
-    EpsG    -   >=0
-                The  subroutine  finishes  its  work   if   the  condition
-                ||G||<EpsG is satisfied, where ||.|| means Euclidian norm,
-                G - gradient.
-    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 |X(k+1)-X(k)| <= EpsX is fulfilled.
-    MaxIts  -   maximum number of iterations. If MaxIts=0, the  number  of
-                iterations is unlimited.
+By default quadratic term is zero.
 
-Passing EpsG=0, EpsF=0, EpsX=0 and MaxIts=0 (simultaneously) will lead to
-automatic stopping criterion selection (small EpsX).
+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.
 
   -- ALGLIB --
-     Copyright 02.04.2010 by Bochkanov Sergey
+     Copyright 11.01.2011 by Bochkanov Sergey
 *************************************************************************/
-void minasasetcond(const minasastate &state, const double epsg, const double epsf, const double epsx, const ae_int_t maxits);
+void minqpsetquadraticterm(const minqpstate &state, const real_2d_array &a, const bool isupper);
+void minqpsetquadraticterm(const minqpstate &state, const real_2d_array &a);
 
 
 /*************************************************************************
-This function turns on/off reporting.
+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
-    NeedXRep-   whether iteration reports are needed or not
-
-If NeedXRep is True, algorithm will call rep() callback function if  it is
-provided to MinASAOptimize().
+    X       -   starting point, array[N].
 
   -- ALGLIB --
-     Copyright 02.04.2010 by Bochkanov Sergey
+     Copyright 11.01.2011 by Bochkanov Sergey
 *************************************************************************/
-void minasasetxrep(const minasastate &state, const bool needxrep);
+void minqpsetstartingpoint(const minqpstate &state, const real_1d_array &x);
 
 
 /*************************************************************************
-This function sets optimization algorithm.
+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 stat
-    UAType  -   algorithm type:
-                * -1    automatic selection of the best algorithm
-                * 0     DY (Dai and Yuan) algorithm
-                * 1     Hybrid DY-HS algorithm
+    State   -   structure which stores algorithm state
+    XOrigin -   origin, array[N].
 
   -- ALGLIB --
-     Copyright 02.04.2010 by Bochkanov Sergey
+     Copyright 11.01.2011 by Bochkanov Sergey
 *************************************************************************/
-void minasasetalgorithm(const minasastate &state, const ae_int_t algotype);
+void minqpsetorigin(const minqpstate &state, const real_1d_array &xorigin);
 
 
 /*************************************************************************
-This function sets maximum step length
+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
-    StpMax  -   maximum step length, >=0. Set StpMax to 0.0,  if you don't
-                want to limit step length (zero by default).
-
-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.
 
   -- ALGLIB --
-     Copyright 02.04.2010 by Bochkanov Sergey
+     Copyright 11.01.2011 by Bochkanov Sergey
 *************************************************************************/
-void minasasetstpmax(const minasastate &state, const double stpmax);
+void minqpsetalgocholesky(const minqpstate &state);
 
 
 /*************************************************************************
-This function provides reverse communication interface
-Reverse communication interface is not documented or recommended to use.
-See below for functions which provide better documented API
+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].
+
+  -- ALGLIB --
+     Copyright 11.01.2011 by Bochkanov Sergey
 *************************************************************************/
-bool minasaiteration(const minasastate &state);
+void minqpsetbc(const minqpstate &state, const real_1d_array &bndl, const real_1d_array &bndu);
 
 
 /*************************************************************************
-This family of functions is used to launcn iterations of nonlinear optimizer
+This function solves quadratic programming problem.
+You should call it after setting solver options with MinQPSet...() calls.
 
-These functions accept following parameters:
-    state   -   algorithm state
-    grad    -   callback which calculates function (or merit function)
-                value func and gradient grad at given point x
-    rep     -   optional callback which is called after each iteration
-                can be NULL
-    ptr     -   optional pointer which is passed to func/grad/hess/jac/rep
-                can be NULL
+INPUT PARAMETERS:
+    State   -   algorithm state
 
+You should use MinQPResults() function to access results after calls
+to this function.
 
   -- ALGLIB --
-     Copyright 20.03.2009 by Bochkanov Sergey
-
+     Copyright 11.01.2011 by Bochkanov Sergey
 *************************************************************************/
-void minasaoptimize(minasastate &state,
-    void (*grad)(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr),
-    void  (*rep)(const real_1d_array &x, double func, void *ptr) = NULL,
-    void *ptr = NULL);
+void minqpoptimize(const minqpstate &state);
 
 
 /*************************************************************************
-ASA results
+QP solver 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
-                * ActiveConstraints contains number of active constraints
+    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.
 
   -- ALGLIB --
-     Copyright 20.03.2009 by Bochkanov Sergey
+     Copyright 11.01.2011 by Bochkanov Sergey
 *************************************************************************/
-void minasaresults(const minasastate &state, real_1d_array &x, minasareport &rep);
+void minqpresults(const minqpstate &state, real_1d_array &x, minqpreport &rep);
 
 
 /*************************************************************************
-ASA results
+QP results
 
-Buffered implementation of MinASAResults() which uses pre-allocated buffer
+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.
 
   -- ALGLIB --
-     Copyright 20.03.2009 by Bochkanov Sergey
+     Copyright 11.01.2011 by Bochkanov Sergey
 *************************************************************************/
-void minasaresultsbuf(const minasastate &state, real_1d_array &x, minasareport &rep);
-
+void minqpresultsbuf(const minqpstate &state, real_1d_array &x, minqpreport &rep);
 
 /*************************************************************************
-This  subroutine  restarts  CG  algorithm from new point. All optimization
-parameters are left unchanged.
+                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.
 
-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 MinCGCreate call.
-    X       -   new starting point.
-    BndL    -   new lower bounds
-    BndU    -   new upper bounds
+    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.
 
   -- ALGLIB --
-     Copyright 30.07.2010 by Bochkanov Sergey
+     Copyright 30.03.2009 by Bochkanov Sergey
 *************************************************************************/
-void minasarestartfrom(const minasastate &state, const real_1d_array &x, const real_1d_array &bndl, const real_1d_array &bndu);
+void minlmcreatevj(const ae_int_t n, const ae_int_t m, const real_1d_array &x, minlmstate &state);
+void minlmcreatevj(const ae_int_t m, const real_1d_array &x, minlmstate &state);
+
 
 /*************************************************************************
-        NONLINEAR CONJUGATE GRADIENT METHOD
+                IMPROVED LEVENBERG-MARQUARDT METHOD FOR
+                 NON-LINEAR LEAST SQUARES OPTIMIZATION
 
 DESCRIPTION:
-The subroutine minimizes function F(x) of N arguments by using one of  the
-nonlinear conjugate gradient methods.
+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.
 
-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:
+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.
+
+  -- ALGLIB --
+     Copyright 30.03.2009 by Bochkanov Sergey
+*************************************************************************/
+void minlmcreatev(const ae_int_t n, const ae_int_t m, const real_1d_array &x, const double diffstep, minlmstate &state);
+void minlmcreatev(const ae_int_t m, const real_1d_array &x, const double diffstep, minlmstate &state);
+
+
+/*************************************************************************
+    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:
-Algorithm will request following information during its operation:
-* function value F and its gradient G (simultaneously) at given point X
+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 MinCGCreate() call
-2. User tunes solver parameters with MinCGSetCond(), MinCGSetStpMax() and
+1. User initializes algorithm state with MinLMCreateFGH() call
+2. User tunes solver parameters with MinLMSetCond(),  MinLMSetStpMax() 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
+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.
-   MinCGRestartFrom() allows to reuse already initialized structure.
+   MinLMRestartFrom() allows to reuse already initialized structure.
 
 
 INPUT PARAMETERS:
-    N       -   problem dimension, N>0:
+    N       -   dimension, N>1
                 * 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].
+    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.
+
   -- ALGLIB --
-     Copyright 25.03.2010 by Bochkanov Sergey
+     Copyright 30.03.2009 by Bochkanov Sergey
 *************************************************************************/
-void mincgcreate(const ae_int_t n, const real_1d_array &x, mincgstate &state);
-void mincgcreate(const real_1d_array &x, mincgstate &state);
+void minlmcreatefgh(const ae_int_t n, const real_1d_array &x, minlmstate &state);
+void minlmcreatefgh(const real_1d_array &x, minlmstate &state);
 
 
 /*************************************************************************
-This function sets stopping conditions for CG optimization algorithm.
+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
-                ||G||<EpsG is satisfied, where ||.|| means Euclidian norm,
-                G - gradient.
+                |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 |X(k+1)-X(k)| <= EpsX is fulfilled.
+                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.
+                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).
@@ -1829,7 +2711,7 @@ automatic stopping criterion selection (small EpsX).
   -- ALGLIB --
      Copyright 02.04.2010 by Bochkanov Sergey
 *************************************************************************/
-void mincgsetcond(const mincgstate &state, const double epsg, const double epsf, const double epsx, const ae_int_t maxits);
+void minlmsetcond(const minlmstate &state, const double epsg, const double epsf, const double epsx, const ae_int_t maxits);
 
 
 /*************************************************************************
@@ -1840,28 +2722,13 @@ INPUT PARAMETERS:
     NeedXRep-   whether iteration reports are needed or not
 
 If NeedXRep is True, algorithm will call rep() callback function if  it is
-provided to MinCGOptimize().
-
-  -- ALGLIB --
-     Copyright 02.04.2010 by Bochkanov Sergey
-*************************************************************************/
-void mincgsetxrep(const mincgstate &state, const bool needxrep);
-
-
-/*************************************************************************
-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
+provided to MinLMOptimize(). Both Levenberg-Marquardt and internal  L-BFGS
+iterations are reported.
 
   -- ALGLIB --
      Copyright 02.04.2010 by Bochkanov Sergey
 *************************************************************************/
-void mincgsetcgtype(const mincgstate &state, const ae_int_t cgtype);
+void minlmsetxrep(const minlmstate &state, const bool needxrep);
 
 
 /*************************************************************************
@@ -1878,350 +2745,304 @@ 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.
+
   -- ALGLIB --
      Copyright 02.04.2010 by Bochkanov Sergey
 *************************************************************************/
-void mincgsetstpmax(const mincgstate &state, const double stpmax);
+void minlmsetstpmax(const minlmstate &state, const double stpmax);
 
 
 /*************************************************************************
-This function allows to suggest initial step length to the CG algorithm.
+This function sets scaling coefficients for LM optimizer.
 
-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.
+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
 
-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.
+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.
 
-This function influences only first iteration of algorithm. It  should  be
-called between MinCGCreate/MinCGRestartFrom() call and MinCGOptimize call.
+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 used to store algorithm state.
-    Stp     -   initial estimate of the step length.
-                Can be zero (no estimate).
+    State   -   structure stores algorithm state
+    S       -   array[N], non-zero scaling coefficients
+                S[i] may be negative, sign doesn't matter.
 
   -- ALGLIB --
-     Copyright 30.07.2010 by Bochkanov Sergey
+     Copyright 14.01.2011 by Bochkanov Sergey
 *************************************************************************/
-void mincgsuggeststep(const mincgstate &state, const double stp);
+void minlmsetscale(const minlmstate &state, const real_1d_array &s);
 
 
 /*************************************************************************
-This function provides reverse communication interface
-Reverse communication interface is not documented or recommended to use.
-See below for functions which provide better documented API
-*************************************************************************/
-bool mincgiteration(const mincgstate &state);
+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.
 
-/*************************************************************************
-This family of functions is used to launcn iterations of nonlinear optimizer
+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).
 
-These functions accept following parameters:
-    state   -   algorithm state
-    grad    -   callback which calculates function (or merit function)
-                value func and gradient grad at given point x
-    rep     -   optional callback which is called after each iteration
-                can be NULL
-    ptr     -   optional pointer which is passed to func/grad/hess/jac/rep
-                can be NULL
+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
 
   -- ALGLIB --
-     Copyright 20.04.2009 by Bochkanov Sergey
-
+     Copyright 14.01.2011 by Bochkanov Sergey
 *************************************************************************/
-void mincgoptimize(mincgstate &state,
-    void (*grad)(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr),
-    void  (*rep)(const real_1d_array &x, double func, void *ptr) = NULL,
-    void *ptr = NULL);
+void minlmsetbc(const minlmstate &state, const real_1d_array &bndl, const real_1d_array &bndu);
 
 
 /*************************************************************************
-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
-                * Rep.IterationsCount contains iterations count
-                * NFEV countains number of function calculations
+This function is used to change acceleration settings
 
-  -- ALGLIB --
-     Copyright 20.04.2009 by Bochkanov Sergey
-*************************************************************************/
-void mincgresults(const mincgstate &state, real_1d_array &x, mincgreport &rep);
+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.
 
-/*************************************************************************
-Conjugate gradient results
+Table below list  optimization  protocols  (XYZ  protocol  corresponds  to
+MinLMCreateXYZ) and acceleration types they support (and use by  default).
 
-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.
+ACCELERATION TYPES SUPPORTED BY OPTIMIZATION PROTOCOLS:
 
-  -- ALGLIB --
-     Copyright 20.04.2009 by Bochkanov Sergey
-*************************************************************************/
-void mincgresultsbuf(const mincgstate &state, real_1d_array &x, mincgreport &rep);
+protocol    0   1   comment
+V           +   +
+VJ          +   +
+FGH         +
 
+DAFAULT VALUES:
 
-/*************************************************************************
-This  subroutine  restarts  CG  algorithm from new point. All optimization
-parameters are left unchanged.
+protocol    0   1   comment
+V               x   without acceleration it is so slooooooooow
+VJ          x
+FGH         x
 
-This  function  allows  to  solve multiple  optimization  problems  (which
-must have same number of dimensions) without object reallocation penalty.
+NOTE: this  function should be called before optimization. Attempt to call
+it during algorithm iterations may result in unexpected behavior.
 
-INPUT PARAMETERS:
-    State   -   structure used to store algorithm state.
-    X       -   new starting point.
+NOTE: attempt to call this function with unsupported protocol/acceleration
+combination will result in exception being thrown.
 
   -- ALGLIB --
-     Copyright 30.07.2010 by Bochkanov Sergey
+     Copyright 14.10.2010 by Bochkanov Sergey
 *************************************************************************/
-void mincgrestartfrom(const mincgstate &state, const real_1d_array &x);
-
-/*************************************************************************
-                     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
+void minlmsetacctype(const minlmstate &state, const ae_int_t acctype);
 
-REQUIREMENTS:
-* function value and gradient
-* grad(f) must be Lipschitz continuous on a level set: L = { x : f(x)<=f(x0) }
-* function must be defined even in the infeasible points (algorithm make take
-  steps in the infeasible area before converging to the feasible point)
-* starting point X0 must be feasible or not too far away from the feasible set
-* problem must satisfy strict complementary conditions
 
-USAGE:
+/*************************************************************************
+This function provides reverse communication interface
+Reverse communication interface is not documented or recommended to use.
+See below for functions which provide better documented API
+*************************************************************************/
+bool minlmiteration(const minlmstate &state);
 
-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
+/*************************************************************************
+This family of functions is used to launcn iterations of nonlinear optimizer
 
-2. USer adds boundary and/or linear constraints by calling
-   MinBLEICSetBC() and MinBLEICSetLC() functions.
+These functions accept following parameters:
+    state   -   algorithm state
+    func    -   callback which calculates function (or merit function)
+                value func at given point x
+    grad    -   callback which calculates function (or merit function)
+                value func and gradient grad at given point x
+    hess    -   callback which calculates function (or merit function)
+                value func, gradient grad and Hessian hess at given point x
+    fvec    -   callback which calculates function vector fi[]
+                at given point x
+    jac     -   callback which calculates function vector fi[]
+                and Jacobian jac at given point x
+    rep     -   optional callback which is called after each iteration
+                can be NULL
+    ptr     -   optional pointer which is passed to func/grad/hess/jac/rep
+                can be NULL
 
-3. User sets stopping conditions for underlying unconstrained solver
-   with MinBLEICSetInnerCond() call.
-   This function controls accuracy of underlying optimization algorithm.
+NOTES:
 
-4. User sets stopping conditions for outer iteration by calling
-   MinBLEICSetOuterCond() function.
-   This function controls handling of boundary and inequality constraints.
+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.
 
-5. User tunes barrier parameters:
-   * barrier width with MinBLEICSetBarrierWidth() call
-   * (optionally) dynamics of the barrier width with MinBLEICSetBarrierDecay() call
-   These functions control handling of boundary and inequality constraints.
+   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.
 
-6. Additionally, user may set limit on number of internal iterations
-   by MinBLEICSetMaxIts() call.
-   This function allows to prevent algorithm from looping forever.
+   Be careful to avoid such errors because there is no way to find them at
+   compile time - you can see them at runtime only.
 
-7. User calls MinBLEICOptimize() function which takes algorithm  state and
-   pointer (delegate, etc.) to callback function which calculates F/G.
+  -- ALGLIB --
+     Copyright 10.03.2009 by Bochkanov Sergey
 
-8. User calls MinBLEICResults() to get solution
+*************************************************************************/
+void minlmoptimize(minlmstate &state,
+    void (*fvec)(const real_1d_array &x, real_1d_array &fi, void *ptr),
+    void  (*rep)(const real_1d_array &x, double func, void *ptr) = NULL,
+    void *ptr = NULL);
+void minlmoptimize(minlmstate &state,
+    void (*fvec)(const real_1d_array &x, real_1d_array &fi, void *ptr),
+    void  (*jac)(const real_1d_array &x, real_1d_array &fi, real_2d_array &jac, void *ptr),
+    void  (*rep)(const real_1d_array &x, double func, void *ptr) = NULL,
+    void *ptr = NULL);
+void minlmoptimize(minlmstate &state,
+    void (*func)(const real_1d_array &x, double &func, void *ptr),
+    void (*grad)(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr),
+    void (*hess)(const real_1d_array &x, double &func, real_1d_array &grad, real_2d_array &hess, void *ptr),
+    void  (*rep)(const real_1d_array &x, double func, void *ptr) = NULL,
+    void *ptr = NULL);
+void minlmoptimize(minlmstate &state,
+    void (*func)(const real_1d_array &x, double &func, void *ptr),
+    void  (*jac)(const real_1d_array &x, real_1d_array &fi, real_2d_array &jac, void *ptr),
+    void  (*rep)(const real_1d_array &x, double func, void *ptr) = NULL,
+    void *ptr = NULL);
+void minlmoptimize(minlmstate &state,
+    void (*func)(const real_1d_array &x, double &func, void *ptr),
+    void (*grad)(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr),
+    void  (*jac)(const real_1d_array &x, real_1d_array &fi, real_2d_array &jac, void *ptr),
+    void  (*rep)(const real_1d_array &x, double func, void *ptr) = NULL,
+    void *ptr = NULL);
 
-9. Optionally user may call MinBLEICRestartFrom() to solve another problem
-   with same N but another starting point.
-   MinBLEICRestartFrom() allows to reuse already initialized structure.
 
+/*************************************************************************
+Levenberg-Marquardt algorithm results
 
 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.
+    State   -   algorithm state
 
 OUTPUT PARAMETERS:
-    State   -   structure stores algorithm state
+    X       -   array[0..N-1], solution
+    Rep     -   optimization report;
+                see comments for this structure for more info.
 
   -- ALGLIB --
-     Copyright 28.11.2010 by Bochkanov Sergey
+     Copyright 10.03.2009 by Bochkanov Sergey
 *************************************************************************/
-void minbleiccreate(const ae_int_t n, const real_1d_array &x, minbleicstate &state);
-void minbleiccreate(const real_1d_array &x, minbleicstate &state);
+void minlmresults(const minlmstate &state, real_1d_array &x, minlmreport &rep);
 
 
 /*************************************************************************
-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().
+Levenberg-Marquardt algorithm results
 
-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.
+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.
 
   -- ALGLIB --
-     Copyright 28.11.2010 by Bochkanov Sergey
+     Copyright 10.03.2009 by Bochkanov Sergey
 *************************************************************************/
-void minbleicsetbc(const minbleicstate &state, const real_1d_array &bndl, const real_1d_array &bndu);
+void minlmresultsbuf(const minlmstate &state, real_1d_array &x, minlmreport &rep);
 
 
 /*************************************************************************
-This function sets linear constraints for BLEIC optimizer.
+This  subroutine  restarts  LM  algorithm from new point. All optimization
+parameters are left unchanged.
 
-Linear constraints are inactive by default (after initial creation).
-They are preserved after algorithm restart with MinBLEICRestartFrom().
+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.
-    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
+    State   -   structure used for reverse communication previously
+                allocated with MinLMCreateXXX call.
+    X       -   new starting point.
 
   -- ALGLIB --
-     Copyright 28.11.2010 by Bochkanov Sergey
+     Copyright 30.07.2010 by Bochkanov Sergey
 *************************************************************************/
-void minbleicsetlc(const minbleicstate &state, const real_2d_array &c, const integer_1d_array &ct, const ae_int_t k);
-void minbleicsetlc(const minbleicstate &state, const real_2d_array &c, const integer_1d_array &ct);
+void minlmrestartfrom(const minlmstate &state, const real_1d_array &x);
 
 
 /*************************************************************************
-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
-                Algorithm finishes its work if 2-norm of the Lagrangian
-                gradient is less than or equal to EpsG.
-    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 |X(k+1)-X(k)| <= EpsX is fulfilled.
-
-Passing EpsG=0, EpsF=0 and EpsX=0 (simultaneously) will lead to
-automatic stopping criterion selection.
+This is obsolete function.
 
-These conditions are used to terminate inner iterations. However, you
-need to tune termination conditions for outer iterations too.
+Since ALGLIB 3.3 it is equivalent to MinLMCreateVJ().
 
   -- ALGLIB --
-     Copyright 28.11.2010 by Bochkanov Sergey
+     Copyright 30.03.2009 by Bochkanov Sergey
 *************************************************************************/
-void minbleicsetinnercond(const minbleicstate &state, const double epsg, const double epsf, const double epsx);
+void minlmcreatevgj(const ae_int_t n, const ae_int_t m, const real_1d_array &x, minlmstate &state);
+void minlmcreatevgj(const ae_int_t m, const real_1d_array &x, minlmstate &state);
 
 
 /*************************************************************************
-This function sets stopping conditions for outer iteration of BLEIC algo.
+This is obsolete function.
 
-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
+Since ALGLIB 3.3 it is equivalent to MinLMCreateFJ().
 
-Both EpsX and EpsI must be non-zero.
+  -- ALGLIB --
+     Copyright 30.03.2009 by Bochkanov Sergey
+*************************************************************************/
+void minlmcreatefgj(const ae_int_t n, const ae_int_t m, const real_1d_array &x, minlmstate &state);
+void minlmcreatefgj(const ae_int_t m, const real_1d_array &x, minlmstate &state);
 
-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.
+/*************************************************************************
+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.
 
-MEANING OF EpsI
+  -- ALGLIB --
+     Copyright 30.03.2009 by Bochkanov Sergey
+*************************************************************************/
+void minlmcreatefj(const ae_int_t n, const ae_int_t m, const real_1d_array &x, minlmstate &state);
+void minlmcreatefj(const ae_int_t m, const real_1d_array &x, minlmstate &state);
 
-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.
+/*************************************************************************
+Obsolete function, use MinLBFGSSetPrecDefault() instead.
 
   -- ALGLIB --
-     Copyright 28.11.2010 by Bochkanov Sergey
+     Copyright 13.10.2010 by Bochkanov Sergey
 *************************************************************************/
-void minbleicsetoutercond(const minbleicstate &state, const double epsx, const double epsi);
+void minlbfgssetdefaultpreconditioner(const minlbfgsstate &state);
 
 
 /*************************************************************************
-This function sets initial barrier width.
-
-BLEIC optimizer uses  modified  barrier  functions  to  handle  inequality
-constraints. These functions are almost constant in the inner parts of the
-feasible  area,  but  grow rapidly to the infinity OUTSIDE of the feasible
-area. Barrier width is a distance from feasible area to  the  point  where
-modified barrier function becomes infinite.
+Obsolete function, use MinLBFGSSetCholeskyPreconditioner() instead.
 
-Barrier width must be:
-* small enough (below some problem-dependent value) in order for algorithm
-  to  converge.  Necessary  condition  is that the target function must be
-  well described by linear model in the areas as small as barrier width.
-* not VERY small (in order to avoid  difficulties  associated  with  rapid
-  changes in the modified function, ill-conditioning, round-off issues).
+  -- ALGLIB --
+     Copyright 13.10.2010 by Bochkanov Sergey
+*************************************************************************/
+void minlbfgssetcholeskypreconditioner(const minlbfgsstate &state, const real_2d_array &p, const bool isupper);
 
-Choosing  appropriate  barrier  width  is  very  important  for  efficient
-optimization, and it often requires error  and  trial.  You  can  use  two
-strategies when choosing barrier width:
-* set barrier width with MinBLEICSetBarrierWidth() call. In this case  you
-  should try different barrier widths and examine results.
-* set decreasing barrier width by combining  MinBLEICSetBarrierWidth() and
-  MinBLEICSetBarrierDecay()  calls.  In  this case algorithm will decrease
-  barrier  width  after  each  outer iteration until it encounters optimal
-  barrier width.
 
-INPUT PARAMETERS:
-    State   -   structure which stores algorithm state
-    Mu      -   >0, initial barrier width
+/*************************************************************************
+This is obsolete function which was used by previous version of the  BLEIC
+optimizer. It does nothing in the current version of BLEIC.
 
   -- ALGLIB --
      Copyright 28.11.2010 by Bochkanov Sergey
@@ -2230,24 +3051,8 @@ void minbleicsetbarrierwidth(const minbleicstate &state, const double mu);
 
 
 /*************************************************************************
-This function sets decay coefficient for barrier width.
-
-By default, no barrier decay is used (Decay=1.0).
-
-BLEIC optimizer uses  modified  barrier  functions  to  handle  inequality
-constraints. These functions are almost constant in the inner parts of the
-feasible  area,  but  grow rapidly to the infinity OUTSIDE of the feasible
-area. Barrier width is a distance from feasible area to  the  point  where
-modified barrier function becomes infinite. Decay coefficient allows us to
-decrease  barrier  width  from  the  initial  (suboptimial)  value   until
-optimal value will be met.
-
-We recommend you either to set MuDecay=1.0 (no decay) or use some moderate
-value like 0.5-0.7
-
-INPUT PARAMETERS:
-    State   -   structure which stores algorithm state
-    MuDecay -   0<MuDecay<=1, decay coefficient
+This is obsolete function which was used by previous version of the  BLEIC
+optimizer. It does nothing in the current version of BLEIC.
 
   -- ALGLIB --
      Copyright 28.11.2010 by Bochkanov Sergey
@@ -2256,54 +3061,54 @@ void minbleicsetbarrierdecay(const minbleicstate &state, const double mudecay);
 
 
 /*************************************************************************
-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.
+Obsolete optimization algorithm.
+Was replaced by MinBLEIC subpackage.
 
   -- ALGLIB --
-     Copyright 28.11.2010 by Bochkanov Sergey
+     Copyright 25.03.2010 by Bochkanov Sergey
 *************************************************************************/
-void minbleicsetmaxits(const minbleicstate &state, const ae_int_t maxits);
+void minasacreate(const ae_int_t n, const real_1d_array &x, const real_1d_array &bndl, const real_1d_array &bndu, minasastate &state);
+void minasacreate(const real_1d_array &x, const real_1d_array &bndl, const real_1d_array &bndu, minasastate &state);
 
 
 /*************************************************************************
-This function turns on/off reporting.
+Obsolete optimization algorithm.
+Was replaced by MinBLEIC subpackage.
 
-INPUT PARAMETERS:
-    State   -   structure which stores algorithm state
-    NeedXRep-   whether iteration reports are needed or not
+  -- ALGLIB --
+     Copyright 02.04.2010 by Bochkanov Sergey
+*************************************************************************/
+void minasasetcond(const minasastate &state, const double epsg, const double epsf, const double epsx, const ae_int_t maxits);
 
-If NeedXRep is True, algorithm will call rep() callback function if  it is
-provided to MinBLEICOptimize().
+
+/*************************************************************************
+Obsolete optimization algorithm.
+Was replaced by MinBLEIC subpackage.
 
   -- ALGLIB --
-     Copyright 28.11.2010 by Bochkanov Sergey
+     Copyright 02.04.2010 by Bochkanov Sergey
 *************************************************************************/
-void minbleicsetxrep(const minbleicstate &state, const bool needxrep);
+void minasasetxrep(const minasastate &state, const bool needxrep);
 
 
 /*************************************************************************
-This function sets maximum step length
+Obsolete optimization algorithm.
+Was replaced by MinBLEIC subpackage.
 
-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.
+  -- ALGLIB --
+     Copyright 02.04.2010 by Bochkanov Sergey
+*************************************************************************/
+void minasasetalgorithm(const minasastate &state, const ae_int_t algotype);
 
-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.
+
+/*************************************************************************
+Obsolete optimization algorithm.
+Was replaced by MinBLEIC subpackage.
 
   -- ALGLIB --
      Copyright 02.04.2010 by Bochkanov Sergey
 *************************************************************************/
-void minbleicsetstpmax(const minbleicstate &state, const double stpmax);
+void minasasetstpmax(const minasastate &state, const double stpmax);
 
 
 /*************************************************************************
@@ -2311,7 +3116,7 @@ This function provides reverse communication interface
 Reverse communication interface is not documented or recommended to use.
 See below for functions which provide better documented API
 *************************************************************************/
-bool minbleiciteration(const minbleicstate &state);
+bool minasaiteration(const minasastate &state);
 
 
 /*************************************************************************
@@ -2328,75 +3133,43 @@ These functions accept following parameters:
 
 
   -- ALGLIB --
-     Copyright 28.11.2010 by Bochkanov Sergey
+     Copyright 20.03.2009 by Bochkanov Sergey
 
 *************************************************************************/
-void minbleicoptimize(minbleicstate &state,
+void minasaoptimize(minasastate &state,
     void (*grad)(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr),
     void  (*rep)(const real_1d_array &x, double func, void *ptr) = NULL,
     void *ptr = NULL);
 
 
 /*************************************************************************
-BLEIC results
-
-INPUT PARAMETERS:
-    State   -   algorithm state
-
-OUTPUT PARAMETERS:
-    X       -   array[0..N-1], solution
-    Rep     -   optimization report:
-                * Rep.TerminationType completetion code:
-                    * -3    inconsistent constraints. Feasible point is
-                            either nonexistent or too hard to find. Try to
-                            restart optimizer with better initial
-                            approximation
-                    * -2    rounding errors prevent further improvement.
-                            X contains best point found.
-                    *  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.
-                * Rep.IterationsCount contains iterations count
-                * NFEV countains number of function calculations
+Obsolete optimization algorithm.
+Was replaced by MinBLEIC subpackage.
 
   -- ALGLIB --
-     Copyright 28.11.2010 by Bochkanov Sergey
+     Copyright 20.03.2009 by Bochkanov Sergey
 *************************************************************************/
-void minbleicresults(const minbleicstate &state, real_1d_array &x, minbleicreport &rep);
+void minasaresults(const minasastate &state, real_1d_array &x, minasareport &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.
+Obsolete optimization algorithm.
+Was replaced by MinBLEIC subpackage.
 
   -- ALGLIB --
-     Copyright 28.11.2010 by Bochkanov Sergey
+     Copyright 20.03.2009 by Bochkanov Sergey
 *************************************************************************/
-void minbleicresultsbuf(const minbleicstate &state, real_1d_array &x, minbleicreport &rep);
+void minasaresultsbuf(const minasastate &state, real_1d_array &x, minasareport &rep);
 
 
 /*************************************************************************
-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.
+Obsolete optimization algorithm.
+Was replaced by MinBLEIC subpackage.
 
   -- ALGLIB --
-     Copyright 28.11.2010 by Bochkanov Sergey
+     Copyright 30.07.2010 by Bochkanov Sergey
 *************************************************************************/
-void minbleicrestartfrom(const minbleicstate &state, const real_1d_array &x);
+void minasarestartfrom(const minasastate &state, const real_1d_array &x, const real_1d_array &bndl, const real_1d_array &bndu);
 }
 
 /////////////////////////////////////////////////////////////////////////
@@ -2406,11 +3179,137 @@ void minbleicrestartfrom(const minbleicstate &state, const real_1d_array &x);
 /////////////////////////////////////////////////////////////////////////
 namespace alglib_impl
 {
+void mincgcreate(ae_int_t n,
+     /* Real    */ ae_vector* x,
+     mincgstate* state,
+     ae_state *_state);
+void mincgcreatef(ae_int_t n,
+     /* Real    */ ae_vector* x,
+     double diffstep,
+     mincgstate* state,
+     ae_state *_state);
+void mincgsetcond(mincgstate* state,
+     double epsg,
+     double epsf,
+     double epsx,
+     ae_int_t maxits,
+     ae_state *_state);
+void mincgsetscale(mincgstate* state,
+     /* Real    */ ae_vector* s,
+     ae_state *_state);
+void mincgsetxrep(mincgstate* state, ae_bool needxrep, ae_state *_state);
+void mincgsetdrep(mincgstate* state, ae_bool needdrep, ae_state *_state);
+void mincgsetcgtype(mincgstate* state, ae_int_t cgtype, ae_state *_state);
+void mincgsetstpmax(mincgstate* state, double stpmax, ae_state *_state);
+void mincgsuggeststep(mincgstate* state, double stp, ae_state *_state);
+void mincgsetprecdefault(mincgstate* state, ae_state *_state);
+void mincgsetprecdiag(mincgstate* state,
+     /* Real    */ ae_vector* d,
+     ae_state *_state);
+void mincgsetprecscale(mincgstate* state, ae_state *_state);
+ae_bool mincgiteration(mincgstate* state, ae_state *_state);
+void mincgresults(mincgstate* state,
+     /* Real    */ ae_vector* x,
+     mincgreport* rep,
+     ae_state *_state);
+void mincgresultsbuf(mincgstate* state,
+     /* Real    */ ae_vector* x,
+     mincgreport* rep,
+     ae_state *_state);
+void mincgrestartfrom(mincgstate* state,
+     /* Real    */ ae_vector* x,
+     ae_state *_state);
+void mincgsetprecdiagfast(mincgstate* state,
+     /* Real    */ ae_vector* d,
+     ae_state *_state);
+void mincgsetpreclowrankfast(mincgstate* state,
+     /* Real    */ ae_vector* d1,
+     /* Real    */ ae_vector* c,
+     /* Real    */ ae_matrix* v,
+     ae_int_t vcnt,
+     ae_state *_state);
+void mincgsetprecvarpart(mincgstate* state,
+     /* Real    */ ae_vector* d2,
+     ae_state *_state);
+ae_bool _mincgstate_init(mincgstate* p, ae_state *_state, ae_bool make_automatic);
+ae_bool _mincgstate_init_copy(mincgstate* dst, mincgstate* src, ae_state *_state, ae_bool make_automatic);
+void _mincgstate_clear(mincgstate* p);
+ae_bool _mincgreport_init(mincgreport* p, ae_state *_state, ae_bool make_automatic);
+ae_bool _mincgreport_init_copy(mincgreport* dst, mincgreport* src, ae_state *_state, ae_bool make_automatic);
+void _mincgreport_clear(mincgreport* p);
+void minbleiccreate(ae_int_t n,
+     /* Real    */ ae_vector* x,
+     minbleicstate* state,
+     ae_state *_state);
+void minbleiccreatef(ae_int_t n,
+     /* Real    */ ae_vector* x,
+     double diffstep,
+     minbleicstate* state,
+     ae_state *_state);
+void minbleicsetbc(minbleicstate* state,
+     /* Real    */ ae_vector* bndl,
+     /* Real    */ ae_vector* bndu,
+     ae_state *_state);
+void minbleicsetlc(minbleicstate* state,
+     /* Real    */ ae_matrix* c,
+     /* Integer */ ae_vector* ct,
+     ae_int_t k,
+     ae_state *_state);
+void minbleicsetinnercond(minbleicstate* state,
+     double epsg,
+     double epsf,
+     double epsx,
+     ae_state *_state);
+void minbleicsetoutercond(minbleicstate* state,
+     double epsx,
+     double epsi,
+     ae_state *_state);
+void minbleicsetscale(minbleicstate* state,
+     /* Real    */ ae_vector* s,
+     ae_state *_state);
+void minbleicsetprecdefault(minbleicstate* state, ae_state *_state);
+void minbleicsetprecdiag(minbleicstate* state,
+     /* Real    */ ae_vector* d,
+     ae_state *_state);
+void minbleicsetprecscale(minbleicstate* state, ae_state *_state);
+void minbleicsetmaxits(minbleicstate* state,
+     ae_int_t maxits,
+     ae_state *_state);
+void minbleicsetxrep(minbleicstate* state,
+     ae_bool needxrep,
+     ae_state *_state);
+void minbleicsetstpmax(minbleicstate* state,
+     double stpmax,
+     ae_state *_state);
+ae_bool minbleiciteration(minbleicstate* state, ae_state *_state);
+void minbleicresults(minbleicstate* state,
+     /* Real    */ ae_vector* x,
+     minbleicreport* rep,
+     ae_state *_state);
+void minbleicresultsbuf(minbleicstate* state,
+     /* Real    */ ae_vector* x,
+     minbleicreport* rep,
+     ae_state *_state);
+void minbleicrestartfrom(minbleicstate* state,
+     /* Real    */ ae_vector* x,
+     ae_state *_state);
+ae_bool _minbleicstate_init(minbleicstate* p, ae_state *_state, ae_bool make_automatic);
+ae_bool _minbleicstate_init_copy(minbleicstate* dst, minbleicstate* src, ae_state *_state, ae_bool make_automatic);
+void _minbleicstate_clear(minbleicstate* p);
+ae_bool _minbleicreport_init(minbleicreport* p, ae_state *_state, ae_bool make_automatic);
+ae_bool _minbleicreport_init_copy(minbleicreport* dst, minbleicreport* src, ae_state *_state, ae_bool make_automatic);
+void _minbleicreport_clear(minbleicreport* p);
 void minlbfgscreate(ae_int_t n,
      ae_int_t m,
      /* Real    */ ae_vector* x,
      minlbfgsstate* state,
      ae_state *_state);
+void minlbfgscreatef(ae_int_t n,
+     ae_int_t m,
+     /* Real    */ ae_vector* x,
+     double diffstep,
+     minlbfgsstate* state,
+     ae_state *_state);
 void minlbfgssetcond(minlbfgsstate* state,
      double epsg,
      double epsf,
@@ -2423,18 +3322,25 @@ void minlbfgssetxrep(minlbfgsstate* state,
 void minlbfgssetstpmax(minlbfgsstate* state,
      double stpmax,
      ae_state *_state);
+void minlbfgssetscale(minlbfgsstate* state,
+     /* Real    */ ae_vector* s,
+     ae_state *_state);
 void minlbfgscreatex(ae_int_t n,
      ae_int_t m,
      /* Real    */ ae_vector* x,
      ae_int_t flags,
+     double diffstep,
      minlbfgsstate* state,
      ae_state *_state);
-void minlbfgssetdefaultpreconditioner(minlbfgsstate* state,
-     ae_state *_state);
-void minlbfgssetcholeskypreconditioner(minlbfgsstate* state,
+void minlbfgssetprecdefault(minlbfgsstate* state, ae_state *_state);
+void minlbfgssetpreccholesky(minlbfgsstate* state,
      /* Real    */ ae_matrix* p,
      ae_bool isupper,
      ae_state *_state);
+void minlbfgssetprecdiag(minlbfgsstate* state,
+     /* Real    */ ae_vector* d,
+     ae_state *_state);
+void minlbfgssetprecscale(minlbfgsstate* state, ae_state *_state);
 ae_bool minlbfgsiteration(minlbfgsstate* state, ae_state *_state);
 void minlbfgsresults(minlbfgsstate* state,
      /* Real    */ ae_vector* x,
@@ -2453,33 +3359,69 @@ void _minlbfgsstate_clear(minlbfgsstate* p);
 ae_bool _minlbfgsreport_init(minlbfgsreport* p, ae_state *_state, ae_bool make_automatic);
 ae_bool _minlbfgsreport_init_copy(minlbfgsreport* dst, minlbfgsreport* src, ae_state *_state, ae_bool make_automatic);
 void _minlbfgsreport_clear(minlbfgsreport* p);
-void minlmcreatevj(ae_int_t n,
-     ae_int_t m,
+void minqpcreate(ae_int_t n, minqpstate* state, ae_state *_state);
+void minqpsetlinearterm(minqpstate* state,
+     /* Real    */ ae_vector* b,
+     ae_state *_state);
+void minqpsetquadraticterm(minqpstate* state,
+     /* Real    */ ae_matrix* a,
+     ae_bool isupper,
+     ae_state *_state);
+void minqpsetstartingpoint(minqpstate* state,
      /* Real    */ ae_vector* x,
-     minlmstate* state,
      ae_state *_state);
-void minlmcreatev(ae_int_t n,
-     ae_int_t m,
+void minqpsetorigin(minqpstate* state,
+     /* Real    */ ae_vector* xorigin,
+     ae_state *_state);
+void minqpsetalgocholesky(minqpstate* state, ae_state *_state);
+void minqpsetbc(minqpstate* state,
+     /* Real    */ ae_vector* bndl,
+     /* Real    */ ae_vector* bndu,
+     ae_state *_state);
+void minqpoptimize(minqpstate* state, ae_state *_state);
+void minqpresults(minqpstate* state,
      /* Real    */ ae_vector* x,
-     double diffstep,
-     minlmstate* state,
+     minqpreport* rep,
      ae_state *_state);
-void minlmcreatefgh(ae_int_t n,
+void minqpresultsbuf(minqpstate* state,
      /* Real    */ ae_vector* x,
-     minlmstate* state,
+     minqpreport* rep,
      ae_state *_state);
-void minlmcreatevgj(ae_int_t n,
+void minqpsetlineartermfast(minqpstate* state,
+     /* Real    */ ae_vector* b,
+     ae_state *_state);
+void minqpsetquadratictermfast(minqpstate* state,
+     /* Real    */ ae_matrix* a,
+     ae_bool isupper,
+     double s,
+     ae_state *_state);
+void minqprewritediagonal(minqpstate* state,
+     /* Real    */ ae_vector* s,
+     ae_state *_state);
+void minqpsetstartingpointfast(minqpstate* state,
+     /* Real    */ ae_vector* x,
+     ae_state *_state);
+void minqpsetoriginfast(minqpstate* state,
+     /* Real    */ ae_vector* xorigin,
+     ae_state *_state);
+ae_bool _minqpstate_init(minqpstate* p, ae_state *_state, ae_bool make_automatic);
+ae_bool _minqpstate_init_copy(minqpstate* dst, minqpstate* src, ae_state *_state, ae_bool make_automatic);
+void _minqpstate_clear(minqpstate* p);
+ae_bool _minqpreport_init(minqpreport* p, ae_state *_state, ae_bool make_automatic);
+ae_bool _minqpreport_init_copy(minqpreport* dst, minqpreport* src, ae_state *_state, ae_bool make_automatic);
+void _minqpreport_clear(minqpreport* p);
+void minlmcreatevj(ae_int_t n,
      ae_int_t m,
      /* Real    */ ae_vector* x,
      minlmstate* state,
      ae_state *_state);
-void minlmcreatefgj(ae_int_t n,
+void minlmcreatev(ae_int_t n,
      ae_int_t m,
      /* Real    */ ae_vector* x,
+     double diffstep,
      minlmstate* state,
      ae_state *_state);
-void minlmcreatefj(ae_int_t n,
-     ae_int_t m,
+void minlmcreatefgh(ae_int_t n,
      /* Real    */ ae_vector* x,
      minlmstate* state,
      ae_state *_state);
@@ -2491,6 +3433,13 @@ void minlmsetcond(minlmstate* state,
      ae_state *_state);
 void minlmsetxrep(minlmstate* state, ae_bool needxrep, ae_state *_state);
 void minlmsetstpmax(minlmstate* state, double stpmax, ae_state *_state);
+void minlmsetscale(minlmstate* state,
+     /* Real    */ ae_vector* s,
+     ae_state *_state);
+void minlmsetbc(minlmstate* state,
+     /* Real    */ ae_vector* bndl,
+     /* Real    */ ae_vector* bndu,
+     ae_state *_state);
 void minlmsetacctype(minlmstate* state,
      ae_int_t acctype,
      ae_state *_state);
@@ -2506,12 +3455,39 @@ void minlmresultsbuf(minlmstate* state,
 void minlmrestartfrom(minlmstate* state,
      /* Real    */ ae_vector* x,
      ae_state *_state);
+void minlmcreatevgj(ae_int_t n,
+     ae_int_t m,
+     /* Real    */ ae_vector* x,
+     minlmstate* state,
+     ae_state *_state);
+void minlmcreatefgj(ae_int_t n,
+     ae_int_t m,
+     /* Real    */ ae_vector* x,
+     minlmstate* state,
+     ae_state *_state);
+void minlmcreatefj(ae_int_t n,
+     ae_int_t m,
+     /* Real    */ ae_vector* x,
+     minlmstate* state,
+     ae_state *_state);
 ae_bool _minlmstate_init(minlmstate* p, ae_state *_state, ae_bool make_automatic);
 ae_bool _minlmstate_init_copy(minlmstate* dst, minlmstate* src, ae_state *_state, ae_bool make_automatic);
 void _minlmstate_clear(minlmstate* p);
 ae_bool _minlmreport_init(minlmreport* p, ae_state *_state, ae_bool make_automatic);
 ae_bool _minlmreport_init_copy(minlmreport* dst, minlmreport* src, ae_state *_state, ae_bool make_automatic);
 void _minlmreport_clear(minlmreport* p);
+void minlbfgssetdefaultpreconditioner(minlbfgsstate* state,
+     ae_state *_state);
+void minlbfgssetcholeskypreconditioner(minlbfgsstate* state,
+     /* Real    */ ae_matrix* p,
+     ae_bool isupper,
+     ae_state *_state);
+void minbleicsetbarrierwidth(minbleicstate* state,
+     double mu,
+     ae_state *_state);
+void minbleicsetbarrierdecay(minbleicstate* state,
+     double mudecay,
+     ae_state *_state);
 void minasacreate(ae_int_t n,
      /* Real    */ ae_vector* x,
      /* Real    */ ae_vector* bndl,
@@ -2549,100 +3525,6 @@ void _minasastate_clear(minasastate* p);
 ae_bool _minasareport_init(minasareport* p, ae_state *_state, ae_bool make_automatic);
 ae_bool _minasareport_init_copy(minasareport* dst, minasareport* src, ae_state *_state, ae_bool make_automatic);
 void _minasareport_clear(minasareport* p);
-void mincgcreate(ae_int_t n,
-     /* Real    */ ae_vector* x,
-     mincgstate* state,
-     ae_state *_state);
-void mincgsetcond(mincgstate* state,
-     double epsg,
-     double epsf,
-     double epsx,
-     ae_int_t maxits,
-     ae_state *_state);
-void mincgsetxrep(mincgstate* state, ae_bool needxrep, ae_state *_state);
-void mincgsetdrep(mincgstate* state, ae_bool needdrep, ae_state *_state);
-void mincgsetcgtype(mincgstate* state, ae_int_t cgtype, ae_state *_state);
-void mincgsetstpmax(mincgstate* state, double stpmax, ae_state *_state);
-void mincgsuggeststep(mincgstate* state, double stp, ae_state *_state);
-ae_bool mincgiteration(mincgstate* state, ae_state *_state);
-void mincgresults(mincgstate* state,
-     /* Real    */ ae_vector* x,
-     mincgreport* rep,
-     ae_state *_state);
-void mincgresultsbuf(mincgstate* state,
-     /* Real    */ ae_vector* x,
-     mincgreport* rep,
-     ae_state *_state);
-void mincgrestartfrom(mincgstate* state,
-     /* Real    */ ae_vector* x,
-     ae_state *_state);
-ae_bool _mincgstate_init(mincgstate* p, ae_state *_state, ae_bool make_automatic);
-ae_bool _mincgstate_init_copy(mincgstate* dst, mincgstate* src, ae_state *_state, ae_bool make_automatic);
-void _mincgstate_clear(mincgstate* p);
-ae_bool _mincgreport_init(mincgreport* p, ae_state *_state, ae_bool make_automatic);
-ae_bool _mincgreport_init_copy(mincgreport* dst, mincgreport* src, ae_state *_state, ae_bool make_automatic);
-void _mincgreport_clear(mincgreport* p);
-void minbleiccreate(ae_int_t n,
-     /* Real    */ ae_vector* x,
-     minbleicstate* state,
-     ae_state *_state);
-void minbleicsetbc(minbleicstate* state,
-     /* Real    */ ae_vector* bndl,
-     /* Real    */ ae_vector* bndu,
-     ae_state *_state);
-void minbleicsetlc(minbleicstate* state,
-     /* Real    */ ae_matrix* c,
-     /* Integer */ ae_vector* ct,
-     ae_int_t k,
-     ae_state *_state);
-void minbleicsetinnercond(minbleicstate* state,
-     double epsg,
-     double epsf,
-     double epsx,
-     ae_state *_state);
-void minbleicsetoutercond(minbleicstate* state,
-     double epsx,
-     double epsi,
-     ae_state *_state);
-void minbleicsetbarrierwidth(minbleicstate* state,
-     double mu,
-     ae_state *_state);
-void minbleicsetbarrierdecay(minbleicstate* state,
-     double mudecay,
-     ae_state *_state);
-void minbleicsetmaxits(minbleicstate* state,
-     ae_int_t maxits,
-     ae_state *_state);
-void minbleicsetxrep(minbleicstate* state,
-     ae_bool needxrep,
-     ae_state *_state);
-void minbleicsetstpmax(minbleicstate* state,
-     double stpmax,
-     ae_state *_state);
-ae_bool minbleiciteration(minbleicstate* state, ae_state *_state);
-void minbleicresults(minbleicstate* state,
-     /* Real    */ ae_vector* x,
-     minbleicreport* rep,
-     ae_state *_state);
-void minbleicresultsbuf(minbleicstate* state,
-     /* Real    */ ae_vector* x,
-     minbleicreport* rep,
-     ae_state *_state);
-void minbleicrestartfrom(minbleicstate* state,
-     /* Real    */ ae_vector* x,
-     ae_state *_state);
-void barrierfunc(double x,
-     double mu,
-     double* f,
-     double* df,
-     double* d2f,
-     ae_state *_state);
-ae_bool _minbleicstate_init(minbleicstate* p, ae_state *_state, ae_bool make_automatic);
-ae_bool _minbleicstate_init_copy(minbleicstate* dst, minbleicstate* src, ae_state *_state, ae_bool make_automatic);
-void _minbleicstate_clear(minbleicstate* p);
-ae_bool _minbleicreport_init(minbleicreport* p, ae_state *_state, ae_bool make_automatic);
-ae_bool _minbleicreport_init_copy(minbleicreport* dst, minbleicreport* src, ae_state *_state, ae_bool make_automatic);
-void _minbleicreport_clear(minbleicreport* p);
 
 }
 #endif
diff --git a/gmshpy/CMakeLists.txt b/gmshpy/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..446992475c61f24e4a56f8cf385dde867829af0f
--- /dev/null
+++ b/gmshpy/CMakeLists.txt
@@ -0,0 +1,92 @@
+# Gmsh - Copyright (C) 1997-2012 C. Geuzaine, J.-F. Remacle
+#
+# See the LICENSE.txt file for license information. Please report all
+# bugs and problems to <gmsh@geuz.org>.
+
+set(SWIG_MODULES
+  gmshCommon
+  gmshGeo
+  gmshNumeric
+  gmshPost
+  gmshSolver
+  gmshMesh
+)
+
+# code backported from CMake git version, see CMake bug 4147
+MACRO(SWIG_GET_WRAPPER_DEPENDENCIES swigFile genWrapper language DEST_VARIABLE)
+  GET_FILENAME_COMPONENT(swig_getdeps_basename ${swigFile} NAME_WE)
+  GET_FILENAME_COMPONENT(swig_getdeps_outdir ${genWrapper} PATH)
+  GET_SOURCE_FILE_PROPERTY(swig_getdeps_extra_flags "${swigFile}" SWIG_FLAGS)
+  IF("${swig_getdeps_extra_flags}" STREQUAL "NOTFOUND")
+    SET(swig_getdeps_extra_flags "")
+  ENDIF("${swig_getdeps_extra_flags}" STREQUAL "NOTFOUND")
+  IF(NOT swig_getdeps_outdir)
+    SET(swig_getdeps_outdir ${CMAKE_CURRENT_BINARY_DIR})
+  ENDIF(NOT swig_getdeps_outdir)
+  SET(swig_getdeps_depsfile
+    ${swig_getdeps_outdir}/swig_${swig_getdeps_basename}_deps.txt)
+  GET_DIRECTORY_PROPERTY(swig_getdeps_include_directories INCLUDE_DIRECTORIES)
+  SET(swig_getdeps_include_dirs)
+  FOREACH(it ${swig_getdeps_include_directories})
+    SET(swig_getdeps_include_dirs ${swig_getdeps_include_dirs} "-I${it}")
+  ENDFOREACH(it)
+  EXECUTE_PROCESS(
+    COMMAND ${SWIG_EXECUTABLE}
+    -MM -MF ${swig_getdeps_depsfile} ${swig_getdeps_extra_flags}
+    ${CMAKE_SWIG_FLAGS} -${language}
+    -o ${genWrapper} ${swig_getdeps_include_dirs} ${swigFile}
+    RESULT_VARIABLE swig_getdeps_result
+    ERROR_VARIABLE swig_getdeps_error
+    OUTPUT_STRIP_TRAILING_WHITESPACE)
+  IF(NOT ${swig_getdeps_error} EQUAL 0)
+    MESSAGE(SEND_ERROR "Command \"${SWIG_EXECUTABLE} -MM -MF ${swig_getdeps_depsfile} ${swig_getdeps_extra_flags} ${CMAKE_SWIG_FLAGS} -${language} -o ${genWrapper} ${swig_getdeps_include_dirs} ${swigFile}\" failed with output:\n${swig_getdeps_error}")
+    SET(swig_getdeps_dependencies "")
+  ELSE(NOT ${swig_getdeps_error} EQUAL 0)
+    FILE(READ ${swig_getdeps_depsfile} ${DEST_VARIABLE})
+    # Remove the first line
+    STRING(REGEX REPLACE "^.+: +\\\\\n +" ""
+      ${DEST_VARIABLE} "${${DEST_VARIABLE}}")
+    # Clean the end of each line
+    STRING(REGEX REPLACE " +(\\\\)?\n" "\n" ${DEST_VARIABLE}
+      "${${DEST_VARIABLE}}")
+    # Clean beginning of each line
+    STRING(REGEX REPLACE "\n +" "\n"
+      ${DEST_VARIABLE} "${${DEST_VARIABLE}}")
+    # clean paths
+    STRING(REGEX REPLACE "\\\\\\\\" "/" ${DEST_VARIABLE}
+      "${${DEST_VARIABLE}}")
+    STRING(REGEX REPLACE "\n" ";"
+      ${DEST_VARIABLE} "${${DEST_VARIABLE}}")
+  ENDIF(NOT ${swig_getdeps_error} EQUAL 0)
+ENDMACRO(SWIG_GET_WRAPPER_DEPENDENCIES)
+
+option(ENABLE_PYTHON_LIB_API "Export all C header files needed to build the python library" OFF)
+if(ENABLE_PYTHON_LIB_API)
+  set(GMSH_API ${GMSH_API} Geo/Curvature.h Mesh/Generator.h Mesh/highOrderTools.h
+      Mesh/meshGFaceLloyd.h Numeric/DivideAndConquer.h Post/PViewFactory.h
+      Solver/linearSystemPETSc.h Fltk/FlGui.h Solver/functionSpace.h
+      Solver/STensor43.h Solver/sparsityPattern.h Solver/SElement.h
+      Solver/groupOfElements.h PARENT_SCOPE)
+endif(ENABLE_PYTHON_LIB_API)
+
+include(${SWIG_USE_FILE})
+include_directories(${PYTHON_INCLUDE_PATH})
+
+foreach(module ${SWIG_MODULES})
+  set_source_files_properties(${module}.i PROPERTIES CPLUSPLUS ON)
+
+  # code backported from CMake git version, see CMake bug 4147
+  swig_get_wrapper_dependencies(${CMAKE_CURRENT_SOURCE_DIR}/\${module}.i 
+    ${CMAKE_CURRENT_BINARY_DIR}/${module}PYTHON_wrap.cxx python swig_extra_dependencies)
+  list(APPEND SWIG_MODULE_${module}_EXTRA_DEPS ${swig_extra_dependencies})
+  swig_add_module(${module} python ${module}.i)
+  swig_link_libraries(${module} ${PYTHON_LIBRARIES} shared)
+  set(GMSH_PYTHON_MODULES_INCLUDE_CODE 
+      "${GMSH_PYTHON_MODULES_INCLUDE_CODE}from ${module} import *\n")
+  list(APPEND GMSHPY_DEPENDS "_${module}")
+endforeach(module)
+
+add_custom_target("_gmshpy" DEPENDS ${GMSHPY_DEPENDS})
+
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/__init__.py.in 
+               ${CMAKE_CURRENT_BINARY_DIR}/__init__.py)
diff --git a/gmshpy/__init__.py.in b/gmshpy/__init__.py.in
new file mode 100644
index 0000000000000000000000000000000000000000..2bab66ff3b161358874f2b607ec889651300e74a
--- /dev/null
+++ b/gmshpy/__init__.py.in
@@ -0,0 +1,5 @@
+# set Ctrl-C to default signal (terminates immediately)
+import signal
+signal.signal(signal.SIGINT, signal.SIG_DFL)
+${GMSH_PYTHON_MODULES_INCLUDE_CODE}
+GmshInitialize()
diff --git a/gmshpy/gmshCommon.i b/gmshpy/gmshCommon.i
new file mode 100644
index 0000000000000000000000000000000000000000..24f4ebd197393e2a2f4cc71bb63f73c8ec8edeb6
--- /dev/null
+++ b/gmshpy/gmshCommon.i
@@ -0,0 +1,53 @@
+%feature("autodoc", "1");
+%module gmshCommon
+
+%include std_string.i
+%include std_vector.i
+%include cpointer.i 
+
+%{
+  #include "GmshConfig.h"
+
+  #include "Context.h"
+  #include "Gmsh.h"
+  #include "GmshDefines.h"
+  #include "GmshMessage.h"
+#if defined(HAVE_FLTK)
+  #include "FlGui.h"
+#endif
+  class errorHandler: public GmshMessage {
+    void operator()(std::string level, std::string message){
+#if defined(HAVE_FLTK)
+      // don't output anything special if we're running in a gui
+      if(FlGui::available()) return;
+#endif
+      std::cout<<level<<" : "<<message<<std::endl;
+      if (level == "Fatal") 
+        Msg::Exit(1);
+    }
+  };
+%}
+
+%init %{
+  errorHandler *eH = new errorHandler;
+  Msg::SetCallback(eH);
+%}
+
+namespace std {
+  %template(IntVector) std::vector<int>;
+  %template(DoubleVector) std::vector<double, std::allocator<double> >;
+  %template(DoubleVectorVector) std::vector<std::vector<double, std::allocator<double> > >;
+  %template(StringVector) std::vector<std::string, std::allocator<std::string> >;
+}
+%pointer_functions(double,doublep)
+%pointer_functions(int,intp)
+
+%include "GmshConfig.h"
+
+%include "Context.h"
+#if defined(HAVE_FLTK)
+%include "FlGui.h"
+#endif
+%include "Gmsh.h"
+%include "GmshDefines.h"
+%include "GmshMessage.h"
diff --git a/gmshpy/gmshGeo.i b/gmshpy/gmshGeo.i
new file mode 100644
index 0000000000000000000000000000000000000000..2fbcf2a9639e04ddc91b7e8cdf8c716998dcd263
--- /dev/null
+++ b/gmshpy/gmshGeo.i
@@ -0,0 +1,85 @@
+%feature("autodoc", "1");
+%module gmshGeo
+
+%include std_string.i
+%include std_list.i
+%include std_vector.i
+%import "gmshCommon.i"
+
+%{
+  #include "GmshConfig.h"
+
+  #include "GModel.h"
+  #include "GPoint.h"  
+  #include "GEntity.h"
+  #include "GVertex.h"
+  #include "GEdge.h"
+  #include "GFace.h"
+  #include "GRegion.h"
+  #include "GPoint.h"
+  #include "discreteFace.h"
+  #include "discreteEdge.h"
+  #include "discreteRegion.h"
+  #include "discreteVertex.h"
+  #include "gmshLevelset.h"
+  #include "MElement.h"
+  #include "MVertex.h"
+  #include "MTriangle.h"
+  #include "MPrism.h"
+  #include "MQuadrangle.h"
+  #include "MLine.h"
+  #include "MEdge.h"
+  #include "MFace.h"
+  #include "MPoint.h"
+  #include "SVector3.h"
+  #include "SPoint3.h"
+  #include "SPoint2.h"
+  #include "SBoundingBox3d.h"
+  #include "Curvature.h"
+%}
+
+namespace std {
+  %template(GEntityVector) vector<GEntity*, std::allocator<GEntity*> >;
+  %template(GVertexVector) vector<GVertex*, std::allocator<GVertex*> >;
+  %template(GEdgeVector) vector<GEdge*, std::allocator<GEdge*> >;
+  %template(GFaceVector) vector<GFace*, std::allocator<GFace*> >;
+  %template(GRegionVector) vector<GRegion*, std::allocator<GRegion*> >;
+  %template(MVertexVector) vector< MVertex *,std::allocator< MVertex * > >;
+  %template(MElementVector) vector< MElement *,std::allocator< MElement * > >;
+  %template(GEdgeVectorVector) vector< std::vector< GEdge *,std::allocator< GEdge * > >,std::allocator< std::vector< GEdge *,std::allocator< GEdge * > > > >;
+  %template(GFaceVectorVector) vector< std::vector< GFace *,std::allocator< GFace * > >,std::allocator< std::vector< GFace *,std::allocator< GFace * > > > >;
+  %template(GFaceList) list<GFace*, std::allocator<GFace*> >;
+  %template(GEdgeList) list<GEdge*, std::allocator<GEdge*> >;
+  %template(GLevelsetVector) vector<gLevelset *, std::allocator<gLevelset *> >;
+}
+
+%include "GmshConfig.h"
+
+%include "GModel.h"
+%include "GPoint.h"  
+%include "GEntity.h"
+%include "GVertex.h"
+%include "GEdge.h"
+%include "GFace.h"
+%include "GRegion.h"
+%include "GPoint.h"
+%include "discreteFace.h"
+%include "discreteEdge.h"
+%include "discreteVertex.h"
+%include "discreteRegion.h"
+%include "MElement.h"
+%include "MVertex.h"
+%include "MTriangle.h"
+%include "MPrism.h"
+%include "MQuadrangle.h"
+%include "MLine.h"
+%include "MEdge.h"
+%include "MFace.h"
+%include "MPoint.h"
+%include "SVector3.h"
+%include "SPoint3.h"
+%include "SPoint2.h"
+%include "SBoundingBox3d.h"
+%include "Curvature.h"
+%include "gmshLevelset.h"
+
diff --git a/gmshpy/gmshMesh.i b/gmshpy/gmshMesh.i
new file mode 100644
index 0000000000000000000000000000000000000000..be0b5c0dc3a3260b784de331e6bed834e5e17e68
--- /dev/null
+++ b/gmshpy/gmshMesh.i
@@ -0,0 +1,28 @@
+%feature("autodoc", "1");
+%module gmshMesh
+%include std_string.i
+
+%{
+  #include "GmshConfig.h"
+  #include "Generator.h"
+  #include "highOrderTools.h"
+  #include "meshGFaceLloyd.h"
+  #include "meshGFaceOptimize.h"
+  #include "meshPartitionOptions.h"
+  #include "simple3D.h"
+  #include "Voronoi3D.h"
+  #include "Levy3D.h"
+  #include "periodical.h"
+%}
+
+%include "GmshConfig.h"
+%include "Generator.h"
+%include "highOrderTools.h"
+%include "meshGFaceLloyd.h"
+%include "meshGFaceOptimize.h"
+%include "meshPartitionOptions.h"
+%include "simple3D.h"
+%include "Voronoi3D.h"
+%include "Levy3D.h"
+%include "periodical.h"
+
diff --git a/gmshpy/gmshNumeric.i b/gmshpy/gmshNumeric.i
new file mode 100644
index 0000000000000000000000000000000000000000..6d0a1653e63591412c8e6d0a4f75d5230664f139
--- /dev/null
+++ b/gmshpy/gmshNumeric.i
@@ -0,0 +1,23 @@
+%feature("autodoc", "1");
+%module gmshNumeric
+
+%include std_string.i
+%include std_vector.i
+
+%{
+  #include "GmshConfig.h"
+
+  #include "DivideAndConquer.h"
+  #include "GaussIntegration.h"
+  #include "JacobianBasis.h"
+  #include "fullMatrix.h"
+  #include "polynomialBasis.h"
+%}
+
+%include "DivideAndConquer.h"
+%include "GaussIntegration.h"
+%include "JacobianBasis.h"  
+%include "fullMatrix.h"
+%template(fullMatrixDouble) fullMatrix<double>;
+%template(fullVectorDouble) fullVector<double>;
+%include "polynomialBasis.h"
diff --git a/gmshpy/gmshPost.i b/gmshpy/gmshPost.i
new file mode 100644
index 0000000000000000000000000000000000000000..db5e70c9d0378e8dae079b17dd0953665f7d1650
--- /dev/null
+++ b/gmshpy/gmshPost.i
@@ -0,0 +1,21 @@
+%feature("autodoc", "1");
+%module gmshPost
+%include typemaps.i
+%include std_string.i
+
+%{
+  #include "GmshConfig.h"
+  #include "fullMatrix.h"
+  #include "PView.h"
+  #include "PViewFactory.h"
+  #include "PViewData.h"
+%}
+
+%include "GmshConfig.h"
+%include "PView.h"
+
+%include "PViewFactory.h"
+
+%apply double &OUTPUT { double &val}
+%include "PViewData.h"
+
diff --git a/gmshpy/gmshSolver.i b/gmshpy/gmshSolver.i
new file mode 100644
index 0000000000000000000000000000000000000000..244f7909e24c7c8ee657b0200df88c444d9a7540
--- /dev/null
+++ b/gmshpy/gmshSolver.i
@@ -0,0 +1,34 @@
+%feature("autodoc", "1");
+%module gmshSolver
+%include std_string.i
+%include std_vector.i
+%import "gmshCommon.i"
+%import "gmshNumeric.i"
+
+%{
+  #include "GmshConfig.h"
+  #include "dofManager.h"
+  #include "elasticitySolver.h"
+  #include "linearSystem.h"
+  #include "linearSystemCSR.h"
+  #include "linearSystemFull.h"
+  #include "linearSystemPETSc.h"
+%}
+
+%include "GmshConfig.h"
+
+%include "dofManager.h"
+%template(dofManagerDouble) dofManager<double>;
+%include "elasticitySolver.h"
+%include "linearSystem.h"
+%template(linearSystemDouble) linearSystem<double>;
+%template(linearSystemFullMatrixDouble) linearSystem<fullMatrix<double> >;
+%include "linearSystemCSR.h"
+%template(linearSystemCSRDouble) linearSystemCSR<double>;
+%template(linearSystemTAUCSDouble) linearSystemCSRTaucs<double>;
+%include "linearSystemFull.h"
+%template(linearSystemFullDouble) linearSystemFull<double> ;
+#ifdef HAVE_PETSC
+%include "linearSystemPETSc.h"
+%template(linearSystemPETScDouble) linearSystemPETSc<double>;
+#endif
diff --git a/wrappers/gmshpy/gmshMesh.i b/wrappers/gmshpy/gmshMesh.i
index c48c77ac35b5c85ece9d214addd1dc597cd049a8..5d5111c2345c4f6680e5b08a40620944fba0b871 100644
--- a/wrappers/gmshpy/gmshMesh.i
+++ b/wrappers/gmshpy/gmshMesh.i
@@ -15,6 +15,9 @@
   #include "meshMetric.h"
   #include "Field.h"
   #include "CenterlineField.h"
+  #include "Voronoi3D.h"
+  #include "simple3D.h"
+  #include "periodical.h"
 %}
 
 %include std_vector.i
@@ -33,3 +36,6 @@ namespace std {
 %include "meshMetric.h"
 %include "Field.h"
 %include "CenterlineField.h"
+%include "Voronoi3D.h"
+%include "simple3D.h"
+%include "periodical.h"