diff --git a/CMakeLists.txt b/CMakeLists.txt index ef344f0059b4d1f83c45e75403d91dfbfccbeb49..cba64a8d9bf94813959ba1915fb7972116be5584 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,6 +26,8 @@ option(ENABLE_ANN "Enable ANN to compute Approximate Nearest Neighbors" ${DEFAUL option(ENABLE_APP_BUNDLE "Create .app bundle on Mac when installing" ${DEFAULT}) option(ENABLE_BAMG "Enable Bamg mesh generator" ${DEFAULT}) option(ENABLE_BFGS "Enable BFGS" ${DEFAULT}) +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)" ${DEFAULT}) option(ENABLE_CGNS "Enable CGNS mesh export" OFF) @@ -93,7 +95,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 @@ -491,6 +493,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/Common/GmshConfig.h.in b/Common/GmshConfig.h.in index 68161a7cb62048954197d9f138289ee805bda5a3..5aefba5904256a43d99f74a2ec2eb3fb3035aeca 100644 --- a/Common/GmshConfig.h.in +++ b/Common/GmshConfig.h.in @@ -54,6 +54,8 @@ #cmakedefine HAVE_SOLVER #cmakedefine HAVE_TAUCS #cmakedefine HAVE_TETGEN +#cmakedefine HAVE_RTREE +#cmakedefine HAVE_Voro3D #define GMSH_CONFIG_OPTIONS "${GMSH_CONFIG_OPTIONS}" diff --git a/Geo/GFaceCompound.cpp b/Geo/GFaceCompound.cpp index ed17b71a6b0559917d1a1774885b035c4413ef50..fb5c2b61559d60dfc5a004c2f9c084d2865c5120 100644 --- a/Geo/GFaceCompound.cpp +++ b/Geo/GFaceCompound.cpp @@ -1891,6 +1891,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..c6663545c77ad879cccf842a71e43b051304cc49 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(); + double get_size(double,double,double); + Tensor get_tensor(double,double,double); + double get_drho_dx(double,double,double,int); + double get_drho_dy(double,double,double,int); + double get_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*********/ + +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&,double&,alglib::real_1d_array&,void*); +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*********/ @@ -70,8 +227,8 @@ SVector3 VoronoiVertex::get_normal2(){ return normal2; } -double VoronoiVertex::get_rho(){ - return rho; +double VoronoiVertex::get_h(){ + return h; } void VoronoiVertex::set_point(SPoint3 new_point){ @@ -106,96 +263,96 @@ void VoronoiVertex::set_normal2(SVector3 new_normal2){ normal2 = new_normal2; } -void VoronoiVertex::set_rho(double new_rho){ - rho = new_rho; +void VoronoiVertex::set_h(double new_h){ + h = new_h; } -/*********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*********/ @@ -224,20 +381,20 @@ double VoronoiElement::get_jacobian(){ return jacobian; } -double VoronoiElement::get_drho_dx(){ - return drho_dx; +double VoronoiElement::get_dh_dx(){ + return dh_dx; } -double VoronoiElement::get_drho_dy(){ - return drho_dy; +double VoronoiElement::get_dh_dy(){ + return dh_dy; } -double VoronoiElement::get_drho_dz(){ - return drho_dz; +double VoronoiElement::get_dh_dz(){ + return dh_dz; } -Metric VoronoiElement::get_metric(){ - return m; +Tensor VoronoiElement::get_tensor(){ + return t; } void VoronoiElement::set_v1(VoronoiVertex new_v1){ @@ -256,30 +413,30 @@ 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){ - double rho1; - double rho2; - double rho3; - double rho4; - double rho; +double VoronoiElement::get_h(double u,double v,double w){ + double h1; + double h2; + double h3; + double h4; + double h; - rho1 = v1.get_rho(); - 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 - return rho; -} - -void VoronoiElement::deriv_rho(){ - double rho1; - double rho2; - double rho3; - double rho4; + h1 = v1.get_h(); + h2 = v2.get_h(); + h3 = v3.get_h(); + h4 = v4.get_h(); + h = T(u,v,w,h1,h2,h3,h4); + return h; +} + +void VoronoiElement::deriv_h(){ + double h1; + double h2; + double h3; + double h4; double x1,y1,z1; double x2,y2,z2; double x3,y3,z3; @@ -291,9 +448,9 @@ void VoronoiElement::deriv_rho(){ double b21,b22,b23; double b31,b32,b33; double jacobian2; - double drho_du; - double drho_dv; - double drho_dw; + double dh_du; + double dh_dv; + double dh_dw; double du_dx; double dv_dx; double dw_dx; @@ -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; @@ -353,17 +510,17 @@ void VoronoiElement::deriv_rho(){ dv_dz = b32/jacobian2; dw_dz = b33/jacobian2; - rho1 = v1.get_rho(); - rho2 = v2.get_rho(); - rho3 = v3.get_rho(); - rho4 = v4.get_rho(); - drho_du = rho2-rho1; - drho_dv = rho3-rho1; - drho_dw = rho4-rho1; + h1 = v1.get_h(); + h2 = v2.get_h(); + h3 = v3.get_h(); + h4 = v4.get_h(); + dh_du = h2-h1; + dh_dv = h3-h1; + dh_dw = h4-h1; - drho_dx = drho_du*du_dx + drho_dv*dv_dx + drho_dw*dw_dx; - drho_dy = drho_du*du_dy + drho_dv*dv_dy + drho_dw*dw_dy; - drho_dz = drho_du*du_dz + drho_dv*dv_dz + drho_dw*dw_dz; + dh_dx = dh_du*du_dx + dh_dv*dv_dx + dh_dw*dw_dx; + dh_dy = dh_du*du_dy + dh_dv*dv_dy + dh_dw*dw_dy; + dh_dz = dh_du*du_dz + dh_dv*dv_dz + dh_dw*dw_dz; } void VoronoiElement::compute_jacobian(){ @@ -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,374 @@ 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(); + + 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){ +void LpCVT::compute_parameters(){ + 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); - 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(); - } + + 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()); + v1.set_h(h1); + v2.set_h(h2); + v3.set_h(h3); + v4.set_h(h4); + 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_h(); + } +} + +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::get_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::get_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::get_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 +957,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 +968,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); @@ -515,8 +979,8 @@ double LpCVT::F(VoronoiElement element,int p){ z = element.T(u,v,w,generator.z(),C1.z(),C2.z(),C3.z()); 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); + rho = h_to_rho(element.get_h(u,v,w),p); //h_to_rho(get_size(x,y,z),p); + energy = energy + weight*rho*f(generator,point,t,p); } energy = element.get_jacobian()*energy; return energy; @@ -532,7 +996,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 +1010,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); @@ -557,10 +1021,10 @@ SVector3 LpCVT::simple(VoronoiElement element,int p){ z = element.T(u,v,w,generator.z(),C1.z(),C2.z(),C3.z()); 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); + rho = h_to_rho(element.get_h(u,v,w),p); //h_to_rho(get_size(x,y,z),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 +1045,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 +1059,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(); @@ -609,18 +1073,18 @@ SVector3 LpCVT::dF_dC1(VoronoiElement element,int p){ z = element.T(u,v,w,gz,C1.z(),C2.z(),C3.z()); point = SPoint3(x,y,z); weight = gauss_weights(i,0); - rho = element.get_rho(u,v,w); - 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; + rho = h_to_rho(element.get_h(u,v,w),p); //h_to_rho(get_size(x,y,z),p); + drho_dx = (-p-3)*pow_int(1.0/element.get_h(u,v,w),p+4)*element.get_dh_dx(); //get_drho_dx(x,y,z,p); + drho_dy = (-p-3)*pow_int(1.0/element.get_h(u,v,w),p+4)*element.get_dh_dy(); //get_drho_dy(x,y,z,p); + drho_dz = (-p-3)*pow_int(1.0/element.get_h(u,v,w),p+4)*element.get_dh_dz(); //get_drho_dz(x,y,z,p); + 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 +1104,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 +1118,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(); @@ -668,18 +1132,18 @@ SVector3 LpCVT::dF_dC2(VoronoiElement element,int p){ z = element.T(u,v,w,generator.z(),C1.z(),C2.z(),C3.z()); point = SPoint3(x,y,z); weight = gauss_weights(i,0); - rho = element.get_rho(u,v,w); - 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; + rho = h_to_rho(element.get_h(u,v,w),p); //h_to_rho(get_size(x,y,z),p); + drho_dx = (-p-3)*pow_int(1.0/element.get_h(u,v,w),p+4)*element.get_dh_dx(); //get_drho_dx(x,y,z,p); + drho_dy = (-p-3)*pow_int(1.0/element.get_h(u,v,w),p+4)*element.get_dh_dy(); //get_drho_dy(x,y,z,p); + drho_dz = (-p-3)*pow_int(1.0/element.get_h(u,v,w),p+4)*element.get_dh_dz(); //get_drho_dz(x,y,z,p); + 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 +1163,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 +1177,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(); @@ -727,30 +1191,30 @@ SVector3 LpCVT::dF_dC3(VoronoiElement element,int p){ z = element.T(u,v,w,gz,C1.z(),C2.z(),C3.z()); point = SPoint3(x,y,z); weight = gauss_weights(i,0); - rho = element.get_rho(u,v,w); - 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; + rho = h_to_rho(element.get_h(u,v,w),p); //h_to_rho(get_size(x,y,z),p); + drho_dx = (-p-3)*pow_int(1.0/element.get_h(u,v,w),p+4)*element.get_dh_dx(); //get_drho_dx(x,y,z,p); + drho_dy = (-p-3)*pow_int(1.0/element.get_h(u,v,w),p+4)*element.get_dh_dy(); //get_drho_dy(x,y,z,p); + drho_dz = (-p-3)*pow_int(1.0/element.get_h(u,v,w),p+4)*element.get_dh_dz(); //get_drho_dz(x,y,z,p); + 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 +1224,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 +1255,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 +1286,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 +1317,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 +1461,173 @@ 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); + + //if((bank.size()-offset)>1){ + //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; -} + 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_dimension(int new_dimension){ - dimension = new_dimension; + 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_iteration(int new_iteration){ - iteration = new_iteration; +double LpSmoother::get_size(double x,double y,double z){ + return 0.25; } -void Wrap::set_max_iteration(int new_max_iteration){ - max_iteration = new_max_iteration; +int LpSmoother::get_nbr_interior_vertices(){ + return interior_vertices.size(); } - -void Wrap::set_initial_energy(double new_initial_energy){ - initial_energy = new_initial_energy; + +MVertex* LpSmoother::get_interior_vertex(int i){ + return interior_vertices[i]; } -void Wrap::set_octree(MElementOctree* new_octree){ - octree = new_octree; -} - -/*********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..53d293607ef67b0aba28cff51d366274365a74fd 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: @@ -24,7 +27,7 @@ class VoronoiVertex{ int index4; SVector3 normal1; SVector3 normal2; - double rho; + double h; public: VoronoiVertex(); ~VoronoiVertex(); @@ -36,7 +39,7 @@ class VoronoiVertex{ int get_index4(); SVector3 get_normal1(); SVector3 get_normal2(); - double get_rho(); + double get_h(); void set_point(SPoint3); void set_category(int); void set_index1(int); @@ -45,39 +48,35 @@ class VoronoiVertex{ void set_index4(int); void set_normal1(SVector3); void set_normal2(SVector3); - void set_rho(double); + void set_h(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; @@ -85,10 +84,10 @@ class VoronoiElement{ VoronoiVertex v3; VoronoiVertex v4; double jacobian; - double drho_dx; - double drho_dy; - double drho_dz; - Metric m; + double dh_dx; + double dh_dy; + double dh_dz; + Tensor t; public: VoronoiElement(); ~VoronoiElement(); @@ -97,92 +96,34 @@ class VoronoiElement{ VoronoiVertex get_v3(); VoronoiVertex get_v4(); double get_jacobian(); - double get_drho_dx(); - double get_drho_dy(); - double get_drho_dz(); - Metric get_metric(); + double get_dh_dx(); + double get_dh_dy(); + double get_dh_dz(); + Tensor get_tensor(); void set_v1(VoronoiVertex); void set_v2(VoronoiVertex); void set_v3(VoronoiVertex); void set_v4(VoronoiVertex); - void set_metric(Metric); - double get_rho(double,double,double); - void deriv_rho(); + void set_tensor(Tensor); + double get_h(double,double,double); + void deriv_h(); 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/Voronoi3D.cpp b/Mesh/Voronoi3D.cpp new file mode 100755 index 0000000000000000000000000000000000000000..87197a0f303fadd87dd359c7bfacca4b4695692b --- /dev/null +++ b/Mesh/Voronoi3D.cpp @@ -0,0 +1,305 @@ +// Gmsh - Copyright (C) 1997-2011 C. Geuzaine, J.-F. Remacle +// +// See the LICENSE.txt file for license information. Please report all +// bugs and problems to <gmsh@geuz.org>. + +#include "Voronoi3D.h" +#include "GModel.h" +#include "MElement.h" +#include "meshGRegion.h" +#include <fstream> +#include "Levy3D.h" +#if defined(HAVE_Voro3D) +#include "voro++.hh" +#endif + +#if defined(HAVE_Voro3D) +using namespace voro; +#endif + +/*********class clip*********/ + +clip::clip(){} + +clip::~clip(){} + +void clip::execute(){ + GRegion* gr; + GModel* model = GModel::current(); + GModel::riter it; + + for(it=model->firstRegion();it!=model->lastRegion();it++) + { + gr = *it; + if(gr->getNumMeshElements()>0){ + execute(gr); + } + } +} + +void clip::execute(GRegion* gr){ + int i; + int j; + MElement* element; + MVertex* vertex; + std::vector<SPoint3> vertices2; + std::set<MVertex*> vertices; + std::set<MVertex*>::iterator it; + std::vector<VoronoiElement> clipped; + + for(i=0;i<gr->getNumMeshElements();i++){ + element = gr->getMeshElement(i); + for(j=0;j<element->getNumVertices();j++){ + vertex = element->getVertex(j); + vertices.insert(vertex); + } + } + + for(it=vertices.begin();it!=vertices.end();it++){ + vertices2.push_back(SPoint3((*it)->x(),(*it)->y(),(*it)->z())); + } + + execute(vertices2,clipped); + printf("%d\n",clipped.size()); + + std::ofstream file("cells.pos"); + file << "View \"test\" {\n"; + for(i=0;i<clipped.size();i++){ + print_segment(clipped[i].get_v1().get_point(),clipped[i].get_v2().get_point(),file); + print_segment(clipped[i].get_v1().get_point(),clipped[i].get_v3().get_point(),file); + print_segment(clipped[i].get_v1().get_point(),clipped[i].get_v4().get_point(),file); + print_segment(clipped[i].get_v2().get_point(),clipped[i].get_v3().get_point(),file); + print_segment(clipped[i].get_v3().get_point(),clipped[i].get_v4().get_point(),file); + print_segment(clipped[i].get_v4().get_point(),clipped[i].get_v2().get_point(),file); + } + file << "};\n"; +} + +void clip::execute(std::vector<SPoint3>& vertices,std::vector<VoronoiElement>& clipped){ +#if defined(HAVE_Voro3D) + int i; + int j; + int start; + int end; + int index; + int index1; + int index2; + int index3; + int count; + int pid; + double x,y,z; + double x1,y1,z1; + double x2,y2,z2; + double x3,y3,z3; + double delta; + double min_x,max_x; + double min_y,max_y; + double min_z,max_z; + double volume1; + double volume2; + double l1,l2,l3,l4,l5; + voronoicell_neighbor* pointer; + voronoicell_neighbor cell; + VoronoiVertex v1,v2,v3,v4; + VoronoiElement e; + std::vector<int> faces; + std::vector<double> voronoi_vertices; + std::vector<voronoicell_neighbor*> pointers; + std::vector<SPoint3> generators; + std::vector<int> IDs; + std::vector<int> IDs2; + std::vector<int> neighbors; + std::vector<std::vector<std::vector<int> > > bisectors; + + min_x = 1000000000.0; + max_x = -1000000000.0; + min_y = 1000000000.0; + max_y = -1000000000.0; + min_z = 1000000000.0; + max_z = -1000000000.0; + for(i=0;i<vertices.size();i++){ + min_x = min(vertices[i].x(),min_x); + max_x = max(vertices[i].x(),max_x); + min_y = min(vertices[i].y(),min_y); + max_y = max(vertices[i].y(),max_y); + min_z = min(vertices[i].z(),min_z); + max_z = max(vertices[i].z(),max_z); + } + + delta = 0.2*(max_x - min_x); + container cont(min_x-delta,max_x+delta,min_y-delta,max_y+delta,min_z-delta,max_z+delta,6,6,6,false,false,false,vertices.size()); + volume1 = (max_x-min_x+2.0*delta)*(max_y-min_y+2.0*delta)*(max_z-min_z+2.0*delta); + + for(i=0;i<vertices.size();i++){ + cont.put(i,vertices[i].x(),vertices[i].y(),vertices[i].z()); + } + + count = 0; + IDs.resize(vertices.size()); + c_loop_all loop(cont); + loop.start(); + do{ + cont.compute_cell(cell,loop); + loop.pos(x,y,z); + pointer = new voronoicell_neighbor(); + *pointer = cell; + pointers.push_back(pointer); + generators.push_back(SPoint3(x,y,z)); + pid = loop.pid(); + IDs[pid] = count; + IDs2.push_back(pid); + count++; + }while(loop.inc()); + + bisectors.resize(pointers.size()); + for(i=0;i<pointers.size();i++){ + faces.clear(); + voronoi_vertices.clear(); + pointers[i]->face_vertices(faces); + pointers[i]->neighbors(neighbors); + pointers[i]->vertices(generators[i].x(),generators[i].y(),generators[i].z(),voronoi_vertices); + bisectors[i].resize(voronoi_vertices.size()/3); + for(j=0;j<bisectors[i].size();j++){ + bisectors[i][j].push_back(IDs2[i]); + } + count = 0; + end = 0; + while(end<faces.size()){ + start = end + 1; + end = start + faces[end]; + for(j=start;j<end;j++){ + index = faces[j]; + bisectors[i][index].push_back(neighbors[count]); + } + count++; + } + } + + for(i=0;i<bisectors.size();i++){ + for(j=0;j<bisectors[i].size();j++){ + //printf("%d %d %d %d %d %d\n",i,IDs2[i],bisectors[i][j][0],bisectors[i][j][1],bisectors[i][j][2],bisectors[i][j][3]); + } + } + + for(i=0;i<pointers.size();i++){ + faces.clear(); + voronoi_vertices.clear(); + pointers[i]->face_vertices(faces); + pointers[i]->vertices(generators[i].x(),generators[i].y(),generators[i].z(),voronoi_vertices); + end = 0; + while(end<faces.size()){ + start = end + 1; + end = start + faces[end]; + for(j=start+1;j<end-1;j++){ + index1 = faces[start]; + index2 = faces[j]; + index3 = faces[j+1]; + x1 = voronoi_vertices[3*index1]; + y1 = voronoi_vertices[3*index1+1]; + z1 = voronoi_vertices[3*index1+2]; + x2 = voronoi_vertices[3*index2]; + y2 = voronoi_vertices[3*index2+1]; + z2 = voronoi_vertices[3*index2+2]; + x3 = voronoi_vertices[3*index3]; + y3 = voronoi_vertices[3*index3+1]; + z3 = voronoi_vertices[3*index3+2]; + v1 = VoronoiVertex(); + v2 = VoronoiVertex(); + v3 = VoronoiVertex(); + v4 = VoronoiVertex(); + v1.set_point(SPoint3(generators[i].x(),generators[i].y(),generators[i].z())); + v1.set_category(4); + v1.set_index1(IDs2[i]); + v2.set_point(SPoint3(x1,y1,z1)); + v2.set_category(category(bisectors[i][index1][0],bisectors[i][index1][1],bisectors[i][index1][2],bisectors[i][index1][3])); + v2.set_index1(bisectors[i][index1][0]); + v2.set_index2(bisectors[i][index1][1]); + v2.set_index3(bisectors[i][index1][2]); + v2.set_index4(bisectors[i][index1][3]); + v3.set_point(SPoint3(x2,y2,z2)); + v3.set_category(category(bisectors[i][index2][0],bisectors[i][index2][1],bisectors[i][index2][2],bisectors[i][index2][3])); + v3.set_index1(bisectors[i][index2][0]); + v3.set_index2(bisectors[i][index2][1]); + v3.set_index3(bisectors[i][index2][2]); + v3.set_index4(bisectors[i][index2][3]); + v4.set_point(SPoint3(x3,y3,z3)); + v4.set_category(category(bisectors[i][index3][0],bisectors[i][index3][1],bisectors[i][index3][2],bisectors[i][index3][3])); + v4.set_index1(bisectors[i][index3][0]); + v4.set_index2(bisectors[i][index3][1]); + v4.set_index3(bisectors[i][index3][2]); + v4.set_index4(bisectors[i][index3][3]); + e = VoronoiElement(); + e.set_v1(v1); + e.set_v2(v2); + e.set_v3(v3); + e.set_v4(v4); + clipped.push_back(e); + } + } + } + + volume2 = 0.0; + for(i=0;i<clipped.size();i++){ + if(clipped[i].get_v2().get_category()==1){ + l1 = (clipped[i].get_v2().get_point()).distance(clipped[i].get_v1().get_point()); + l2 = (clipped[i].get_v2().get_point()).distance(generators[IDs[clipped[i].get_v2().get_index1()]]); + l3 = (clipped[i].get_v2().get_point()).distance(generators[IDs[clipped[i].get_v2().get_index2()]]); + l4 = (clipped[i].get_v2().get_point()).distance(generators[IDs[clipped[i].get_v2().get_index3()]]); + l5 = (clipped[i].get_v2().get_point()).distance(generators[IDs[clipped[i].get_v2().get_index4()]]); + //printf("%f %f %f %f %f %f %f %f %f\n",l1,l2,l3,l4,l5,l1-l2,l1-l3,l1-l4,l1-l5); + } + if(clipped[i].get_v3().get_category()==1){ + l1 = (clipped[i].get_v3().get_point()).distance(clipped[i].get_v1().get_point()); + l2 = (clipped[i].get_v3().get_point()).distance(generators[IDs[clipped[i].get_v3().get_index1()]]); + l3 = (clipped[i].get_v3().get_point()).distance(generators[IDs[clipped[i].get_v3().get_index2()]]); + l4 = (clipped[i].get_v3().get_point()).distance(generators[IDs[clipped[i].get_v3().get_index3()]]); + l5 = (clipped[i].get_v3().get_point()).distance(generators[IDs[clipped[i].get_v3().get_index4()]]); + //printf("%f %f %f %f %f %f %f %f %f\n",l1,l2,l3,l4,l5,l1-l2,l1-l3,l1-l4,l1-l5); + } + if(clipped[i].get_v4().get_category()==1){ + l1 = (clipped[i].get_v4().get_point()).distance(clipped[i].get_v1().get_point()); + l2 = (clipped[i].get_v4().get_point()).distance(generators[IDs[clipped[i].get_v4().get_index1()]]); + l3 = (clipped[i].get_v4().get_point()).distance(generators[IDs[clipped[i].get_v4().get_index2()]]); + l4 = (clipped[i].get_v4().get_point()).distance(generators[IDs[clipped[i].get_v4().get_index3()]]); + l5 = (clipped[i].get_v4().get_point()).distance(generators[IDs[clipped[i].get_v4().get_index4()]]); + //printf("%f %f %f %f %f %f %f %f %f\n",l1,l2,l3,l4,l5,l1-l2,l1-l3,l1-l4,l1-l5); + } + clipped[i].compute_jacobian(); + volume2 = volume2 + fabs(clipped[i].get_jacobian())/6.0; + } + //printf("%f %f\n",volume1,volume2); + + for(i=0;i<pointers.size();i++) delete pointers[i]; +#endif +} + +double clip::min(double a,double b){ + if(a<b) return a; + else return b; +} + +double clip::max(double a,double b){ + if(a>b) return a; + else return b; +} + +int clip::category(int a,int b,int c,int d) +{ + int count; + count = 0; + if(a<0) count++; + if(b<0) count++; + if(c<0) count++; + if(d<0) count++; + if(count==0) return 1; + else if(count==1) return 2; + else if(count==2) return 3; + else return 4; +} + +void clip::print_segment(SPoint3 p1,SPoint3 p2,std::ofstream& file){ + file << "SL (" + << p1.x() << ", " << p1.y() << ", " << p1.z() << ", " + << p2.x() << ", " << p2.y() << ", " << p2.z() + << "){10, 20};\n"; +} \ No newline at end of file diff --git a/Mesh/Voronoi3D.h b/Mesh/Voronoi3D.h new file mode 100755 index 0000000000000000000000000000000000000000..d8b28456a27018dc91a734857ec92d7c81ef22e2 --- /dev/null +++ b/Mesh/Voronoi3D.h @@ -0,0 +1,21 @@ +// Gmsh - Copyright (C) 1997-2011 C. Geuzaine, J.-F. Remacle +// +// See the LICENSE.txt file for license information. Please report all +// bugs and problems to <gmsh@geuz.org>. + +#include "GRegion.h" + +class VoronoiElement; + +class clip{ + public: + clip(); + ~clip(); + void execute(); + void execute(GRegion*); + void execute(std::vector<SPoint3>&,std::vector<VoronoiElement>&); + double min(double,double); + double max(double,double); + int category(int,int,int,int); + void print_segment(SPoint3,SPoint3,std::ofstream&); +}; \ 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*> ®ions) 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/Mesh/periodical.cpp b/Mesh/periodical.cpp new file mode 100755 index 0000000000000000000000000000000000000000..7a98fcbb6f9071cec3345bdc2f11fc0facfb28e6 --- /dev/null +++ b/Mesh/periodical.cpp @@ -0,0 +1,348 @@ +// Gmsh - Copyright (C) 1997-2011 C. Geuzaine, J.-F. Remacle +// +// See the LICENSE.txt file for license information. Please report all +// bugs and problems to <gmsh@geuz.org>. + +#include "periodical.h" +#include "GModel.h" +#include "meshGRegion.h" +#include <fstream> +#include <algorithm> +#include "MElement.h" +#if defined(HAVE_Voro3D) +#include "voro++.hh" +#endif + +#if defined(HAVE_Voro3D) +using namespace voro; +#endif + +/*********definitions*********/ + +class geo_cell{ + public: + std::vector<std::pair<int,int> > lines; + std::vector<std::vector<int> > line_loops; + std::vector<std::vector<int> > orientations; + + std::vector<int> points2; + std::vector<int> lines2; + std::vector<int> line_loops2; + std::vector<int> faces2; + int face_loops2; + + geo_cell(); + ~geo_cell(); + + int search_line(std::pair<int,int>); +}; + +/*********class geo_cell*********/ + +geo_cell::geo_cell(){} + +geo_cell::~geo_cell(){} + +int geo_cell::search_line(std::pair<int,int> line){ + int i; + + for(i=0;i<lines.size();i++){ + if(lines[i].first==line.first && lines[i].second==line.second) return i; + if(lines[i].first==line.second && lines[i].second==line.first) return i; + } + + return -1; +} + +/*********class voroMetal3D*********/ + +voroMetal3D::voroMetal3D(){} + +voroMetal3D::~voroMetal3D(){} + +void voroMetal3D::execute(){ + GRegion* gr; + GModel* model = GModel::current(); + GModel::riter it; + + for(it=model->firstRegion();it!=model->lastRegion();it++) + { + gr = *it; + if(gr->getNumMeshElements()>0){ + execute(gr); + } + } +} + +void voroMetal3D::execute(GRegion* gr){ + int i; + int j; + MElement* element; + MVertex* vertex; + std::vector<SPoint3> vertices2; + std::set<MVertex*> vertices; + std::set<MVertex*>::iterator it; + + for(i=0;i<gr->getNumMeshElements();i++){ + element = gr->getMeshElement(i); + for(j=0;j<element->getNumVertices();j++){ + vertex = element->getVertex(j); + vertices.insert(vertex); + } + } + + for(it=vertices.begin();it!=vertices.end();it++){ + vertices2.push_back(SPoint3((*it)->x(),(*it)->y(),(*it)->z())); + } + + execute(vertices2); +} + +void voroMetal3D::execute(std::vector<SPoint3>& vertices){ +#if defined(HAVE_Voro3D) + int i; + int j; + int k; + int start; + int end; + int index1; + int index2; + int val; + int face_number; + int last; + double x,y,z; + double x1,y1,z1; + double x2,y2,z2; + double delta; + double min_x,max_x; + double min_y,max_y; + double min_z,max_z; + voronoicell_neighbor* pointer; + voronoicell_neighbor cell; + std::vector<int> faces; + std::vector<double> voronoi_vertices; + std::vector<voronoicell_neighbor*> pointers; + std::vector<SPoint3> generators; + std::vector<int> temp; + std::vector<int> temp2; + geo_cell obj; + + min_x = 1000000000.0; + max_x = -1000000000.0; + min_y = 1000000000.0; + max_y = -1000000000.0; + min_z = 1000000000.0; + max_z = -1000000000.0; + for(i=0;i<vertices.size();i++){ + min_x = std::min(vertices[i].x(),min_x); + max_x = std::max(vertices[i].x(),max_x); + min_y = std::min(vertices[i].y(),min_y); + max_y = std::max(vertices[i].y(),max_y); + min_z = std::min(vertices[i].z(),min_z); + max_z = std::max(vertices[i].z(),max_z); + } + + delta = 0.2*(max_x - min_x); + container cont(min_x-delta,max_x+delta,min_y-delta,max_y+delta,min_z-delta,max_z+delta,6,6,6,true,true,true,vertices.size()); + + for(i=0;i<vertices.size();i++){ + cont.put(i,vertices[i].x(),vertices[i].y(),vertices[i].z()); + } + + c_loop_all loop(cont); + loop.start(); + do{ + cont.compute_cell(cell,loop); + loop.pos(x,y,z); + pointer = new voronoicell_neighbor(); + *pointer = cell; + pointers.push_back(pointer); + generators.push_back(SPoint3(x,y,z)); + }while(loop.inc()); + + initialize_counter(); + + std::ofstream file("cells.pos"); + file << "View \"test\" {\n"; + std::ofstream file2("cells.geo"); + file2 << "c = 1.0;\n"; + for(i=0;i<pointers.size();i++){ + obj = geo_cell(); + + faces.clear(); + voronoi_vertices.clear(); + pointers[i]->face_vertices(faces); + pointers[i]->vertices(generators[i].x(),generators[i].y(),generators[i].z(),voronoi_vertices); + + obj.line_loops.resize(pointers[i]->number_of_faces()); + obj.orientations.resize(pointers[i]->number_of_faces()); + + face_number = 0; + end = 0; + while(end<faces.size()){ + start = end + 1; + end = start + faces[end]; + for(j=start;j<end;j++){ + if(j<end-1){ + index1 = faces[j]; + index2 = faces[j+1]; + } + else{ + index1 = faces[end-1]; + index2 = faces[start]; + } + x1 = voronoi_vertices[3*index1]; + y1 = voronoi_vertices[3*index1+1]; + z1 = voronoi_vertices[3*index1+2]; + x2 = voronoi_vertices[3*index2]; + y2 = voronoi_vertices[3*index2+1]; + z2 = voronoi_vertices[3*index2+2]; + print_segment(SPoint3(x1,y1,z1),SPoint3(x2,y2,z2),file); + + val = obj.search_line(std::pair<int,int>(index1,index2)); + if(val==-1){ + obj.lines.push_back(std::pair<int,int>(index1,index2)); + obj.line_loops[face_number].push_back(obj.lines.size()-1); + val = obj.lines.size()-1; + } + else{ + obj.line_loops[face_number].push_back(val); + } + + last = obj.line_loops[face_number].size()-1; + if(last==0){ + obj.orientations[face_number].push_back(0); + } + else if(obj.lines[obj.line_loops[face_number][last-1]].second==obj.lines[val].first){ + obj.orientations[face_number][last-1] = 0; + obj.orientations[face_number].push_back(0); + } + else if(obj.lines[obj.line_loops[face_number][last-1]].first==obj.lines[val].first){ + obj.orientations[face_number][last-1] = 1; + obj.orientations[face_number].push_back(0); + } + else if(obj.lines[obj.line_loops[face_number][last-1]].second==obj.lines[val].second){ + obj.orientations[face_number][last-1] = 0; + obj.orientations[face_number].push_back(1); + } + else{ + obj.orientations[face_number][last-1] = 1; + obj.orientations[face_number].push_back(1); + } + } + + face_number++; + } + + for(j=0;j<voronoi_vertices.size()/3;j++){ + print_geo_point(get_counter(),voronoi_vertices[3*j],voronoi_vertices[3*j+1],voronoi_vertices[3*j+2],file2); + obj.points2.push_back(get_counter()); + increase_counter(); + } + + for(j=0;j<obj.lines.size();j++){ + print_geo_line(get_counter(),obj.points2[obj.lines[j].first],obj.points2[obj.lines[j].second],file2); + obj.lines2.push_back(get_counter()); + increase_counter(); + } + + for(j=0;j<obj.line_loops.size();j++){ + temp.clear(); + temp2.clear(); + for(k=0;k<obj.line_loops[j].size();k++){ + temp.push_back(obj.lines2[obj.line_loops[j][k]]); + temp2.push_back(obj.orientations[j][k]); + } + print_geo_line_loop(get_counter(),temp,temp2,file2); + obj.line_loops2.push_back(get_counter()); + increase_counter(); + } + + for(j=0;j<obj.line_loops2.size();j++){ + print_geo_face(get_counter(),obj.line_loops2[j],file2); + obj.faces2.push_back(get_counter()); + increase_counter(); + } + + print_geo_face_loop(get_counter(),obj.faces2,file2); + obj.face_loops2 = get_counter(); + increase_counter(); + + print_geo_volume(get_counter(),obj.face_loops2,file2); + increase_counter(); + } + file << "};\n"; + + for(i=0;i<pointers.size();i++) delete pointers[i]; +#endif +} + +void voroMetal3D::print_segment(SPoint3 p1,SPoint3 p2,std::ofstream& file){ + file << "SL (" + << p1.x() << ", " << p1.y() << ", " << p1.z() << ", " + << p2.x() << ", " << p2.y() << ", " << p2.z() + << "){10, 20};\n"; +} + +void voroMetal3D::initialize_counter(){ + counter = 1; +} + +void voroMetal3D::increase_counter(){ + counter = counter+1; +} + +int voroMetal3D::get_counter(){ + return counter; +} + +void voroMetal3D::print_geo_point(int index,double x,double y,double z,std::ofstream& file){ + file << "Point(" << index << ")={" + << x << "," << y << "," << z + << ",c};\n"; +} + +void voroMetal3D::print_geo_line(int index1,int index2,int index3,std::ofstream& file){ + file << "Line(" << index1 << ")={" + << index2 << "," << index3 + << "};\n"; +} + +void voroMetal3D::print_geo_face(int index1,int index2,std::ofstream& file){ + file << "Plane Surface(" << index1 << ")={" + << index2 + << "};\n"; +} + +void voroMetal3D::print_geo_volume(int index1,int index2,std::ofstream& file){ + file << "Volume(" << index1 << ")={" + << index2 + << "};\n"; +} + +void voroMetal3D::print_geo_line_loop(int index,std::vector<int>& indices,std::vector<int>& orientations,std::ofstream& file){ + int i; + + file << "Line Loop(" << index << ")={"; + + for(i=0;i<indices.size();i++){ + if(orientations[i]==1) file << "-"; + file << indices[i]; + if(i<indices.size()-1) file << ","; + } + + file << "};\n"; +} + +void voroMetal3D::print_geo_face_loop(int index,std::vector<int>& indices,std::ofstream& file){ + int i; + + file << "Surface Loop(" << index << ")={"; + + for(i=0;i<indices.size();i++){ + file << indices[i]; + if(i<indices.size()-1) file << ","; + } + + file << "};\n"; +} \ No newline at end of file diff --git a/Mesh/periodical.h b/Mesh/periodical.h new file mode 100755 index 0000000000000000000000000000000000000000..f40fdb84239d46de39259d710c8542f373838b76 --- /dev/null +++ b/Mesh/periodical.h @@ -0,0 +1,27 @@ +// Gmsh - Copyright (C) 1997-2011 C. Geuzaine, J.-F. Remacle +// +// See the LICENSE.txt file for license information. Please report all +// bugs and problems to <gmsh@geuz.org>. + +#include "GRegion.h" + +class voroMetal3D{ + private: + int counter; + public: + voroMetal3D(); + ~voroMetal3D(); + void execute(); + void execute(GRegion*); + void execute(std::vector<SPoint3>&); + void print_segment(SPoint3,SPoint3,std::ofstream&); + void initialize_counter(); + void increase_counter(); + int get_counter(); + void print_geo_point(int,double,double,double,std::ofstream&); + void print_geo_line(int,int,int,std::ofstream&); + void print_geo_face(int,int,std::ofstream&); + void print_geo_volume(int,int,std::ofstream&); + void print_geo_line_loop(int,std::vector<int>&,std::vector<int>&,std::ofstream&); + void print_geo_face_loop(int,std::vector<int>&,std::ofstream&); +}; \ No newline at end of file diff --git a/Mesh/simple3D.cpp b/Mesh/simple3D.cpp new file mode 100755 index 0000000000000000000000000000000000000000..1ea5e074ef275c2fd67b0a5e35e70240ac61f694 --- /dev/null +++ b/Mesh/simple3D.cpp @@ -0,0 +1,667 @@ +// Gmsh - Copyright (C) 1997-2011 C. Geuzaine, J.-F. Remacle +// +// See the LICENSE.txt file for license information. Please report all +// bugs and problems to <gmsh@geuz.org>. + +#include "simple3D.h" +#include "GModel.h" +#include "MElement.h" +#include "MElementOctree.h" +#include "meshGRegion.h" +#include <queue> +#include <fstream> + +#if defined(HAVE_RTREE) +#include "rtree.h" +#endif + +#define k1 0.7 //k1*h is the minimal distance between two nodes +#define k2 0.5 //k2*h is the minimal distance to the boundary +#define sqrt2 1.4143 + +/*********definitions*********/ + +class Metric{ + private: + double m11,m21,m31,m12,m22,m32,m13,m23,m33; + public: + Metric(); + ~Metric(); + void set_m11(double); + void set_m21(double); + void set_m31(double); + void set_m12(double); + void set_m22(double); + void set_m32(double); + void set_m13(double); + void set_m23(double); + void set_m33(double); + double get_m11(); + double get_m21(); + double get_m31(); + double get_m12(); + double get_m22(); + double get_m32(); + double get_m13(); + double get_m23(); + double get_m33(); +}; + +class Node{ + private: + double h; + Metric m; + SPoint3 point; + public: + double min[3]; + double max[3]; + Node(); + Node(SPoint3); + ~Node(); + void set_size(double); + void set_metric(Metric); + void set_point(SPoint3); + double get_size(); + Metric get_metric(); + SPoint3 get_point(); +}; + +class Wrapper{ + private: + bool too_close; + Node* spawn; + Node* parent; + public: + Wrapper(); + Wrapper(Node*,Node*); + ~Wrapper(); + void set_too_close(bool); + void set_spawn(Node*); + void set_parent(Node*); + bool get_too_close(); + Node* get_spawn(); + Node* get_parent(); +}; + +/*********functions*********/ + +double max(double a,double b){ + if(a>b) return a; + else return b; +} + +double uniform_distance(SPoint3 p1,SPoint3 p2,Metric m){ + double det; + double distance; + double a,b,c,d,e,f,g,h,i; + double x1,y1,z1; + double x2,y2,z2; + + det = m.get_m11()*(m.get_m22()*m.get_m33() - m.get_m32()*m.get_m23()); + det = det - m.get_m12()*(m.get_m21()*m.get_m33() - m.get_m31()*m.get_m23()); + det = det + m.get_m13()*(m.get_m21()*m.get_m32() - m.get_m31()*m.get_m22()); + + a = (m.get_m22()*m.get_m33() - m.get_m32()*m.get_m23())/det; + b = (m.get_m13()*m.get_m32() - m.get_m33()*m.get_m12())/det; + c = (m.get_m12()*m.get_m23() - m.get_m22()*m.get_m13())/det; + d = (m.get_m23()*m.get_m31() - m.get_m33()*m.get_m21())/det; + e = (m.get_m11()*m.get_m33() - m.get_m31()*m.get_m13())/det; + f = (m.get_m13()*m.get_m21() - m.get_m23()*m.get_m11())/det; + g = (m.get_m21()*m.get_m32() - m.get_m31()*m.get_m22())/det; + h = (m.get_m12()*m.get_m31() - m.get_m32()*m.get_m11())/det; + i = (m.get_m11()*m.get_m22() - m.get_m21()*m.get_m12())/det; + + x1 = a*p1.x() + b*p1.y() + c*p1.z(); + y1 = d*p1.x() + e*p1.y() + f*p1.z(); + z1 = g*p1.x() + h*p1.y() + i*p1.z(); + + x2 = a*p2.x() + b*p2.y() + c*p2.z(); + y2 = d*p2.x() + e*p2.y() + f*p2.z(); + z2 = g*p2.x() + h*p2.y() + i*p2.z(); + + distance = max(max(fabs(x2-x1),fabs(y2-y1)),fabs(z2-z1)); + return distance; +} + +bool rtree_callback(Node* neighbour,void* w){ + double h; + double distance; + Metric m; + Node *spawn,*parent; + Wrapper* wrapper; + + wrapper = static_cast<Wrapper*>(w); + spawn = wrapper->get_spawn(); + parent = wrapper->get_parent(); + h = spawn->get_size(); + m = spawn->get_metric(); + + if(neighbour!=parent){ + distance = uniform_distance(spawn->get_point(),neighbour->get_point(),m); + if(distance<k1*h){ + wrapper->set_too_close(1); + return false; + } + } + + return true; +} + +/*********class Metric*********/ + +Metric::Metric(){ + m11 = 1.0; + m21 = 0.0; + m31 = 0.0; + m12 = 0.0; + m22 = 1.0; + m32 = 0.0; + m13 = 0.0; + m23 = 0.0; + m33 = 1.0; +} + +Metric::~Metric(){} + +void Metric::set_m11(double new_m11){ + m11 = new_m11; +} + +void Metric::set_m21(double new_m21){ + m21 = new_m21; +} + +void Metric::set_m31(double new_m31){ + m31 = new_m31; +} + +void Metric::set_m12(double new_m12){ + m12 = new_m12; +} + +void Metric::set_m22(double new_m22){ + m22 = new_m22; +} + +void Metric::set_m32(double new_m32){ + m32 = new_m32; +} + +void Metric::set_m13(double new_m13){ + m13 = new_m13; +} + +void Metric::set_m23(double new_m23){ + m23 = new_m23; +} + +void Metric::set_m33(double new_m33){ + m33 = new_m33; +} + +double Metric::get_m11(){ + return m11; +} + +double Metric::get_m21(){ + return m21; +} + +double Metric::get_m31(){ + return m31; +} + +double Metric::get_m12(){ + return m12; +} + +double Metric::get_m22(){ + return m22; +} + +double Metric::get_m32(){ + return m32; +} + +double Metric::get_m13(){ + return m13; +} + +double Metric::get_m23(){ + return m23; +} + +double Metric::get_m33(){ + return m33; +} + +/*********class Node*********/ + +Node::Node(){} + +Node::Node(SPoint3 new_point){ + point = new_point; +} + +Node::~Node(){} + +void Node::set_size(double new_h){ + h = new_h; +} + +void Node::set_metric(Metric new_m){ + m = new_m; +} + +void Node::set_point(SPoint3 new_point){ + point = new_point; +} + +double Node::get_size(){ + return h; +} + +Metric Node::get_metric(){ + return m; +} + +SPoint3 Node::get_point(){ + return point; +} + +/*********class Wrapper*********/ + +Wrapper::Wrapper(){ + too_close = 0; +} + +Wrapper::Wrapper(Node* new_spawn,Node* new_parent){ + too_close = 0; + spawn = new_spawn; + parent = new_parent; +} + +Wrapper::~Wrapper(){} + +void Wrapper::set_too_close(bool new_too_close){ + too_close = new_too_close; +} + +void Wrapper::set_spawn(Node* new_spawn){ + spawn = new_spawn; +} + +void Wrapper::set_parent(Node* new_parent){ + parent = new_parent; +} + +bool Wrapper::get_too_close(){ + return too_close; +} + +Node* Wrapper::get_spawn(){ + return spawn; +} + +Node* Wrapper::get_parent(){ + return parent; +} + +/*********class Filler*********/ + +Filler::Filler(){} + +Filler::~Filler(){} + +void Filler::treat_model(){ + GRegion* gr; + GModel* model = GModel::current(); + GModel::riter it; + + for(it=model->firstRegion();it!=model->lastRegion();it++) + { + gr = *it; + if(gr->getNumMeshElements()>0){ + treat_region(gr); + } + } +} + +void Filler::treat_region(GRegion* gr){ +#if defined(HAVE_RTREE) + int i,j; + int count; + bool ok; + double x,y,z; + SPoint3 point; + Node *node,*spawn,*parent,*n1,*n2,*n3,*n4,*n5,*n6; + MVertex* vertex; + MElement* element; + MElementOctree* octree; + deMeshGRegion deleter; + Wrapper wrapper; + std::queue<Node*> fifo; + std::vector<Node*> data; + std::vector<Node*> garbage; + std::vector<MVertex*> boundary_vertices; + std::set<MVertex*> old_vertices; + std::set<MVertex*>::iterator it; + RTree<Node*,double,3,double> rtree; + + 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); + old_vertices.insert(vertex); + } + } + + for(it=old_vertices.begin();it!=old_vertices.end();it++){ + if((*it)->onWhat()->dim()<3){ + boundary_vertices.push_back(*it); + } + } + + std::ofstream file("nodes.pos"); + file << "View \"test\" {\n"; + for(i=0;i<boundary_vertices.size();i++){ + x = boundary_vertices[i]->x(); + y = boundary_vertices[i]->y(); + z = boundary_vertices[i]->z(); + node = new Node(SPoint3(x,y,z)); + compute_parameters(node); + rtree.Insert(node->min,node->max,node); + fifo.push(node); + print_node(node,file); + } + file << "};\n"; + + count = 1; + while(!fifo.empty()){ + parent = fifo.front(); + fifo.pop(); + garbage.push_back(parent); + n1 = new Node(); + n2 = new Node(); + n3 = new Node(); + n4 = new Node(); + n5 = new Node(); + n6 = new Node(); + offsprings(octree,parent,n1,n2,n3,n4,n5,n6); + data.clear(); + data.push_back(n1); + data.push_back(n2); + data.push_back(n3); + data.push_back(n4); + data.push_back(n5); + data.push_back(n6); + for(i=0;i<6;i++){ + ok = 0; + spawn = data[i]; + point = spawn->get_point(); + x = point.x(); + y = point.y(); + z = point.z(); + if(inside_domain(octree,x,y,z)){ + compute_parameters(spawn); + if(far_from_boundary(octree,spawn)){ + wrapper.set_too_close(0); + wrapper.set_spawn(spawn); + wrapper.set_parent(parent); + rtree.Search(spawn->min,spawn->max,rtree_callback,&wrapper); + if(!wrapper.get_too_close()){ + fifo.push(spawn); + rtree.Insert(spawn->min,spawn->max,spawn); + vertex = new MVertex(x,y,z,gr,0); + new_vertices.push_back(vertex); + ok = 1; + } + } + } + if(!ok) delete spawn; + } + printf("%d\n",count); + count++; + } + + deleter(gr); + std::vector<GRegion*> regions; + regions.push_back(gr); + meshGRegion mesher(regions); //? + mesher(gr); //? + MeshDelaunayVolume(regions); + + delete octree; + for(i=0;i<garbage.size();i++) delete garbage[i]; + for(i=0;i<new_vertices.size();i++) delete new_vertices[i]; + new_vertices.clear(); +#endif +} + +Metric Filler::get_metric(double x,double y,double z){ + double angle; + Metric m; + + angle = atan2(z,x); + m = Metric(); + + m.set_m11(1.0); + m.set_m21(0.0); + m.set_m31(0.0); + + m.set_m12(0.0); + m.set_m22(1.0); + m.set_m32(0.0); + + m.set_m13(0.0); + m.set_m23(0.0); + m.set_m33(1.0); + + return m; +} + +double Filler::get_size(double x,double y,double z){ + return 0.25; +} + +bool Filler::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; +} + +bool Filler::far_from_boundary(MElementOctree* octree,Node* node){ + double x,y,z; + double h; + SPoint3 point; + MElement *e1,*e2,*e3,*e4,*e5,*e6; + + point = node->get_point(); + x = point.x(); + y = point.y(); + z = point.z(); + h = node->get_size(); + + e1 = (MElement*)octree->find(x+k2*h,y,z,3,true); + e2 = (MElement*)octree->find(x-k2*h,y,z,3,true); + e3 = (MElement*)octree->find(x,y+k2*h,z,3,true); + e4 = (MElement*)octree->find(x,y-k2*h,z,3,true); + e5 = (MElement*)octree->find(x,y,z+k2*h,3,true); + e6 = (MElement*)octree->find(x,y,z-k2*h,3,true); + + if(e1!=NULL && e2!=NULL && e3!=NULL && e4!=NULL && e5!=NULL && e6!=NULL) return 1; + else return 0; +} + +void Filler::compute_parameters(Node* node){ + double x,y,z; + double h; + Metric m; + SPoint3 point; + + point = node->get_point(); + x = point.x(); + y = point.y(); + z = point.z(); + m = get_metric(x,y,z); + h = get_size(x,y,z); + node->set_size(h); + node->set_metric(m); + node->min[0] = x - sqrt2*k1*h; + node->min[1] = y - sqrt2*k1*h; + node->min[2] = z - sqrt2*k1*h; + node->max[0] = x + sqrt2*k1*h; + node->max[1] = y + sqrt2*k1*h; + node->max[2] = z + sqrt2*k1*h; +} + +void Filler::offsprings(MElementOctree* octree,Node* node,Node* n1,Node* n2,Node* n3,Node* n4,Node* n5,Node* n6){ + double x,y,z; + double x1,y1,z1; + double x2,y2,z2; + double x3,y3,z3; + double x4,y4,z4; + double x5,y5,z5; + double x6,y6,z6; + double h; + double h1,h2,h3,h4,h5,h6; + Metric m; + SPoint3 point; + + point = node->get_point(); + x = point.x(); + y = point.y(); + z = point.z(); + h = node->get_size(); + m = node->get_metric(); + + h1 = improvement(octree,point,h,SVector3(m.get_m11(),m.get_m21(),m.get_m31())); + x1 = x + h1*m.get_m11(); + y1 = y + h1*m.get_m21(); + z1 = z + h1*m.get_m31(); + + h2 = improvement(octree,point,h,SVector3(-m.get_m11(),-m.get_m21(),-m.get_m31())); + x2 = x - h2*m.get_m11(); + y2 = y - h2*m.get_m21(); + z2 = z - h2*m.get_m31(); + + h3 = improvement(octree,point,h,SVector3(m.get_m12(),m.get_m22(),m.get_m32())); + x3 = x + h3*m.get_m12(); + y3 = y + h3*m.get_m22(); + z3 = z + h3*m.get_m32(); + + h4 = improvement(octree,point,h,SVector3(-m.get_m12(),-m.get_m22(),-m.get_m32())); + x4 = x - h4*m.get_m12(); + y4 = y - h4*m.get_m22(); + z4 = z - h4*m.get_m32(); + + h5 = improvement(octree,point,h,SVector3(m.get_m13(),m.get_m23(),m.get_m33())); + x5 = x + h5*m.get_m13(); + y5 = y + h5*m.get_m23(); + z5 = z + h5*m.get_m33(); + + h6 = improvement(octree,point,h,SVector3(-m.get_m13(),-m.get_m23(),-m.get_m33())); + x6 = x - h6*m.get_m13(); + y6 = y - h6*m.get_m23(); + z6 = z - h6*m.get_m33(); + + *n1 = Node(SPoint3(x1,y1,z1)); + *n2 = Node(SPoint3(x2,y2,z2)); + *n3 = Node(SPoint3(x3,y3,z3)); + *n4 = Node(SPoint3(x4,y4,z4)); + *n5 = Node(SPoint3(x5,y5,z5)); + *n6 = Node(SPoint3(x6,y6,z6)); +} + +double Filler::improvement(MElementOctree* octree,SPoint3 point,double h_nearer,SVector3 direction){ + double x,y,z; + double average; + double h_farther; + double coeffA,coeffB; + + x = point.x() + h_nearer*direction.x(); + y = point.y() + h_nearer*direction.y(); + z = point.z() + h_nearer*direction.z(); + if(inside_domain(octree,x,y,z)){ + h_farther = get_size(x,y,z); + } + else h_farther = h_nearer; + + coeffA = 1.0; + coeffB = 0.2; + if(h_farther>h_nearer){ + average = coeffA*h_nearer + (1.0-coeffA)*h_farther; + } + else{ + average = coeffB*h_nearer + (1.0-coeffB)*h_farther; + } + return average; +} + +int Filler::get_nbr_new_vertices(){ + return new_vertices.size(); +} + +MVertex* Filler::get_new_vertex(int i){ + return new_vertices[i]; +} + +void Filler::print_segment(SPoint3 p1,SPoint3 p2,std::ofstream& file){ + file << "SL (" + << p1.x() << ", " << p1.y() << ", " << p1.z() << ", " + << p2.x() << ", " << p2.y() << ", " << p2.z() << ")" + << "{10, 20};\n"; +} + +void Filler::print_node(Node* node,std::ofstream& file){ + double x,y,z; + double x1,y1,z1; + double x2,y2,z2; + double x3,y3,z3; + double x4,y4,z4; + double x5,y5,z5; + double x6,y6,z6; + double h; + Metric m; + SPoint3 point; + + point = node->get_point(); + x = point.x(); + y = point.y(); + z = point.z(); + h = node->get_size(); + m = node->get_metric(); + + x1 = x + h*m.get_m11(); + y1 = y + h*m.get_m21(); + z1 = z + h*m.get_m31(); + x2 = x - h*m.get_m11(); + y2 = y - h*m.get_m21(); + z2 = z - h*m.get_m31(); + x3 = x + h*m.get_m12(); + y3 = y + h*m.get_m22(); + z3 = z + h*m.get_m32(); + x4 = x - h*m.get_m12(); + y4 = y - h*m.get_m22(); + z4 = z - h*m.get_m32(); + x5 = x + h*m.get_m13(); + y5 = y + h*m.get_m23(); + z5 = z + h*m.get_m33(); + x6 = x - h*m.get_m13(); + y6 = y - h*m.get_m23(); + z6 = z - h*m.get_m33(); + + print_segment(SPoint3(x,y,z),SPoint3(x1,y1,z1),file); + print_segment(SPoint3(x,y,z),SPoint3(x2,y2,z2),file); + print_segment(SPoint3(x,y,z),SPoint3(x3,y3,z3),file); + print_segment(SPoint3(x,y,z),SPoint3(x4,y4,z4),file); + print_segment(SPoint3(x,y,z),SPoint3(x5,y5,z5),file); + print_segment(SPoint3(x,y,z),SPoint3(x6,y6,z6),file); +} + +/*********static declarations*********/ + +std::vector<MVertex*> Filler::new_vertices; diff --git a/Mesh/simple3D.h b/Mesh/simple3D.h new file mode 100755 index 0000000000000000000000000000000000000000..41e29a7af387772924862091092cf28ac33491e2 --- /dev/null +++ b/Mesh/simple3D.h @@ -0,0 +1,33 @@ +// Gmsh - Copyright (C) 1997-2011 C. Geuzaine, J.-F. Remacle +// +// See the LICENSE.txt file for license information. Please report all +// bugs and problems to <gmsh@geuz.org>. + +#include "SVector3.h" +#include <list> +#include "GRegion.h" +#include "MElementOctree.h" + +class Node; +class Metric; + +class Filler{ + private: + static std::vector<MVertex*> new_vertices; + Metric get_metric(double,double,double); + double get_size(double,double,double); + bool inside_domain(MElementOctree*,double,double,double); + bool far_from_boundary(MElementOctree*,Node*); + void compute_parameters(Node*); + void offsprings(MElementOctree*,Node*,Node*,Node*,Node*,Node*,Node*,Node*); + double improvement(MElementOctree*,SPoint3,double,SVector3); + void print_segment(SPoint3,SPoint3,std::ofstream&); + void print_node(Node*,std::ofstream&); + public: + Filler(); + ~Filler(); + void treat_model(); + void treat_region(GRegion*); + static int get_nbr_new_vertices(); + static MVertex* get_new_vertex(int); +}; \ No newline at end of file diff --git a/Mesh/voronoi3D.cpp b/Mesh/voronoi3D.cpp new file mode 100755 index 0000000000000000000000000000000000000000..87197a0f303fadd87dd359c7bfacca4b4695692b --- /dev/null +++ b/Mesh/voronoi3D.cpp @@ -0,0 +1,305 @@ +// Gmsh - Copyright (C) 1997-2011 C. Geuzaine, J.-F. Remacle +// +// See the LICENSE.txt file for license information. Please report all +// bugs and problems to <gmsh@geuz.org>. + +#include "Voronoi3D.h" +#include "GModel.h" +#include "MElement.h" +#include "meshGRegion.h" +#include <fstream> +#include "Levy3D.h" +#if defined(HAVE_Voro3D) +#include "voro++.hh" +#endif + +#if defined(HAVE_Voro3D) +using namespace voro; +#endif + +/*********class clip*********/ + +clip::clip(){} + +clip::~clip(){} + +void clip::execute(){ + GRegion* gr; + GModel* model = GModel::current(); + GModel::riter it; + + for(it=model->firstRegion();it!=model->lastRegion();it++) + { + gr = *it; + if(gr->getNumMeshElements()>0){ + execute(gr); + } + } +} + +void clip::execute(GRegion* gr){ + int i; + int j; + MElement* element; + MVertex* vertex; + std::vector<SPoint3> vertices2; + std::set<MVertex*> vertices; + std::set<MVertex*>::iterator it; + std::vector<VoronoiElement> clipped; + + for(i=0;i<gr->getNumMeshElements();i++){ + element = gr->getMeshElement(i); + for(j=0;j<element->getNumVertices();j++){ + vertex = element->getVertex(j); + vertices.insert(vertex); + } + } + + for(it=vertices.begin();it!=vertices.end();it++){ + vertices2.push_back(SPoint3((*it)->x(),(*it)->y(),(*it)->z())); + } + + execute(vertices2,clipped); + printf("%d\n",clipped.size()); + + std::ofstream file("cells.pos"); + file << "View \"test\" {\n"; + for(i=0;i<clipped.size();i++){ + print_segment(clipped[i].get_v1().get_point(),clipped[i].get_v2().get_point(),file); + print_segment(clipped[i].get_v1().get_point(),clipped[i].get_v3().get_point(),file); + print_segment(clipped[i].get_v1().get_point(),clipped[i].get_v4().get_point(),file); + print_segment(clipped[i].get_v2().get_point(),clipped[i].get_v3().get_point(),file); + print_segment(clipped[i].get_v3().get_point(),clipped[i].get_v4().get_point(),file); + print_segment(clipped[i].get_v4().get_point(),clipped[i].get_v2().get_point(),file); + } + file << "};\n"; +} + +void clip::execute(std::vector<SPoint3>& vertices,std::vector<VoronoiElement>& clipped){ +#if defined(HAVE_Voro3D) + int i; + int j; + int start; + int end; + int index; + int index1; + int index2; + int index3; + int count; + int pid; + double x,y,z; + double x1,y1,z1; + double x2,y2,z2; + double x3,y3,z3; + double delta; + double min_x,max_x; + double min_y,max_y; + double min_z,max_z; + double volume1; + double volume2; + double l1,l2,l3,l4,l5; + voronoicell_neighbor* pointer; + voronoicell_neighbor cell; + VoronoiVertex v1,v2,v3,v4; + VoronoiElement e; + std::vector<int> faces; + std::vector<double> voronoi_vertices; + std::vector<voronoicell_neighbor*> pointers; + std::vector<SPoint3> generators; + std::vector<int> IDs; + std::vector<int> IDs2; + std::vector<int> neighbors; + std::vector<std::vector<std::vector<int> > > bisectors; + + min_x = 1000000000.0; + max_x = -1000000000.0; + min_y = 1000000000.0; + max_y = -1000000000.0; + min_z = 1000000000.0; + max_z = -1000000000.0; + for(i=0;i<vertices.size();i++){ + min_x = min(vertices[i].x(),min_x); + max_x = max(vertices[i].x(),max_x); + min_y = min(vertices[i].y(),min_y); + max_y = max(vertices[i].y(),max_y); + min_z = min(vertices[i].z(),min_z); + max_z = max(vertices[i].z(),max_z); + } + + delta = 0.2*(max_x - min_x); + container cont(min_x-delta,max_x+delta,min_y-delta,max_y+delta,min_z-delta,max_z+delta,6,6,6,false,false,false,vertices.size()); + volume1 = (max_x-min_x+2.0*delta)*(max_y-min_y+2.0*delta)*(max_z-min_z+2.0*delta); + + for(i=0;i<vertices.size();i++){ + cont.put(i,vertices[i].x(),vertices[i].y(),vertices[i].z()); + } + + count = 0; + IDs.resize(vertices.size()); + c_loop_all loop(cont); + loop.start(); + do{ + cont.compute_cell(cell,loop); + loop.pos(x,y,z); + pointer = new voronoicell_neighbor(); + *pointer = cell; + pointers.push_back(pointer); + generators.push_back(SPoint3(x,y,z)); + pid = loop.pid(); + IDs[pid] = count; + IDs2.push_back(pid); + count++; + }while(loop.inc()); + + bisectors.resize(pointers.size()); + for(i=0;i<pointers.size();i++){ + faces.clear(); + voronoi_vertices.clear(); + pointers[i]->face_vertices(faces); + pointers[i]->neighbors(neighbors); + pointers[i]->vertices(generators[i].x(),generators[i].y(),generators[i].z(),voronoi_vertices); + bisectors[i].resize(voronoi_vertices.size()/3); + for(j=0;j<bisectors[i].size();j++){ + bisectors[i][j].push_back(IDs2[i]); + } + count = 0; + end = 0; + while(end<faces.size()){ + start = end + 1; + end = start + faces[end]; + for(j=start;j<end;j++){ + index = faces[j]; + bisectors[i][index].push_back(neighbors[count]); + } + count++; + } + } + + for(i=0;i<bisectors.size();i++){ + for(j=0;j<bisectors[i].size();j++){ + //printf("%d %d %d %d %d %d\n",i,IDs2[i],bisectors[i][j][0],bisectors[i][j][1],bisectors[i][j][2],bisectors[i][j][3]); + } + } + + for(i=0;i<pointers.size();i++){ + faces.clear(); + voronoi_vertices.clear(); + pointers[i]->face_vertices(faces); + pointers[i]->vertices(generators[i].x(),generators[i].y(),generators[i].z(),voronoi_vertices); + end = 0; + while(end<faces.size()){ + start = end + 1; + end = start + faces[end]; + for(j=start+1;j<end-1;j++){ + index1 = faces[start]; + index2 = faces[j]; + index3 = faces[j+1]; + x1 = voronoi_vertices[3*index1]; + y1 = voronoi_vertices[3*index1+1]; + z1 = voronoi_vertices[3*index1+2]; + x2 = voronoi_vertices[3*index2]; + y2 = voronoi_vertices[3*index2+1]; + z2 = voronoi_vertices[3*index2+2]; + x3 = voronoi_vertices[3*index3]; + y3 = voronoi_vertices[3*index3+1]; + z3 = voronoi_vertices[3*index3+2]; + v1 = VoronoiVertex(); + v2 = VoronoiVertex(); + v3 = VoronoiVertex(); + v4 = VoronoiVertex(); + v1.set_point(SPoint3(generators[i].x(),generators[i].y(),generators[i].z())); + v1.set_category(4); + v1.set_index1(IDs2[i]); + v2.set_point(SPoint3(x1,y1,z1)); + v2.set_category(category(bisectors[i][index1][0],bisectors[i][index1][1],bisectors[i][index1][2],bisectors[i][index1][3])); + v2.set_index1(bisectors[i][index1][0]); + v2.set_index2(bisectors[i][index1][1]); + v2.set_index3(bisectors[i][index1][2]); + v2.set_index4(bisectors[i][index1][3]); + v3.set_point(SPoint3(x2,y2,z2)); + v3.set_category(category(bisectors[i][index2][0],bisectors[i][index2][1],bisectors[i][index2][2],bisectors[i][index2][3])); + v3.set_index1(bisectors[i][index2][0]); + v3.set_index2(bisectors[i][index2][1]); + v3.set_index3(bisectors[i][index2][2]); + v3.set_index4(bisectors[i][index2][3]); + v4.set_point(SPoint3(x3,y3,z3)); + v4.set_category(category(bisectors[i][index3][0],bisectors[i][index3][1],bisectors[i][index3][2],bisectors[i][index3][3])); + v4.set_index1(bisectors[i][index3][0]); + v4.set_index2(bisectors[i][index3][1]); + v4.set_index3(bisectors[i][index3][2]); + v4.set_index4(bisectors[i][index3][3]); + e = VoronoiElement(); + e.set_v1(v1); + e.set_v2(v2); + e.set_v3(v3); + e.set_v4(v4); + clipped.push_back(e); + } + } + } + + volume2 = 0.0; + for(i=0;i<clipped.size();i++){ + if(clipped[i].get_v2().get_category()==1){ + l1 = (clipped[i].get_v2().get_point()).distance(clipped[i].get_v1().get_point()); + l2 = (clipped[i].get_v2().get_point()).distance(generators[IDs[clipped[i].get_v2().get_index1()]]); + l3 = (clipped[i].get_v2().get_point()).distance(generators[IDs[clipped[i].get_v2().get_index2()]]); + l4 = (clipped[i].get_v2().get_point()).distance(generators[IDs[clipped[i].get_v2().get_index3()]]); + l5 = (clipped[i].get_v2().get_point()).distance(generators[IDs[clipped[i].get_v2().get_index4()]]); + //printf("%f %f %f %f %f %f %f %f %f\n",l1,l2,l3,l4,l5,l1-l2,l1-l3,l1-l4,l1-l5); + } + if(clipped[i].get_v3().get_category()==1){ + l1 = (clipped[i].get_v3().get_point()).distance(clipped[i].get_v1().get_point()); + l2 = (clipped[i].get_v3().get_point()).distance(generators[IDs[clipped[i].get_v3().get_index1()]]); + l3 = (clipped[i].get_v3().get_point()).distance(generators[IDs[clipped[i].get_v3().get_index2()]]); + l4 = (clipped[i].get_v3().get_point()).distance(generators[IDs[clipped[i].get_v3().get_index3()]]); + l5 = (clipped[i].get_v3().get_point()).distance(generators[IDs[clipped[i].get_v3().get_index4()]]); + //printf("%f %f %f %f %f %f %f %f %f\n",l1,l2,l3,l4,l5,l1-l2,l1-l3,l1-l4,l1-l5); + } + if(clipped[i].get_v4().get_category()==1){ + l1 = (clipped[i].get_v4().get_point()).distance(clipped[i].get_v1().get_point()); + l2 = (clipped[i].get_v4().get_point()).distance(generators[IDs[clipped[i].get_v4().get_index1()]]); + l3 = (clipped[i].get_v4().get_point()).distance(generators[IDs[clipped[i].get_v4().get_index2()]]); + l4 = (clipped[i].get_v4().get_point()).distance(generators[IDs[clipped[i].get_v4().get_index3()]]); + l5 = (clipped[i].get_v4().get_point()).distance(generators[IDs[clipped[i].get_v4().get_index4()]]); + //printf("%f %f %f %f %f %f %f %f %f\n",l1,l2,l3,l4,l5,l1-l2,l1-l3,l1-l4,l1-l5); + } + clipped[i].compute_jacobian(); + volume2 = volume2 + fabs(clipped[i].get_jacobian())/6.0; + } + //printf("%f %f\n",volume1,volume2); + + for(i=0;i<pointers.size();i++) delete pointers[i]; +#endif +} + +double clip::min(double a,double b){ + if(a<b) return a; + else return b; +} + +double clip::max(double a,double b){ + if(a>b) return a; + else return b; +} + +int clip::category(int a,int b,int c,int d) +{ + int count; + count = 0; + if(a<0) count++; + if(b<0) count++; + if(c<0) count++; + if(d<0) count++; + if(count==0) return 1; + else if(count==1) return 2; + else if(count==2) return 3; + else return 4; +} + +void clip::print_segment(SPoint3 p1,SPoint3 p2,std::ofstream& file){ + file << "SL (" + << p1.x() << ", " << p1.y() << ", " << p1.z() << ", " + << p2.x() << ", " << p2.y() << ", " << p2.z() + << "){10, 20};\n"; +} \ No newline at end of file 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/contrib/lbfgs/solvers.cpp b/contrib/lbfgs/solvers.cpp new file mode 100755 index 0000000000000000000000000000000000000000..595486b309f676d0fd0c3d51cfe3d2b8e1564ca1 --- /dev/null +++ b/contrib/lbfgs/solvers.cpp @@ -0,0 +1,5665 @@ +/************************************************************************* +Copyright (c) Sergey Bochkanov (ALGLIB project). + +>>> SOURCE LICENSE >>> +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation (www.fsf.org); either version 2 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +A copy of the GNU General Public License is available at +http://www.fsf.org/licensing/licenses +>>> END OF LICENSE >>> +*************************************************************************/ +#include "stdafx.h" +#include "solvers.h" + +// disable some irrelevant warnings +#if (AE_COMPILER==AE_MSVC) +#pragma warning(disable:4100) +#pragma warning(disable:4127) +#pragma warning(disable:4702) +#pragma warning(disable:4996) +#endif +using namespace std; + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS IMPLEMENTATION OF C++ INTERFACE +// +///////////////////////////////////////////////////////////////////////// +namespace alglib +{ + + +/************************************************************************* + +*************************************************************************/ +_densesolverreport_owner::_densesolverreport_owner() +{ + p_struct = (alglib_impl::densesolverreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::densesolverreport), NULL); + if( p_struct==NULL ) + throw ap_error("ALGLIB: malloc error"); + if( !alglib_impl::_densesolverreport_init(p_struct, NULL, ae_false) ) + throw ap_error("ALGLIB: malloc error"); +} + +_densesolverreport_owner::_densesolverreport_owner(const _densesolverreport_owner &rhs) +{ + p_struct = (alglib_impl::densesolverreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::densesolverreport), NULL); + if( p_struct==NULL ) + throw ap_error("ALGLIB: malloc error"); + if( !alglib_impl::_densesolverreport_init_copy(p_struct, const_cast<alglib_impl::densesolverreport*>(rhs.p_struct), NULL, ae_false) ) + throw ap_error("ALGLIB: malloc error"); +} + +_densesolverreport_owner& _densesolverreport_owner::operator=(const _densesolverreport_owner &rhs) +{ + if( this==&rhs ) + return *this; + alglib_impl::_densesolverreport_clear(p_struct); + if( !alglib_impl::_densesolverreport_init_copy(p_struct, const_cast<alglib_impl::densesolverreport*>(rhs.p_struct), NULL, ae_false) ) + throw ap_error("ALGLIB: malloc error"); + return *this; +} + +_densesolverreport_owner::~_densesolverreport_owner() +{ + alglib_impl::_densesolverreport_clear(p_struct); + ae_free(p_struct); +} + +alglib_impl::densesolverreport* _densesolverreport_owner::c_ptr() +{ + return p_struct; +} + +alglib_impl::densesolverreport* _densesolverreport_owner::c_ptr() const +{ + return const_cast<alglib_impl::densesolverreport*>(p_struct); +} +densesolverreport::densesolverreport() : _densesolverreport_owner() ,r1(p_struct->r1),rinf(p_struct->rinf) +{ +} + +densesolverreport::densesolverreport(const densesolverreport &rhs):_densesolverreport_owner(rhs) ,r1(p_struct->r1),rinf(p_struct->rinf) +{ +} + +densesolverreport& densesolverreport::operator=(const densesolverreport &rhs) +{ + if( this==&rhs ) + return *this; + _densesolverreport_owner::operator=(rhs); + return *this; +} + +densesolverreport::~densesolverreport() +{ +} + + +/************************************************************************* + +*************************************************************************/ +_densesolverlsreport_owner::_densesolverlsreport_owner() +{ + p_struct = (alglib_impl::densesolverlsreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::densesolverlsreport), NULL); + if( p_struct==NULL ) + throw ap_error("ALGLIB: malloc error"); + if( !alglib_impl::_densesolverlsreport_init(p_struct, NULL, ae_false) ) + throw ap_error("ALGLIB: malloc error"); +} + +_densesolverlsreport_owner::_densesolverlsreport_owner(const _densesolverlsreport_owner &rhs) +{ + p_struct = (alglib_impl::densesolverlsreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::densesolverlsreport), NULL); + if( p_struct==NULL ) + throw ap_error("ALGLIB: malloc error"); + if( !alglib_impl::_densesolverlsreport_init_copy(p_struct, const_cast<alglib_impl::densesolverlsreport*>(rhs.p_struct), NULL, ae_false) ) + throw ap_error("ALGLIB: malloc error"); +} + +_densesolverlsreport_owner& _densesolverlsreport_owner::operator=(const _densesolverlsreport_owner &rhs) +{ + if( this==&rhs ) + return *this; + alglib_impl::_densesolverlsreport_clear(p_struct); + if( !alglib_impl::_densesolverlsreport_init_copy(p_struct, const_cast<alglib_impl::densesolverlsreport*>(rhs.p_struct), NULL, ae_false) ) + throw ap_error("ALGLIB: malloc error"); + return *this; +} + +_densesolverlsreport_owner::~_densesolverlsreport_owner() +{ + alglib_impl::_densesolverlsreport_clear(p_struct); + ae_free(p_struct); +} + +alglib_impl::densesolverlsreport* _densesolverlsreport_owner::c_ptr() +{ + return p_struct; +} + +alglib_impl::densesolverlsreport* _densesolverlsreport_owner::c_ptr() const +{ + return const_cast<alglib_impl::densesolverlsreport*>(p_struct); +} +densesolverlsreport::densesolverlsreport() : _densesolverlsreport_owner() ,r2(p_struct->r2),cx(&p_struct->cx),n(p_struct->n),k(p_struct->k) +{ +} + +densesolverlsreport::densesolverlsreport(const densesolverlsreport &rhs):_densesolverlsreport_owner(rhs) ,r2(p_struct->r2),cx(&p_struct->cx),n(p_struct->n),k(p_struct->k) +{ +} + +densesolverlsreport& densesolverlsreport::operator=(const densesolverlsreport &rhs) +{ + if( this==&rhs ) + return *this; + _densesolverlsreport_owner::operator=(rhs); + return *this; +} + +densesolverlsreport::~densesolverlsreport() +{ +} + +/************************************************************************* +Dense solver. + +This subroutine solves a system A*x=b, where A is NxN non-denegerate +real matrix, x and b are vectors. + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* iterative refinement +* O(N^3) complexity + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + B - array[0..N-1], right part + +OUTPUT PARAMETERS + Info - return code: + * -3 A is singular, or VERY close to singular. + X is filled by zeros in such cases. + * -1 N<=0 was passed + * 1 task is solved (but matrix A may be ill-conditioned, + check R1/RInf parameters for condition numbers). + Rep - solver report, see below for more info + X - array[0..N-1], it contains: + * solution of A*x=b if A is non-singular (well-conditioned + or ill-conditioned, but not very close to singular) + * zeros, if A is singular or VERY close to singular + (in this case Info=-3). + +SOLVER REPORT + +Subroutine sets following fields of the Rep structure: +* R1 reciprocal of condition number: 1/cond(A), 1-norm. +* RInf reciprocal of condition number: 1/cond(A), inf-norm. + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void rmatrixsolve(const real_2d_array &a, const ae_int_t n, const real_1d_array &b, ae_int_t &info, densesolverreport &rep, real_1d_array &x) +{ + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + try + { + alglib_impl::rmatrixsolve(const_cast<alglib_impl::ae_matrix*>(a.c_ptr()), n, const_cast<alglib_impl::ae_vector*>(b.c_ptr()), &info, const_cast<alglib_impl::densesolverreport*>(rep.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; + } +} + +/************************************************************************* +Dense solver. + +Similar to RMatrixSolve() but solves task with multiple right parts (where +b and x are NxM matrices). + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* optional iterative refinement +* O(N^3+M*N^2) complexity + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + B - array[0..N-1,0..M-1], right part + M - right part size + RFS - iterative refinement switch: + * True - refinement is used. + Less performance, more precision. + * False - refinement is not used. + More performance, less precision. + +OUTPUT PARAMETERS + Info - same as in RMatrixSolve + Rep - same as in RMatrixSolve + X - same as in RMatrixSolve + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void rmatrixsolvem(const real_2d_array &a, const ae_int_t n, const real_2d_array &b, const ae_int_t m, const bool rfs, ae_int_t &info, densesolverreport &rep, real_2d_array &x) +{ + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + try + { + alglib_impl::rmatrixsolvem(const_cast<alglib_impl::ae_matrix*>(a.c_ptr()), n, const_cast<alglib_impl::ae_matrix*>(b.c_ptr()), m, rfs, &info, const_cast<alglib_impl::densesolverreport*>(rep.c_ptr()), const_cast<alglib_impl::ae_matrix*>(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; + } +} + +/************************************************************************* +Dense solver. + +This subroutine solves a system A*X=B, where A is NxN non-denegerate +real matrix given by its LU decomposition, X and B are NxM real matrices. + +Algorithm features: +* automatic detection of degenerate cases +* O(N^2) complexity +* condition number estimation + +No iterative refinement is provided because exact form of original matrix +is not known to subroutine. Use RMatrixSolve or RMatrixMixedSolve if you +need iterative refinement. + +INPUT PARAMETERS + LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result + P - array[0..N-1], pivots array, RMatrixLU result + N - size of A + B - array[0..N-1], right part + +OUTPUT PARAMETERS + Info - same as in RMatrixSolve + Rep - same as in RMatrixSolve + X - same as in RMatrixSolve + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void rmatrixlusolve(const real_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const real_1d_array &b, ae_int_t &info, densesolverreport &rep, real_1d_array &x) +{ + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + try + { + alglib_impl::rmatrixlusolve(const_cast<alglib_impl::ae_matrix*>(lua.c_ptr()), const_cast<alglib_impl::ae_vector*>(p.c_ptr()), n, const_cast<alglib_impl::ae_vector*>(b.c_ptr()), &info, const_cast<alglib_impl::densesolverreport*>(rep.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; + } +} + +/************************************************************************* +Dense solver. + +Similar to RMatrixLUSolve() but solves task with multiple right parts +(where b and x are NxM matrices). + +Algorithm features: +* automatic detection of degenerate cases +* O(M*N^2) complexity +* condition number estimation + +No iterative refinement is provided because exact form of original matrix +is not known to subroutine. Use RMatrixSolve or RMatrixMixedSolve if you +need iterative refinement. + +INPUT PARAMETERS + LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result + P - array[0..N-1], pivots array, RMatrixLU result + N - size of A + B - array[0..N-1,0..M-1], right part + M - right part size + +OUTPUT PARAMETERS + Info - same as in RMatrixSolve + Rep - same as in RMatrixSolve + X - same as in RMatrixSolve + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void rmatrixlusolvem(const real_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const real_2d_array &b, const ae_int_t m, ae_int_t &info, densesolverreport &rep, real_2d_array &x) +{ + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + try + { + alglib_impl::rmatrixlusolvem(const_cast<alglib_impl::ae_matrix*>(lua.c_ptr()), const_cast<alglib_impl::ae_vector*>(p.c_ptr()), n, const_cast<alglib_impl::ae_matrix*>(b.c_ptr()), m, &info, const_cast<alglib_impl::densesolverreport*>(rep.c_ptr()), const_cast<alglib_impl::ae_matrix*>(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; + } +} + +/************************************************************************* +Dense solver. + +This subroutine solves a system A*x=b, where BOTH ORIGINAL A AND ITS +LU DECOMPOSITION ARE KNOWN. You can use it if for some reasons you have +both A and its LU decomposition. + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* iterative refinement +* O(N^2) complexity + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result + P - array[0..N-1], pivots array, RMatrixLU result + N - size of A + B - array[0..N-1], right part + +OUTPUT PARAMETERS + Info - same as in RMatrixSolveM + Rep - same as in RMatrixSolveM + X - same as in RMatrixSolveM + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void rmatrixmixedsolve(const real_2d_array &a, const real_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const real_1d_array &b, ae_int_t &info, densesolverreport &rep, real_1d_array &x) +{ + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + try + { + alglib_impl::rmatrixmixedsolve(const_cast<alglib_impl::ae_matrix*>(a.c_ptr()), const_cast<alglib_impl::ae_matrix*>(lua.c_ptr()), const_cast<alglib_impl::ae_vector*>(p.c_ptr()), n, const_cast<alglib_impl::ae_vector*>(b.c_ptr()), &info, const_cast<alglib_impl::densesolverreport*>(rep.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; + } +} + +/************************************************************************* +Dense solver. + +Similar to RMatrixMixedSolve() but solves task with multiple right parts +(where b and x are NxM matrices). + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* iterative refinement +* O(M*N^2) complexity + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result + P - array[0..N-1], pivots array, RMatrixLU result + N - size of A + B - array[0..N-1,0..M-1], right part + M - right part size + +OUTPUT PARAMETERS + Info - same as in RMatrixSolveM + Rep - same as in RMatrixSolveM + X - same as in RMatrixSolveM + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void rmatrixmixedsolvem(const real_2d_array &a, const real_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const real_2d_array &b, const ae_int_t m, ae_int_t &info, densesolverreport &rep, real_2d_array &x) +{ + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + try + { + alglib_impl::rmatrixmixedsolvem(const_cast<alglib_impl::ae_matrix*>(a.c_ptr()), const_cast<alglib_impl::ae_matrix*>(lua.c_ptr()), const_cast<alglib_impl::ae_vector*>(p.c_ptr()), n, const_cast<alglib_impl::ae_matrix*>(b.c_ptr()), m, &info, const_cast<alglib_impl::densesolverreport*>(rep.c_ptr()), const_cast<alglib_impl::ae_matrix*>(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; + } +} + +/************************************************************************* +Dense solver. Same as RMatrixSolveM(), but for complex matrices. + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* iterative refinement +* O(N^3+M*N^2) complexity + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + B - array[0..N-1,0..M-1], right part + M - right part size + RFS - iterative refinement switch: + * True - refinement is used. + Less performance, more precision. + * False - refinement is not used. + More performance, less precision. + +OUTPUT PARAMETERS + Info - same as in RMatrixSolve + Rep - same as in RMatrixSolve + X - same as in RMatrixSolve + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void cmatrixsolvem(const complex_2d_array &a, const ae_int_t n, const complex_2d_array &b, const ae_int_t m, const bool rfs, ae_int_t &info, densesolverreport &rep, complex_2d_array &x) +{ + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + try + { + alglib_impl::cmatrixsolvem(const_cast<alglib_impl::ae_matrix*>(a.c_ptr()), n, const_cast<alglib_impl::ae_matrix*>(b.c_ptr()), m, rfs, &info, const_cast<alglib_impl::densesolverreport*>(rep.c_ptr()), const_cast<alglib_impl::ae_matrix*>(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; + } +} + +/************************************************************************* +Dense solver. Same as RMatrixSolve(), but for complex matrices. + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* iterative refinement +* O(N^3) complexity + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + B - array[0..N-1], right part + +OUTPUT PARAMETERS + Info - same as in RMatrixSolve + Rep - same as in RMatrixSolve + X - same as in RMatrixSolve + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void cmatrixsolve(const complex_2d_array &a, const ae_int_t n, const complex_1d_array &b, ae_int_t &info, densesolverreport &rep, complex_1d_array &x) +{ + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + try + { + alglib_impl::cmatrixsolve(const_cast<alglib_impl::ae_matrix*>(a.c_ptr()), n, const_cast<alglib_impl::ae_vector*>(b.c_ptr()), &info, const_cast<alglib_impl::densesolverreport*>(rep.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; + } +} + +/************************************************************************* +Dense solver. Same as RMatrixLUSolveM(), but for complex matrices. + +Algorithm features: +* automatic detection of degenerate cases +* O(M*N^2) complexity +* condition number estimation + +No iterative refinement is provided because exact form of original matrix +is not known to subroutine. Use CMatrixSolve or CMatrixMixedSolve if you +need iterative refinement. + +INPUT PARAMETERS + LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result + P - array[0..N-1], pivots array, RMatrixLU result + N - size of A + B - array[0..N-1,0..M-1], right part + M - right part size + +OUTPUT PARAMETERS + Info - same as in RMatrixSolve + Rep - same as in RMatrixSolve + X - same as in RMatrixSolve + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void cmatrixlusolvem(const complex_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const complex_2d_array &b, const ae_int_t m, ae_int_t &info, densesolverreport &rep, complex_2d_array &x) +{ + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + try + { + alglib_impl::cmatrixlusolvem(const_cast<alglib_impl::ae_matrix*>(lua.c_ptr()), const_cast<alglib_impl::ae_vector*>(p.c_ptr()), n, const_cast<alglib_impl::ae_matrix*>(b.c_ptr()), m, &info, const_cast<alglib_impl::densesolverreport*>(rep.c_ptr()), const_cast<alglib_impl::ae_matrix*>(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; + } +} + +/************************************************************************* +Dense solver. Same as RMatrixLUSolve(), but for complex matrices. + +Algorithm features: +* automatic detection of degenerate cases +* O(N^2) complexity +* condition number estimation + +No iterative refinement is provided because exact form of original matrix +is not known to subroutine. Use CMatrixSolve or CMatrixMixedSolve if you +need iterative refinement. + +INPUT PARAMETERS + LUA - array[0..N-1,0..N-1], LU decomposition, CMatrixLU result + P - array[0..N-1], pivots array, CMatrixLU result + N - size of A + B - array[0..N-1], right part + +OUTPUT PARAMETERS + Info - same as in RMatrixSolve + Rep - same as in RMatrixSolve + X - same as in RMatrixSolve + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void cmatrixlusolve(const complex_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const complex_1d_array &b, ae_int_t &info, densesolverreport &rep, complex_1d_array &x) +{ + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + try + { + alglib_impl::cmatrixlusolve(const_cast<alglib_impl::ae_matrix*>(lua.c_ptr()), const_cast<alglib_impl::ae_vector*>(p.c_ptr()), n, const_cast<alglib_impl::ae_vector*>(b.c_ptr()), &info, const_cast<alglib_impl::densesolverreport*>(rep.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; + } +} + +/************************************************************************* +Dense solver. Same as RMatrixMixedSolveM(), but for complex matrices. + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* iterative refinement +* O(M*N^2) complexity + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + LUA - array[0..N-1,0..N-1], LU decomposition, CMatrixLU result + P - array[0..N-1], pivots array, CMatrixLU result + N - size of A + B - array[0..N-1,0..M-1], right part + M - right part size + +OUTPUT PARAMETERS + Info - same as in RMatrixSolveM + Rep - same as in RMatrixSolveM + X - same as in RMatrixSolveM + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void cmatrixmixedsolvem(const complex_2d_array &a, const complex_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const complex_2d_array &b, const ae_int_t m, ae_int_t &info, densesolverreport &rep, complex_2d_array &x) +{ + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + try + { + alglib_impl::cmatrixmixedsolvem(const_cast<alglib_impl::ae_matrix*>(a.c_ptr()), const_cast<alglib_impl::ae_matrix*>(lua.c_ptr()), const_cast<alglib_impl::ae_vector*>(p.c_ptr()), n, const_cast<alglib_impl::ae_matrix*>(b.c_ptr()), m, &info, const_cast<alglib_impl::densesolverreport*>(rep.c_ptr()), const_cast<alglib_impl::ae_matrix*>(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; + } +} + +/************************************************************************* +Dense solver. Same as RMatrixMixedSolve(), but for complex matrices. + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* iterative refinement +* O(N^2) complexity + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + LUA - array[0..N-1,0..N-1], LU decomposition, CMatrixLU result + P - array[0..N-1], pivots array, CMatrixLU result + N - size of A + B - array[0..N-1], right part + +OUTPUT PARAMETERS + Info - same as in RMatrixSolveM + Rep - same as in RMatrixSolveM + X - same as in RMatrixSolveM + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void cmatrixmixedsolve(const complex_2d_array &a, const complex_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const complex_1d_array &b, ae_int_t &info, densesolverreport &rep, complex_1d_array &x) +{ + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + try + { + alglib_impl::cmatrixmixedsolve(const_cast<alglib_impl::ae_matrix*>(a.c_ptr()), const_cast<alglib_impl::ae_matrix*>(lua.c_ptr()), const_cast<alglib_impl::ae_vector*>(p.c_ptr()), n, const_cast<alglib_impl::ae_vector*>(b.c_ptr()), &info, const_cast<alglib_impl::densesolverreport*>(rep.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; + } +} + +/************************************************************************* +Dense solver. Same as RMatrixSolveM(), but for symmetric positive definite +matrices. + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* O(N^3+M*N^2) complexity +* matrix is represented by its upper or lower triangle + +No iterative refinement is provided because such partial representation of +matrix does not allow efficient calculation of extra-precise matrix-vector +products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you +need iterative refinement. + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + IsUpper - what half of A is provided + B - array[0..N-1,0..M-1], right part + M - right part size + +OUTPUT PARAMETERS + Info - same as in RMatrixSolve. + Returns -3 for non-SPD matrices. + Rep - same as in RMatrixSolve + X - same as in RMatrixSolve + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void spdmatrixsolvem(const real_2d_array &a, const ae_int_t n, const bool isupper, const real_2d_array &b, const ae_int_t m, ae_int_t &info, densesolverreport &rep, real_2d_array &x) +{ + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + try + { + alglib_impl::spdmatrixsolvem(const_cast<alglib_impl::ae_matrix*>(a.c_ptr()), n, isupper, const_cast<alglib_impl::ae_matrix*>(b.c_ptr()), m, &info, const_cast<alglib_impl::densesolverreport*>(rep.c_ptr()), const_cast<alglib_impl::ae_matrix*>(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; + } +} + +/************************************************************************* +Dense solver. Same as RMatrixSolve(), but for SPD matrices. + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* O(N^3) complexity +* matrix is represented by its upper or lower triangle + +No iterative refinement is provided because such partial representation of +matrix does not allow efficient calculation of extra-precise matrix-vector +products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you +need iterative refinement. + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + IsUpper - what half of A is provided + B - array[0..N-1], right part + +OUTPUT PARAMETERS + Info - same as in RMatrixSolve + Returns -3 for non-SPD matrices. + Rep - same as in RMatrixSolve + X - same as in RMatrixSolve + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void spdmatrixsolve(const real_2d_array &a, const ae_int_t n, const bool isupper, const real_1d_array &b, ae_int_t &info, densesolverreport &rep, real_1d_array &x) +{ + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + try + { + alglib_impl::spdmatrixsolve(const_cast<alglib_impl::ae_matrix*>(a.c_ptr()), n, isupper, const_cast<alglib_impl::ae_vector*>(b.c_ptr()), &info, const_cast<alglib_impl::densesolverreport*>(rep.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; + } +} + +/************************************************************************* +Dense solver. Same as RMatrixLUSolveM(), but for SPD matrices represented +by their Cholesky decomposition. + +Algorithm features: +* automatic detection of degenerate cases +* O(M*N^2) complexity +* condition number estimation +* matrix is represented by its upper or lower triangle + +No iterative refinement is provided because such partial representation of +matrix does not allow efficient calculation of extra-precise matrix-vector +products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you +need iterative refinement. + +INPUT PARAMETERS + CHA - array[0..N-1,0..N-1], Cholesky decomposition, + SPDMatrixCholesky result + N - size of CHA + IsUpper - what half of CHA is provided + B - array[0..N-1,0..M-1], right part + M - right part size + +OUTPUT PARAMETERS + Info - same as in RMatrixSolve + Rep - same as in RMatrixSolve + X - same as in RMatrixSolve + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void spdmatrixcholeskysolvem(const real_2d_array &cha, const ae_int_t n, const bool isupper, const real_2d_array &b, const ae_int_t m, ae_int_t &info, densesolverreport &rep, real_2d_array &x) +{ + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + try + { + alglib_impl::spdmatrixcholeskysolvem(const_cast<alglib_impl::ae_matrix*>(cha.c_ptr()), n, isupper, const_cast<alglib_impl::ae_matrix*>(b.c_ptr()), m, &info, const_cast<alglib_impl::densesolverreport*>(rep.c_ptr()), const_cast<alglib_impl::ae_matrix*>(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; + } +} + +/************************************************************************* +Dense solver. Same as RMatrixLUSolve(), but for SPD matrices represented +by their Cholesky decomposition. + +Algorithm features: +* automatic detection of degenerate cases +* O(N^2) complexity +* condition number estimation +* matrix is represented by its upper or lower triangle + +No iterative refinement is provided because such partial representation of +matrix does not allow efficient calculation of extra-precise matrix-vector +products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you +need iterative refinement. + +INPUT PARAMETERS + CHA - array[0..N-1,0..N-1], Cholesky decomposition, + SPDMatrixCholesky result + N - size of A + IsUpper - what half of CHA is provided + B - array[0..N-1], right part + +OUTPUT PARAMETERS + Info - same as in RMatrixSolve + Rep - same as in RMatrixSolve + X - same as in RMatrixSolve + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void spdmatrixcholeskysolve(const real_2d_array &cha, const ae_int_t n, const bool isupper, const real_1d_array &b, ae_int_t &info, densesolverreport &rep, real_1d_array &x) +{ + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + try + { + alglib_impl::spdmatrixcholeskysolve(const_cast<alglib_impl::ae_matrix*>(cha.c_ptr()), n, isupper, const_cast<alglib_impl::ae_vector*>(b.c_ptr()), &info, const_cast<alglib_impl::densesolverreport*>(rep.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; + } +} + +/************************************************************************* +Dense solver. Same as RMatrixSolveM(), but for Hermitian positive definite +matrices. + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* O(N^3+M*N^2) complexity +* matrix is represented by its upper or lower triangle + +No iterative refinement is provided because such partial representation of +matrix does not allow efficient calculation of extra-precise matrix-vector +products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you +need iterative refinement. + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + IsUpper - what half of A is provided + B - array[0..N-1,0..M-1], right part + M - right part size + +OUTPUT PARAMETERS + Info - same as in RMatrixSolve. + Returns -3 for non-HPD matrices. + Rep - same as in RMatrixSolve + X - same as in RMatrixSolve + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void hpdmatrixsolvem(const complex_2d_array &a, const ae_int_t n, const bool isupper, const complex_2d_array &b, const ae_int_t m, ae_int_t &info, densesolverreport &rep, complex_2d_array &x) +{ + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + try + { + alglib_impl::hpdmatrixsolvem(const_cast<alglib_impl::ae_matrix*>(a.c_ptr()), n, isupper, const_cast<alglib_impl::ae_matrix*>(b.c_ptr()), m, &info, const_cast<alglib_impl::densesolverreport*>(rep.c_ptr()), const_cast<alglib_impl::ae_matrix*>(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; + } +} + +/************************************************************************* +Dense solver. Same as RMatrixSolve(), but for Hermitian positive definite +matrices. + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* O(N^3) complexity +* matrix is represented by its upper or lower triangle + +No iterative refinement is provided because such partial representation of +matrix does not allow efficient calculation of extra-precise matrix-vector +products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you +need iterative refinement. + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + IsUpper - what half of A is provided + B - array[0..N-1], right part + +OUTPUT PARAMETERS + Info - same as in RMatrixSolve + Returns -3 for non-HPD matrices. + Rep - same as in RMatrixSolve + X - same as in RMatrixSolve + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void hpdmatrixsolve(const complex_2d_array &a, const ae_int_t n, const bool isupper, const complex_1d_array &b, ae_int_t &info, densesolverreport &rep, complex_1d_array &x) +{ + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + try + { + alglib_impl::hpdmatrixsolve(const_cast<alglib_impl::ae_matrix*>(a.c_ptr()), n, isupper, const_cast<alglib_impl::ae_vector*>(b.c_ptr()), &info, const_cast<alglib_impl::densesolverreport*>(rep.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; + } +} + +/************************************************************************* +Dense solver. Same as RMatrixLUSolveM(), but for HPD matrices represented +by their Cholesky decomposition. + +Algorithm features: +* automatic detection of degenerate cases +* O(M*N^2) complexity +* condition number estimation +* matrix is represented by its upper or lower triangle + +No iterative refinement is provided because such partial representation of +matrix does not allow efficient calculation of extra-precise matrix-vector +products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you +need iterative refinement. + +INPUT PARAMETERS + CHA - array[0..N-1,0..N-1], Cholesky decomposition, + HPDMatrixCholesky result + N - size of CHA + IsUpper - what half of CHA is provided + B - array[0..N-1,0..M-1], right part + M - right part size + +OUTPUT PARAMETERS + Info - same as in RMatrixSolve + Rep - same as in RMatrixSolve + X - same as in RMatrixSolve + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void hpdmatrixcholeskysolvem(const complex_2d_array &cha, const ae_int_t n, const bool isupper, const complex_2d_array &b, const ae_int_t m, ae_int_t &info, densesolverreport &rep, complex_2d_array &x) +{ + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + try + { + alglib_impl::hpdmatrixcholeskysolvem(const_cast<alglib_impl::ae_matrix*>(cha.c_ptr()), n, isupper, const_cast<alglib_impl::ae_matrix*>(b.c_ptr()), m, &info, const_cast<alglib_impl::densesolverreport*>(rep.c_ptr()), const_cast<alglib_impl::ae_matrix*>(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; + } +} + +/************************************************************************* +Dense solver. Same as RMatrixLUSolve(), but for HPD matrices represented +by their Cholesky decomposition. + +Algorithm features: +* automatic detection of degenerate cases +* O(N^2) complexity +* condition number estimation +* matrix is represented by its upper or lower triangle + +No iterative refinement is provided because such partial representation of +matrix does not allow efficient calculation of extra-precise matrix-vector +products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you +need iterative refinement. + +INPUT PARAMETERS + CHA - array[0..N-1,0..N-1], Cholesky decomposition, + SPDMatrixCholesky result + N - size of A + IsUpper - what half of CHA is provided + B - array[0..N-1], right part + +OUTPUT PARAMETERS + Info - same as in RMatrixSolve + Rep - same as in RMatrixSolve + X - same as in RMatrixSolve + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void hpdmatrixcholeskysolve(const complex_2d_array &cha, const ae_int_t n, const bool isupper, const complex_1d_array &b, ae_int_t &info, densesolverreport &rep, complex_1d_array &x) +{ + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + try + { + alglib_impl::hpdmatrixcholeskysolve(const_cast<alglib_impl::ae_matrix*>(cha.c_ptr()), n, isupper, const_cast<alglib_impl::ae_vector*>(b.c_ptr()), &info, const_cast<alglib_impl::densesolverreport*>(rep.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; + } +} + +/************************************************************************* +Dense solver. + +This subroutine finds solution of the linear system A*X=B with non-square, +possibly degenerate A. System is solved in the least squares sense, and +general least squares solution X = X0 + CX*y which minimizes |A*X-B| is +returned. If A is non-degenerate, solution in the usual sense is returned + +Algorithm features: +* automatic detection of degenerate cases +* iterative refinement +* O(N^3) complexity + +INPUT PARAMETERS + A - array[0..NRows-1,0..NCols-1], system matrix + NRows - vertical size of A + NCols - horizontal size of A + B - array[0..NCols-1], right part + Threshold- a number in [0,1]. Singular values beyond Threshold are + considered zero. Set it to 0.0, if you don't understand + what it means, so the solver will choose good value on its + own. + +OUTPUT PARAMETERS + Info - return code: + * -4 SVD subroutine failed + * -1 if NRows<=0 or NCols<=0 or Threshold<0 was passed + * 1 if task is solved + Rep - solver report, see below for more info + X - array[0..N-1,0..M-1], it contains: + * solution of A*X=B if A is non-singular (well-conditioned + or ill-conditioned, but not very close to singular) + * zeros, if A is singular or VERY close to singular + (in this case Info=-3). + +SOLVER REPORT + +Subroutine sets following fields of the Rep structure: +* R2 reciprocal of condition number: 1/cond(A), 2-norm. +* N = NCols +* K dim(Null(A)) +* CX array[0..N-1,0..K-1], kernel of A. + Columns of CX store such vectors that A*CX[i]=0. + + -- ALGLIB -- + Copyright 24.08.2009 by Bochkanov Sergey +*************************************************************************/ +void rmatrixsolvels(const real_2d_array &a, const ae_int_t nrows, const ae_int_t ncols, const real_1d_array &b, const double threshold, ae_int_t &info, densesolverlsreport &rep, real_1d_array &x) +{ + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + try + { + alglib_impl::rmatrixsolvels(const_cast<alglib_impl::ae_matrix*>(a.c_ptr()), nrows, ncols, const_cast<alglib_impl::ae_vector*>(b.c_ptr()), threshold, &info, const_cast<alglib_impl::densesolverlsreport*>(rep.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; + } +} + +/************************************************************************* + +*************************************************************************/ +_nleqstate_owner::_nleqstate_owner() +{ + p_struct = (alglib_impl::nleqstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::nleqstate), NULL); + if( p_struct==NULL ) + throw ap_error("ALGLIB: malloc error"); + if( !alglib_impl::_nleqstate_init(p_struct, NULL, ae_false) ) + throw ap_error("ALGLIB: malloc error"); +} + +_nleqstate_owner::_nleqstate_owner(const _nleqstate_owner &rhs) +{ + p_struct = (alglib_impl::nleqstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::nleqstate), NULL); + if( p_struct==NULL ) + throw ap_error("ALGLIB: malloc error"); + if( !alglib_impl::_nleqstate_init_copy(p_struct, const_cast<alglib_impl::nleqstate*>(rhs.p_struct), NULL, ae_false) ) + throw ap_error("ALGLIB: malloc error"); +} + +_nleqstate_owner& _nleqstate_owner::operator=(const _nleqstate_owner &rhs) +{ + if( this==&rhs ) + return *this; + alglib_impl::_nleqstate_clear(p_struct); + if( !alglib_impl::_nleqstate_init_copy(p_struct, const_cast<alglib_impl::nleqstate*>(rhs.p_struct), NULL, ae_false) ) + throw ap_error("ALGLIB: malloc error"); + return *this; +} + +_nleqstate_owner::~_nleqstate_owner() +{ + alglib_impl::_nleqstate_clear(p_struct); + ae_free(p_struct); +} + +alglib_impl::nleqstate* _nleqstate_owner::c_ptr() +{ + return p_struct; +} + +alglib_impl::nleqstate* _nleqstate_owner::c_ptr() const +{ + return const_cast<alglib_impl::nleqstate*>(p_struct); +} +nleqstate::nleqstate() : _nleqstate_owner() ,needf(p_struct->needf),needfij(p_struct->needfij),xupdated(p_struct->xupdated),f(p_struct->f),fi(&p_struct->fi),j(&p_struct->j),x(&p_struct->x) +{ +} + +nleqstate::nleqstate(const nleqstate &rhs):_nleqstate_owner(rhs) ,needf(p_struct->needf),needfij(p_struct->needfij),xupdated(p_struct->xupdated),f(p_struct->f),fi(&p_struct->fi),j(&p_struct->j),x(&p_struct->x) +{ +} + +nleqstate& nleqstate::operator=(const nleqstate &rhs) +{ + if( this==&rhs ) + return *this; + _nleqstate_owner::operator=(rhs); + return *this; +} + +nleqstate::~nleqstate() +{ +} + + +/************************************************************************* + +*************************************************************************/ +_nleqreport_owner::_nleqreport_owner() +{ + p_struct = (alglib_impl::nleqreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::nleqreport), NULL); + if( p_struct==NULL ) + throw ap_error("ALGLIB: malloc error"); + if( !alglib_impl::_nleqreport_init(p_struct, NULL, ae_false) ) + throw ap_error("ALGLIB: malloc error"); +} + +_nleqreport_owner::_nleqreport_owner(const _nleqreport_owner &rhs) +{ + p_struct = (alglib_impl::nleqreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::nleqreport), NULL); + if( p_struct==NULL ) + throw ap_error("ALGLIB: malloc error"); + if( !alglib_impl::_nleqreport_init_copy(p_struct, const_cast<alglib_impl::nleqreport*>(rhs.p_struct), NULL, ae_false) ) + throw ap_error("ALGLIB: malloc error"); +} + +_nleqreport_owner& _nleqreport_owner::operator=(const _nleqreport_owner &rhs) +{ + if( this==&rhs ) + return *this; + alglib_impl::_nleqreport_clear(p_struct); + if( !alglib_impl::_nleqreport_init_copy(p_struct, const_cast<alglib_impl::nleqreport*>(rhs.p_struct), NULL, ae_false) ) + throw ap_error("ALGLIB: malloc error"); + return *this; +} + +_nleqreport_owner::~_nleqreport_owner() +{ + alglib_impl::_nleqreport_clear(p_struct); + ae_free(p_struct); +} + +alglib_impl::nleqreport* _nleqreport_owner::c_ptr() +{ + return p_struct; +} + +alglib_impl::nleqreport* _nleqreport_owner::c_ptr() const +{ + return const_cast<alglib_impl::nleqreport*>(p_struct); +} +nleqreport::nleqreport() : _nleqreport_owner() ,iterationscount(p_struct->iterationscount),nfunc(p_struct->nfunc),njac(p_struct->njac),terminationtype(p_struct->terminationtype) +{ +} + +nleqreport::nleqreport(const nleqreport &rhs):_nleqreport_owner(rhs) ,iterationscount(p_struct->iterationscount),nfunc(p_struct->nfunc),njac(p_struct->njac),terminationtype(p_struct->terminationtype) +{ +} + +nleqreport& nleqreport::operator=(const nleqreport &rhs) +{ + if( this==&rhs ) + return *this; + _nleqreport_owner::operator=(rhs); + return *this; +} + +nleqreport::~nleqreport() +{ +} + +/************************************************************************* + LEVENBERG-MARQUARDT-LIKE NONLINEAR SOLVER + +DESCRIPTION: +This algorithm solves system of nonlinear equations + F[0](x[0], ..., x[n-1]) = 0 + F[1](x[0], ..., x[n-1]) = 0 + ... + F[M-1](x[0], ..., x[n-1]) = 0 +with M/N do not necessarily coincide. Algorithm converges quadratically +under following conditions: + * the solution set XS is nonempty + * for some xs in XS there exist such neighbourhood N(xs) that: + * vector function F(x) and its Jacobian J(x) are continuously + differentiable on N + * ||F(x)|| provides local error bound on N, i.e. there exists such + c1, that ||F(x)||>c1*distance(x,XS) +Note that these conditions are much more weaker than usual non-singularity +conditions. For example, algorithm will converge for any affine function +F (whether its Jacobian singular or not). + + +REQUIREMENTS: +Algorithm will request following information during its operation: +* function vector F[] and Jacobian matrix at given point X +* value of merit function f(x)=F[0]^2(x)+...+F[M-1]^2(x) at given point X + + +USAGE: +1. User initializes algorithm state with NLEQCreateLM() call +2. User tunes solver parameters with NLEQSetCond(), NLEQSetStpMax() and + other functions +3. User calls NLEQSolve() function which takes algorithm state and + pointers (delegates, etc.) to callback functions which calculate merit + function value and Jacobian. +4. User calls NLEQResults() to get solution +5. Optionally, user may call NLEQRestartFrom() to solve another problem + with same parameters (N/M) but another starting point and/or another + function vector. NLEQRestartFrom() allows to reuse already initialized + structure. + + +INPUT PARAMETERS: + N - space dimension, N>1: + * if provided, only leading N elements of X are used + * if not provided, determined automatically from size of X + M - system size + X - starting point + + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + + +NOTES: +1. you may tune stopping conditions with NLEQSetCond() function +2. if target function contains exp() or other fast growing functions, and + optimization algorithm makes too large steps which leads to overflow, + use NLEQSetStpMax() function to bound algorithm's steps. +3. this algorithm is a slightly modified implementation of the method + described in 'Levenberg-Marquardt method for constrained nonlinear + equations with strong local convergence properties' by Christian Kanzow + Nobuo Yamashita and Masao Fukushima and further developed in 'On the + convergence of a New Levenberg-Marquardt Method' by Jin-yan Fan and + Ya-Xiang Yuan. + + + -- ALGLIB -- + Copyright 20.08.2009 by Bochkanov Sergey +*************************************************************************/ +void nleqcreatelm(const ae_int_t n, const ae_int_t m, const real_1d_array &x, nleqstate &state) +{ + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + try + { + alglib_impl::nleqcreatelm(n, m, const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::nleqstate*>(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; + } +} + +/************************************************************************* + LEVENBERG-MARQUARDT-LIKE NONLINEAR SOLVER + +DESCRIPTION: +This algorithm solves system of nonlinear equations + F[0](x[0], ..., x[n-1]) = 0 + F[1](x[0], ..., x[n-1]) = 0 + ... + F[M-1](x[0], ..., x[n-1]) = 0 +with M/N do not necessarily coincide. Algorithm converges quadratically +under following conditions: + * the solution set XS is nonempty + * for some xs in XS there exist such neighbourhood N(xs) that: + * vector function F(x) and its Jacobian J(x) are continuously + differentiable on N + * ||F(x)|| provides local error bound on N, i.e. there exists such + c1, that ||F(x)||>c1*distance(x,XS) +Note that these conditions are much more weaker than usual non-singularity +conditions. For example, algorithm will converge for any affine function +F (whether its Jacobian singular or not). + + +REQUIREMENTS: +Algorithm will request following information during its operation: +* function vector F[] and Jacobian matrix at given point X +* value of merit function f(x)=F[0]^2(x)+...+F[M-1]^2(x) at given point X + + +USAGE: +1. User initializes algorithm state with NLEQCreateLM() call +2. User tunes solver parameters with NLEQSetCond(), NLEQSetStpMax() and + other functions +3. User calls NLEQSolve() function which takes algorithm state and + pointers (delegates, etc.) to callback functions which calculate merit + function value and Jacobian. +4. User calls NLEQResults() to get solution +5. Optionally, user may call NLEQRestartFrom() to solve another problem + with same parameters (N/M) but another starting point and/or another + function vector. NLEQRestartFrom() allows to reuse already initialized + structure. + + +INPUT PARAMETERS: + N - space dimension, N>1: + * if provided, only leading N elements of X are used + * if not provided, determined automatically from size of X + M - system size + X - starting point + + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + + +NOTES: +1. you may tune stopping conditions with NLEQSetCond() function +2. if target function contains exp() or other fast growing functions, and + optimization algorithm makes too large steps which leads to overflow, + use NLEQSetStpMax() function to bound algorithm's steps. +3. this algorithm is a slightly modified implementation of the method + described in 'Levenberg-Marquardt method for constrained nonlinear + equations with strong local convergence properties' by Christian Kanzow + Nobuo Yamashita and Masao Fukushima and further developed in 'On the + convergence of a New Levenberg-Marquardt Method' by Jin-yan Fan and + Ya-Xiang Yuan. + + + -- ALGLIB -- + Copyright 20.08.2009 by Bochkanov Sergey +*************************************************************************/ +void nleqcreatelm(const ae_int_t m, const real_1d_array &x, nleqstate &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::nleqcreatelm(n, m, const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::nleqstate*>(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 sets stopping conditions for the nonlinear solver + +INPUT PARAMETERS: + State - structure which stores algorithm state + EpsF - >=0 + The subroutine finishes its work if on k+1-th iteration + the condition ||F||<=EpsF is satisfied + MaxIts - maximum number of iterations. If MaxIts=0, the number of + iterations is unlimited. + +Passing EpsF=0 and MaxIts=0 simultaneously will lead to automatic +stopping criterion selection (small EpsF). + +NOTES: + + -- ALGLIB -- + Copyright 20.08.2010 by Bochkanov Sergey +*************************************************************************/ +void nleqsetcond(const nleqstate &state, const double epsf, const ae_int_t maxits) +{ + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + try + { + alglib_impl::nleqsetcond(const_cast<alglib_impl::nleqstate*>(state.c_ptr()), epsf, 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; + } +} + +/************************************************************************* +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 NLEQSolve(). + + -- ALGLIB -- + Copyright 20.08.2010 by Bochkanov Sergey +*************************************************************************/ +void nleqsetxrep(const nleqstate &state, const bool needxrep) +{ + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + try + { + alglib_impl::nleqsetxrep(const_cast<alglib_impl::nleqstate*>(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, if you don't + want to limit step length. + +Use this subroutine when target function contains exp() or other fast +growing functions, and 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 20.08.2010 by Bochkanov Sergey +*************************************************************************/ +void nleqsetstpmax(const nleqstate &state, const double stpmax) +{ + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + try + { + alglib_impl::nleqsetstpmax(const_cast<alglib_impl::nleqstate*>(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 provides reverse communication interface +Reverse communication interface is not documented or recommended to use. +See below for functions which provide better documented API +*************************************************************************/ +bool nleqiteration(const nleqstate &state) +{ + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + try + { + ae_bool result = alglib_impl::nleqiteration(const_cast<alglib_impl::nleqstate*>(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; + } +} + + +void nleqsolve(nleqstate &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 'nleqsolve()' (func is NULL)"); + if( jac==NULL ) + throw ap_error("ALGLIB: error in 'nleqsolve()' (jac is NULL)"); + alglib_impl::ae_state_init(&_alglib_env_state); + try + { + while( alglib_impl::nleqiteration(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 'nleqsolve' (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; + } +} + + + +/************************************************************************* +NLEQ solver results + +INPUT PARAMETERS: + State - algorithm state. + +OUTPUT PARAMETERS: + X - array[0..N-1], solution + Rep - optimization report: + * Rep.TerminationType completetion code: + * -4 ERROR: algorithm has converged to the + stationary point Xf which is local minimum of + f=F[0]^2+...+F[m-1]^2, but is not solution of + nonlinear system. + * 1 sqrt(f)<=EpsF. + * 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 + + -- ALGLIB -- + Copyright 20.08.2009 by Bochkanov Sergey +*************************************************************************/ +void nleqresults(const nleqstate &state, real_1d_array &x, nleqreport &rep) +{ + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + try + { + alglib_impl::nleqresults(const_cast<alglib_impl::nleqstate*>(state.c_ptr()), const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::nleqreport*>(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; + } +} + +/************************************************************************* +NLEQ solver results + +Buffered implementation of NLEQResults(), 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.2009 by Bochkanov Sergey +*************************************************************************/ +void nleqresultsbuf(const nleqstate &state, real_1d_array &x, nleqreport &rep) +{ + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + try + { + alglib_impl::nleqresultsbuf(const_cast<alglib_impl::nleqstate*>(state.c_ptr()), const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::nleqreport*>(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 for reverse communication 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 +*************************************************************************/ +void nleqrestartfrom(const nleqstate &state, const real_1d_array &x) +{ + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + try + { + alglib_impl::nleqrestartfrom(const_cast<alglib_impl::nleqstate*>(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 SECTION CONTAINS IMPLEMENTATION OF COMPUTATIONAL CORE +// +///////////////////////////////////////////////////////////////////////// +namespace alglib_impl +{ +static void densesolver_rmatrixlusolveinternal(/* Real */ ae_matrix* lua, + /* Integer */ ae_vector* p, + double scalea, + ae_int_t n, + /* Real */ ae_matrix* a, + ae_bool havea, + /* Real */ ae_matrix* b, + ae_int_t m, + ae_int_t* info, + densesolverreport* rep, + /* Real */ ae_matrix* x, + ae_state *_state); +static void densesolver_spdmatrixcholeskysolveinternal(/* Real */ ae_matrix* cha, + double sqrtscalea, + ae_int_t n, + ae_bool isupper, + /* Real */ ae_matrix* a, + ae_bool havea, + /* Real */ ae_matrix* b, + ae_int_t m, + ae_int_t* info, + densesolverreport* rep, + /* Real */ ae_matrix* x, + ae_state *_state); +static void densesolver_cmatrixlusolveinternal(/* Complex */ ae_matrix* lua, + /* Integer */ ae_vector* p, + double scalea, + ae_int_t n, + /* Complex */ ae_matrix* a, + ae_bool havea, + /* Complex */ ae_matrix* b, + ae_int_t m, + ae_int_t* info, + densesolverreport* rep, + /* Complex */ ae_matrix* x, + ae_state *_state); +static void densesolver_hpdmatrixcholeskysolveinternal(/* Complex */ ae_matrix* cha, + double sqrtscalea, + ae_int_t n, + ae_bool isupper, + /* Complex */ ae_matrix* a, + ae_bool havea, + /* Complex */ ae_matrix* b, + ae_int_t m, + ae_int_t* info, + densesolverreport* rep, + /* Complex */ ae_matrix* x, + ae_state *_state); +static ae_int_t densesolver_densesolverrfsmax(ae_int_t n, + double r1, + double rinf, + ae_state *_state); +static ae_int_t densesolver_densesolverrfsmaxv2(ae_int_t n, + double r2, + ae_state *_state); +static void densesolver_rbasiclusolve(/* Real */ ae_matrix* lua, + /* Integer */ ae_vector* p, + double scalea, + ae_int_t n, + /* Real */ ae_vector* xb, + /* Real */ ae_vector* tmp, + ae_state *_state); +static void densesolver_spdbasiccholeskysolve(/* Real */ ae_matrix* cha, + double sqrtscalea, + ae_int_t n, + ae_bool isupper, + /* Real */ ae_vector* xb, + /* Real */ ae_vector* tmp, + ae_state *_state); +static void densesolver_cbasiclusolve(/* Complex */ ae_matrix* lua, + /* Integer */ ae_vector* p, + double scalea, + ae_int_t n, + /* Complex */ ae_vector* xb, + /* Complex */ ae_vector* tmp, + ae_state *_state); +static void densesolver_hpdbasiccholeskysolve(/* Complex */ ae_matrix* cha, + double sqrtscalea, + ae_int_t n, + ae_bool isupper, + /* Complex */ ae_vector* xb, + /* Complex */ ae_vector* tmp, + ae_state *_state); + + +static ae_int_t nleq_armijomaxfev = 20; +static void nleq_clearrequestfields(nleqstate* state, ae_state *_state); +static ae_bool nleq_increaselambda(double* lambdav, + double* nu, + double lambdaup, + ae_state *_state); +static void nleq_decreaselambda(double* lambdav, + double* nu, + double lambdadown, + ae_state *_state); + + + + + +/************************************************************************* +Dense solver. + +This subroutine solves a system A*x=b, where A is NxN non-denegerate +real matrix, x and b are vectors. + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* iterative refinement +* O(N^3) complexity + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + B - array[0..N-1], right part + +OUTPUT PARAMETERS + Info - return code: + * -3 A is singular, or VERY close to singular. + X is filled by zeros in such cases. + * -1 N<=0 was passed + * 1 task is solved (but matrix A may be ill-conditioned, + check R1/RInf parameters for condition numbers). + Rep - solver report, see below for more info + X - array[0..N-1], it contains: + * solution of A*x=b if A is non-singular (well-conditioned + or ill-conditioned, but not very close to singular) + * zeros, if A is singular or VERY close to singular + (in this case Info=-3). + +SOLVER REPORT + +Subroutine sets following fields of the Rep structure: +* R1 reciprocal of condition number: 1/cond(A), 1-norm. +* RInf reciprocal of condition number: 1/cond(A), inf-norm. + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void rmatrixsolve(/* Real */ ae_matrix* a, + ae_int_t n, + /* Real */ ae_vector* b, + ae_int_t* info, + densesolverreport* rep, + /* Real */ ae_vector* x, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix bm; + ae_matrix xm; + + ae_frame_make(_state, &_frame_block); + *info = 0; + _densesolverreport_clear(rep); + ae_vector_clear(x); + ae_matrix_init(&bm, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&xm, 0, 0, DT_REAL, _state, ae_true); + + if( n<=0 ) + { + *info = -1; + ae_frame_leave(_state); + return; + } + ae_matrix_set_length(&bm, n, 1, _state); + ae_v_move(&bm.ptr.pp_double[0][0], bm.stride, &b->ptr.p_double[0], 1, ae_v_len(0,n-1)); + rmatrixsolvem(a, n, &bm, 1, ae_true, info, rep, &xm, _state); + ae_vector_set_length(x, n, _state); + ae_v_move(&x->ptr.p_double[0], 1, &xm.ptr.pp_double[0][0], xm.stride, ae_v_len(0,n-1)); + ae_frame_leave(_state); +} + + +/************************************************************************* +Dense solver. + +Similar to RMatrixSolve() but solves task with multiple right parts (where +b and x are NxM matrices). + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* optional iterative refinement +* O(N^3+M*N^2) complexity + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + B - array[0..N-1,0..M-1], right part + M - right part size + RFS - iterative refinement switch: + * True - refinement is used. + Less performance, more precision. + * False - refinement is not used. + More performance, less precision. + +OUTPUT PARAMETERS + Info - same as in RMatrixSolve + Rep - same as in RMatrixSolve + X - same as in RMatrixSolve + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void rmatrixsolvem(/* Real */ ae_matrix* a, + ae_int_t n, + /* Real */ ae_matrix* b, + ae_int_t m, + ae_bool rfs, + ae_int_t* info, + densesolverreport* rep, + /* Real */ ae_matrix* x, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix da; + ae_matrix emptya; + ae_vector p; + double scalea; + ae_int_t i; + ae_int_t j; + + ae_frame_make(_state, &_frame_block); + *info = 0; + _densesolverreport_clear(rep); + ae_matrix_clear(x); + ae_matrix_init(&da, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&emptya, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&p, 0, DT_INT, _state, ae_true); + + + /* + * prepare: check inputs, allocate space... + */ + if( n<=0||m<=0 ) + { + *info = -1; + ae_frame_leave(_state); + return; + } + ae_matrix_set_length(&da, n, n, _state); + + /* + * 1. scale matrix, max(|A[i,j]|) + * 2. factorize scaled matrix + * 3. solve + */ + scalea = 0; + for(i=0; i<=n-1; i++) + { + for(j=0; j<=n-1; j++) + { + scalea = ae_maxreal(scalea, ae_fabs(a->ptr.pp_double[i][j], _state), _state); + } + } + if( ae_fp_eq(scalea,0) ) + { + scalea = 1; + } + scalea = 1/scalea; + for(i=0; i<=n-1; i++) + { + ae_v_move(&da.ptr.pp_double[i][0], 1, &a->ptr.pp_double[i][0], 1, ae_v_len(0,n-1)); + } + rmatrixlu(&da, n, n, &p, _state); + if( rfs ) + { + densesolver_rmatrixlusolveinternal(&da, &p, scalea, n, a, ae_true, b, m, info, rep, x, _state); + } + else + { + densesolver_rmatrixlusolveinternal(&da, &p, scalea, n, &emptya, ae_false, b, m, info, rep, x, _state); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Dense solver. + +This subroutine solves a system A*X=B, where A is NxN non-denegerate +real matrix given by its LU decomposition, X and B are NxM real matrices. + +Algorithm features: +* automatic detection of degenerate cases +* O(N^2) complexity +* condition number estimation + +No iterative refinement is provided because exact form of original matrix +is not known to subroutine. Use RMatrixSolve or RMatrixMixedSolve if you +need iterative refinement. + +INPUT PARAMETERS + LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result + P - array[0..N-1], pivots array, RMatrixLU result + N - size of A + B - array[0..N-1], right part + +OUTPUT PARAMETERS + Info - same as in RMatrixSolve + Rep - same as in RMatrixSolve + X - same as in RMatrixSolve + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void rmatrixlusolve(/* Real */ ae_matrix* lua, + /* Integer */ ae_vector* p, + ae_int_t n, + /* Real */ ae_vector* b, + ae_int_t* info, + densesolverreport* rep, + /* Real */ ae_vector* x, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix bm; + ae_matrix xm; + + ae_frame_make(_state, &_frame_block); + *info = 0; + _densesolverreport_clear(rep); + ae_vector_clear(x); + ae_matrix_init(&bm, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&xm, 0, 0, DT_REAL, _state, ae_true); + + if( n<=0 ) + { + *info = -1; + ae_frame_leave(_state); + return; + } + ae_matrix_set_length(&bm, n, 1, _state); + ae_v_move(&bm.ptr.pp_double[0][0], bm.stride, &b->ptr.p_double[0], 1, ae_v_len(0,n-1)); + rmatrixlusolvem(lua, p, n, &bm, 1, info, rep, &xm, _state); + ae_vector_set_length(x, n, _state); + ae_v_move(&x->ptr.p_double[0], 1, &xm.ptr.pp_double[0][0], xm.stride, ae_v_len(0,n-1)); + ae_frame_leave(_state); +} + + +/************************************************************************* +Dense solver. + +Similar to RMatrixLUSolve() but solves task with multiple right parts +(where b and x are NxM matrices). + +Algorithm features: +* automatic detection of degenerate cases +* O(M*N^2) complexity +* condition number estimation + +No iterative refinement is provided because exact form of original matrix +is not known to subroutine. Use RMatrixSolve or RMatrixMixedSolve if you +need iterative refinement. + +INPUT PARAMETERS + LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result + P - array[0..N-1], pivots array, RMatrixLU result + N - size of A + B - array[0..N-1,0..M-1], right part + M - right part size + +OUTPUT PARAMETERS + Info - same as in RMatrixSolve + Rep - same as in RMatrixSolve + X - same as in RMatrixSolve + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void rmatrixlusolvem(/* Real */ ae_matrix* lua, + /* Integer */ ae_vector* p, + ae_int_t n, + /* Real */ ae_matrix* b, + ae_int_t m, + ae_int_t* info, + densesolverreport* rep, + /* Real */ ae_matrix* x, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix emptya; + ae_int_t i; + ae_int_t j; + double scalea; + + ae_frame_make(_state, &_frame_block); + *info = 0; + _densesolverreport_clear(rep); + ae_matrix_clear(x); + ae_matrix_init(&emptya, 0, 0, DT_REAL, _state, ae_true); + + + /* + * prepare: check inputs, allocate space... + */ + if( n<=0||m<=0 ) + { + *info = -1; + ae_frame_leave(_state); + return; + } + + /* + * 1. scale matrix, max(|U[i,j]|) + * we assume that LU is in its normal form, i.e. |L[i,j]|<=1 + * 2. solve + */ + scalea = 0; + for(i=0; i<=n-1; i++) + { + for(j=i; j<=n-1; j++) + { + scalea = ae_maxreal(scalea, ae_fabs(lua->ptr.pp_double[i][j], _state), _state); + } + } + if( ae_fp_eq(scalea,0) ) + { + scalea = 1; + } + scalea = 1/scalea; + densesolver_rmatrixlusolveinternal(lua, p, scalea, n, &emptya, ae_false, b, m, info, rep, x, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Dense solver. + +This subroutine solves a system A*x=b, where BOTH ORIGINAL A AND ITS +LU DECOMPOSITION ARE KNOWN. You can use it if for some reasons you have +both A and its LU decomposition. + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* iterative refinement +* O(N^2) complexity + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result + P - array[0..N-1], pivots array, RMatrixLU result + N - size of A + B - array[0..N-1], right part + +OUTPUT PARAMETERS + Info - same as in RMatrixSolveM + Rep - same as in RMatrixSolveM + X - same as in RMatrixSolveM + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void rmatrixmixedsolve(/* Real */ ae_matrix* a, + /* Real */ ae_matrix* lua, + /* Integer */ ae_vector* p, + ae_int_t n, + /* Real */ ae_vector* b, + ae_int_t* info, + densesolverreport* rep, + /* Real */ ae_vector* x, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix bm; + ae_matrix xm; + + ae_frame_make(_state, &_frame_block); + *info = 0; + _densesolverreport_clear(rep); + ae_vector_clear(x); + ae_matrix_init(&bm, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&xm, 0, 0, DT_REAL, _state, ae_true); + + if( n<=0 ) + { + *info = -1; + ae_frame_leave(_state); + return; + } + ae_matrix_set_length(&bm, n, 1, _state); + ae_v_move(&bm.ptr.pp_double[0][0], bm.stride, &b->ptr.p_double[0], 1, ae_v_len(0,n-1)); + rmatrixmixedsolvem(a, lua, p, n, &bm, 1, info, rep, &xm, _state); + ae_vector_set_length(x, n, _state); + ae_v_move(&x->ptr.p_double[0], 1, &xm.ptr.pp_double[0][0], xm.stride, ae_v_len(0,n-1)); + ae_frame_leave(_state); +} + + +/************************************************************************* +Dense solver. + +Similar to RMatrixMixedSolve() but solves task with multiple right parts +(where b and x are NxM matrices). + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* iterative refinement +* O(M*N^2) complexity + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result + P - array[0..N-1], pivots array, RMatrixLU result + N - size of A + B - array[0..N-1,0..M-1], right part + M - right part size + +OUTPUT PARAMETERS + Info - same as in RMatrixSolveM + Rep - same as in RMatrixSolveM + X - same as in RMatrixSolveM + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void rmatrixmixedsolvem(/* Real */ ae_matrix* a, + /* Real */ ae_matrix* lua, + /* Integer */ ae_vector* p, + ae_int_t n, + /* Real */ ae_matrix* b, + ae_int_t m, + ae_int_t* info, + densesolverreport* rep, + /* Real */ ae_matrix* x, + ae_state *_state) +{ + double scalea; + ae_int_t i; + ae_int_t j; + + *info = 0; + _densesolverreport_clear(rep); + ae_matrix_clear(x); + + + /* + * prepare: check inputs, allocate space... + */ + if( n<=0||m<=0 ) + { + *info = -1; + return; + } + + /* + * 1. scale matrix, max(|A[i,j]|) + * 2. factorize scaled matrix + * 3. solve + */ + scalea = 0; + for(i=0; i<=n-1; i++) + { + for(j=0; j<=n-1; j++) + { + scalea = ae_maxreal(scalea, ae_fabs(a->ptr.pp_double[i][j], _state), _state); + } + } + if( ae_fp_eq(scalea,0) ) + { + scalea = 1; + } + scalea = 1/scalea; + densesolver_rmatrixlusolveinternal(lua, p, scalea, n, a, ae_true, b, m, info, rep, x, _state); +} + + +/************************************************************************* +Dense solver. Same as RMatrixSolveM(), but for complex matrices. + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* iterative refinement +* O(N^3+M*N^2) complexity + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + B - array[0..N-1,0..M-1], right part + M - right part size + RFS - iterative refinement switch: + * True - refinement is used. + Less performance, more precision. + * False - refinement is not used. + More performance, less precision. + +OUTPUT PARAMETERS + Info - same as in RMatrixSolve + Rep - same as in RMatrixSolve + X - same as in RMatrixSolve + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void cmatrixsolvem(/* Complex */ ae_matrix* a, + ae_int_t n, + /* Complex */ ae_matrix* b, + ae_int_t m, + ae_bool rfs, + ae_int_t* info, + densesolverreport* rep, + /* Complex */ ae_matrix* x, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix da; + ae_matrix emptya; + ae_vector p; + double scalea; + ae_int_t i; + ae_int_t j; + + ae_frame_make(_state, &_frame_block); + *info = 0; + _densesolverreport_clear(rep); + ae_matrix_clear(x); + ae_matrix_init(&da, 0, 0, DT_COMPLEX, _state, ae_true); + ae_matrix_init(&emptya, 0, 0, DT_COMPLEX, _state, ae_true); + ae_vector_init(&p, 0, DT_INT, _state, ae_true); + + + /* + * prepare: check inputs, allocate space... + */ + if( n<=0||m<=0 ) + { + *info = -1; + ae_frame_leave(_state); + return; + } + ae_matrix_set_length(&da, n, n, _state); + + /* + * 1. scale matrix, max(|A[i,j]|) + * 2. factorize scaled matrix + * 3. solve + */ + scalea = 0; + for(i=0; i<=n-1; i++) + { + for(j=0; j<=n-1; j++) + { + scalea = ae_maxreal(scalea, ae_c_abs(a->ptr.pp_complex[i][j], _state), _state); + } + } + if( ae_fp_eq(scalea,0) ) + { + scalea = 1; + } + scalea = 1/scalea; + for(i=0; i<=n-1; i++) + { + ae_v_cmove(&da.ptr.pp_complex[i][0], 1, &a->ptr.pp_complex[i][0], 1, "N", ae_v_len(0,n-1)); + } + cmatrixlu(&da, n, n, &p, _state); + if( rfs ) + { + densesolver_cmatrixlusolveinternal(&da, &p, scalea, n, a, ae_true, b, m, info, rep, x, _state); + } + else + { + densesolver_cmatrixlusolveinternal(&da, &p, scalea, n, &emptya, ae_false, b, m, info, rep, x, _state); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Dense solver. Same as RMatrixSolve(), but for complex matrices. + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* iterative refinement +* O(N^3) complexity + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + B - array[0..N-1], right part + +OUTPUT PARAMETERS + Info - same as in RMatrixSolve + Rep - same as in RMatrixSolve + X - same as in RMatrixSolve + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void cmatrixsolve(/* Complex */ ae_matrix* a, + ae_int_t n, + /* Complex */ ae_vector* b, + ae_int_t* info, + densesolverreport* rep, + /* Complex */ ae_vector* x, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix bm; + ae_matrix xm; + + ae_frame_make(_state, &_frame_block); + *info = 0; + _densesolverreport_clear(rep); + ae_vector_clear(x); + ae_matrix_init(&bm, 0, 0, DT_COMPLEX, _state, ae_true); + ae_matrix_init(&xm, 0, 0, DT_COMPLEX, _state, ae_true); + + if( n<=0 ) + { + *info = -1; + ae_frame_leave(_state); + return; + } + ae_matrix_set_length(&bm, n, 1, _state); + ae_v_cmove(&bm.ptr.pp_complex[0][0], bm.stride, &b->ptr.p_complex[0], 1, "N", ae_v_len(0,n-1)); + cmatrixsolvem(a, n, &bm, 1, ae_true, info, rep, &xm, _state); + ae_vector_set_length(x, n, _state); + ae_v_cmove(&x->ptr.p_complex[0], 1, &xm.ptr.pp_complex[0][0], xm.stride, "N", ae_v_len(0,n-1)); + ae_frame_leave(_state); +} + + +/************************************************************************* +Dense solver. Same as RMatrixLUSolveM(), but for complex matrices. + +Algorithm features: +* automatic detection of degenerate cases +* O(M*N^2) complexity +* condition number estimation + +No iterative refinement is provided because exact form of original matrix +is not known to subroutine. Use CMatrixSolve or CMatrixMixedSolve if you +need iterative refinement. + +INPUT PARAMETERS + LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result + P - array[0..N-1], pivots array, RMatrixLU result + N - size of A + B - array[0..N-1,0..M-1], right part + M - right part size + +OUTPUT PARAMETERS + Info - same as in RMatrixSolve + Rep - same as in RMatrixSolve + X - same as in RMatrixSolve + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void cmatrixlusolvem(/* Complex */ ae_matrix* lua, + /* Integer */ ae_vector* p, + ae_int_t n, + /* Complex */ ae_matrix* b, + ae_int_t m, + ae_int_t* info, + densesolverreport* rep, + /* Complex */ ae_matrix* x, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix emptya; + ae_int_t i; + ae_int_t j; + double scalea; + + ae_frame_make(_state, &_frame_block); + *info = 0; + _densesolverreport_clear(rep); + ae_matrix_clear(x); + ae_matrix_init(&emptya, 0, 0, DT_COMPLEX, _state, ae_true); + + + /* + * prepare: check inputs, allocate space... + */ + if( n<=0||m<=0 ) + { + *info = -1; + ae_frame_leave(_state); + return; + } + + /* + * 1. scale matrix, max(|U[i,j]|) + * we assume that LU is in its normal form, i.e. |L[i,j]|<=1 + * 2. solve + */ + scalea = 0; + for(i=0; i<=n-1; i++) + { + for(j=i; j<=n-1; j++) + { + scalea = ae_maxreal(scalea, ae_c_abs(lua->ptr.pp_complex[i][j], _state), _state); + } + } + if( ae_fp_eq(scalea,0) ) + { + scalea = 1; + } + scalea = 1/scalea; + densesolver_cmatrixlusolveinternal(lua, p, scalea, n, &emptya, ae_false, b, m, info, rep, x, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Dense solver. Same as RMatrixLUSolve(), but for complex matrices. + +Algorithm features: +* automatic detection of degenerate cases +* O(N^2) complexity +* condition number estimation + +No iterative refinement is provided because exact form of original matrix +is not known to subroutine. Use CMatrixSolve or CMatrixMixedSolve if you +need iterative refinement. + +INPUT PARAMETERS + LUA - array[0..N-1,0..N-1], LU decomposition, CMatrixLU result + P - array[0..N-1], pivots array, CMatrixLU result + N - size of A + B - array[0..N-1], right part + +OUTPUT PARAMETERS + Info - same as in RMatrixSolve + Rep - same as in RMatrixSolve + X - same as in RMatrixSolve + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void cmatrixlusolve(/* Complex */ ae_matrix* lua, + /* Integer */ ae_vector* p, + ae_int_t n, + /* Complex */ ae_vector* b, + ae_int_t* info, + densesolverreport* rep, + /* Complex */ ae_vector* x, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix bm; + ae_matrix xm; + + ae_frame_make(_state, &_frame_block); + *info = 0; + _densesolverreport_clear(rep); + ae_vector_clear(x); + ae_matrix_init(&bm, 0, 0, DT_COMPLEX, _state, ae_true); + ae_matrix_init(&xm, 0, 0, DT_COMPLEX, _state, ae_true); + + if( n<=0 ) + { + *info = -1; + ae_frame_leave(_state); + return; + } + ae_matrix_set_length(&bm, n, 1, _state); + ae_v_cmove(&bm.ptr.pp_complex[0][0], bm.stride, &b->ptr.p_complex[0], 1, "N", ae_v_len(0,n-1)); + cmatrixlusolvem(lua, p, n, &bm, 1, info, rep, &xm, _state); + ae_vector_set_length(x, n, _state); + ae_v_cmove(&x->ptr.p_complex[0], 1, &xm.ptr.pp_complex[0][0], xm.stride, "N", ae_v_len(0,n-1)); + ae_frame_leave(_state); +} + + +/************************************************************************* +Dense solver. Same as RMatrixMixedSolveM(), but for complex matrices. + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* iterative refinement +* O(M*N^2) complexity + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + LUA - array[0..N-1,0..N-1], LU decomposition, CMatrixLU result + P - array[0..N-1], pivots array, CMatrixLU result + N - size of A + B - array[0..N-1,0..M-1], right part + M - right part size + +OUTPUT PARAMETERS + Info - same as in RMatrixSolveM + Rep - same as in RMatrixSolveM + X - same as in RMatrixSolveM + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void cmatrixmixedsolvem(/* Complex */ ae_matrix* a, + /* Complex */ ae_matrix* lua, + /* Integer */ ae_vector* p, + ae_int_t n, + /* Complex */ ae_matrix* b, + ae_int_t m, + ae_int_t* info, + densesolverreport* rep, + /* Complex */ ae_matrix* x, + ae_state *_state) +{ + double scalea; + ae_int_t i; + ae_int_t j; + + *info = 0; + _densesolverreport_clear(rep); + ae_matrix_clear(x); + + + /* + * prepare: check inputs, allocate space... + */ + if( n<=0||m<=0 ) + { + *info = -1; + return; + } + + /* + * 1. scale matrix, max(|A[i,j]|) + * 2. factorize scaled matrix + * 3. solve + */ + scalea = 0; + for(i=0; i<=n-1; i++) + { + for(j=0; j<=n-1; j++) + { + scalea = ae_maxreal(scalea, ae_c_abs(a->ptr.pp_complex[i][j], _state), _state); + } + } + if( ae_fp_eq(scalea,0) ) + { + scalea = 1; + } + scalea = 1/scalea; + densesolver_cmatrixlusolveinternal(lua, p, scalea, n, a, ae_true, b, m, info, rep, x, _state); +} + + +/************************************************************************* +Dense solver. Same as RMatrixMixedSolve(), but for complex matrices. + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* iterative refinement +* O(N^2) complexity + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + LUA - array[0..N-1,0..N-1], LU decomposition, CMatrixLU result + P - array[0..N-1], pivots array, CMatrixLU result + N - size of A + B - array[0..N-1], right part + +OUTPUT PARAMETERS + Info - same as in RMatrixSolveM + Rep - same as in RMatrixSolveM + X - same as in RMatrixSolveM + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void cmatrixmixedsolve(/* Complex */ ae_matrix* a, + /* Complex */ ae_matrix* lua, + /* Integer */ ae_vector* p, + ae_int_t n, + /* Complex */ ae_vector* b, + ae_int_t* info, + densesolverreport* rep, + /* Complex */ ae_vector* x, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix bm; + ae_matrix xm; + + ae_frame_make(_state, &_frame_block); + *info = 0; + _densesolverreport_clear(rep); + ae_vector_clear(x); + ae_matrix_init(&bm, 0, 0, DT_COMPLEX, _state, ae_true); + ae_matrix_init(&xm, 0, 0, DT_COMPLEX, _state, ae_true); + + if( n<=0 ) + { + *info = -1; + ae_frame_leave(_state); + return; + } + ae_matrix_set_length(&bm, n, 1, _state); + ae_v_cmove(&bm.ptr.pp_complex[0][0], bm.stride, &b->ptr.p_complex[0], 1, "N", ae_v_len(0,n-1)); + cmatrixmixedsolvem(a, lua, p, n, &bm, 1, info, rep, &xm, _state); + ae_vector_set_length(x, n, _state); + ae_v_cmove(&x->ptr.p_complex[0], 1, &xm.ptr.pp_complex[0][0], xm.stride, "N", ae_v_len(0,n-1)); + ae_frame_leave(_state); +} + + +/************************************************************************* +Dense solver. Same as RMatrixSolveM(), but for symmetric positive definite +matrices. + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* O(N^3+M*N^2) complexity +* matrix is represented by its upper or lower triangle + +No iterative refinement is provided because such partial representation of +matrix does not allow efficient calculation of extra-precise matrix-vector +products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you +need iterative refinement. + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + IsUpper - what half of A is provided + B - array[0..N-1,0..M-1], right part + M - right part size + +OUTPUT PARAMETERS + Info - same as in RMatrixSolve. + Returns -3 for non-SPD matrices. + Rep - same as in RMatrixSolve + X - same as in RMatrixSolve + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void spdmatrixsolvem(/* Real */ ae_matrix* a, + ae_int_t n, + ae_bool isupper, + /* Real */ ae_matrix* b, + ae_int_t m, + ae_int_t* info, + densesolverreport* rep, + /* Real */ ae_matrix* x, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix da; + double sqrtscalea; + ae_int_t i; + ae_int_t j; + ae_int_t j1; + ae_int_t j2; + + ae_frame_make(_state, &_frame_block); + *info = 0; + _densesolverreport_clear(rep); + ae_matrix_clear(x); + ae_matrix_init(&da, 0, 0, DT_REAL, _state, ae_true); + + + /* + * prepare: check inputs, allocate space... + */ + if( n<=0||m<=0 ) + { + *info = -1; + ae_frame_leave(_state); + return; + } + ae_matrix_set_length(&da, n, n, _state); + + /* + * 1. scale matrix, max(|A[i,j]|) + * 2. factorize scaled matrix + * 3. solve + */ + sqrtscalea = 0; + 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++) + { + sqrtscalea = ae_maxreal(sqrtscalea, ae_fabs(a->ptr.pp_double[i][j], _state), _state); + } + } + if( ae_fp_eq(sqrtscalea,0) ) + { + sqrtscalea = 1; + } + sqrtscalea = 1/sqrtscalea; + sqrtscalea = ae_sqrt(sqrtscalea, _state); + for(i=0; i<=n-1; i++) + { + if( isupper ) + { + j1 = i; + j2 = n-1; + } + else + { + j1 = 0; + j2 = i; + } + ae_v_move(&da.ptr.pp_double[i][j1], 1, &a->ptr.pp_double[i][j1], 1, ae_v_len(j1,j2)); + } + if( !spdmatrixcholesky(&da, n, isupper, _state) ) + { + ae_matrix_set_length(x, n, m, _state); + for(i=0; i<=n-1; i++) + { + for(j=0; j<=m-1; j++) + { + x->ptr.pp_double[i][j] = 0; + } + } + rep->r1 = 0; + rep->rinf = 0; + *info = -3; + ae_frame_leave(_state); + return; + } + *info = 1; + densesolver_spdmatrixcholeskysolveinternal(&da, sqrtscalea, n, isupper, a, ae_true, b, m, info, rep, x, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Dense solver. Same as RMatrixSolve(), but for SPD matrices. + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* O(N^3) complexity +* matrix is represented by its upper or lower triangle + +No iterative refinement is provided because such partial representation of +matrix does not allow efficient calculation of extra-precise matrix-vector +products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you +need iterative refinement. + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + IsUpper - what half of A is provided + B - array[0..N-1], right part + +OUTPUT PARAMETERS + Info - same as in RMatrixSolve + Returns -3 for non-SPD matrices. + Rep - same as in RMatrixSolve + X - same as in RMatrixSolve + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void spdmatrixsolve(/* Real */ ae_matrix* a, + ae_int_t n, + ae_bool isupper, + /* Real */ ae_vector* b, + ae_int_t* info, + densesolverreport* rep, + /* Real */ ae_vector* x, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix bm; + ae_matrix xm; + + ae_frame_make(_state, &_frame_block); + *info = 0; + _densesolverreport_clear(rep); + ae_vector_clear(x); + ae_matrix_init(&bm, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&xm, 0, 0, DT_REAL, _state, ae_true); + + if( n<=0 ) + { + *info = -1; + ae_frame_leave(_state); + return; + } + ae_matrix_set_length(&bm, n, 1, _state); + ae_v_move(&bm.ptr.pp_double[0][0], bm.stride, &b->ptr.p_double[0], 1, ae_v_len(0,n-1)); + spdmatrixsolvem(a, n, isupper, &bm, 1, info, rep, &xm, _state); + ae_vector_set_length(x, n, _state); + ae_v_move(&x->ptr.p_double[0], 1, &xm.ptr.pp_double[0][0], xm.stride, ae_v_len(0,n-1)); + ae_frame_leave(_state); +} + + +/************************************************************************* +Dense solver. Same as RMatrixLUSolveM(), but for SPD matrices represented +by their Cholesky decomposition. + +Algorithm features: +* automatic detection of degenerate cases +* O(M*N^2) complexity +* condition number estimation +* matrix is represented by its upper or lower triangle + +No iterative refinement is provided because such partial representation of +matrix does not allow efficient calculation of extra-precise matrix-vector +products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you +need iterative refinement. + +INPUT PARAMETERS + CHA - array[0..N-1,0..N-1], Cholesky decomposition, + SPDMatrixCholesky result + N - size of CHA + IsUpper - what half of CHA is provided + B - array[0..N-1,0..M-1], right part + M - right part size + +OUTPUT PARAMETERS + Info - same as in RMatrixSolve + Rep - same as in RMatrixSolve + X - same as in RMatrixSolve + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void spdmatrixcholeskysolvem(/* Real */ ae_matrix* cha, + ae_int_t n, + ae_bool isupper, + /* Real */ ae_matrix* b, + ae_int_t m, + ae_int_t* info, + densesolverreport* rep, + /* Real */ ae_matrix* x, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix emptya; + double sqrtscalea; + ae_int_t i; + ae_int_t j; + ae_int_t j1; + ae_int_t j2; + + ae_frame_make(_state, &_frame_block); + *info = 0; + _densesolverreport_clear(rep); + ae_matrix_clear(x); + ae_matrix_init(&emptya, 0, 0, DT_REAL, _state, ae_true); + + + /* + * prepare: check inputs, allocate space... + */ + if( n<=0||m<=0 ) + { + *info = -1; + ae_frame_leave(_state); + return; + } + + /* + * 1. scale matrix, max(|U[i,j]|) + * 2. factorize scaled matrix + * 3. solve + */ + sqrtscalea = 0; + 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++) + { + sqrtscalea = ae_maxreal(sqrtscalea, ae_fabs(cha->ptr.pp_double[i][j], _state), _state); + } + } + if( ae_fp_eq(sqrtscalea,0) ) + { + sqrtscalea = 1; + } + sqrtscalea = 1/sqrtscalea; + densesolver_spdmatrixcholeskysolveinternal(cha, sqrtscalea, n, isupper, &emptya, ae_false, b, m, info, rep, x, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Dense solver. Same as RMatrixLUSolve(), but for SPD matrices represented +by their Cholesky decomposition. + +Algorithm features: +* automatic detection of degenerate cases +* O(N^2) complexity +* condition number estimation +* matrix is represented by its upper or lower triangle + +No iterative refinement is provided because such partial representation of +matrix does not allow efficient calculation of extra-precise matrix-vector +products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you +need iterative refinement. + +INPUT PARAMETERS + CHA - array[0..N-1,0..N-1], Cholesky decomposition, + SPDMatrixCholesky result + N - size of A + IsUpper - what half of CHA is provided + B - array[0..N-1], right part + +OUTPUT PARAMETERS + Info - same as in RMatrixSolve + Rep - same as in RMatrixSolve + X - same as in RMatrixSolve + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void spdmatrixcholeskysolve(/* Real */ ae_matrix* cha, + ae_int_t n, + ae_bool isupper, + /* Real */ ae_vector* b, + ae_int_t* info, + densesolverreport* rep, + /* Real */ ae_vector* x, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix bm; + ae_matrix xm; + + ae_frame_make(_state, &_frame_block); + *info = 0; + _densesolverreport_clear(rep); + ae_vector_clear(x); + ae_matrix_init(&bm, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&xm, 0, 0, DT_REAL, _state, ae_true); + + if( n<=0 ) + { + *info = -1; + ae_frame_leave(_state); + return; + } + ae_matrix_set_length(&bm, n, 1, _state); + ae_v_move(&bm.ptr.pp_double[0][0], bm.stride, &b->ptr.p_double[0], 1, ae_v_len(0,n-1)); + spdmatrixcholeskysolvem(cha, n, isupper, &bm, 1, info, rep, &xm, _state); + ae_vector_set_length(x, n, _state); + ae_v_move(&x->ptr.p_double[0], 1, &xm.ptr.pp_double[0][0], xm.stride, ae_v_len(0,n-1)); + ae_frame_leave(_state); +} + + +/************************************************************************* +Dense solver. Same as RMatrixSolveM(), but for Hermitian positive definite +matrices. + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* O(N^3+M*N^2) complexity +* matrix is represented by its upper or lower triangle + +No iterative refinement is provided because such partial representation of +matrix does not allow efficient calculation of extra-precise matrix-vector +products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you +need iterative refinement. + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + IsUpper - what half of A is provided + B - array[0..N-1,0..M-1], right part + M - right part size + +OUTPUT PARAMETERS + Info - same as in RMatrixSolve. + Returns -3 for non-HPD matrices. + Rep - same as in RMatrixSolve + X - same as in RMatrixSolve + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void hpdmatrixsolvem(/* Complex */ ae_matrix* a, + ae_int_t n, + ae_bool isupper, + /* Complex */ ae_matrix* b, + ae_int_t m, + ae_int_t* info, + densesolverreport* rep, + /* Complex */ ae_matrix* x, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix da; + double sqrtscalea; + ae_int_t i; + ae_int_t j; + ae_int_t j1; + ae_int_t j2; + + ae_frame_make(_state, &_frame_block); + *info = 0; + _densesolverreport_clear(rep); + ae_matrix_clear(x); + ae_matrix_init(&da, 0, 0, DT_COMPLEX, _state, ae_true); + + + /* + * prepare: check inputs, allocate space... + */ + if( n<=0||m<=0 ) + { + *info = -1; + ae_frame_leave(_state); + return; + } + ae_matrix_set_length(&da, n, n, _state); + + /* + * 1. scale matrix, max(|A[i,j]|) + * 2. factorize scaled matrix + * 3. solve + */ + sqrtscalea = 0; + 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++) + { + sqrtscalea = ae_maxreal(sqrtscalea, ae_c_abs(a->ptr.pp_complex[i][j], _state), _state); + } + } + if( ae_fp_eq(sqrtscalea,0) ) + { + sqrtscalea = 1; + } + sqrtscalea = 1/sqrtscalea; + sqrtscalea = ae_sqrt(sqrtscalea, _state); + for(i=0; i<=n-1; i++) + { + if( isupper ) + { + j1 = i; + j2 = n-1; + } + else + { + j1 = 0; + j2 = i; + } + ae_v_cmove(&da.ptr.pp_complex[i][j1], 1, &a->ptr.pp_complex[i][j1], 1, "N", ae_v_len(j1,j2)); + } + if( !hpdmatrixcholesky(&da, n, isupper, _state) ) + { + ae_matrix_set_length(x, n, m, _state); + for(i=0; i<=n-1; i++) + { + for(j=0; j<=m-1; j++) + { + x->ptr.pp_complex[i][j] = ae_complex_from_d(0); + } + } + rep->r1 = 0; + rep->rinf = 0; + *info = -3; + ae_frame_leave(_state); + return; + } + *info = 1; + densesolver_hpdmatrixcholeskysolveinternal(&da, sqrtscalea, n, isupper, a, ae_true, b, m, info, rep, x, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Dense solver. Same as RMatrixSolve(), but for Hermitian positive definite +matrices. + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* O(N^3) complexity +* matrix is represented by its upper or lower triangle + +No iterative refinement is provided because such partial representation of +matrix does not allow efficient calculation of extra-precise matrix-vector +products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you +need iterative refinement. + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + IsUpper - what half of A is provided + B - array[0..N-1], right part + +OUTPUT PARAMETERS + Info - same as in RMatrixSolve + Returns -3 for non-HPD matrices. + Rep - same as in RMatrixSolve + X - same as in RMatrixSolve + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void hpdmatrixsolve(/* Complex */ ae_matrix* a, + ae_int_t n, + ae_bool isupper, + /* Complex */ ae_vector* b, + ae_int_t* info, + densesolverreport* rep, + /* Complex */ ae_vector* x, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix bm; + ae_matrix xm; + + ae_frame_make(_state, &_frame_block); + *info = 0; + _densesolverreport_clear(rep); + ae_vector_clear(x); + ae_matrix_init(&bm, 0, 0, DT_COMPLEX, _state, ae_true); + ae_matrix_init(&xm, 0, 0, DT_COMPLEX, _state, ae_true); + + if( n<=0 ) + { + *info = -1; + ae_frame_leave(_state); + return; + } + ae_matrix_set_length(&bm, n, 1, _state); + ae_v_cmove(&bm.ptr.pp_complex[0][0], bm.stride, &b->ptr.p_complex[0], 1, "N", ae_v_len(0,n-1)); + hpdmatrixsolvem(a, n, isupper, &bm, 1, info, rep, &xm, _state); + ae_vector_set_length(x, n, _state); + ae_v_cmove(&x->ptr.p_complex[0], 1, &xm.ptr.pp_complex[0][0], xm.stride, "N", ae_v_len(0,n-1)); + ae_frame_leave(_state); +} + + +/************************************************************************* +Dense solver. Same as RMatrixLUSolveM(), but for HPD matrices represented +by their Cholesky decomposition. + +Algorithm features: +* automatic detection of degenerate cases +* O(M*N^2) complexity +* condition number estimation +* matrix is represented by its upper or lower triangle + +No iterative refinement is provided because such partial representation of +matrix does not allow efficient calculation of extra-precise matrix-vector +products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you +need iterative refinement. + +INPUT PARAMETERS + CHA - array[0..N-1,0..N-1], Cholesky decomposition, + HPDMatrixCholesky result + N - size of CHA + IsUpper - what half of CHA is provided + B - array[0..N-1,0..M-1], right part + M - right part size + +OUTPUT PARAMETERS + Info - same as in RMatrixSolve + Rep - same as in RMatrixSolve + X - same as in RMatrixSolve + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void hpdmatrixcholeskysolvem(/* Complex */ ae_matrix* cha, + ae_int_t n, + ae_bool isupper, + /* Complex */ ae_matrix* b, + ae_int_t m, + ae_int_t* info, + densesolverreport* rep, + /* Complex */ ae_matrix* x, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix emptya; + double sqrtscalea; + ae_int_t i; + ae_int_t j; + ae_int_t j1; + ae_int_t j2; + + ae_frame_make(_state, &_frame_block); + *info = 0; + _densesolverreport_clear(rep); + ae_matrix_clear(x); + ae_matrix_init(&emptya, 0, 0, DT_COMPLEX, _state, ae_true); + + + /* + * prepare: check inputs, allocate space... + */ + if( n<=0||m<=0 ) + { + *info = -1; + ae_frame_leave(_state); + return; + } + + /* + * 1. scale matrix, max(|U[i,j]|) + * 2. factorize scaled matrix + * 3. solve + */ + sqrtscalea = 0; + 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++) + { + sqrtscalea = ae_maxreal(sqrtscalea, ae_c_abs(cha->ptr.pp_complex[i][j], _state), _state); + } + } + if( ae_fp_eq(sqrtscalea,0) ) + { + sqrtscalea = 1; + } + sqrtscalea = 1/sqrtscalea; + densesolver_hpdmatrixcholeskysolveinternal(cha, sqrtscalea, n, isupper, &emptya, ae_false, b, m, info, rep, x, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Dense solver. Same as RMatrixLUSolve(), but for HPD matrices represented +by their Cholesky decomposition. + +Algorithm features: +* automatic detection of degenerate cases +* O(N^2) complexity +* condition number estimation +* matrix is represented by its upper or lower triangle + +No iterative refinement is provided because such partial representation of +matrix does not allow efficient calculation of extra-precise matrix-vector +products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you +need iterative refinement. + +INPUT PARAMETERS + CHA - array[0..N-1,0..N-1], Cholesky decomposition, + SPDMatrixCholesky result + N - size of A + IsUpper - what half of CHA is provided + B - array[0..N-1], right part + +OUTPUT PARAMETERS + Info - same as in RMatrixSolve + Rep - same as in RMatrixSolve + X - same as in RMatrixSolve + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void hpdmatrixcholeskysolve(/* Complex */ ae_matrix* cha, + ae_int_t n, + ae_bool isupper, + /* Complex */ ae_vector* b, + ae_int_t* info, + densesolverreport* rep, + /* Complex */ ae_vector* x, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix bm; + ae_matrix xm; + + ae_frame_make(_state, &_frame_block); + *info = 0; + _densesolverreport_clear(rep); + ae_vector_clear(x); + ae_matrix_init(&bm, 0, 0, DT_COMPLEX, _state, ae_true); + ae_matrix_init(&xm, 0, 0, DT_COMPLEX, _state, ae_true); + + if( n<=0 ) + { + *info = -1; + ae_frame_leave(_state); + return; + } + ae_matrix_set_length(&bm, n, 1, _state); + ae_v_cmove(&bm.ptr.pp_complex[0][0], bm.stride, &b->ptr.p_complex[0], 1, "N", ae_v_len(0,n-1)); + hpdmatrixcholeskysolvem(cha, n, isupper, &bm, 1, info, rep, &xm, _state); + ae_vector_set_length(x, n, _state); + ae_v_cmove(&x->ptr.p_complex[0], 1, &xm.ptr.pp_complex[0][0], xm.stride, "N", ae_v_len(0,n-1)); + ae_frame_leave(_state); +} + + +/************************************************************************* +Dense solver. + +This subroutine finds solution of the linear system A*X=B with non-square, +possibly degenerate A. System is solved in the least squares sense, and +general least squares solution X = X0 + CX*y which minimizes |A*X-B| is +returned. If A is non-degenerate, solution in the usual sense is returned + +Algorithm features: +* automatic detection of degenerate cases +* iterative refinement +* O(N^3) complexity + +INPUT PARAMETERS + A - array[0..NRows-1,0..NCols-1], system matrix + NRows - vertical size of A + NCols - horizontal size of A + B - array[0..NCols-1], right part + Threshold- a number in [0,1]. Singular values beyond Threshold are + considered zero. Set it to 0.0, if you don't understand + what it means, so the solver will choose good value on its + own. + +OUTPUT PARAMETERS + Info - return code: + * -4 SVD subroutine failed + * -1 if NRows<=0 or NCols<=0 or Threshold<0 was passed + * 1 if task is solved + Rep - solver report, see below for more info + X - array[0..N-1,0..M-1], it contains: + * solution of A*X=B if A is non-singular (well-conditioned + or ill-conditioned, but not very close to singular) + * zeros, if A is singular or VERY close to singular + (in this case Info=-3). + +SOLVER REPORT + +Subroutine sets following fields of the Rep structure: +* R2 reciprocal of condition number: 1/cond(A), 2-norm. +* N = NCols +* K dim(Null(A)) +* CX array[0..N-1,0..K-1], kernel of A. + Columns of CX store such vectors that A*CX[i]=0. + + -- ALGLIB -- + Copyright 24.08.2009 by Bochkanov Sergey +*************************************************************************/ +void rmatrixsolvels(/* Real */ ae_matrix* a, + ae_int_t nrows, + ae_int_t ncols, + /* Real */ ae_vector* b, + double threshold, + ae_int_t* info, + densesolverlsreport* rep, + /* Real */ ae_vector* x, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector sv; + ae_matrix u; + ae_matrix vt; + ae_vector rp; + ae_vector utb; + ae_vector sutb; + ae_vector tmp; + ae_vector ta; + ae_vector tx; + ae_vector buf; + ae_vector w; + ae_int_t i; + ae_int_t j; + ae_int_t nsv; + ae_int_t kernelidx; + double v; + double verr; + ae_bool svdfailed; + ae_bool zeroa; + ae_int_t rfs; + ae_int_t nrfs; + ae_bool terminatenexttime; + ae_bool smallerr; + + ae_frame_make(_state, &_frame_block); + *info = 0; + _densesolverlsreport_clear(rep); + ae_vector_clear(x); + ae_vector_init(&sv, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&u, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&vt, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&rp, 0, DT_REAL, _state, ae_true); + ae_vector_init(&utb, 0, DT_REAL, _state, ae_true); + ae_vector_init(&sutb, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tmp, 0, DT_REAL, _state, ae_true); + ae_vector_init(&ta, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tx, 0, DT_REAL, _state, ae_true); + ae_vector_init(&buf, 0, DT_REAL, _state, ae_true); + ae_vector_init(&w, 0, DT_REAL, _state, ae_true); + + if( (nrows<=0||ncols<=0)||ae_fp_less(threshold,0) ) + { + *info = -1; + ae_frame_leave(_state); + return; + } + if( ae_fp_eq(threshold,0) ) + { + threshold = 1000*ae_machineepsilon; + } + + /* + * Factorize A first + */ + svdfailed = !rmatrixsvd(a, nrows, ncols, 1, 2, 2, &sv, &u, &vt, _state); + zeroa = ae_fp_eq(sv.ptr.p_double[0],0); + if( svdfailed||zeroa ) + { + if( svdfailed ) + { + *info = -4; + } + else + { + *info = 1; + } + ae_vector_set_length(x, ncols, _state); + for(i=0; i<=ncols-1; i++) + { + x->ptr.p_double[i] = 0; + } + rep->n = ncols; + rep->k = ncols; + ae_matrix_set_length(&rep->cx, ncols, ncols, _state); + for(i=0; i<=ncols-1; i++) + { + for(j=0; j<=ncols-1; j++) + { + if( i==j ) + { + rep->cx.ptr.pp_double[i][j] = 1; + } + else + { + rep->cx.ptr.pp_double[i][j] = 0; + } + } + } + rep->r2 = 0; + ae_frame_leave(_state); + return; + } + nsv = ae_minint(ncols, nrows, _state); + if( nsv==ncols ) + { + rep->r2 = sv.ptr.p_double[nsv-1]/sv.ptr.p_double[0]; + } + else + { + rep->r2 = 0; + } + rep->n = ncols; + *info = 1; + + /* + * Iterative refinement of xc combined with solution: + * 1. xc = 0 + * 2. calculate r = bc-A*xc using extra-precise dot product + * 3. solve A*y = r + * 4. update x:=x+r + * 5. goto 2 + * + * This cycle is executed until one of two things happens: + * 1. maximum number of iterations reached + * 2. last iteration decreased error to the lower limit + */ + ae_vector_set_length(&utb, nsv, _state); + ae_vector_set_length(&sutb, nsv, _state); + ae_vector_set_length(x, ncols, _state); + ae_vector_set_length(&tmp, ncols, _state); + ae_vector_set_length(&ta, ncols+1, _state); + ae_vector_set_length(&tx, ncols+1, _state); + ae_vector_set_length(&buf, ncols+1, _state); + for(i=0; i<=ncols-1; i++) + { + x->ptr.p_double[i] = 0; + } + kernelidx = nsv; + for(i=0; i<=nsv-1; i++) + { + if( ae_fp_less_eq(sv.ptr.p_double[i],threshold*sv.ptr.p_double[0]) ) + { + kernelidx = i; + break; + } + } + rep->k = ncols-kernelidx; + nrfs = densesolver_densesolverrfsmaxv2(ncols, rep->r2, _state); + terminatenexttime = ae_false; + ae_vector_set_length(&rp, nrows, _state); + for(rfs=0; rfs<=nrfs; rfs++) + { + if( terminatenexttime ) + { + break; + } + + /* + * calculate right part + */ + if( rfs==0 ) + { + ae_v_move(&rp.ptr.p_double[0], 1, &b->ptr.p_double[0], 1, ae_v_len(0,nrows-1)); + } + else + { + smallerr = ae_true; + for(i=0; i<=nrows-1; i++) + { + ae_v_move(&ta.ptr.p_double[0], 1, &a->ptr.pp_double[i][0], 1, ae_v_len(0,ncols-1)); + ta.ptr.p_double[ncols] = -1; + ae_v_move(&tx.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,ncols-1)); + tx.ptr.p_double[ncols] = b->ptr.p_double[i]; + xdot(&ta, &tx, ncols+1, &buf, &v, &verr, _state); + rp.ptr.p_double[i] = -v; + smallerr = smallerr&&ae_fp_less(ae_fabs(v, _state),4*verr); + } + if( smallerr ) + { + terminatenexttime = ae_true; + } + } + + /* + * solve A*dx = rp + */ + for(i=0; i<=ncols-1; i++) + { + tmp.ptr.p_double[i] = 0; + } + for(i=0; i<=nsv-1; i++) + { + utb.ptr.p_double[i] = 0; + } + for(i=0; i<=nrows-1; i++) + { + v = rp.ptr.p_double[i]; + ae_v_addd(&utb.ptr.p_double[0], 1, &u.ptr.pp_double[i][0], 1, ae_v_len(0,nsv-1), v); + } + for(i=0; i<=nsv-1; i++) + { + if( i<kernelidx ) + { + sutb.ptr.p_double[i] = utb.ptr.p_double[i]/sv.ptr.p_double[i]; + } + else + { + sutb.ptr.p_double[i] = 0; + } + } + for(i=0; i<=nsv-1; i++) + { + v = sutb.ptr.p_double[i]; + ae_v_addd(&tmp.ptr.p_double[0], 1, &vt.ptr.pp_double[i][0], 1, ae_v_len(0,ncols-1), v); + } + + /* + * update x: x:=x+dx + */ + ae_v_add(&x->ptr.p_double[0], 1, &tmp.ptr.p_double[0], 1, ae_v_len(0,ncols-1)); + } + + /* + * fill CX + */ + if( rep->k>0 ) + { + ae_matrix_set_length(&rep->cx, ncols, rep->k, _state); + for(i=0; i<=rep->k-1; i++) + { + ae_v_move(&rep->cx.ptr.pp_double[0][i], rep->cx.stride, &vt.ptr.pp_double[kernelidx+i][0], 1, ae_v_len(0,ncols-1)); + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Internal LU solver + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +static void densesolver_rmatrixlusolveinternal(/* Real */ ae_matrix* lua, + /* Integer */ ae_vector* p, + double scalea, + ae_int_t n, + /* Real */ ae_matrix* a, + ae_bool havea, + /* Real */ ae_matrix* b, + ae_int_t m, + ae_int_t* info, + densesolverreport* rep, + /* Real */ ae_matrix* x, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t rfs; + ae_int_t nrfs; + ae_vector xc; + ae_vector y; + ae_vector bc; + ae_vector xa; + ae_vector xb; + ae_vector tx; + double v; + double verr; + double mxb; + double scaleright; + ae_bool smallerr; + ae_bool terminatenexttime; + + ae_frame_make(_state, &_frame_block); + *info = 0; + _densesolverreport_clear(rep); + ae_matrix_clear(x); + ae_vector_init(&xc, 0, DT_REAL, _state, ae_true); + ae_vector_init(&y, 0, DT_REAL, _state, ae_true); + ae_vector_init(&bc, 0, DT_REAL, _state, ae_true); + ae_vector_init(&xa, 0, DT_REAL, _state, ae_true); + ae_vector_init(&xb, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tx, 0, DT_REAL, _state, ae_true); + + ae_assert(ae_fp_greater(scalea,0), "Assertion failed", _state); + + /* + * prepare: check inputs, allocate space... + */ + if( n<=0||m<=0 ) + { + *info = -1; + ae_frame_leave(_state); + return; + } + for(i=0; i<=n-1; i++) + { + if( p->ptr.p_int[i]>n-1||p->ptr.p_int[i]<i ) + { + *info = -1; + ae_frame_leave(_state); + return; + } + } + ae_matrix_set_length(x, n, m, _state); + ae_vector_set_length(&y, n, _state); + ae_vector_set_length(&xc, n, _state); + ae_vector_set_length(&bc, n, _state); + ae_vector_set_length(&tx, n+1, _state); + ae_vector_set_length(&xa, n+1, _state); + ae_vector_set_length(&xb, n+1, _state); + + /* + * estimate condition number, test for near singularity + */ + rep->r1 = rmatrixlurcond1(lua, n, _state); + rep->rinf = rmatrixlurcondinf(lua, n, _state); + if( ae_fp_less(rep->r1,rcondthreshold(_state))||ae_fp_less(rep->rinf,rcondthreshold(_state)) ) + { + for(i=0; i<=n-1; i++) + { + for(j=0; j<=m-1; j++) + { + x->ptr.pp_double[i][j] = 0; + } + } + rep->r1 = 0; + rep->rinf = 0; + *info = -3; + ae_frame_leave(_state); + return; + } + *info = 1; + + /* + * solve + */ + for(k=0; k<=m-1; k++) + { + + /* + * copy B to contiguous storage + */ + ae_v_move(&bc.ptr.p_double[0], 1, &b->ptr.pp_double[0][k], b->stride, ae_v_len(0,n-1)); + + /* + * Scale right part: + * * MX stores max(|Bi|) + * * ScaleRight stores actual scaling applied to B when solving systems + * it is chosen to make |scaleRight*b| close to 1. + */ + mxb = 0; + for(i=0; i<=n-1; i++) + { + mxb = ae_maxreal(mxb, ae_fabs(bc.ptr.p_double[i], _state), _state); + } + if( ae_fp_eq(mxb,0) ) + { + mxb = 1; + } + scaleright = 1/mxb; + + /* + * First, non-iterative part of solution process. + * We use separate code for this task because + * XDot is quite slow and we want to save time. + */ + ae_v_moved(&xc.ptr.p_double[0], 1, &bc.ptr.p_double[0], 1, ae_v_len(0,n-1), scaleright); + densesolver_rbasiclusolve(lua, p, scalea, n, &xc, &tx, _state); + + /* + * Iterative refinement of xc: + * * calculate r = bc-A*xc using extra-precise dot product + * * solve A*y = r + * * update x:=x+r + * + * This cycle is executed until one of two things happens: + * 1. maximum number of iterations reached + * 2. last iteration decreased error to the lower limit + */ + if( havea ) + { + nrfs = densesolver_densesolverrfsmax(n, rep->r1, rep->rinf, _state); + terminatenexttime = ae_false; + for(rfs=0; rfs<=nrfs-1; rfs++) + { + if( terminatenexttime ) + { + break; + } + + /* + * generate right part + */ + smallerr = ae_true; + ae_v_move(&xb.ptr.p_double[0], 1, &xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); + for(i=0; i<=n-1; i++) + { + ae_v_moved(&xa.ptr.p_double[0], 1, &a->ptr.pp_double[i][0], 1, ae_v_len(0,n-1), scalea); + xa.ptr.p_double[n] = -1; + xb.ptr.p_double[n] = scaleright*bc.ptr.p_double[i]; + xdot(&xa, &xb, n+1, &tx, &v, &verr, _state); + y.ptr.p_double[i] = -v; + smallerr = smallerr&&ae_fp_less(ae_fabs(v, _state),4*verr); + } + if( smallerr ) + { + terminatenexttime = ae_true; + } + + /* + * solve and update + */ + densesolver_rbasiclusolve(lua, p, scalea, n, &y, &tx, _state); + ae_v_add(&xc.ptr.p_double[0], 1, &y.ptr.p_double[0], 1, ae_v_len(0,n-1)); + } + } + + /* + * Store xc. + * Post-scale result. + */ + v = scalea*mxb; + ae_v_moved(&x->ptr.pp_double[0][k], x->stride, &xc.ptr.p_double[0], 1, ae_v_len(0,n-1), v); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Internal Cholesky solver + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +static void densesolver_spdmatrixcholeskysolveinternal(/* Real */ ae_matrix* cha, + double sqrtscalea, + ae_int_t n, + ae_bool isupper, + /* Real */ ae_matrix* a, + ae_bool havea, + /* Real */ ae_matrix* b, + ae_int_t m, + ae_int_t* info, + densesolverreport* rep, + /* Real */ ae_matrix* x, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_vector xc; + ae_vector y; + ae_vector bc; + ae_vector xa; + ae_vector xb; + ae_vector tx; + double v; + double mxb; + double scaleright; + + ae_frame_make(_state, &_frame_block); + *info = 0; + _densesolverreport_clear(rep); + ae_matrix_clear(x); + ae_vector_init(&xc, 0, DT_REAL, _state, ae_true); + ae_vector_init(&y, 0, DT_REAL, _state, ae_true); + ae_vector_init(&bc, 0, DT_REAL, _state, ae_true); + ae_vector_init(&xa, 0, DT_REAL, _state, ae_true); + ae_vector_init(&xb, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tx, 0, DT_REAL, _state, ae_true); + + ae_assert(ae_fp_greater(sqrtscalea,0), "Assertion failed", _state); + + /* + * prepare: check inputs, allocate space... + */ + if( n<=0||m<=0 ) + { + *info = -1; + ae_frame_leave(_state); + return; + } + ae_matrix_set_length(x, n, m, _state); + ae_vector_set_length(&y, n, _state); + ae_vector_set_length(&xc, n, _state); + ae_vector_set_length(&bc, n, _state); + ae_vector_set_length(&tx, n+1, _state); + ae_vector_set_length(&xa, n+1, _state); + ae_vector_set_length(&xb, n+1, _state); + + /* + * estimate condition number, test for near singularity + */ + rep->r1 = spdmatrixcholeskyrcond(cha, n, isupper, _state); + rep->rinf = rep->r1; + if( ae_fp_less(rep->r1,rcondthreshold(_state)) ) + { + for(i=0; i<=n-1; i++) + { + for(j=0; j<=m-1; j++) + { + x->ptr.pp_double[i][j] = 0; + } + } + rep->r1 = 0; + rep->rinf = 0; + *info = -3; + ae_frame_leave(_state); + return; + } + *info = 1; + + /* + * solve + */ + for(k=0; k<=m-1; k++) + { + + /* + * copy B to contiguous storage + */ + ae_v_move(&bc.ptr.p_double[0], 1, &b->ptr.pp_double[0][k], b->stride, ae_v_len(0,n-1)); + + /* + * Scale right part: + * * MX stores max(|Bi|) + * * ScaleRight stores actual scaling applied to B when solving systems + * it is chosen to make |scaleRight*b| close to 1. + */ + mxb = 0; + for(i=0; i<=n-1; i++) + { + mxb = ae_maxreal(mxb, ae_fabs(bc.ptr.p_double[i], _state), _state); + } + if( ae_fp_eq(mxb,0) ) + { + mxb = 1; + } + scaleright = 1/mxb; + + /* + * First, non-iterative part of solution process. + * We use separate code for this task because + * XDot is quite slow and we want to save time. + */ + ae_v_moved(&xc.ptr.p_double[0], 1, &bc.ptr.p_double[0], 1, ae_v_len(0,n-1), scaleright); + densesolver_spdbasiccholeskysolve(cha, sqrtscalea, n, isupper, &xc, &tx, _state); + + /* + * Store xc. + * Post-scale result. + */ + v = ae_sqr(sqrtscalea, _state)*mxb; + ae_v_moved(&x->ptr.pp_double[0][k], x->stride, &xc.ptr.p_double[0], 1, ae_v_len(0,n-1), v); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Internal LU solver + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +static void densesolver_cmatrixlusolveinternal(/* Complex */ ae_matrix* lua, + /* Integer */ ae_vector* p, + double scalea, + ae_int_t n, + /* Complex */ ae_matrix* a, + ae_bool havea, + /* Complex */ ae_matrix* b, + ae_int_t m, + ae_int_t* info, + densesolverreport* rep, + /* Complex */ ae_matrix* x, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t rfs; + ae_int_t nrfs; + ae_vector xc; + ae_vector y; + ae_vector bc; + ae_vector xa; + ae_vector xb; + ae_vector tx; + ae_vector tmpbuf; + ae_complex v; + double verr; + double mxb; + double scaleright; + ae_bool smallerr; + ae_bool terminatenexttime; + + ae_frame_make(_state, &_frame_block); + *info = 0; + _densesolverreport_clear(rep); + ae_matrix_clear(x); + ae_vector_init(&xc, 0, DT_COMPLEX, _state, ae_true); + ae_vector_init(&y, 0, DT_COMPLEX, _state, ae_true); + ae_vector_init(&bc, 0, DT_COMPLEX, _state, ae_true); + ae_vector_init(&xa, 0, DT_COMPLEX, _state, ae_true); + ae_vector_init(&xb, 0, DT_COMPLEX, _state, ae_true); + ae_vector_init(&tx, 0, DT_COMPLEX, _state, ae_true); + ae_vector_init(&tmpbuf, 0, DT_REAL, _state, ae_true); + + ae_assert(ae_fp_greater(scalea,0), "Assertion failed", _state); + + /* + * prepare: check inputs, allocate space... + */ + if( n<=0||m<=0 ) + { + *info = -1; + ae_frame_leave(_state); + return; + } + for(i=0; i<=n-1; i++) + { + if( p->ptr.p_int[i]>n-1||p->ptr.p_int[i]<i ) + { + *info = -1; + ae_frame_leave(_state); + return; + } + } + ae_matrix_set_length(x, n, m, _state); + ae_vector_set_length(&y, n, _state); + ae_vector_set_length(&xc, n, _state); + ae_vector_set_length(&bc, n, _state); + ae_vector_set_length(&tx, n, _state); + ae_vector_set_length(&xa, n+1, _state); + ae_vector_set_length(&xb, n+1, _state); + ae_vector_set_length(&tmpbuf, 2*n+2, _state); + + /* + * estimate condition number, test for near singularity + */ + rep->r1 = cmatrixlurcond1(lua, n, _state); + rep->rinf = cmatrixlurcondinf(lua, n, _state); + if( ae_fp_less(rep->r1,rcondthreshold(_state))||ae_fp_less(rep->rinf,rcondthreshold(_state)) ) + { + for(i=0; i<=n-1; i++) + { + for(j=0; j<=m-1; j++) + { + x->ptr.pp_complex[i][j] = ae_complex_from_d(0); + } + } + rep->r1 = 0; + rep->rinf = 0; + *info = -3; + ae_frame_leave(_state); + return; + } + *info = 1; + + /* + * solve + */ + for(k=0; k<=m-1; k++) + { + + /* + * copy B to contiguous storage + */ + ae_v_cmove(&bc.ptr.p_complex[0], 1, &b->ptr.pp_complex[0][k], b->stride, "N", ae_v_len(0,n-1)); + + /* + * Scale right part: + * * MX stores max(|Bi|) + * * ScaleRight stores actual scaling applied to B when solving systems + * it is chosen to make |scaleRight*b| close to 1. + */ + mxb = 0; + for(i=0; i<=n-1; i++) + { + mxb = ae_maxreal(mxb, ae_c_abs(bc.ptr.p_complex[i], _state), _state); + } + if( ae_fp_eq(mxb,0) ) + { + mxb = 1; + } + scaleright = 1/mxb; + + /* + * First, non-iterative part of solution process. + * We use separate code for this task because + * XDot is quite slow and we want to save time. + */ + ae_v_cmoved(&xc.ptr.p_complex[0], 1, &bc.ptr.p_complex[0], 1, "N", ae_v_len(0,n-1), scaleright); + densesolver_cbasiclusolve(lua, p, scalea, n, &xc, &tx, _state); + + /* + * Iterative refinement of xc: + * * calculate r = bc-A*xc using extra-precise dot product + * * solve A*y = r + * * update x:=x+r + * + * This cycle is executed until one of two things happens: + * 1. maximum number of iterations reached + * 2. last iteration decreased error to the lower limit + */ + if( havea ) + { + nrfs = densesolver_densesolverrfsmax(n, rep->r1, rep->rinf, _state); + terminatenexttime = ae_false; + for(rfs=0; rfs<=nrfs-1; rfs++) + { + if( terminatenexttime ) + { + break; + } + + /* + * generate right part + */ + smallerr = ae_true; + ae_v_cmove(&xb.ptr.p_complex[0], 1, &xc.ptr.p_complex[0], 1, "N", ae_v_len(0,n-1)); + for(i=0; i<=n-1; i++) + { + ae_v_cmoved(&xa.ptr.p_complex[0], 1, &a->ptr.pp_complex[i][0], 1, "N", ae_v_len(0,n-1), scalea); + xa.ptr.p_complex[n] = ae_complex_from_d(-1); + xb.ptr.p_complex[n] = ae_c_mul_d(bc.ptr.p_complex[i],scaleright); + xcdot(&xa, &xb, n+1, &tmpbuf, &v, &verr, _state); + y.ptr.p_complex[i] = ae_c_neg(v); + smallerr = smallerr&&ae_fp_less(ae_c_abs(v, _state),4*verr); + } + if( smallerr ) + { + terminatenexttime = ae_true; + } + + /* + * solve and update + */ + densesolver_cbasiclusolve(lua, p, scalea, n, &y, &tx, _state); + ae_v_cadd(&xc.ptr.p_complex[0], 1, &y.ptr.p_complex[0], 1, "N", ae_v_len(0,n-1)); + } + } + + /* + * Store xc. + * Post-scale result. + */ + v = ae_complex_from_d(scalea*mxb); + ae_v_cmovec(&x->ptr.pp_complex[0][k], x->stride, &xc.ptr.p_complex[0], 1, "N", ae_v_len(0,n-1), v); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Internal Cholesky solver + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +static void densesolver_hpdmatrixcholeskysolveinternal(/* Complex */ ae_matrix* cha, + double sqrtscalea, + ae_int_t n, + ae_bool isupper, + /* Complex */ ae_matrix* a, + ae_bool havea, + /* Complex */ ae_matrix* b, + ae_int_t m, + ae_int_t* info, + densesolverreport* rep, + /* Complex */ ae_matrix* x, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_vector xc; + ae_vector y; + ae_vector bc; + ae_vector xa; + ae_vector xb; + ae_vector tx; + double v; + double mxb; + double scaleright; + + ae_frame_make(_state, &_frame_block); + *info = 0; + _densesolverreport_clear(rep); + ae_matrix_clear(x); + ae_vector_init(&xc, 0, DT_COMPLEX, _state, ae_true); + ae_vector_init(&y, 0, DT_COMPLEX, _state, ae_true); + ae_vector_init(&bc, 0, DT_COMPLEX, _state, ae_true); + ae_vector_init(&xa, 0, DT_COMPLEX, _state, ae_true); + ae_vector_init(&xb, 0, DT_COMPLEX, _state, ae_true); + ae_vector_init(&tx, 0, DT_COMPLEX, _state, ae_true); + + ae_assert(ae_fp_greater(sqrtscalea,0), "Assertion failed", _state); + + /* + * prepare: check inputs, allocate space... + */ + if( n<=0||m<=0 ) + { + *info = -1; + ae_frame_leave(_state); + return; + } + ae_matrix_set_length(x, n, m, _state); + ae_vector_set_length(&y, n, _state); + ae_vector_set_length(&xc, n, _state); + ae_vector_set_length(&bc, n, _state); + ae_vector_set_length(&tx, n+1, _state); + ae_vector_set_length(&xa, n+1, _state); + ae_vector_set_length(&xb, n+1, _state); + + /* + * estimate condition number, test for near singularity + */ + rep->r1 = hpdmatrixcholeskyrcond(cha, n, isupper, _state); + rep->rinf = rep->r1; + if( ae_fp_less(rep->r1,rcondthreshold(_state)) ) + { + for(i=0; i<=n-1; i++) + { + for(j=0; j<=m-1; j++) + { + x->ptr.pp_complex[i][j] = ae_complex_from_d(0); + } + } + rep->r1 = 0; + rep->rinf = 0; + *info = -3; + ae_frame_leave(_state); + return; + } + *info = 1; + + /* + * solve + */ + for(k=0; k<=m-1; k++) + { + + /* + * copy B to contiguous storage + */ + ae_v_cmove(&bc.ptr.p_complex[0], 1, &b->ptr.pp_complex[0][k], b->stride, "N", ae_v_len(0,n-1)); + + /* + * Scale right part: + * * MX stores max(|Bi|) + * * ScaleRight stores actual scaling applied to B when solving systems + * it is chosen to make |scaleRight*b| close to 1. + */ + mxb = 0; + for(i=0; i<=n-1; i++) + { + mxb = ae_maxreal(mxb, ae_c_abs(bc.ptr.p_complex[i], _state), _state); + } + if( ae_fp_eq(mxb,0) ) + { + mxb = 1; + } + scaleright = 1/mxb; + + /* + * First, non-iterative part of solution process. + * We use separate code for this task because + * XDot is quite slow and we want to save time. + */ + ae_v_cmoved(&xc.ptr.p_complex[0], 1, &bc.ptr.p_complex[0], 1, "N", ae_v_len(0,n-1), scaleright); + densesolver_hpdbasiccholeskysolve(cha, sqrtscalea, n, isupper, &xc, &tx, _state); + + /* + * Store xc. + * Post-scale result. + */ + v = ae_sqr(sqrtscalea, _state)*mxb; + ae_v_cmoved(&x->ptr.pp_complex[0][k], x->stride, &xc.ptr.p_complex[0], 1, "N", ae_v_len(0,n-1), v); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Internal subroutine. +Returns maximum count of RFS iterations as function of: +1. machine epsilon +2. task size. +3. condition number + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +static ae_int_t densesolver_densesolverrfsmax(ae_int_t n, + double r1, + double rinf, + ae_state *_state) +{ + ae_int_t result; + + + result = 5; + return result; +} + + +/************************************************************************* +Internal subroutine. +Returns maximum count of RFS iterations as function of: +1. machine epsilon +2. task size. +3. norm-2 condition number + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +static ae_int_t densesolver_densesolverrfsmaxv2(ae_int_t n, + double r2, + ae_state *_state) +{ + ae_int_t result; + + + result = densesolver_densesolverrfsmax(n, 0, 0, _state); + return result; +} + + +/************************************************************************* +Basic LU solver for ScaleA*PLU*x = y. + +This subroutine assumes that: +* L is well-scaled, and it is U which needs scaling by ScaleA. +* A=PLU is well-conditioned, so no zero divisions or overflow may occur + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +static void densesolver_rbasiclusolve(/* Real */ ae_matrix* lua, + /* Integer */ ae_vector* p, + double scalea, + ae_int_t n, + /* Real */ ae_vector* xb, + /* Real */ ae_vector* tmp, + ae_state *_state) +{ + ae_int_t i; + double v; + + + for(i=0; i<=n-1; i++) + { + if( p->ptr.p_int[i]!=i ) + { + v = xb->ptr.p_double[i]; + xb->ptr.p_double[i] = xb->ptr.p_double[p->ptr.p_int[i]]; + xb->ptr.p_double[p->ptr.p_int[i]] = v; + } + } + for(i=1; i<=n-1; i++) + { + v = ae_v_dotproduct(&lua->ptr.pp_double[i][0], 1, &xb->ptr.p_double[0], 1, ae_v_len(0,i-1)); + xb->ptr.p_double[i] = xb->ptr.p_double[i]-v; + } + xb->ptr.p_double[n-1] = xb->ptr.p_double[n-1]/(scalea*lua->ptr.pp_double[n-1][n-1]); + for(i=n-2; i>=0; i--) + { + ae_v_moved(&tmp->ptr.p_double[i+1], 1, &lua->ptr.pp_double[i][i+1], 1, ae_v_len(i+1,n-1), scalea); + v = ae_v_dotproduct(&tmp->ptr.p_double[i+1], 1, &xb->ptr.p_double[i+1], 1, ae_v_len(i+1,n-1)); + xb->ptr.p_double[i] = (xb->ptr.p_double[i]-v)/(scalea*lua->ptr.pp_double[i][i]); + } +} + + +/************************************************************************* +Basic Cholesky solver for ScaleA*Cholesky(A)'*x = y. + +This subroutine assumes that: +* A*ScaleA is well scaled +* A is well-conditioned, so no zero divisions or overflow may occur + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +static void densesolver_spdbasiccholeskysolve(/* Real */ ae_matrix* cha, + double sqrtscalea, + ae_int_t n, + ae_bool isupper, + /* Real */ ae_vector* xb, + /* Real */ ae_vector* tmp, + ae_state *_state) +{ + ae_int_t i; + double v; + + + + /* + * A = L*L' or A=U'*U + */ + if( isupper ) + { + + /* + * Solve U'*y=b first. + */ + for(i=0; i<=n-1; i++) + { + xb->ptr.p_double[i] = xb->ptr.p_double[i]/(sqrtscalea*cha->ptr.pp_double[i][i]); + if( i<n-1 ) + { + v = xb->ptr.p_double[i]; + ae_v_moved(&tmp->ptr.p_double[i+1], 1, &cha->ptr.pp_double[i][i+1], 1, ae_v_len(i+1,n-1), sqrtscalea); + ae_v_subd(&xb->ptr.p_double[i+1], 1, &tmp->ptr.p_double[i+1], 1, ae_v_len(i+1,n-1), v); + } + } + + /* + * Solve U*x=y then. + */ + for(i=n-1; i>=0; i--) + { + if( i<n-1 ) + { + ae_v_moved(&tmp->ptr.p_double[i+1], 1, &cha->ptr.pp_double[i][i+1], 1, ae_v_len(i+1,n-1), sqrtscalea); + v = ae_v_dotproduct(&tmp->ptr.p_double[i+1], 1, &xb->ptr.p_double[i+1], 1, ae_v_len(i+1,n-1)); + xb->ptr.p_double[i] = xb->ptr.p_double[i]-v; + } + xb->ptr.p_double[i] = xb->ptr.p_double[i]/(sqrtscalea*cha->ptr.pp_double[i][i]); + } + } + else + { + + /* + * Solve L*y=b first + */ + for(i=0; i<=n-1; i++) + { + if( i>0 ) + { + ae_v_moved(&tmp->ptr.p_double[0], 1, &cha->ptr.pp_double[i][0], 1, ae_v_len(0,i-1), sqrtscalea); + v = ae_v_dotproduct(&tmp->ptr.p_double[0], 1, &xb->ptr.p_double[0], 1, ae_v_len(0,i-1)); + xb->ptr.p_double[i] = xb->ptr.p_double[i]-v; + } + xb->ptr.p_double[i] = xb->ptr.p_double[i]/(sqrtscalea*cha->ptr.pp_double[i][i]); + } + + /* + * Solve L'*x=y then. + */ + for(i=n-1; i>=0; i--) + { + xb->ptr.p_double[i] = xb->ptr.p_double[i]/(sqrtscalea*cha->ptr.pp_double[i][i]); + if( i>0 ) + { + v = xb->ptr.p_double[i]; + ae_v_moved(&tmp->ptr.p_double[0], 1, &cha->ptr.pp_double[i][0], 1, ae_v_len(0,i-1), sqrtscalea); + ae_v_subd(&xb->ptr.p_double[0], 1, &tmp->ptr.p_double[0], 1, ae_v_len(0,i-1), v); + } + } + } +} + + +/************************************************************************* +Basic LU solver for ScaleA*PLU*x = y. + +This subroutine assumes that: +* L is well-scaled, and it is U which needs scaling by ScaleA. +* A=PLU is well-conditioned, so no zero divisions or overflow may occur + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +static void densesolver_cbasiclusolve(/* Complex */ ae_matrix* lua, + /* Integer */ ae_vector* p, + double scalea, + ae_int_t n, + /* Complex */ ae_vector* xb, + /* Complex */ ae_vector* tmp, + ae_state *_state) +{ + ae_int_t i; + ae_complex v; + + + for(i=0; i<=n-1; i++) + { + if( p->ptr.p_int[i]!=i ) + { + v = xb->ptr.p_complex[i]; + xb->ptr.p_complex[i] = xb->ptr.p_complex[p->ptr.p_int[i]]; + xb->ptr.p_complex[p->ptr.p_int[i]] = v; + } + } + for(i=1; i<=n-1; i++) + { + v = ae_v_cdotproduct(&lua->ptr.pp_complex[i][0], 1, "N", &xb->ptr.p_complex[0], 1, "N", ae_v_len(0,i-1)); + xb->ptr.p_complex[i] = ae_c_sub(xb->ptr.p_complex[i],v); + } + xb->ptr.p_complex[n-1] = ae_c_div(xb->ptr.p_complex[n-1],ae_c_mul_d(lua->ptr.pp_complex[n-1][n-1],scalea)); + for(i=n-2; i>=0; i--) + { + ae_v_cmoved(&tmp->ptr.p_complex[i+1], 1, &lua->ptr.pp_complex[i][i+1], 1, "N", ae_v_len(i+1,n-1), scalea); + v = ae_v_cdotproduct(&tmp->ptr.p_complex[i+1], 1, "N", &xb->ptr.p_complex[i+1], 1, "N", ae_v_len(i+1,n-1)); + xb->ptr.p_complex[i] = ae_c_div(ae_c_sub(xb->ptr.p_complex[i],v),ae_c_mul_d(lua->ptr.pp_complex[i][i],scalea)); + } +} + + +/************************************************************************* +Basic Cholesky solver for ScaleA*Cholesky(A)'*x = y. + +This subroutine assumes that: +* A*ScaleA is well scaled +* A is well-conditioned, so no zero divisions or overflow may occur + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +static void densesolver_hpdbasiccholeskysolve(/* Complex */ ae_matrix* cha, + double sqrtscalea, + ae_int_t n, + ae_bool isupper, + /* Complex */ ae_vector* xb, + /* Complex */ ae_vector* tmp, + ae_state *_state) +{ + ae_int_t i; + ae_complex v; + + + + /* + * A = L*L' or A=U'*U + */ + if( isupper ) + { + + /* + * Solve U'*y=b first. + */ + for(i=0; i<=n-1; i++) + { + xb->ptr.p_complex[i] = ae_c_div(xb->ptr.p_complex[i],ae_c_mul_d(ae_c_conj(cha->ptr.pp_complex[i][i], _state),sqrtscalea)); + if( i<n-1 ) + { + v = xb->ptr.p_complex[i]; + ae_v_cmoved(&tmp->ptr.p_complex[i+1], 1, &cha->ptr.pp_complex[i][i+1], 1, "Conj", ae_v_len(i+1,n-1), sqrtscalea); + ae_v_csubc(&xb->ptr.p_complex[i+1], 1, &tmp->ptr.p_complex[i+1], 1, "N", ae_v_len(i+1,n-1), v); + } + } + + /* + * Solve U*x=y then. + */ + for(i=n-1; i>=0; i--) + { + if( i<n-1 ) + { + ae_v_cmoved(&tmp->ptr.p_complex[i+1], 1, &cha->ptr.pp_complex[i][i+1], 1, "N", ae_v_len(i+1,n-1), sqrtscalea); + v = ae_v_cdotproduct(&tmp->ptr.p_complex[i+1], 1, "N", &xb->ptr.p_complex[i+1], 1, "N", ae_v_len(i+1,n-1)); + xb->ptr.p_complex[i] = ae_c_sub(xb->ptr.p_complex[i],v); + } + xb->ptr.p_complex[i] = ae_c_div(xb->ptr.p_complex[i],ae_c_mul_d(cha->ptr.pp_complex[i][i],sqrtscalea)); + } + } + else + { + + /* + * Solve L*y=b first + */ + for(i=0; i<=n-1; i++) + { + if( i>0 ) + { + ae_v_cmoved(&tmp->ptr.p_complex[0], 1, &cha->ptr.pp_complex[i][0], 1, "N", ae_v_len(0,i-1), sqrtscalea); + v = ae_v_cdotproduct(&tmp->ptr.p_complex[0], 1, "N", &xb->ptr.p_complex[0], 1, "N", ae_v_len(0,i-1)); + xb->ptr.p_complex[i] = ae_c_sub(xb->ptr.p_complex[i],v); + } + xb->ptr.p_complex[i] = ae_c_div(xb->ptr.p_complex[i],ae_c_mul_d(cha->ptr.pp_complex[i][i],sqrtscalea)); + } + + /* + * Solve L'*x=y then. + */ + for(i=n-1; i>=0; i--) + { + xb->ptr.p_complex[i] = ae_c_div(xb->ptr.p_complex[i],ae_c_mul_d(ae_c_conj(cha->ptr.pp_complex[i][i], _state),sqrtscalea)); + if( i>0 ) + { + v = xb->ptr.p_complex[i]; + ae_v_cmoved(&tmp->ptr.p_complex[0], 1, &cha->ptr.pp_complex[i][0], 1, "Conj", ae_v_len(0,i-1), sqrtscalea); + ae_v_csubc(&xb->ptr.p_complex[0], 1, &tmp->ptr.p_complex[0], 1, "N", ae_v_len(0,i-1), v); + } + } + } +} + + +ae_bool _densesolverreport_init(densesolverreport* p, ae_state *_state, ae_bool make_automatic) +{ + return ae_true; +} + + +ae_bool _densesolverreport_init_copy(densesolverreport* dst, densesolverreport* src, ae_state *_state, ae_bool make_automatic) +{ + dst->r1 = src->r1; + dst->rinf = src->rinf; + return ae_true; +} + + +void _densesolverreport_clear(densesolverreport* p) +{ +} + + +ae_bool _densesolverlsreport_init(densesolverlsreport* p, ae_state *_state, ae_bool make_automatic) +{ + if( !ae_matrix_init(&p->cx, 0, 0, DT_REAL, _state, make_automatic) ) + return ae_false; + return ae_true; +} + + +ae_bool _densesolverlsreport_init_copy(densesolverlsreport* dst, densesolverlsreport* src, ae_state *_state, ae_bool make_automatic) +{ + dst->r2 = src->r2; + if( !ae_matrix_init_copy(&dst->cx, &src->cx, _state, make_automatic) ) + return ae_false; + dst->n = src->n; + dst->k = src->k; + return ae_true; +} + + +void _densesolverlsreport_clear(densesolverlsreport* p) +{ + ae_matrix_clear(&p->cx); +} + + + + +/************************************************************************* + LEVENBERG-MARQUARDT-LIKE NONLINEAR SOLVER + +DESCRIPTION: +This algorithm solves system of nonlinear equations + F[0](x[0], ..., x[n-1]) = 0 + F[1](x[0], ..., x[n-1]) = 0 + ... + F[M-1](x[0], ..., x[n-1]) = 0 +with M/N do not necessarily coincide. Algorithm converges quadratically +under following conditions: + * the solution set XS is nonempty + * for some xs in XS there exist such neighbourhood N(xs) that: + * vector function F(x) and its Jacobian J(x) are continuously + differentiable on N + * ||F(x)|| provides local error bound on N, i.e. there exists such + c1, that ||F(x)||>c1*distance(x,XS) +Note that these conditions are much more weaker than usual non-singularity +conditions. For example, algorithm will converge for any affine function +F (whether its Jacobian singular or not). + + +REQUIREMENTS: +Algorithm will request following information during its operation: +* function vector F[] and Jacobian matrix at given point X +* value of merit function f(x)=F[0]^2(x)+...+F[M-1]^2(x) at given point X + + +USAGE: +1. User initializes algorithm state with NLEQCreateLM() call +2. User tunes solver parameters with NLEQSetCond(), NLEQSetStpMax() and + other functions +3. User calls NLEQSolve() function which takes algorithm state and + pointers (delegates, etc.) to callback functions which calculate merit + function value and Jacobian. +4. User calls NLEQResults() to get solution +5. Optionally, user may call NLEQRestartFrom() to solve another problem + with same parameters (N/M) but another starting point and/or another + function vector. NLEQRestartFrom() allows to reuse already initialized + structure. + + +INPUT PARAMETERS: + N - space dimension, N>1: + * if provided, only leading N elements of X are used + * if not provided, determined automatically from size of X + M - system size + X - starting point + + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + + +NOTES: +1. you may tune stopping conditions with NLEQSetCond() function +2. if target function contains exp() or other fast growing functions, and + optimization algorithm makes too large steps which leads to overflow, + use NLEQSetStpMax() function to bound algorithm's steps. +3. this algorithm is a slightly modified implementation of the method + described in 'Levenberg-Marquardt method for constrained nonlinear + equations with strong local convergence properties' by Christian Kanzow + Nobuo Yamashita and Masao Fukushima and further developed in 'On the + convergence of a New Levenberg-Marquardt Method' by Jin-yan Fan and + Ya-Xiang Yuan. + + + -- ALGLIB -- + Copyright 20.08.2009 by Bochkanov Sergey +*************************************************************************/ +void nleqcreatelm(ae_int_t n, + ae_int_t m, + /* Real */ ae_vector* x, + nleqstate* state, + ae_state *_state) +{ + + _nleqstate_clear(state); + + ae_assert(n>=1, "NLEQCreateLM: N<1!", _state); + ae_assert(m>=1, "NLEQCreateLM: M<1!", _state); + ae_assert(x->cnt>=n, "NLEQCreateLM: Length(X)<N!", _state); + ae_assert(isfinitevector(x, n, _state), "NLEQCreateLM: X contains infinite or NaN values!", _state); + + /* + * Initialize + */ + state->n = n; + state->m = m; + nleqsetcond(state, 0, 0, _state); + nleqsetxrep(state, ae_false, _state); + nleqsetstpmax(state, 0, _state); + ae_vector_set_length(&state->x, n, _state); + ae_vector_set_length(&state->xbase, n, _state); + ae_matrix_set_length(&state->j, m, n, _state); + ae_vector_set_length(&state->fi, m, _state); + ae_vector_set_length(&state->rightpart, n, _state); + ae_vector_set_length(&state->candstep, n, _state); + nleqrestartfrom(state, x, _state); +} + + +/************************************************************************* +This function sets stopping conditions for the nonlinear solver + +INPUT PARAMETERS: + State - structure which stores algorithm state + EpsF - >=0 + The subroutine finishes its work if on k+1-th iteration + the condition ||F||<=EpsF is satisfied + MaxIts - maximum number of iterations. If MaxIts=0, the number of + iterations is unlimited. + +Passing EpsF=0 and MaxIts=0 simultaneously will lead to automatic +stopping criterion selection (small EpsF). + +NOTES: + + -- ALGLIB -- + Copyright 20.08.2010 by Bochkanov Sergey +*************************************************************************/ +void nleqsetcond(nleqstate* state, + double epsf, + ae_int_t maxits, + ae_state *_state) +{ + + + ae_assert(ae_isfinite(epsf, _state), "NLEQSetCond: EpsF is not finite number!", _state); + ae_assert(ae_fp_greater_eq(epsf,0), "NLEQSetCond: negative EpsF!", _state); + ae_assert(maxits>=0, "NLEQSetCond: negative MaxIts!", _state); + if( ae_fp_eq(epsf,0)&&maxits==0 ) + { + epsf = 1.0E-6; + } + state->epsf = epsf; + 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 NLEQSolve(). + + -- ALGLIB -- + Copyright 20.08.2010 by Bochkanov Sergey +*************************************************************************/ +void nleqsetxrep(nleqstate* 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 target function contains exp() or other fast +growing functions, and 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 20.08.2010 by Bochkanov Sergey +*************************************************************************/ +void nleqsetstpmax(nleqstate* state, double stpmax, ae_state *_state) +{ + + + ae_assert(ae_isfinite(stpmax, _state), "NLEQSetStpMax: StpMax is not finite!", _state); + ae_assert(ae_fp_greater_eq(stpmax,0), "NLEQSetStpMax: StpMax<0!", _state); + state->stpmax = stpmax; +} + + +/************************************************************************* + + -- ALGLIB -- + Copyright 20.03.2009 by Bochkanov Sergey +*************************************************************************/ +ae_bool nleqiteration(nleqstate* state, ae_state *_state) +{ + ae_int_t n; + ae_int_t m; + ae_int_t i; + double lambdaup; + double lambdadown; + double lambdav; + double rho; + double mu; + double stepnorm; + ae_bool b; + 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]; + i = state->rstate.ia.ptr.p_int[2]; + b = state->rstate.ba.ptr.p_bool[0]; + lambdaup = state->rstate.ra.ptr.p_double[0]; + lambdadown = state->rstate.ra.ptr.p_double[1]; + lambdav = state->rstate.ra.ptr.p_double[2]; + rho = state->rstate.ra.ptr.p_double[3]; + mu = state->rstate.ra.ptr.p_double[4]; + stepnorm = state->rstate.ra.ptr.p_double[5]; + } + else + { + n = -983; + m = -989; + i = -834; + b = ae_false; + lambdaup = -287; + lambdadown = 364; + lambdav = 214; + rho = -338; + mu = -686; + stepnorm = 912; + } + 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; + } + + /* + * Routine body + */ + + /* + * Prepare + */ + n = state->n; + m = state->m; + state->repterminationtype = 0; + state->repiterationscount = 0; + state->repnfunc = 0; + state->repnjac = 0; + + /* + * Calculate F/G, initialize algorithm + */ + nleq_clearrequestfields(state, _state); + state->needf = ae_true; + state->rstate.stage = 0; + goto lbl_rcomm; +lbl_0: + state->needf = ae_false; + state->repnfunc = state->repnfunc+1; + ae_v_move(&state->xbase.ptr.p_double[0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,n-1)); + state->fbase = state->f; + state->fprev = ae_maxrealnumber; + if( !state->xrep ) + { + goto lbl_5; + } + + /* + * progress report + */ + nleq_clearrequestfields(state, _state); + state->xupdated = ae_true; + state->rstate.stage = 1; + goto lbl_rcomm; +lbl_1: + state->xupdated = ae_false; +lbl_5: + if( ae_fp_less_eq(state->f,ae_sqr(state->epsf, _state)) ) + { + state->repterminationtype = 1; + result = ae_false; + return result; + } + + /* + * Main cycle + */ + lambdaup = 10; + lambdadown = 0.3; + lambdav = 0.001; + rho = 1; +lbl_7: + if( ae_false ) + { + goto lbl_8; + } + + /* + * Get Jacobian; + * before we get to this point we already have State.XBase filled + * with current point and State.FBase filled with function value + * at XBase + */ + nleq_clearrequestfields(state, _state); + state->needfij = ae_true; + ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); + state->rstate.stage = 2; + goto lbl_rcomm; +lbl_2: + state->needfij = ae_false; + state->repnfunc = state->repnfunc+1; + state->repnjac = state->repnjac+1; + rmatrixmv(n, m, &state->j, 0, 0, 1, &state->fi, 0, &state->rightpart, 0, _state); + ae_v_muld(&state->rightpart.ptr.p_double[0], 1, ae_v_len(0,n-1), -1); + + /* + * Inner cycle: find good lambda + */ +lbl_9: + if( ae_false ) + { + goto lbl_10; + } + + /* + * Solve (J^T*J + (Lambda+Mu)*I)*y = J^T*F + * to get step d=-y where: + * * Mu=||F|| - is damping parameter for nonlinear system + * * Lambda - is additional Levenberg-Marquardt parameter + * for better convergence when far away from minimum + */ + for(i=0; i<=n-1; i++) + { + state->candstep.ptr.p_double[i] = 0; + } + fblssolvecgx(&state->j, m, n, lambdav, &state->rightpart, &state->candstep, &state->cgbuf, _state); + + /* + * Normalize step (it must be no more than StpMax) + */ + stepnorm = 0; + for(i=0; i<=n-1; i++) + { + if( ae_fp_neq(state->candstep.ptr.p_double[i],0) ) + { + stepnorm = 1; + break; + } + } + linminnormalized(&state->candstep, &stepnorm, n, _state); + if( ae_fp_neq(state->stpmax,0) ) + { + stepnorm = ae_minreal(stepnorm, state->stpmax, _state); + } + + /* + * Test new step - is it good enough? + * * if not, Lambda is increased and we try again. + * * if step is good, we decrease Lambda and move on. + * + * We can break this cycle on two occasions: + * * step is so small that x+step==x (in floating point arithmetics) + * * lambda is so large + */ + 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_addd(&state->x.ptr.p_double[0], 1, &state->candstep.ptr.p_double[0], 1, ae_v_len(0,n-1), stepnorm); + b = ae_true; + for(i=0; i<=n-1; i++) + { + if( ae_fp_neq(state->x.ptr.p_double[i],state->xbase.ptr.p_double[i]) ) + { + b = ae_false; + break; + } + } + if( b ) + { + + /* + * Step is too small, force zero step and break + */ + stepnorm = 0; + 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; + goto lbl_10; + } + nleq_clearrequestfields(state, _state); + state->needf = ae_true; + state->rstate.stage = 3; + goto lbl_rcomm; +lbl_3: + state->needf = ae_false; + state->repnfunc = state->repnfunc+1; + if( ae_fp_less(state->f,state->fbase) ) + { + + /* + * function value decreased, move on + */ + nleq_decreaselambda(&lambdav, &rho, lambdadown, _state); + goto lbl_10; + } + if( !nleq_increaselambda(&lambdav, &rho, lambdaup, _state) ) + { + + /* + * Lambda is too large (near overflow), force zero step and break + */ + stepnorm = 0; + 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; + goto lbl_10; + } + goto lbl_9; +lbl_10: + + /* + * Accept step: + * * new position + * * new function value + */ + state->fbase = state->f; + ae_v_addd(&state->xbase.ptr.p_double[0], 1, &state->candstep.ptr.p_double[0], 1, ae_v_len(0,n-1), stepnorm); + state->repiterationscount = state->repiterationscount+1; + + /* + * Report new iteration + */ + if( !state->xrep ) + { + goto lbl_11; + } + nleq_clearrequestfields(state, _state); + state->xupdated = ae_true; + state->f = state->fbase; + ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); + state->rstate.stage = 4; + goto lbl_rcomm; +lbl_4: + state->xupdated = ae_false; +lbl_11: + + /* + * Test stopping conditions on F, step (zero/non-zero) and MaxIts; + * If one of the conditions is met, RepTerminationType is changed. + */ + if( ae_fp_less_eq(ae_sqrt(state->f, _state),state->epsf) ) + { + state->repterminationtype = 1; + } + if( ae_fp_eq(stepnorm,0)&&state->repterminationtype==0 ) + { + state->repterminationtype = -4; + } + if( state->repiterationscount>=state->maxits&&state->maxits>0 ) + { + state->repterminationtype = 5; + } + if( state->repterminationtype!=0 ) + { + goto lbl_8; + } + + /* + * Now, iteration is finally over + */ + goto lbl_7; +lbl_8: + 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] = i; + state->rstate.ba.ptr.p_bool[0] = b; + state->rstate.ra.ptr.p_double[0] = lambdaup; + state->rstate.ra.ptr.p_double[1] = lambdadown; + state->rstate.ra.ptr.p_double[2] = lambdav; + state->rstate.ra.ptr.p_double[3] = rho; + state->rstate.ra.ptr.p_double[4] = mu; + state->rstate.ra.ptr.p_double[5] = stepnorm; + return result; +} + + +/************************************************************************* +NLEQ solver results + +INPUT PARAMETERS: + State - algorithm state. + +OUTPUT PARAMETERS: + X - array[0..N-1], solution + Rep - optimization report: + * Rep.TerminationType completetion code: + * -4 ERROR: algorithm has converged to the + stationary point Xf which is local minimum of + f=F[0]^2+...+F[m-1]^2, but is not solution of + nonlinear system. + * 1 sqrt(f)<=EpsF. + * 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 + + -- ALGLIB -- + Copyright 20.08.2009 by Bochkanov Sergey +*************************************************************************/ +void nleqresults(nleqstate* state, + /* Real */ ae_vector* x, + nleqreport* rep, + ae_state *_state) +{ + + ae_vector_clear(x); + _nleqreport_clear(rep); + + nleqresultsbuf(state, x, rep, _state); +} + + +/************************************************************************* +NLEQ solver results + +Buffered implementation of NLEQResults(), 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.2009 by Bochkanov Sergey +*************************************************************************/ +void nleqresultsbuf(nleqstate* state, + /* Real */ ae_vector* x, + nleqreport* 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->xbase.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); + rep->iterationscount = state->repiterationscount; + rep->nfunc = state->repnfunc; + rep->njac = state->repnjac; + rep->terminationtype = state->repterminationtype; +} + + +/************************************************************************* +This subroutine restarts CG algorithm from new point. All optimization +parameters are left unchanged. + +This function allows to solve multiple optimization problems (which +must have same number of dimensions) without object reallocation penalty. + +INPUT PARAMETERS: + State - structure used for reverse communication 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 +*************************************************************************/ +void nleqrestartfrom(nleqstate* state, + /* Real */ ae_vector* x, + ae_state *_state) +{ + + + ae_assert(x->cnt>=state->n, "NLEQRestartFrom: Length(X)<N!", _state); + ae_assert(isfinitevector(x, state->n, _state), "NLEQRestartFrom: 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, 2+1, _state); + ae_vector_set_length(&state->rstate.ba, 0+1, _state); + ae_vector_set_length(&state->rstate.ra, 5+1, _state); + state->rstate.stage = -1; + nleq_clearrequestfields(state, _state); +} + + +/************************************************************************* +Clears request fileds (to be sure that we don't forgot to clear something) +*************************************************************************/ +static void nleq_clearrequestfields(nleqstate* state, ae_state *_state) +{ + + + state->needf = ae_false; + state->needfij = ae_false; + state->xupdated = ae_false; +} + + +/************************************************************************* +Increases lambda, returns False when there is a danger of overflow +*************************************************************************/ +static ae_bool nleq_increaselambda(double* lambdav, + double* nu, + double lambdaup, + 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(lambdaup, _state); + lnnu = ae_log(*nu, _state); + lnmax = 0.5*ae_log(ae_maxrealnumber, _state); + if( ae_fp_greater(lnlambda+lnlambdaup+lnnu,lnmax) ) + { + return result; + } + if( ae_fp_greater(lnnu+ae_log(2, _state),lnmax) ) + { + return result; + } + *lambdav = *lambdav*lambdaup*(*nu); + *nu = *nu*2; + result = ae_true; + return result; +} + + +/************************************************************************* +Decreases lambda, but leaves it unchanged when there is danger of underflow. +*************************************************************************/ +static void nleq_decreaselambda(double* lambdav, + double* nu, + double lambdadown, + ae_state *_state) +{ + + + *nu = 1; + if( ae_fp_less(ae_log(*lambdav, _state)+ae_log(lambdadown, _state),ae_log(ae_minrealnumber, _state)) ) + { + *lambdav = ae_minrealnumber; + } + else + { + *lambdav = *lambdav*lambdadown; + } +} + + +ae_bool _nleqstate_init(nleqstate* 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( !_rcommstate_init(&p->rstate, _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->candstep, 0, DT_REAL, _state, make_automatic) ) + return ae_false; + if( !ae_vector_init(&p->rightpart, 0, DT_REAL, _state, make_automatic) ) + return ae_false; + if( !ae_vector_init(&p->cgbuf, 0, DT_REAL, _state, make_automatic) ) + return ae_false; + return ae_true; +} + + +ae_bool _nleqstate_init_copy(nleqstate* dst, nleqstate* src, ae_state *_state, ae_bool make_automatic) +{ + dst->n = src->n; + dst->m = src->m; + dst->epsf = src->epsf; + dst->maxits = src->maxits; + dst->xrep = src->xrep; + dst->stpmax = src->stpmax; + 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; + dst->needf = src->needf; + dst->needfij = src->needfij; + dst->xupdated = src->xupdated; + if( !_rcommstate_init_copy(&dst->rstate, &src->rstate, _state, make_automatic) ) + return ae_false; + dst->repiterationscount = src->repiterationscount; + dst->repnfunc = src->repnfunc; + dst->repnjac = src->repnjac; + dst->repterminationtype = src->repterminationtype; + if( !ae_vector_init_copy(&dst->xbase, &src->xbase, _state, make_automatic) ) + return ae_false; + dst->fbase = src->fbase; + dst->fprev = src->fprev; + if( !ae_vector_init_copy(&dst->candstep, &src->candstep, _state, make_automatic) ) + return ae_false; + if( !ae_vector_init_copy(&dst->rightpart, &src->rightpart, _state, make_automatic) ) + return ae_false; + if( !ae_vector_init_copy(&dst->cgbuf, &src->cgbuf, _state, make_automatic) ) + return ae_false; + return ae_true; +} + + +void _nleqstate_clear(nleqstate* p) +{ + ae_vector_clear(&p->x); + ae_vector_clear(&p->fi); + ae_matrix_clear(&p->j); + _rcommstate_clear(&p->rstate); + ae_vector_clear(&p->xbase); + ae_vector_clear(&p->candstep); + ae_vector_clear(&p->rightpart); + ae_vector_clear(&p->cgbuf); +} + + +ae_bool _nleqreport_init(nleqreport* p, ae_state *_state, ae_bool make_automatic) +{ + return ae_true; +} + + +ae_bool _nleqreport_init_copy(nleqreport* dst, nleqreport* src, ae_state *_state, ae_bool make_automatic) +{ + dst->iterationscount = src->iterationscount; + dst->nfunc = src->nfunc; + dst->njac = src->njac; + dst->terminationtype = src->terminationtype; + return ae_true; +} + + +void _nleqreport_clear(nleqreport* p) +{ +} + + + +} + diff --git a/contrib/lbfgs/solvers.h b/contrib/lbfgs/solvers.h new file mode 100755 index 0000000000000000000000000000000000000000..2f7e1b5ae6f01b82158c67ec89a026cfb5700788 --- /dev/null +++ b/contrib/lbfgs/solvers.h @@ -0,0 +1,1353 @@ +/************************************************************************* +Copyright (c) Sergey Bochkanov (ALGLIB project). + +>>> SOURCE LICENSE >>> +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation (www.fsf.org); either version 2 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +A copy of the GNU General Public License is available at +http://www.fsf.org/licensing/licenses +>>> END OF LICENSE >>> +*************************************************************************/ +#ifndef _solvers_pkg_h +#define _solvers_pkg_h +#include "ap.h" +#include "alglibinternal.h" +#include "linalg.h" +#include "alglibmisc.h" + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (DATATYPES) +// +///////////////////////////////////////////////////////////////////////// +namespace alglib_impl +{ +typedef struct +{ + double r1; + double rinf; +} densesolverreport; +typedef struct +{ + double r2; + ae_matrix cx; + ae_int_t n; + ae_int_t k; +} densesolverlsreport; +typedef struct +{ + ae_int_t n; + ae_int_t m; + double epsf; + ae_int_t maxits; + ae_bool xrep; + double stpmax; + ae_vector x; + double f; + ae_vector fi; + ae_matrix j; + ae_bool needf; + ae_bool needfij; + ae_bool xupdated; + rcommstate rstate; + ae_int_t repiterationscount; + ae_int_t repnfunc; + ae_int_t repnjac; + ae_int_t repterminationtype; + ae_vector xbase; + double fbase; + double fprev; + ae_vector candstep; + ae_vector rightpart; + ae_vector cgbuf; +} nleqstate; +typedef struct +{ + ae_int_t iterationscount; + ae_int_t nfunc; + ae_int_t njac; + ae_int_t terminationtype; +} nleqreport; + +} + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS C++ INTERFACE +// +///////////////////////////////////////////////////////////////////////// +namespace alglib +{ + +/************************************************************************* + +*************************************************************************/ +class _densesolverreport_owner +{ +public: + _densesolverreport_owner(); + _densesolverreport_owner(const _densesolverreport_owner &rhs); + _densesolverreport_owner& operator=(const _densesolverreport_owner &rhs); + virtual ~_densesolverreport_owner(); + alglib_impl::densesolverreport* c_ptr(); + alglib_impl::densesolverreport* c_ptr() const; +protected: + alglib_impl::densesolverreport *p_struct; +}; +class densesolverreport : public _densesolverreport_owner +{ +public: + densesolverreport(); + densesolverreport(const densesolverreport &rhs); + densesolverreport& operator=(const densesolverreport &rhs); + virtual ~densesolverreport(); + double &r1; + double &rinf; + +}; + + +/************************************************************************* + +*************************************************************************/ +class _densesolverlsreport_owner +{ +public: + _densesolverlsreport_owner(); + _densesolverlsreport_owner(const _densesolverlsreport_owner &rhs); + _densesolverlsreport_owner& operator=(const _densesolverlsreport_owner &rhs); + virtual ~_densesolverlsreport_owner(); + alglib_impl::densesolverlsreport* c_ptr(); + alglib_impl::densesolverlsreport* c_ptr() const; +protected: + alglib_impl::densesolverlsreport *p_struct; +}; +class densesolverlsreport : public _densesolverlsreport_owner +{ +public: + densesolverlsreport(); + densesolverlsreport(const densesolverlsreport &rhs); + densesolverlsreport& operator=(const densesolverlsreport &rhs); + virtual ~densesolverlsreport(); + double &r2; + real_2d_array cx; + ae_int_t &n; + ae_int_t &k; + +}; + +/************************************************************************* + +*************************************************************************/ +class _nleqstate_owner +{ +public: + _nleqstate_owner(); + _nleqstate_owner(const _nleqstate_owner &rhs); + _nleqstate_owner& operator=(const _nleqstate_owner &rhs); + virtual ~_nleqstate_owner(); + alglib_impl::nleqstate* c_ptr(); + alglib_impl::nleqstate* c_ptr() const; +protected: + alglib_impl::nleqstate *p_struct; +}; +class nleqstate : public _nleqstate_owner +{ +public: + nleqstate(); + nleqstate(const nleqstate &rhs); + nleqstate& operator=(const nleqstate &rhs); + virtual ~nleqstate(); + ae_bool &needf; + ae_bool &needfij; + ae_bool &xupdated; + double &f; + real_1d_array fi; + real_2d_array j; + real_1d_array x; + +}; + + +/************************************************************************* + +*************************************************************************/ +class _nleqreport_owner +{ +public: + _nleqreport_owner(); + _nleqreport_owner(const _nleqreport_owner &rhs); + _nleqreport_owner& operator=(const _nleqreport_owner &rhs); + virtual ~_nleqreport_owner(); + alglib_impl::nleqreport* c_ptr(); + alglib_impl::nleqreport* c_ptr() const; +protected: + alglib_impl::nleqreport *p_struct; +}; +class nleqreport : public _nleqreport_owner +{ +public: + nleqreport(); + nleqreport(const nleqreport &rhs); + nleqreport& operator=(const nleqreport &rhs); + virtual ~nleqreport(); + ae_int_t &iterationscount; + ae_int_t &nfunc; + ae_int_t &njac; + ae_int_t &terminationtype; + +}; + +/************************************************************************* +Dense solver. + +This subroutine solves a system A*x=b, where A is NxN non-denegerate +real matrix, x and b are vectors. + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* iterative refinement +* O(N^3) complexity + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + B - array[0..N-1], right part + +OUTPUT PARAMETERS + Info - return code: + * -3 A is singular, or VERY close to singular. + X is filled by zeros in such cases. + * -1 N<=0 was passed + * 1 task is solved (but matrix A may be ill-conditioned, + check R1/RInf parameters for condition numbers). + Rep - solver report, see below for more info + X - array[0..N-1], it contains: + * solution of A*x=b if A is non-singular (well-conditioned + or ill-conditioned, but not very close to singular) + * zeros, if A is singular or VERY close to singular + (in this case Info=-3). + +SOLVER REPORT + +Subroutine sets following fields of the Rep structure: +* R1 reciprocal of condition number: 1/cond(A), 1-norm. +* RInf reciprocal of condition number: 1/cond(A), inf-norm. + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void rmatrixsolve(const real_2d_array &a, const ae_int_t n, const real_1d_array &b, ae_int_t &info, densesolverreport &rep, real_1d_array &x); + + +/************************************************************************* +Dense solver. + +Similar to RMatrixSolve() but solves task with multiple right parts (where +b and x are NxM matrices). + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* optional iterative refinement +* O(N^3+M*N^2) complexity + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + B - array[0..N-1,0..M-1], right part + M - right part size + RFS - iterative refinement switch: + * True - refinement is used. + Less performance, more precision. + * False - refinement is not used. + More performance, less precision. + +OUTPUT PARAMETERS + Info - same as in RMatrixSolve + Rep - same as in RMatrixSolve + X - same as in RMatrixSolve + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void rmatrixsolvem(const real_2d_array &a, const ae_int_t n, const real_2d_array &b, const ae_int_t m, const bool rfs, ae_int_t &info, densesolverreport &rep, real_2d_array &x); + + +/************************************************************************* +Dense solver. + +This subroutine solves a system A*X=B, where A is NxN non-denegerate +real matrix given by its LU decomposition, X and B are NxM real matrices. + +Algorithm features: +* automatic detection of degenerate cases +* O(N^2) complexity +* condition number estimation + +No iterative refinement is provided because exact form of original matrix +is not known to subroutine. Use RMatrixSolve or RMatrixMixedSolve if you +need iterative refinement. + +INPUT PARAMETERS + LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result + P - array[0..N-1], pivots array, RMatrixLU result + N - size of A + B - array[0..N-1], right part + +OUTPUT PARAMETERS + Info - same as in RMatrixSolve + Rep - same as in RMatrixSolve + X - same as in RMatrixSolve + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void rmatrixlusolve(const real_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const real_1d_array &b, ae_int_t &info, densesolverreport &rep, real_1d_array &x); + + +/************************************************************************* +Dense solver. + +Similar to RMatrixLUSolve() but solves task with multiple right parts +(where b and x are NxM matrices). + +Algorithm features: +* automatic detection of degenerate cases +* O(M*N^2) complexity +* condition number estimation + +No iterative refinement is provided because exact form of original matrix +is not known to subroutine. Use RMatrixSolve or RMatrixMixedSolve if you +need iterative refinement. + +INPUT PARAMETERS + LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result + P - array[0..N-1], pivots array, RMatrixLU result + N - size of A + B - array[0..N-1,0..M-1], right part + M - right part size + +OUTPUT PARAMETERS + Info - same as in RMatrixSolve + Rep - same as in RMatrixSolve + X - same as in RMatrixSolve + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void rmatrixlusolvem(const real_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const real_2d_array &b, const ae_int_t m, ae_int_t &info, densesolverreport &rep, real_2d_array &x); + + +/************************************************************************* +Dense solver. + +This subroutine solves a system A*x=b, where BOTH ORIGINAL A AND ITS +LU DECOMPOSITION ARE KNOWN. You can use it if for some reasons you have +both A and its LU decomposition. + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* iterative refinement +* O(N^2) complexity + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result + P - array[0..N-1], pivots array, RMatrixLU result + N - size of A + B - array[0..N-1], right part + +OUTPUT PARAMETERS + Info - same as in RMatrixSolveM + Rep - same as in RMatrixSolveM + X - same as in RMatrixSolveM + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void rmatrixmixedsolve(const real_2d_array &a, const real_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const real_1d_array &b, ae_int_t &info, densesolverreport &rep, real_1d_array &x); + + +/************************************************************************* +Dense solver. + +Similar to RMatrixMixedSolve() but solves task with multiple right parts +(where b and x are NxM matrices). + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* iterative refinement +* O(M*N^2) complexity + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result + P - array[0..N-1], pivots array, RMatrixLU result + N - size of A + B - array[0..N-1,0..M-1], right part + M - right part size + +OUTPUT PARAMETERS + Info - same as in RMatrixSolveM + Rep - same as in RMatrixSolveM + X - same as in RMatrixSolveM + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void rmatrixmixedsolvem(const real_2d_array &a, const real_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const real_2d_array &b, const ae_int_t m, ae_int_t &info, densesolverreport &rep, real_2d_array &x); + + +/************************************************************************* +Dense solver. Same as RMatrixSolveM(), but for complex matrices. + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* iterative refinement +* O(N^3+M*N^2) complexity + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + B - array[0..N-1,0..M-1], right part + M - right part size + RFS - iterative refinement switch: + * True - refinement is used. + Less performance, more precision. + * False - refinement is not used. + More performance, less precision. + +OUTPUT PARAMETERS + Info - same as in RMatrixSolve + Rep - same as in RMatrixSolve + X - same as in RMatrixSolve + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void cmatrixsolvem(const complex_2d_array &a, const ae_int_t n, const complex_2d_array &b, const ae_int_t m, const bool rfs, ae_int_t &info, densesolverreport &rep, complex_2d_array &x); + + +/************************************************************************* +Dense solver. Same as RMatrixSolve(), but for complex matrices. + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* iterative refinement +* O(N^3) complexity + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + B - array[0..N-1], right part + +OUTPUT PARAMETERS + Info - same as in RMatrixSolve + Rep - same as in RMatrixSolve + X - same as in RMatrixSolve + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void cmatrixsolve(const complex_2d_array &a, const ae_int_t n, const complex_1d_array &b, ae_int_t &info, densesolverreport &rep, complex_1d_array &x); + + +/************************************************************************* +Dense solver. Same as RMatrixLUSolveM(), but for complex matrices. + +Algorithm features: +* automatic detection of degenerate cases +* O(M*N^2) complexity +* condition number estimation + +No iterative refinement is provided because exact form of original matrix +is not known to subroutine. Use CMatrixSolve or CMatrixMixedSolve if you +need iterative refinement. + +INPUT PARAMETERS + LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result + P - array[0..N-1], pivots array, RMatrixLU result + N - size of A + B - array[0..N-1,0..M-1], right part + M - right part size + +OUTPUT PARAMETERS + Info - same as in RMatrixSolve + Rep - same as in RMatrixSolve + X - same as in RMatrixSolve + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void cmatrixlusolvem(const complex_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const complex_2d_array &b, const ae_int_t m, ae_int_t &info, densesolverreport &rep, complex_2d_array &x); + + +/************************************************************************* +Dense solver. Same as RMatrixLUSolve(), but for complex matrices. + +Algorithm features: +* automatic detection of degenerate cases +* O(N^2) complexity +* condition number estimation + +No iterative refinement is provided because exact form of original matrix +is not known to subroutine. Use CMatrixSolve or CMatrixMixedSolve if you +need iterative refinement. + +INPUT PARAMETERS + LUA - array[0..N-1,0..N-1], LU decomposition, CMatrixLU result + P - array[0..N-1], pivots array, CMatrixLU result + N - size of A + B - array[0..N-1], right part + +OUTPUT PARAMETERS + Info - same as in RMatrixSolve + Rep - same as in RMatrixSolve + X - same as in RMatrixSolve + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void cmatrixlusolve(const complex_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const complex_1d_array &b, ae_int_t &info, densesolverreport &rep, complex_1d_array &x); + + +/************************************************************************* +Dense solver. Same as RMatrixMixedSolveM(), but for complex matrices. + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* iterative refinement +* O(M*N^2) complexity + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + LUA - array[0..N-1,0..N-1], LU decomposition, CMatrixLU result + P - array[0..N-1], pivots array, CMatrixLU result + N - size of A + B - array[0..N-1,0..M-1], right part + M - right part size + +OUTPUT PARAMETERS + Info - same as in RMatrixSolveM + Rep - same as in RMatrixSolveM + X - same as in RMatrixSolveM + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void cmatrixmixedsolvem(const complex_2d_array &a, const complex_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const complex_2d_array &b, const ae_int_t m, ae_int_t &info, densesolverreport &rep, complex_2d_array &x); + + +/************************************************************************* +Dense solver. Same as RMatrixMixedSolve(), but for complex matrices. + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* iterative refinement +* O(N^2) complexity + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + LUA - array[0..N-1,0..N-1], LU decomposition, CMatrixLU result + P - array[0..N-1], pivots array, CMatrixLU result + N - size of A + B - array[0..N-1], right part + +OUTPUT PARAMETERS + Info - same as in RMatrixSolveM + Rep - same as in RMatrixSolveM + X - same as in RMatrixSolveM + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void cmatrixmixedsolve(const complex_2d_array &a, const complex_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const complex_1d_array &b, ae_int_t &info, densesolverreport &rep, complex_1d_array &x); + + +/************************************************************************* +Dense solver. Same as RMatrixSolveM(), but for symmetric positive definite +matrices. + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* O(N^3+M*N^2) complexity +* matrix is represented by its upper or lower triangle + +No iterative refinement is provided because such partial representation of +matrix does not allow efficient calculation of extra-precise matrix-vector +products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you +need iterative refinement. + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + IsUpper - what half of A is provided + B - array[0..N-1,0..M-1], right part + M - right part size + +OUTPUT PARAMETERS + Info - same as in RMatrixSolve. + Returns -3 for non-SPD matrices. + Rep - same as in RMatrixSolve + X - same as in RMatrixSolve + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void spdmatrixsolvem(const real_2d_array &a, const ae_int_t n, const bool isupper, const real_2d_array &b, const ae_int_t m, ae_int_t &info, densesolverreport &rep, real_2d_array &x); + + +/************************************************************************* +Dense solver. Same as RMatrixSolve(), but for SPD matrices. + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* O(N^3) complexity +* matrix is represented by its upper or lower triangle + +No iterative refinement is provided because such partial representation of +matrix does not allow efficient calculation of extra-precise matrix-vector +products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you +need iterative refinement. + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + IsUpper - what half of A is provided + B - array[0..N-1], right part + +OUTPUT PARAMETERS + Info - same as in RMatrixSolve + Returns -3 for non-SPD matrices. + Rep - same as in RMatrixSolve + X - same as in RMatrixSolve + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void spdmatrixsolve(const real_2d_array &a, const ae_int_t n, const bool isupper, const real_1d_array &b, ae_int_t &info, densesolverreport &rep, real_1d_array &x); + + +/************************************************************************* +Dense solver. Same as RMatrixLUSolveM(), but for SPD matrices represented +by their Cholesky decomposition. + +Algorithm features: +* automatic detection of degenerate cases +* O(M*N^2) complexity +* condition number estimation +* matrix is represented by its upper or lower triangle + +No iterative refinement is provided because such partial representation of +matrix does not allow efficient calculation of extra-precise matrix-vector +products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you +need iterative refinement. + +INPUT PARAMETERS + CHA - array[0..N-1,0..N-1], Cholesky decomposition, + SPDMatrixCholesky result + N - size of CHA + IsUpper - what half of CHA is provided + B - array[0..N-1,0..M-1], right part + M - right part size + +OUTPUT PARAMETERS + Info - same as in RMatrixSolve + Rep - same as in RMatrixSolve + X - same as in RMatrixSolve + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void spdmatrixcholeskysolvem(const real_2d_array &cha, const ae_int_t n, const bool isupper, const real_2d_array &b, const ae_int_t m, ae_int_t &info, densesolverreport &rep, real_2d_array &x); + + +/************************************************************************* +Dense solver. Same as RMatrixLUSolve(), but for SPD matrices represented +by their Cholesky decomposition. + +Algorithm features: +* automatic detection of degenerate cases +* O(N^2) complexity +* condition number estimation +* matrix is represented by its upper or lower triangle + +No iterative refinement is provided because such partial representation of +matrix does not allow efficient calculation of extra-precise matrix-vector +products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you +need iterative refinement. + +INPUT PARAMETERS + CHA - array[0..N-1,0..N-1], Cholesky decomposition, + SPDMatrixCholesky result + N - size of A + IsUpper - what half of CHA is provided + B - array[0..N-1], right part + +OUTPUT PARAMETERS + Info - same as in RMatrixSolve + Rep - same as in RMatrixSolve + X - same as in RMatrixSolve + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void spdmatrixcholeskysolve(const real_2d_array &cha, const ae_int_t n, const bool isupper, const real_1d_array &b, ae_int_t &info, densesolverreport &rep, real_1d_array &x); + + +/************************************************************************* +Dense solver. Same as RMatrixSolveM(), but for Hermitian positive definite +matrices. + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* O(N^3+M*N^2) complexity +* matrix is represented by its upper or lower triangle + +No iterative refinement is provided because such partial representation of +matrix does not allow efficient calculation of extra-precise matrix-vector +products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you +need iterative refinement. + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + IsUpper - what half of A is provided + B - array[0..N-1,0..M-1], right part + M - right part size + +OUTPUT PARAMETERS + Info - same as in RMatrixSolve. + Returns -3 for non-HPD matrices. + Rep - same as in RMatrixSolve + X - same as in RMatrixSolve + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void hpdmatrixsolvem(const complex_2d_array &a, const ae_int_t n, const bool isupper, const complex_2d_array &b, const ae_int_t m, ae_int_t &info, densesolverreport &rep, complex_2d_array &x); + + +/************************************************************************* +Dense solver. Same as RMatrixSolve(), but for Hermitian positive definite +matrices. + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* O(N^3) complexity +* matrix is represented by its upper or lower triangle + +No iterative refinement is provided because such partial representation of +matrix does not allow efficient calculation of extra-precise matrix-vector +products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you +need iterative refinement. + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + IsUpper - what half of A is provided + B - array[0..N-1], right part + +OUTPUT PARAMETERS + Info - same as in RMatrixSolve + Returns -3 for non-HPD matrices. + Rep - same as in RMatrixSolve + X - same as in RMatrixSolve + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void hpdmatrixsolve(const complex_2d_array &a, const ae_int_t n, const bool isupper, const complex_1d_array &b, ae_int_t &info, densesolverreport &rep, complex_1d_array &x); + + +/************************************************************************* +Dense solver. Same as RMatrixLUSolveM(), but for HPD matrices represented +by their Cholesky decomposition. + +Algorithm features: +* automatic detection of degenerate cases +* O(M*N^2) complexity +* condition number estimation +* matrix is represented by its upper or lower triangle + +No iterative refinement is provided because such partial representation of +matrix does not allow efficient calculation of extra-precise matrix-vector +products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you +need iterative refinement. + +INPUT PARAMETERS + CHA - array[0..N-1,0..N-1], Cholesky decomposition, + HPDMatrixCholesky result + N - size of CHA + IsUpper - what half of CHA is provided + B - array[0..N-1,0..M-1], right part + M - right part size + +OUTPUT PARAMETERS + Info - same as in RMatrixSolve + Rep - same as in RMatrixSolve + X - same as in RMatrixSolve + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void hpdmatrixcholeskysolvem(const complex_2d_array &cha, const ae_int_t n, const bool isupper, const complex_2d_array &b, const ae_int_t m, ae_int_t &info, densesolverreport &rep, complex_2d_array &x); + + +/************************************************************************* +Dense solver. Same as RMatrixLUSolve(), but for HPD matrices represented +by their Cholesky decomposition. + +Algorithm features: +* automatic detection of degenerate cases +* O(N^2) complexity +* condition number estimation +* matrix is represented by its upper or lower triangle + +No iterative refinement is provided because such partial representation of +matrix does not allow efficient calculation of extra-precise matrix-vector +products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you +need iterative refinement. + +INPUT PARAMETERS + CHA - array[0..N-1,0..N-1], Cholesky decomposition, + SPDMatrixCholesky result + N - size of A + IsUpper - what half of CHA is provided + B - array[0..N-1], right part + +OUTPUT PARAMETERS + Info - same as in RMatrixSolve + Rep - same as in RMatrixSolve + X - same as in RMatrixSolve + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void hpdmatrixcholeskysolve(const complex_2d_array &cha, const ae_int_t n, const bool isupper, const complex_1d_array &b, ae_int_t &info, densesolverreport &rep, complex_1d_array &x); + + +/************************************************************************* +Dense solver. + +This subroutine finds solution of the linear system A*X=B with non-square, +possibly degenerate A. System is solved in the least squares sense, and +general least squares solution X = X0 + CX*y which minimizes |A*X-B| is +returned. If A is non-degenerate, solution in the usual sense is returned + +Algorithm features: +* automatic detection of degenerate cases +* iterative refinement +* O(N^3) complexity + +INPUT PARAMETERS + A - array[0..NRows-1,0..NCols-1], system matrix + NRows - vertical size of A + NCols - horizontal size of A + B - array[0..NCols-1], right part + Threshold- a number in [0,1]. Singular values beyond Threshold are + considered zero. Set it to 0.0, if you don't understand + what it means, so the solver will choose good value on its + own. + +OUTPUT PARAMETERS + Info - return code: + * -4 SVD subroutine failed + * -1 if NRows<=0 or NCols<=0 or Threshold<0 was passed + * 1 if task is solved + Rep - solver report, see below for more info + X - array[0..N-1,0..M-1], it contains: + * solution of A*X=B if A is non-singular (well-conditioned + or ill-conditioned, but not very close to singular) + * zeros, if A is singular or VERY close to singular + (in this case Info=-3). + +SOLVER REPORT + +Subroutine sets following fields of the Rep structure: +* R2 reciprocal of condition number: 1/cond(A), 2-norm. +* N = NCols +* K dim(Null(A)) +* CX array[0..N-1,0..K-1], kernel of A. + Columns of CX store such vectors that A*CX[i]=0. + + -- ALGLIB -- + Copyright 24.08.2009 by Bochkanov Sergey +*************************************************************************/ +void rmatrixsolvels(const real_2d_array &a, const ae_int_t nrows, const ae_int_t ncols, const real_1d_array &b, const double threshold, ae_int_t &info, densesolverlsreport &rep, real_1d_array &x); + +/************************************************************************* + LEVENBERG-MARQUARDT-LIKE NONLINEAR SOLVER + +DESCRIPTION: +This algorithm solves system of nonlinear equations + F[0](x[0], ..., x[n-1]) = 0 + F[1](x[0], ..., x[n-1]) = 0 + ... + F[M-1](x[0], ..., x[n-1]) = 0 +with M/N do not necessarily coincide. Algorithm converges quadratically +under following conditions: + * the solution set XS is nonempty + * for some xs in XS there exist such neighbourhood N(xs) that: + * vector function F(x) and its Jacobian J(x) are continuously + differentiable on N + * ||F(x)|| provides local error bound on N, i.e. there exists such + c1, that ||F(x)||>c1*distance(x,XS) +Note that these conditions are much more weaker than usual non-singularity +conditions. For example, algorithm will converge for any affine function +F (whether its Jacobian singular or not). + + +REQUIREMENTS: +Algorithm will request following information during its operation: +* function vector F[] and Jacobian matrix at given point X +* value of merit function f(x)=F[0]^2(x)+...+F[M-1]^2(x) at given point X + + +USAGE: +1. User initializes algorithm state with NLEQCreateLM() call +2. User tunes solver parameters with NLEQSetCond(), NLEQSetStpMax() and + other functions +3. User calls NLEQSolve() function which takes algorithm state and + pointers (delegates, etc.) to callback functions which calculate merit + function value and Jacobian. +4. User calls NLEQResults() to get solution +5. Optionally, user may call NLEQRestartFrom() to solve another problem + with same parameters (N/M) but another starting point and/or another + function vector. NLEQRestartFrom() allows to reuse already initialized + structure. + + +INPUT PARAMETERS: + N - space dimension, N>1: + * if provided, only leading N elements of X are used + * if not provided, determined automatically from size of X + M - system size + X - starting point + + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + + +NOTES: +1. you may tune stopping conditions with NLEQSetCond() function +2. if target function contains exp() or other fast growing functions, and + optimization algorithm makes too large steps which leads to overflow, + use NLEQSetStpMax() function to bound algorithm's steps. +3. this algorithm is a slightly modified implementation of the method + described in 'Levenberg-Marquardt method for constrained nonlinear + equations with strong local convergence properties' by Christian Kanzow + Nobuo Yamashita and Masao Fukushima and further developed in 'On the + convergence of a New Levenberg-Marquardt Method' by Jin-yan Fan and + Ya-Xiang Yuan. + + + -- ALGLIB -- + Copyright 20.08.2009 by Bochkanov Sergey +*************************************************************************/ +void nleqcreatelm(const ae_int_t n, const ae_int_t m, const real_1d_array &x, nleqstate &state); +void nleqcreatelm(const ae_int_t m, const real_1d_array &x, nleqstate &state); + + +/************************************************************************* +This function sets stopping conditions for the nonlinear solver + +INPUT PARAMETERS: + State - structure which stores algorithm state + EpsF - >=0 + The subroutine finishes its work if on k+1-th iteration + the condition ||F||<=EpsF is satisfied + MaxIts - maximum number of iterations. If MaxIts=0, the number of + iterations is unlimited. + +Passing EpsF=0 and MaxIts=0 simultaneously will lead to automatic +stopping criterion selection (small EpsF). + +NOTES: + + -- ALGLIB -- + Copyright 20.08.2010 by Bochkanov Sergey +*************************************************************************/ +void nleqsetcond(const nleqstate &state, const double epsf, 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 NLEQSolve(). + + -- ALGLIB -- + Copyright 20.08.2010 by Bochkanov Sergey +*************************************************************************/ +void nleqsetxrep(const nleqstate &state, const bool 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 target function contains exp() or other fast +growing functions, and 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 20.08.2010 by Bochkanov Sergey +*************************************************************************/ +void nleqsetstpmax(const nleqstate &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 nleqiteration(const nleqstate &state); + + +/************************************************************************* +This family of functions is used to launcn iterations of nonlinear solver + +These functions accept following parameters: + state - algorithm state + func - callback which calculates function (or merit function) + value func 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 + + + -- ALGLIB -- + Copyright 20.03.2009 by Bochkanov Sergey + +*************************************************************************/ +void nleqsolve(nleqstate &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); + + +/************************************************************************* +NLEQ solver results + +INPUT PARAMETERS: + State - algorithm state. + +OUTPUT PARAMETERS: + X - array[0..N-1], solution + Rep - optimization report: + * Rep.TerminationType completetion code: + * -4 ERROR: algorithm has converged to the + stationary point Xf which is local minimum of + f=F[0]^2+...+F[m-1]^2, but is not solution of + nonlinear system. + * 1 sqrt(f)<=EpsF. + * 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 + + -- ALGLIB -- + Copyright 20.08.2009 by Bochkanov Sergey +*************************************************************************/ +void nleqresults(const nleqstate &state, real_1d_array &x, nleqreport &rep); + + +/************************************************************************* +NLEQ solver results + +Buffered implementation of NLEQResults(), 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.2009 by Bochkanov Sergey +*************************************************************************/ +void nleqresultsbuf(const nleqstate &state, real_1d_array &x, nleqreport &rep); + + +/************************************************************************* +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 MinCGCreate call. + X - new starting point. + BndL - new lower bounds + BndU - new upper bounds + + -- ALGLIB -- + Copyright 30.07.2010 by Bochkanov Sergey +*************************************************************************/ +void nleqrestartfrom(const nleqstate &state, const real_1d_array &x); +} + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (FUNCTIONS) +// +///////////////////////////////////////////////////////////////////////// +namespace alglib_impl +{ +void rmatrixsolve(/* Real */ ae_matrix* a, + ae_int_t n, + /* Real */ ae_vector* b, + ae_int_t* info, + densesolverreport* rep, + /* Real */ ae_vector* x, + ae_state *_state); +void rmatrixsolvem(/* Real */ ae_matrix* a, + ae_int_t n, + /* Real */ ae_matrix* b, + ae_int_t m, + ae_bool rfs, + ae_int_t* info, + densesolverreport* rep, + /* Real */ ae_matrix* x, + ae_state *_state); +void rmatrixlusolve(/* Real */ ae_matrix* lua, + /* Integer */ ae_vector* p, + ae_int_t n, + /* Real */ ae_vector* b, + ae_int_t* info, + densesolverreport* rep, + /* Real */ ae_vector* x, + ae_state *_state); +void rmatrixlusolvem(/* Real */ ae_matrix* lua, + /* Integer */ ae_vector* p, + ae_int_t n, + /* Real */ ae_matrix* b, + ae_int_t m, + ae_int_t* info, + densesolverreport* rep, + /* Real */ ae_matrix* x, + ae_state *_state); +void rmatrixmixedsolve(/* Real */ ae_matrix* a, + /* Real */ ae_matrix* lua, + /* Integer */ ae_vector* p, + ae_int_t n, + /* Real */ ae_vector* b, + ae_int_t* info, + densesolverreport* rep, + /* Real */ ae_vector* x, + ae_state *_state); +void rmatrixmixedsolvem(/* Real */ ae_matrix* a, + /* Real */ ae_matrix* lua, + /* Integer */ ae_vector* p, + ae_int_t n, + /* Real */ ae_matrix* b, + ae_int_t m, + ae_int_t* info, + densesolverreport* rep, + /* Real */ ae_matrix* x, + ae_state *_state); +void cmatrixsolvem(/* Complex */ ae_matrix* a, + ae_int_t n, + /* Complex */ ae_matrix* b, + ae_int_t m, + ae_bool rfs, + ae_int_t* info, + densesolverreport* rep, + /* Complex */ ae_matrix* x, + ae_state *_state); +void cmatrixsolve(/* Complex */ ae_matrix* a, + ae_int_t n, + /* Complex */ ae_vector* b, + ae_int_t* info, + densesolverreport* rep, + /* Complex */ ae_vector* x, + ae_state *_state); +void cmatrixlusolvem(/* Complex */ ae_matrix* lua, + /* Integer */ ae_vector* p, + ae_int_t n, + /* Complex */ ae_matrix* b, + ae_int_t m, + ae_int_t* info, + densesolverreport* rep, + /* Complex */ ae_matrix* x, + ae_state *_state); +void cmatrixlusolve(/* Complex */ ae_matrix* lua, + /* Integer */ ae_vector* p, + ae_int_t n, + /* Complex */ ae_vector* b, + ae_int_t* info, + densesolverreport* rep, + /* Complex */ ae_vector* x, + ae_state *_state); +void cmatrixmixedsolvem(/* Complex */ ae_matrix* a, + /* Complex */ ae_matrix* lua, + /* Integer */ ae_vector* p, + ae_int_t n, + /* Complex */ ae_matrix* b, + ae_int_t m, + ae_int_t* info, + densesolverreport* rep, + /* Complex */ ae_matrix* x, + ae_state *_state); +void cmatrixmixedsolve(/* Complex */ ae_matrix* a, + /* Complex */ ae_matrix* lua, + /* Integer */ ae_vector* p, + ae_int_t n, + /* Complex */ ae_vector* b, + ae_int_t* info, + densesolverreport* rep, + /* Complex */ ae_vector* x, + ae_state *_state); +void spdmatrixsolvem(/* Real */ ae_matrix* a, + ae_int_t n, + ae_bool isupper, + /* Real */ ae_matrix* b, + ae_int_t m, + ae_int_t* info, + densesolverreport* rep, + /* Real */ ae_matrix* x, + ae_state *_state); +void spdmatrixsolve(/* Real */ ae_matrix* a, + ae_int_t n, + ae_bool isupper, + /* Real */ ae_vector* b, + ae_int_t* info, + densesolverreport* rep, + /* Real */ ae_vector* x, + ae_state *_state); +void spdmatrixcholeskysolvem(/* Real */ ae_matrix* cha, + ae_int_t n, + ae_bool isupper, + /* Real */ ae_matrix* b, + ae_int_t m, + ae_int_t* info, + densesolverreport* rep, + /* Real */ ae_matrix* x, + ae_state *_state); +void spdmatrixcholeskysolve(/* Real */ ae_matrix* cha, + ae_int_t n, + ae_bool isupper, + /* Real */ ae_vector* b, + ae_int_t* info, + densesolverreport* rep, + /* Real */ ae_vector* x, + ae_state *_state); +void hpdmatrixsolvem(/* Complex */ ae_matrix* a, + ae_int_t n, + ae_bool isupper, + /* Complex */ ae_matrix* b, + ae_int_t m, + ae_int_t* info, + densesolverreport* rep, + /* Complex */ ae_matrix* x, + ae_state *_state); +void hpdmatrixsolve(/* Complex */ ae_matrix* a, + ae_int_t n, + ae_bool isupper, + /* Complex */ ae_vector* b, + ae_int_t* info, + densesolverreport* rep, + /* Complex */ ae_vector* x, + ae_state *_state); +void hpdmatrixcholeskysolvem(/* Complex */ ae_matrix* cha, + ae_int_t n, + ae_bool isupper, + /* Complex */ ae_matrix* b, + ae_int_t m, + ae_int_t* info, + densesolverreport* rep, + /* Complex */ ae_matrix* x, + ae_state *_state); +void hpdmatrixcholeskysolve(/* Complex */ ae_matrix* cha, + ae_int_t n, + ae_bool isupper, + /* Complex */ ae_vector* b, + ae_int_t* info, + densesolverreport* rep, + /* Complex */ ae_vector* x, + ae_state *_state); +void rmatrixsolvels(/* Real */ ae_matrix* a, + ae_int_t nrows, + ae_int_t ncols, + /* Real */ ae_vector* b, + double threshold, + ae_int_t* info, + densesolverlsreport* rep, + /* Real */ ae_vector* x, + ae_state *_state); +ae_bool _densesolverreport_init(densesolverreport* p, ae_state *_state, ae_bool make_automatic); +ae_bool _densesolverreport_init_copy(densesolverreport* dst, densesolverreport* src, ae_state *_state, ae_bool make_automatic); +void _densesolverreport_clear(densesolverreport* p); +ae_bool _densesolverlsreport_init(densesolverlsreport* p, ae_state *_state, ae_bool make_automatic); +ae_bool _densesolverlsreport_init_copy(densesolverlsreport* dst, densesolverlsreport* src, ae_state *_state, ae_bool make_automatic); +void _densesolverlsreport_clear(densesolverlsreport* p); +void nleqcreatelm(ae_int_t n, + ae_int_t m, + /* Real */ ae_vector* x, + nleqstate* state, + ae_state *_state); +void nleqsetcond(nleqstate* state, + double epsf, + ae_int_t maxits, + ae_state *_state); +void nleqsetxrep(nleqstate* state, ae_bool needxrep, ae_state *_state); +void nleqsetstpmax(nleqstate* state, double stpmax, ae_state *_state); +ae_bool nleqiteration(nleqstate* state, ae_state *_state); +void nleqresults(nleqstate* state, + /* Real */ ae_vector* x, + nleqreport* rep, + ae_state *_state); +void nleqresultsbuf(nleqstate* state, + /* Real */ ae_vector* x, + nleqreport* rep, + ae_state *_state); +void nleqrestartfrom(nleqstate* state, + /* Real */ ae_vector* x, + ae_state *_state); +ae_bool _nleqstate_init(nleqstate* p, ae_state *_state, ae_bool make_automatic); +ae_bool _nleqstate_init_copy(nleqstate* dst, nleqstate* src, ae_state *_state, ae_bool make_automatic); +void _nleqstate_clear(nleqstate* p); +ae_bool _nleqreport_init(nleqreport* p, ae_state *_state, ae_bool make_automatic); +ae_bool _nleqreport_init_copy(nleqreport* dst, nleqreport* src, ae_state *_state, ae_bool make_automatic); +void _nleqreport_clear(nleqreport* p); + +} +#endif + diff --git a/contrib/rtree/rtree.h b/contrib/rtree/rtree.h new file mode 100644 index 0000000000000000000000000000000000000000..ffd63ed751fc39ae7ee545f23a0cae32dae7b4b1 --- /dev/null +++ b/contrib/rtree/rtree.h @@ -0,0 +1,1593 @@ +#ifndef RTREE_H +#define RTREE_H +#include <algorithm> + +// NOTE This file compiles under MSVC 6 SP5 and MSVC .Net 2003 it may not work on other compilers without modification. + +// NOTE These next few lines may be win32 specific, you may need to modify them to compile on other platform +#include <stdio.h> +#include <math.h> +#include <assert.h> +#include <stdlib.h> + +#define ASSERT assert // RTree uses ASSERT( condition ) +#ifndef Min + #define Min std::min +#endif //Min +#ifndef Max + #define Max std::max +#endif //Max + +// +// RTree.h +// + +#define RTREE_TEMPLATE template<class DATATYPE, class ELEMTYPE, int NUMDIMS, class ELEMTYPEREAL, int TMAXNODES, int TMINNODES> +#define RTREE_QUAL RTree<DATATYPE, ELEMTYPE, NUMDIMS, ELEMTYPEREAL, TMAXNODES, TMINNODES> + +#define RTREE_DONT_USE_MEMPOOLS // This version does not contain a fixed memory allocator, fill in lines with EXAMPLE to implement one. +#define RTREE_USE_SPHERICAL_VOLUME // Better split classification, may be slower on some systems + +// Fwd decl +class RTFileStream; // File I/O helper class, look below for implementation and notes. + + +/// \class RTree +/// Implementation of RTree, a multidimensional bounding rectangle tree. +/// Example usage: For a 3-dimensional tree use RTree<Object*, float, 3> myTree; +/// +/// This modified, templated C++ version by Greg Douglas at Auran (http://www.auran.com) +/// +/// DATATYPE Referenced data, should be int, void*, obj* etc. no larger than sizeof<void*> and simple type +/// ELEMTYPE Type of element such as int or float +/// NUMDIMS Number of dimensions such as 2 or 3 +/// ELEMTYPEREAL Type of element that allows fractional and large values such as float or double, for use in volume calcs +/// +/// NOTES: Inserting and removing data requires the knowledge of its constant Minimal Bounding Rectangle. +/// This version uses new/delete for nodes, I recommend using a fixed size allocator for efficiency. +/// Instead of using a callback function for returned results, I recommend and efficient pre-sized, grow-only memory +/// array similar to MFC CArray or STL Vector for returning search query result. +/// +template<class DATATYPE, class ELEMTYPE, int NUMDIMS, + class ELEMTYPEREAL = ELEMTYPE, int TMAXNODES = 8, int TMINNODES = TMAXNODES / 2> +class RTree +{ +protected: + + struct Node; // Fwd decl. Used by other internal structs and iterator + +public: + + // These constant must be declared after Branch and before Node struct + // Stuck up here for MSVC 6 compiler. NSVC .NET 2003 is much happier. + enum + { + MAXNODES = TMAXNODES, ///< Max elements in node + MINNODES = TMINNODES, ///< Min elements in node + }; + + +public: + + RTree(); + virtual ~RTree(); + + /// Insert entry + /// \param a_min Min of bounding rect + /// \param a_max Max of bounding rect + /// \param a_dataId Positive Id of data. Maybe zero, but negative numbers not allowed. + void Insert(const ELEMTYPE a_min[NUMDIMS], const ELEMTYPE a_max[NUMDIMS], const DATATYPE& a_dataId); + + /// Remove entry + /// \param a_min Min of bounding rect + /// \param a_max Max of bounding rect + /// \param a_dataId Positive Id of data. Maybe zero, but negative numbers not allowed. + void Remove(const ELEMTYPE a_min[NUMDIMS], const ELEMTYPE a_max[NUMDIMS], const DATATYPE& a_dataId); + + /// Find all within search rectangle + /// \param a_min Min of search bounding rect + /// \param a_max Max of search bounding rect + /// \param a_resultCallback Callback function to return result. Callback should return 'true' to continue searching + /// \param a_context User context to pass as parameter to a_resultCallback + /// \return Returns the number of entries found + int Search(const ELEMTYPE a_min[NUMDIMS], const ELEMTYPE a_max[NUMDIMS], bool a_resultCallback(DATATYPE a_data, void* a_context), void* a_context); + + /// Remove all entries from tree + void RemoveAll(); + + /// Count the data elements in this container. This is slow as no internal counter is maintained. + int Count(); + + /// Load tree contents from file + bool Load(const char* a_fileName); + /// Load tree contents from stream + bool Load(RTFileStream& a_stream); + + + /// Save tree contents to file + bool Save(const char* a_fileName); + /// Save tree contents to stream + bool Save(RTFileStream& a_stream); + + /// Iterator is not remove safe. + class Iterator + { + private: + + enum { MAX_STACK = 32 }; // Max stack size. Allows almost n^32 where n is number of branches in node + + struct StackElement + { + Node* m_node; + int m_branchIndex; + }; + + public: + + Iterator() { Init(); } + + ~Iterator() { } + + /// Is iterator invalid + bool IsNull() { return (m_tos <= 0); } + + /// Is iterator pointing to valid data + bool IsNotNull() { return (m_tos > 0); } + + /// Access the current data element. Caller must be sure iterator is not NULL first. + DATATYPE& operator*() + { + ASSERT(IsNotNull()); + StackElement& curTos = m_stack[m_tos - 1]; + return curTos.m_node->m_branch[curTos.m_branchIndex].m_data; + } + + /// Access the current data element. Caller must be sure iterator is not NULL first. + const DATATYPE& operator*() const + { + ASSERT(IsNotNull()); + StackElement& curTos = m_stack[m_tos - 1]; + return curTos.m_node->m_branch[curTos.m_branchIndex].m_data; + } + + /// Find the next data element + bool operator++() { return FindNextData(); } + + /// Get the bounds for this node + void GetBounds(ELEMTYPE a_min[NUMDIMS], ELEMTYPE a_max[NUMDIMS]) + { + ASSERT(IsNotNull()); + StackElement& curTos = m_stack[m_tos - 1]; + Branch& curBranch = curTos.m_node->m_branch[curTos.m_branchIndex]; + + for(int index = 0; index < NUMDIMS; ++index) + { + a_min[index] = curBranch.m_rect.m_min[index]; + a_max[index] = curBranch.m_rect.m_max[index]; + } + } + + private: + + /// Reset iterator + void Init() { m_tos = 0; } + + /// Find the next data element in the tree (For internal use only) + bool FindNextData() + { + for(;;) + { + if(m_tos <= 0) + { + return false; + } + StackElement curTos = Pop(); // Copy stack top cause it may change as we use it + + if(curTos.m_node->IsLeaf()) + { + // Keep walking through data while we can + if(curTos.m_branchIndex+1 < curTos.m_node->m_count) + { + // There is more data, just point to the next one + Push(curTos.m_node, curTos.m_branchIndex + 1); + return true; + } + // No more data, so it will fall back to previous level + } + else + { + if(curTos.m_branchIndex+1 < curTos.m_node->m_count) + { + // Push sibling on for future tree walk + // This is the 'fall back' node when we finish with the current level + Push(curTos.m_node, curTos.m_branchIndex + 1); + } + // Since cur node is not a leaf, push first of next level to get deeper into the tree + Node* nextLevelnode = curTos.m_node->m_branch[curTos.m_branchIndex].m_child; + Push(nextLevelnode, 0); + + // If we pushed on a new leaf, exit as the data is ready at TOS + if(nextLevelnode->IsLeaf()) + { + return true; + } + } + } + } + + /// Push node and branch onto iteration stack (For internal use only) + void Push(Node* a_node, int a_branchIndex) + { + m_stack[m_tos].m_node = a_node; + m_stack[m_tos].m_branchIndex = a_branchIndex; + ++m_tos; + ASSERT(m_tos <= MAX_STACK); + } + + /// Pop element off iteration stack (For internal use only) + StackElement& Pop() + { + ASSERT(m_tos > 0); + --m_tos; + return m_stack[m_tos]; + } + + StackElement m_stack[MAX_STACK]; ///< Stack as we are doing iteration instead of recursion + int m_tos; ///< Top Of Stack index + + friend class RTree; // Allow hiding of non-public functions while allowing manipulation by logical owner + }; + + /// Get 'first' for iteration + void GetFirst(Iterator& a_it) + { + a_it.Init(); + Node* first = m_root; + while(first) + { + if(first->IsInternalNode() && first->m_count > 1) + { + a_it.Push(first, 1); // Descend sibling branch later + } + else if(first->IsLeaf()) + { + if(first->m_count) + { + a_it.Push(first, 0); + } + break; + } + first = first->m_branch[0].m_child; + } + } + + /// Get Next for iteration + void GetNext(Iterator& a_it) { ++a_it; } + + /// Is iterator NULL, or at end? + bool IsNull(Iterator& a_it) { return a_it.IsNull(); } + + /// Get object at iterator position + DATATYPE& GetAt(Iterator& a_it) { return *a_it; } + +protected: + + /// Minimal bounding rectangle (n-dimensional) + struct Rect + { + ELEMTYPE m_min[NUMDIMS]; ///< Min dimensions of bounding box + ELEMTYPE m_max[NUMDIMS]; ///< Max dimensions of bounding box + }; + + /// May be data or may be another subtree + /// The parents level determines this. + /// If the parents level is 0, then this is data + struct Branch + { + Rect m_rect; ///< Bounds + union + { + Node* m_child; ///< Child node + DATATYPE m_data; ///< Data Id or Ptr + }; + }; + + /// Node for each branch level + struct Node + { + bool IsInternalNode() { return (m_level > 0); } // Not a leaf, but a internal node + bool IsLeaf() { return (m_level == 0); } // A leaf, contains data + + int m_count; ///< Count + int m_level; ///< Leaf is zero, others positive + Branch m_branch[MAXNODES]; ///< Branch + }; + + /// A link list of nodes for reinsertion after a delete operation + struct ListNode + { + ListNode* m_next; ///< Next in list + Node* m_node; ///< Node + }; + + /// Variables for finding a split partition + struct PartitionVars + { + int m_partition[MAXNODES+1]; + int m_total; + int m_minFill; + int m_taken[MAXNODES+1]; + int m_count[2]; + Rect m_cover[2]; + ELEMTYPEREAL m_area[2]; + + Branch m_branchBuf[MAXNODES+1]; + int m_branchCount; + Rect m_coverSplit; + ELEMTYPEREAL m_coverSplitArea; + }; + + Node* AllocNode(); + void FreeNode(Node* a_node); + void InitNode(Node* a_node); + void InitRect(Rect* a_rect); + bool InsertRectRec(Rect* a_rect, const DATATYPE& a_id, Node* a_node, Node** a_newNode, int a_level); + bool InsertRect(Rect* a_rect, const DATATYPE& a_id, Node** a_root, int a_level); + Rect NodeCover(Node* a_node); + bool AddBranch(Branch* a_branch, Node* a_node, Node** a_newNode); + void DisconnectBranch(Node* a_node, int a_index); + int PickBranch(Rect* a_rect, Node* a_node); + Rect CombineRect(Rect* a_rectA, Rect* a_rectB); + void SplitNode(Node* a_node, Branch* a_branch, Node** a_newNode); + ELEMTYPEREAL RectSphericalVolume(Rect* a_rect); + ELEMTYPEREAL RectVolume(Rect* a_rect); + ELEMTYPEREAL CalcRectVolume(Rect* a_rect); + void GetBranches(Node* a_node, Branch* a_branch, PartitionVars* a_parVars); + void ChoosePartition(PartitionVars* a_parVars, int a_minFill); + void LoadNodes(Node* a_nodeA, Node* a_nodeB, PartitionVars* a_parVars); + void InitParVars(PartitionVars* a_parVars, int a_maxRects, int a_minFill); + void PickSeeds(PartitionVars* a_parVars); + void Classify(int a_index, int a_group, PartitionVars* a_parVars); + bool RemoveRect(Rect* a_rect, const DATATYPE& a_id, Node** a_root); + bool RemoveRectRec(Rect* a_rect, const DATATYPE& a_id, Node* a_node, ListNode** a_listNode); + ListNode* AllocListNode(); + void FreeListNode(ListNode* a_listNode); + bool Overlap(Rect* a_rectA, Rect* a_rectB); + void ReInsert(Node* a_node, ListNode** a_listNode); + bool Search(Node* a_node, Rect* a_rect, int& a_foundCount, bool a_resultCallback(DATATYPE a_data, void* a_context), void* a_context); + void RemoveAllRec(Node* a_node); + void Reset(); + void CountRec(Node* a_node, int& a_count); + + bool SaveRec(Node* a_node, RTFileStream& a_stream); + bool LoadRec(Node* a_node, RTFileStream& a_stream); + + Node* m_root; ///< Root of tree + ELEMTYPEREAL m_unitSphereVolume; ///< Unit sphere constant for required number of dimensions +}; + + +// Because there is not stream support, this is a quick and dirty file I/O helper. +// Users will likely replace its usage with a Stream implementation from their favorite API. +class RTFileStream +{ + FILE* m_file; + +public: + + + RTFileStream() + { + m_file = NULL; + } + + ~RTFileStream() + { + Close(); + } + + bool OpenRead(const char* a_fileName) + { + m_file = fopen(a_fileName, "rb"); + if(!m_file) + { + return false; + } + return true; + } + + bool OpenWrite(const char* a_fileName) + { + m_file = fopen(a_fileName, "wb"); + if(!m_file) + { + return false; + } + return true; + } + + void Close() + { + if(m_file) + { + fclose(m_file); + m_file = NULL; + } + } + + template< typename TYPE > + size_t Write(const TYPE& a_value) + { + ASSERT(m_file); + return fwrite((void*)&a_value, sizeof(a_value), 1, m_file); + } + + template< typename TYPE > + size_t WriteArray(const TYPE* a_array, int a_count) + { + ASSERT(m_file); + return fwrite((void*)a_array, sizeof(TYPE) * a_count, 1, m_file); + } + + template< typename TYPE > + size_t Read(TYPE& a_value) + { + ASSERT(m_file); + return fread((void*)&a_value, sizeof(a_value), 1, m_file); + } + + template< typename TYPE > + size_t ReadArray(TYPE* a_array, int a_count) + { + ASSERT(m_file); + return fread((void*)a_array, sizeof(TYPE) * a_count, 1, m_file); + } +}; + + +RTREE_TEMPLATE +RTREE_QUAL::RTree() +{ + ASSERT(MAXNODES > MINNODES); + ASSERT(MINNODES > 0); + + + // We only support machine word size simple data type eg. integer index or object pointer. + // Since we are storing as union with non data branch + ASSERT(sizeof(DATATYPE) == sizeof(void*) || sizeof(DATATYPE) == sizeof(int)); + + // Precomputed volumes of the unit spheres for the first few dimensions + const float UNIT_SPHERE_VOLUMES[] = { + 0.000000f, 2.000000f, 3.141593f, // Dimension 0,1,2 + 4.188790f, 4.934802f, 5.263789f, // Dimension 3,4,5 + 5.167713f, 4.724766f, 4.058712f, // Dimension 6,7,8 + 3.298509f, 2.550164f, 1.884104f, // Dimension 9,10,11 + 1.335263f, 0.910629f, 0.599265f, // Dimension 12,13,14 + 0.381443f, 0.235331f, 0.140981f, // Dimension 15,16,17 + 0.082146f, 0.046622f, 0.025807f, // Dimension 18,19,20 + }; + + m_root = AllocNode(); + m_root->m_level = 0; + m_unitSphereVolume = (ELEMTYPEREAL)UNIT_SPHERE_VOLUMES[NUMDIMS]; +} + + +RTREE_TEMPLATE +RTREE_QUAL::~RTree() +{ + Reset(); // Free, or reset node memory +} + + +RTREE_TEMPLATE +void RTREE_QUAL::Insert(const ELEMTYPE a_min[NUMDIMS], const ELEMTYPE a_max[NUMDIMS], const DATATYPE& a_dataId) +{ +#ifdef _DEBUG + for(int index=0; index<NUMDIMS; ++index) + { + ASSERT(a_min[index] <= a_max[index]); + } +#endif //_DEBUG + + Rect rect; + + for(int axis=0; axis<NUMDIMS; ++axis) + { + rect.m_min[axis] = a_min[axis]; + rect.m_max[axis] = a_max[axis]; + } + + InsertRect(&rect, a_dataId, &m_root, 0); +} + + +RTREE_TEMPLATE +void RTREE_QUAL::Remove(const ELEMTYPE a_min[NUMDIMS], const ELEMTYPE a_max[NUMDIMS], const DATATYPE& a_dataId) +{ +#ifdef _DEBUG + for(int index=0; index<NUMDIMS; ++index) + { + ASSERT(a_min[index] <= a_max[index]); + } +#endif //_DEBUG + + Rect rect; + + for(int axis=0; axis<NUMDIMS; ++axis) + { + rect.m_min[axis] = a_min[axis]; + rect.m_max[axis] = a_max[axis]; + } + + RemoveRect(&rect, a_dataId, &m_root); +} + + +RTREE_TEMPLATE +int RTREE_QUAL::Search(const ELEMTYPE a_min[NUMDIMS], const ELEMTYPE a_max[NUMDIMS], bool a_resultCallback(DATATYPE a_data, void* a_context), void* a_context) +{ +#ifdef _DEBUG + for(int index=0; index<NUMDIMS; ++index) + { + ASSERT(a_min[index] <= a_max[index]); + } +#endif //_DEBUG + + Rect rect; + + for(int axis=0; axis<NUMDIMS; ++axis) + { + rect.m_min[axis] = a_min[axis]; + rect.m_max[axis] = a_max[axis]; + } + + // NOTE: May want to return search result another way, perhaps returning the number of found elements here. + + int foundCount = 0; + Search(m_root, &rect, foundCount, a_resultCallback, a_context); + + return foundCount; +} + + +RTREE_TEMPLATE +int RTREE_QUAL::Count() +{ + int count = 0; + CountRec(m_root, count); + + return count; +} + + + +RTREE_TEMPLATE +void RTREE_QUAL::CountRec(Node* a_node, int& a_count) +{ + if(a_node->IsInternalNode()) // not a leaf node + { + for(int index = 0; index < a_node->m_count; ++index) + { + CountRec(a_node->m_branch[index].m_child, a_count); + } + } + else // A leaf node + { + a_count += a_node->m_count; + } +} + + +RTREE_TEMPLATE +bool RTREE_QUAL::Load(const char* a_fileName) +{ + RemoveAll(); // Clear existing tree + + RTFileStream stream; + if(!stream.OpenRead(a_fileName)) + { + return false; + } + + bool result = Load(stream); + + stream.Close(); + + return result; +}; + + + +RTREE_TEMPLATE +bool RTREE_QUAL::Load(RTFileStream& a_stream) +{ + // Write some kind of header + int _dataFileId = ('R'<<0)|('T'<<8)|('R'<<16)|('E'<<24); + int _dataSize = sizeof(DATATYPE); + int _dataNumDims = NUMDIMS; + int _dataElemSize = sizeof(ELEMTYPE); + int _dataElemRealSize = sizeof(ELEMTYPEREAL); + int _dataMaxNodes = TMAXNODES; + int _dataMinNodes = TMINNODES; + + int dataFileId = 0; + int dataSize = 0; + int dataNumDims = 0; + int dataElemSize = 0; + int dataElemRealSize = 0; + int dataMaxNodes = 0; + int dataMinNodes = 0; + + a_stream.Read(dataFileId); + a_stream.Read(dataSize); + a_stream.Read(dataNumDims); + a_stream.Read(dataElemSize); + a_stream.Read(dataElemRealSize); + a_stream.Read(dataMaxNodes); + a_stream.Read(dataMinNodes); + + bool result = false; + + // Test if header was valid and compatible + if( (dataFileId == _dataFileId) + && (dataSize == _dataSize) + && (dataNumDims == _dataNumDims) + && (dataElemSize == _dataElemSize) + && (dataElemRealSize == _dataElemRealSize) + && (dataMaxNodes == _dataMaxNodes) + && (dataMinNodes == _dataMinNodes) + ) + { + // Recursively load tree + result = LoadRec(m_root, a_stream); + } + + return result; +} + + +RTREE_TEMPLATE +bool RTREE_QUAL::LoadRec(Node* a_node, RTFileStream& a_stream) +{ + a_stream.Read(a_node->m_level); + a_stream.Read(a_node->m_count); + + if(a_node->IsInternalNode()) // not a leaf node + { + for(int index = 0; index < a_node->m_count; ++index) + { + Branch* curBranch = &a_node->m_branch[index]; + + a_stream.ReadArray(curBranch->m_rect.m_min, NUMDIMS); + a_stream.ReadArray(curBranch->m_rect.m_max, NUMDIMS); + + curBranch->m_child = AllocNode(); + LoadRec(curBranch->m_child, a_stream); + } + } + else // A leaf node + { + for(int index = 0; index < a_node->m_count; ++index) + { + Branch* curBranch = &a_node->m_branch[index]; + + a_stream.ReadArray(curBranch->m_rect.m_min, NUMDIMS); + a_stream.ReadArray(curBranch->m_rect.m_max, NUMDIMS); + + a_stream.Read(curBranch->m_data); + } + } + + return true; // Should do more error checking on I/O operations +} + + +RTREE_TEMPLATE +bool RTREE_QUAL::Save(const char* a_fileName) +{ + RTFileStream stream; + if(!stream.OpenWrite(a_fileName)) + { + return false; + } + + bool result = Save(stream); + + stream.Close(); + + return result; +} + + +RTREE_TEMPLATE +bool RTREE_QUAL::Save(RTFileStream& a_stream) +{ + // Write some kind of header + int dataFileId = ('R'<<0)|('T'<<8)|('R'<<16)|('E'<<24); + int dataSize = sizeof(DATATYPE); + int dataNumDims = NUMDIMS; + int dataElemSize = sizeof(ELEMTYPE); + int dataElemRealSize = sizeof(ELEMTYPEREAL); + int dataMaxNodes = TMAXNODES; + int dataMinNodes = TMINNODES; + + a_stream.Write(dataFileId); + a_stream.Write(dataSize); + a_stream.Write(dataNumDims); + a_stream.Write(dataElemSize); + a_stream.Write(dataElemRealSize); + a_stream.Write(dataMaxNodes); + a_stream.Write(dataMinNodes); + + // Recursively save tree + bool result = SaveRec(m_root, a_stream); + + return result; +} + + +RTREE_TEMPLATE +bool RTREE_QUAL::SaveRec(Node* a_node, RTFileStream& a_stream) +{ + a_stream.Write(a_node->m_level); + a_stream.Write(a_node->m_count); + + if(a_node->IsInternalNode()) // not a leaf node + { + for(int index = 0; index < a_node->m_count; ++index) + { + Branch* curBranch = &a_node->m_branch[index]; + + a_stream.WriteArray(curBranch->m_rect.m_min, NUMDIMS); + a_stream.WriteArray(curBranch->m_rect.m_max, NUMDIMS); + + SaveRec(curBranch->m_child, a_stream); + } + } + else // A leaf node + { + for(int index = 0; index < a_node->m_count; ++index) + { + Branch* curBranch = &a_node->m_branch[index]; + + a_stream.WriteArray(curBranch->m_rect.m_min, NUMDIMS); + a_stream.WriteArray(curBranch->m_rect.m_max, NUMDIMS); + + a_stream.Write(curBranch->m_data); + } + } + + return true; // Should do more error checking on I/O operations +} + + +RTREE_TEMPLATE +void RTREE_QUAL::RemoveAll() +{ + // Delete all existing nodes + Reset(); + + m_root = AllocNode(); + m_root->m_level = 0; +} + + +RTREE_TEMPLATE +void RTREE_QUAL::Reset() +{ +#ifdef RTREE_DONT_USE_MEMPOOLS + // Delete all existing nodes + RemoveAllRec(m_root); +#else // RTREE_DONT_USE_MEMPOOLS + // Just reset memory pools. We are not using complex types + // EXAMPLE +#endif // RTREE_DONT_USE_MEMPOOLS +} + + +RTREE_TEMPLATE +void RTREE_QUAL::RemoveAllRec(Node* a_node) +{ + ASSERT(a_node); + ASSERT(a_node->m_level >= 0); + + if(a_node->IsInternalNode()) // This is an internal node in the tree + { + for(int index=0; index < a_node->m_count; ++index) + { + RemoveAllRec(a_node->m_branch[index].m_child); + } + } + FreeNode(a_node); +} + + +RTREE_TEMPLATE +typename RTREE_QUAL::Node* RTREE_QUAL::AllocNode() +{ + Node* newNode; +#ifdef RTREE_DONT_USE_MEMPOOLS + newNode = new Node; +#else // RTREE_DONT_USE_MEMPOOLS + // EXAMPLE +#endif // RTREE_DONT_USE_MEMPOOLS + InitNode(newNode); + return newNode; +} + + +RTREE_TEMPLATE +void RTREE_QUAL::FreeNode(Node* a_node) +{ + ASSERT(a_node); + +#ifdef RTREE_DONT_USE_MEMPOOLS + delete a_node; +#else // RTREE_DONT_USE_MEMPOOLS + // EXAMPLE +#endif // RTREE_DONT_USE_MEMPOOLS +} + + +// Allocate space for a node in the list used in DeletRect to +// store Nodes that are too empty. +RTREE_TEMPLATE +typename RTREE_QUAL::ListNode* RTREE_QUAL::AllocListNode() +{ +#ifdef RTREE_DONT_USE_MEMPOOLS + return new ListNode; +#else // RTREE_DONT_USE_MEMPOOLS + // EXAMPLE +#endif // RTREE_DONT_USE_MEMPOOLS +} + + +RTREE_TEMPLATE +void RTREE_QUAL::FreeListNode(ListNode* a_listNode) +{ +#ifdef RTREE_DONT_USE_MEMPOOLS + delete a_listNode; +#else // RTREE_DONT_USE_MEMPOOLS + // EXAMPLE +#endif // RTREE_DONT_USE_MEMPOOLS +} + + +RTREE_TEMPLATE +void RTREE_QUAL::InitNode(Node* a_node) +{ + a_node->m_count = 0; + a_node->m_level = -1; +} + + +RTREE_TEMPLATE +void RTREE_QUAL::InitRect(Rect* a_rect) +{ + for(int index = 0; index < NUMDIMS; ++index) + { + a_rect->m_min[index] = (ELEMTYPE)0; + a_rect->m_max[index] = (ELEMTYPE)0; + } +} + + +// Inserts a new data rectangle into the index structure. +// Recursively descends tree, propagates splits back up. +// Returns 0 if node was not split. Old node updated. +// If node was split, returns 1 and sets the pointer pointed to by +// new_node to point to the new node. Old node updated to become one of two. +// The level argument specifies the number of steps up from the leaf +// level to insert; e.g. a data rectangle goes in at level = 0. +RTREE_TEMPLATE +bool RTREE_QUAL::InsertRectRec(Rect* a_rect, const DATATYPE& a_id, Node* a_node, Node** a_newNode, int a_level) +{ + ASSERT(a_rect && a_node && a_newNode); + ASSERT(a_level >= 0 && a_level <= a_node->m_level); + + int index; + Branch branch; + Node* otherNode; + + // Still above level for insertion, go down tree recursively + if(a_node->m_level > a_level) + { + index = PickBranch(a_rect, a_node); + if (!InsertRectRec(a_rect, a_id, a_node->m_branch[index].m_child, &otherNode, a_level)) + { + // Child was not split + a_node->m_branch[index].m_rect = CombineRect(a_rect, &(a_node->m_branch[index].m_rect)); + return false; + } + else // Child was split + { + a_node->m_branch[index].m_rect = NodeCover(a_node->m_branch[index].m_child); + branch.m_child = otherNode; + branch.m_rect = NodeCover(otherNode); + return AddBranch(&branch, a_node, a_newNode); + } + } + else if(a_node->m_level == a_level) // Have reached level for insertion. Add rect, split if necessary + { + branch.m_rect = *a_rect; + branch.m_child = (Node*) a_id; + // Child field of leaves contains id of data record + return AddBranch(&branch, a_node, a_newNode); + } + else + { + // Should never occur + ASSERT(0); + return false; + } +} + + +// Insert a data rectangle into an index structure. +// InsertRect provides for splitting the root; +// returns 1 if root was split, 0 if it was not. +// The level argument specifies the number of steps up from the leaf +// level to insert; e.g. a data rectangle goes in at level = 0. +// InsertRect2 does the recursion. +// +RTREE_TEMPLATE +bool RTREE_QUAL::InsertRect(Rect* a_rect, const DATATYPE& a_id, Node** a_root, int a_level) +{ + ASSERT(a_rect && a_root); + ASSERT(a_level >= 0 && a_level <= (*a_root)->m_level); +#ifdef _DEBUG + for(int index=0; index < NUMDIMS; ++index) + { + ASSERT(a_rect->m_min[index] <= a_rect->m_max[index]); + } +#endif //_DEBUG + + Node* newRoot; + Node* newNode; + Branch branch; + + if(InsertRectRec(a_rect, a_id, *a_root, &newNode, a_level)) // Root split + { + newRoot = AllocNode(); // Grow tree taller and new root + newRoot->m_level = (*a_root)->m_level + 1; + branch.m_rect = NodeCover(*a_root); + branch.m_child = *a_root; + AddBranch(&branch, newRoot, NULL); + branch.m_rect = NodeCover(newNode); + branch.m_child = newNode; + AddBranch(&branch, newRoot, NULL); + *a_root = newRoot; + return true; + } + + return false; +} + + +// Find the smallest rectangle that includes all rectangles in branches of a node. +RTREE_TEMPLATE +typename RTREE_QUAL::Rect RTREE_QUAL::NodeCover(Node* a_node) +{ + ASSERT(a_node); + + int firstTime = true; + Rect rect; + InitRect(&rect); + + for(int index = 0; index < a_node->m_count; ++index) + { + if(firstTime) + { + rect = a_node->m_branch[index].m_rect; + firstTime = false; + } + else + { + rect = CombineRect(&rect, &(a_node->m_branch[index].m_rect)); + } + } + + return rect; +} + + +// Add a branch to a node. Split the node if necessary. +// Returns 0 if node not split. Old node updated. +// Returns 1 if node split, sets *new_node to address of new node. +// Old node updated, becomes one of two. +RTREE_TEMPLATE +bool RTREE_QUAL::AddBranch(Branch* a_branch, Node* a_node, Node** a_newNode) +{ + ASSERT(a_branch); + ASSERT(a_node); + + if(a_node->m_count < MAXNODES) // Split won't be necessary + { + a_node->m_branch[a_node->m_count] = *a_branch; + ++a_node->m_count; + + return false; + } + else + { + ASSERT(a_newNode); + + SplitNode(a_node, a_branch, a_newNode); + return true; + } +} + + +// Disconnect a dependent node. +// Caller must return (or stop using iteration index) after this as count has changed +RTREE_TEMPLATE +void RTREE_QUAL::DisconnectBranch(Node* a_node, int a_index) +{ + ASSERT(a_node && (a_index >= 0) && (a_index < MAXNODES)); + ASSERT(a_node->m_count > 0); + + // Remove element by swapping with the last element to prevent gaps in array + a_node->m_branch[a_index] = a_node->m_branch[a_node->m_count - 1]; + + --a_node->m_count; +} + + +// Pick a branch. Pick the one that will need the smallest increase +// in area to accomodate the new rectangle. This will result in the +// least total area for the covering rectangles in the current node. +// In case of a tie, pick the one which was smaller before, to get +// the best resolution when searching. +RTREE_TEMPLATE +int RTREE_QUAL::PickBranch(Rect* a_rect, Node* a_node) +{ + ASSERT(a_rect && a_node); + + bool firstTime = true; + ELEMTYPEREAL increase; + ELEMTYPEREAL bestIncr = (ELEMTYPEREAL)-1; + ELEMTYPEREAL area; + ELEMTYPEREAL bestArea; + int best; + Rect tempRect; + + for(int index=0; index < a_node->m_count; ++index) + { + Rect* curRect = &a_node->m_branch[index].m_rect; + area = CalcRectVolume(curRect); + tempRect = CombineRect(a_rect, curRect); + increase = CalcRectVolume(&tempRect) - area; + if((increase < bestIncr) || firstTime) + { + best = index; + bestArea = area; + bestIncr = increase; + firstTime = false; + } + else if((increase == bestIncr) && (area < bestArea)) + { + best = index; + bestArea = area; + bestIncr = increase; + } + } + return best; +} + + +// Combine two rectangles into larger one containing both +RTREE_TEMPLATE +typename RTREE_QUAL::Rect RTREE_QUAL::CombineRect(Rect* a_rectA, Rect* a_rectB) +{ + ASSERT(a_rectA && a_rectB); + + Rect newRect; + + for(int index = 0; index < NUMDIMS; ++index) + { + newRect.m_min[index] = Min(a_rectA->m_min[index], a_rectB->m_min[index]); + newRect.m_max[index] = Max(a_rectA->m_max[index], a_rectB->m_max[index]); + } + + return newRect; +} + + + +// Split a node. +// Divides the nodes branches and the extra one between two nodes. +// Old node is one of the new ones, and one really new one is created. +// Tries more than one method for choosing a partition, uses best result. +RTREE_TEMPLATE +void RTREE_QUAL::SplitNode(Node* a_node, Branch* a_branch, Node** a_newNode) +{ + ASSERT(a_node); + ASSERT(a_branch); + + // Could just use local here, but member or external is faster since it is reused + PartitionVars localVars; + PartitionVars* parVars = &localVars; + int level; + + // Load all the branches into a buffer, initialize old node + level = a_node->m_level; + GetBranches(a_node, a_branch, parVars); + + // Find partition + ChoosePartition(parVars, MINNODES); + + // Put branches from buffer into 2 nodes according to chosen partition + *a_newNode = AllocNode(); + (*a_newNode)->m_level = a_node->m_level = level; + LoadNodes(a_node, *a_newNode, parVars); + + ASSERT((a_node->m_count + (*a_newNode)->m_count) == parVars->m_total); +} + + +// Calculate the n-dimensional volume of a rectangle +RTREE_TEMPLATE +ELEMTYPEREAL RTREE_QUAL::RectVolume(Rect* a_rect) +{ + ASSERT(a_rect); + + ELEMTYPEREAL volume = (ELEMTYPEREAL)1; + + for(int index=0; index<NUMDIMS; ++index) + { + volume *= a_rect->m_max[index] - a_rect->m_min[index]; + } + + ASSERT(volume >= (ELEMTYPEREAL)0); + + return volume; +} + + +// The exact volume of the bounding sphere for the given Rect +RTREE_TEMPLATE +ELEMTYPEREAL RTREE_QUAL::RectSphericalVolume(Rect* a_rect) +{ + ASSERT(a_rect); + + ELEMTYPEREAL sumOfSquares = (ELEMTYPEREAL)0; + ELEMTYPEREAL radius; + + for(int index=0; index < NUMDIMS; ++index) + { + ELEMTYPEREAL halfExtent = ((ELEMTYPEREAL)a_rect->m_max[index] - (ELEMTYPEREAL)a_rect->m_min[index]) * 0.5f; + sumOfSquares += halfExtent * halfExtent; + } + + radius = (ELEMTYPEREAL)sqrt(sumOfSquares); + + // Pow maybe slow, so test for common dims like 2,3 and just use x*x, x*x*x. + if(NUMDIMS == 3) + { + return (radius * radius * radius * m_unitSphereVolume); + } + else if(NUMDIMS == 2) + { + return (radius * radius * m_unitSphereVolume); + } + else + { + return (ELEMTYPEREAL)(pow(radius, NUMDIMS) * m_unitSphereVolume); + } +} + + +// Use one of the methods to calculate retangle volume +RTREE_TEMPLATE +ELEMTYPEREAL RTREE_QUAL::CalcRectVolume(Rect* a_rect) +{ +#ifdef RTREE_USE_SPHERICAL_VOLUME + return RectSphericalVolume(a_rect); // Slower but helps certain merge cases +#else // RTREE_USE_SPHERICAL_VOLUME + return RectVolume(a_rect); // Faster but can cause poor merges +#endif // RTREE_USE_SPHERICAL_VOLUME +} + + +// Load branch buffer with branches from full node plus the extra branch. +RTREE_TEMPLATE +void RTREE_QUAL::GetBranches(Node* a_node, Branch* a_branch, PartitionVars* a_parVars) +{ + ASSERT(a_node); + ASSERT(a_branch); + + ASSERT(a_node->m_count == MAXNODES); + + // Load the branch buffer + for(int index=0; index < MAXNODES; ++index) + { + a_parVars->m_branchBuf[index] = a_node->m_branch[index]; + } + a_parVars->m_branchBuf[MAXNODES] = *a_branch; + a_parVars->m_branchCount = MAXNODES + 1; + + // Calculate rect containing all in the set + a_parVars->m_coverSplit = a_parVars->m_branchBuf[0].m_rect; + for(int index=1; index < MAXNODES+1; ++index) + { + a_parVars->m_coverSplit = CombineRect(&a_parVars->m_coverSplit, &a_parVars->m_branchBuf[index].m_rect); + } + a_parVars->m_coverSplitArea = CalcRectVolume(&a_parVars->m_coverSplit); + + InitNode(a_node); +} + + +// Method #0 for choosing a partition: +// As the seeds for the two groups, pick the two rects that would waste the +// most area if covered by a single rectangle, i.e. evidently the worst pair +// to have in the same group. +// Of the remaining, one at a time is chosen to be put in one of the two groups. +// The one chosen is the one with the greatest difference in area expansion +// depending on which group - the rect most strongly attracted to one group +// and repelled from the other. +// If one group gets too full (more would force other group to violate min +// fill requirement) then other group gets the rest. +// These last are the ones that can go in either group most easily. +RTREE_TEMPLATE +void RTREE_QUAL::ChoosePartition(PartitionVars* a_parVars, int a_minFill) +{ + ASSERT(a_parVars); + + ELEMTYPEREAL biggestDiff; + int group, chosen, betterGroup; + + InitParVars(a_parVars, a_parVars->m_branchCount, a_minFill); + PickSeeds(a_parVars); + + while (((a_parVars->m_count[0] + a_parVars->m_count[1]) < a_parVars->m_total) + && (a_parVars->m_count[0] < (a_parVars->m_total - a_parVars->m_minFill)) + && (a_parVars->m_count[1] < (a_parVars->m_total - a_parVars->m_minFill))) + { + biggestDiff = (ELEMTYPEREAL) -1; + for(int index=0; index<a_parVars->m_total; ++index) + { + if(!a_parVars->m_taken[index]) + { + Rect* curRect = &a_parVars->m_branchBuf[index].m_rect; + Rect rect0 = CombineRect(curRect, &a_parVars->m_cover[0]); + Rect rect1 = CombineRect(curRect, &a_parVars->m_cover[1]); + ELEMTYPEREAL growth0 = CalcRectVolume(&rect0) - a_parVars->m_area[0]; + ELEMTYPEREAL growth1 = CalcRectVolume(&rect1) - a_parVars->m_area[1]; + ELEMTYPEREAL diff = growth1 - growth0; + if(diff >= 0) + { + group = 0; + } + else + { + group = 1; + diff = -diff; + } + + if(diff > biggestDiff) + { + biggestDiff = diff; + chosen = index; + betterGroup = group; + } + else if((diff == biggestDiff) && (a_parVars->m_count[group] < a_parVars->m_count[betterGroup])) + { + chosen = index; + betterGroup = group; + } + } + } + Classify(chosen, betterGroup, a_parVars); + } + + // If one group too full, put remaining rects in the other + if((a_parVars->m_count[0] + a_parVars->m_count[1]) < a_parVars->m_total) + { + if(a_parVars->m_count[0] >= a_parVars->m_total - a_parVars->m_minFill) + { + group = 1; + } + else + { + group = 0; + } + for(int index=0; index<a_parVars->m_total; ++index) + { + if(!a_parVars->m_taken[index]) + { + Classify(index, group, a_parVars); + } + } + } + + ASSERT((a_parVars->m_count[0] + a_parVars->m_count[1]) == a_parVars->m_total); + ASSERT((a_parVars->m_count[0] >= a_parVars->m_minFill) && + (a_parVars->m_count[1] >= a_parVars->m_minFill)); +} + + +// Copy branches from the buffer into two nodes according to the partition. +RTREE_TEMPLATE +void RTREE_QUAL::LoadNodes(Node* a_nodeA, Node* a_nodeB, PartitionVars* a_parVars) +{ + ASSERT(a_nodeA); + ASSERT(a_nodeB); + ASSERT(a_parVars); + + for(int index=0; index < a_parVars->m_total; ++index) + { + ASSERT(a_parVars->m_partition[index] == 0 || a_parVars->m_partition[index] == 1); + + if(a_parVars->m_partition[index] == 0) + { + AddBranch(&a_parVars->m_branchBuf[index], a_nodeA, NULL); + } + else if(a_parVars->m_partition[index] == 1) + { + AddBranch(&a_parVars->m_branchBuf[index], a_nodeB, NULL); + } + } +} + + +// Initialize a PartitionVars structure. +RTREE_TEMPLATE +void RTREE_QUAL::InitParVars(PartitionVars* a_parVars, int a_maxRects, int a_minFill) +{ + ASSERT(a_parVars); + + a_parVars->m_count[0] = a_parVars->m_count[1] = 0; + a_parVars->m_area[0] = a_parVars->m_area[1] = (ELEMTYPEREAL)0; + a_parVars->m_total = a_maxRects; + a_parVars->m_minFill = a_minFill; + for(int index=0; index < a_maxRects; ++index) + { + a_parVars->m_taken[index] = false; + a_parVars->m_partition[index] = -1; + } +} + + +RTREE_TEMPLATE +void RTREE_QUAL::PickSeeds(PartitionVars* a_parVars) +{ + int seed0, seed1; + ELEMTYPEREAL worst, waste; + ELEMTYPEREAL area[MAXNODES+1]; + + for(int index=0; index<a_parVars->m_total; ++index) + { + area[index] = CalcRectVolume(&a_parVars->m_branchBuf[index].m_rect); + } + + worst = -a_parVars->m_coverSplitArea - 1; + for(int indexA=0; indexA < a_parVars->m_total-1; ++indexA) + { + for(int indexB = indexA+1; indexB < a_parVars->m_total; ++indexB) + { + Rect oneRect = CombineRect(&a_parVars->m_branchBuf[indexA].m_rect, &a_parVars->m_branchBuf[indexB].m_rect); + waste = CalcRectVolume(&oneRect) - area[indexA] - area[indexB]; + if(waste > worst) + { + worst = waste; + seed0 = indexA; + seed1 = indexB; + } + } + } + Classify(seed0, 0, a_parVars); + Classify(seed1, 1, a_parVars); +} + + +// Put a branch in one of the groups. +RTREE_TEMPLATE +void RTREE_QUAL::Classify(int a_index, int a_group, PartitionVars* a_parVars) +{ + ASSERT(a_parVars); + ASSERT(!a_parVars->m_taken[a_index]); + + a_parVars->m_partition[a_index] = a_group; + a_parVars->m_taken[a_index] = true; + + if (a_parVars->m_count[a_group] == 0) + { + a_parVars->m_cover[a_group] = a_parVars->m_branchBuf[a_index].m_rect; + } + else + { + a_parVars->m_cover[a_group] = CombineRect(&a_parVars->m_branchBuf[a_index].m_rect, &a_parVars->m_cover[a_group]); + } + a_parVars->m_area[a_group] = CalcRectVolume(&a_parVars->m_cover[a_group]); + ++a_parVars->m_count[a_group]; +} + + +// Delete a data rectangle from an index structure. +// Pass in a pointer to a Rect, the tid of the record, ptr to ptr to root node. +// Returns 1 if record not found, 0 if success. +// RemoveRect provides for eliminating the root. +RTREE_TEMPLATE +bool RTREE_QUAL::RemoveRect(Rect* a_rect, const DATATYPE& a_id, Node** a_root) +{ + ASSERT(a_rect && a_root); + ASSERT(*a_root); + + Node* tempNode; + ListNode* reInsertList = NULL; + + if(!RemoveRectRec(a_rect, a_id, *a_root, &reInsertList)) + { + // Found and deleted a data item + // Reinsert any branches from eliminated nodes + while(reInsertList) + { + tempNode = reInsertList->m_node; + + for(int index = 0; index < tempNode->m_count; ++index) + { + InsertRect(&(tempNode->m_branch[index].m_rect), + tempNode->m_branch[index].m_data, + a_root, + tempNode->m_level); + } + + ListNode* remLNode = reInsertList; + reInsertList = reInsertList->m_next; + + FreeNode(remLNode->m_node); + FreeListNode(remLNode); + } + + // Check for redundant root (not leaf, 1 child) and eliminate + if((*a_root)->m_count == 1 && (*a_root)->IsInternalNode()) + { + tempNode = (*a_root)->m_branch[0].m_child; + + ASSERT(tempNode); + FreeNode(*a_root); + *a_root = tempNode; + } + return false; + } + else + { + return true; + } +} + + +// Delete a rectangle from non-root part of an index structure. +// Called by RemoveRect. Descends tree recursively, +// merges branches on the way back up. +// Returns 1 if record not found, 0 if success. +RTREE_TEMPLATE +bool RTREE_QUAL::RemoveRectRec(Rect* a_rect, const DATATYPE& a_id, Node* a_node, ListNode** a_listNode) +{ + ASSERT(a_rect && a_node && a_listNode); + ASSERT(a_node->m_level >= 0); + + if(a_node->IsInternalNode()) // not a leaf node + { + for(int index = 0; index < a_node->m_count; ++index) + { + if(Overlap(a_rect, &(a_node->m_branch[index].m_rect))) + { + if(!RemoveRectRec(a_rect, a_id, a_node->m_branch[index].m_child, a_listNode)) + { + if(a_node->m_branch[index].m_child->m_count >= MINNODES) + { + // child removed, just resize parent rect + a_node->m_branch[index].m_rect = NodeCover(a_node->m_branch[index].m_child); + } + else + { + // child removed, not enough entries in node, eliminate node + ReInsert(a_node->m_branch[index].m_child, a_listNode); + DisconnectBranch(a_node, index); // Must return after this call as count has changed + } + return false; + } + } + } + return true; + } + else // A leaf node + { + for(int index = 0; index < a_node->m_count; ++index) + { + if(a_node->m_branch[index].m_child == (Node*)a_id) + { + DisconnectBranch(a_node, index); // Must return after this call as count has changed + return false; + } + } + return true; + } +} + + +// Decide whether two rectangles overlap. +RTREE_TEMPLATE +bool RTREE_QUAL::Overlap(Rect* a_rectA, Rect* a_rectB) +{ + ASSERT(a_rectA && a_rectB); + + for(int index=0; index < NUMDIMS; ++index) + { + if (a_rectA->m_min[index] > a_rectB->m_max[index] || + a_rectB->m_min[index] > a_rectA->m_max[index]) + { + return false; + } + } + return true; +} + + +// Add a node to the reinsertion list. All its branches will later +// be reinserted into the index structure. +RTREE_TEMPLATE +void RTREE_QUAL::ReInsert(Node* a_node, ListNode** a_listNode) +{ + ListNode* newListNode; + + newListNode = AllocListNode(); + newListNode->m_node = a_node; + newListNode->m_next = *a_listNode; + *a_listNode = newListNode; +} + + +// Search in an index tree or subtree for all data retangles that overlap the argument rectangle. +RTREE_TEMPLATE +bool RTREE_QUAL::Search(Node* a_node, Rect* a_rect, int& a_foundCount, bool a_resultCallback(DATATYPE a_data, void* a_context), void* a_context) +{ + ASSERT(a_node); + ASSERT(a_node->m_level >= 0); + ASSERT(a_rect); + + if(a_node->IsInternalNode()) // This is an internal node in the tree + { + for(int index=0; index < a_node->m_count; ++index) + { + if(Overlap(a_rect, &a_node->m_branch[index].m_rect)) + { + if(!Search(a_node->m_branch[index].m_child, a_rect, a_foundCount, a_resultCallback, a_context)) + { + return false; // Don't continue searching + } + } + } + } + else // This is a leaf node + { + for(int index=0; index < a_node->m_count; ++index) + { + if(Overlap(a_rect, &a_node->m_branch[index].m_rect)) + { + DATATYPE& id = a_node->m_branch[index].m_data; + + // NOTE: There are different ways to return results. Here's where to modify + if(&a_resultCallback) + { + ++a_foundCount; + if(!a_resultCallback(id, a_context)) + { + return false; // Don't continue searching + } + } + } + } + } + + return true; // Continue searching +} + + +#undef RTREE_TEMPLATE +#undef RTREE_QUAL + +#endif //RTREE_H diff --git a/contrib/voro++/CMakeLists.txt b/contrib/voro++/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..34ce709fee6daa6bdc5b36953af95580f538b628 --- /dev/null +++ b/contrib/voro++/CMakeLists.txt @@ -0,0 +1,6 @@ +set(SRC + src/voro++.cc +) + +file(GLOB_RECURSE HDR RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.h) +append_gmsh_src(contrib/voro++ "${SRC};${HDR}") diff --git a/contrib/voro++/LICENSE b/contrib/voro++/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..7b05ace523955707b7c4c26b7ba2139218d660b7 --- /dev/null +++ b/contrib/voro++/LICENSE @@ -0,0 +1,39 @@ +Voro++ Copyright (c) 2008, The Regents of the University of California, through +Lawrence Berkeley National Laboratory (subject to receipt of any required +approvals from the U.S. Dept. of Energy). All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +(1) Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +(2) Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +(3) Neither the name of the University of California, Lawrence Berkeley +National Laboratory, U.S. Dept. of Energy nor the names of its contributors may +be used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +You are under no obligation whatsoever to provide any bug fixes, patches, or +upgrades to the features, functionality or performance of the source code +("Enhancements") to anyone; however, if you choose to make your Enhancements +available either publicly, or directly to Lawrence Berkeley National +Laboratory, without imposing a separate written license agreement for such +Enhancements, then you hereby grant the following license: a non-exclusive, +royalty-free perpetual license to install, use, modify, prepare derivative +works, incorporate into other computer software, distribute, and sublicense +such enhancements or derivative works thereof, in binary and source code form. diff --git a/contrib/voro++/Makefile b/contrib/voro++/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..01675af871a5ea3ddb14ce58dff25a9def5499df --- /dev/null +++ b/contrib/voro++/Makefile @@ -0,0 +1,72 @@ +# Voro++ makefile +# +# Author : Chris H. Rycroft (LBL / UC Berkeley) +# Email : chr@alum.mit.edu +# Date : August 30th 2011 + +# Tell make that these are phony targets +.PHONY: all help clean install uninstall + +include config.mk + +# Build all of the executable files +all: + $(MAKE) -C src + $(MAKE) -C examples + +# Build the help files (with Doxygen) +help: + $(MAKE) -C src help + +# Clean up the executable files +clean: + $(MAKE) -C src clean + $(MAKE) -C examples clean + +# Install the executable, man page, and shared library +install: + $(MAKE) -C src + $(INSTALL) -d $(IFLAGS_EXEC) $(PREFIX)/bin + $(INSTALL) -d $(IFLAGS_EXEC) $(PREFIX)/lib + $(INSTALL) -d $(IFLAGS_EXEC) $(PREFIX)/man + $(INSTALL) -d $(IFLAGS_EXEC) $(PREFIX)/man/man1 + $(INSTALL) -d $(IFLAGS_EXEC) $(PREFIX)/include + $(INSTALL) -d $(IFLAGS_EXEC) $(PREFIX)/include/voro++ + $(INSTALL) $(IFLAGS_EXEC) src/voro++ $(PREFIX)/bin + $(INSTALL) $(IFLAGS) man/voro++.1 $(PREFIX)/man/man1 + $(INSTALL) $(IFLAGS) src/libvoro++.a $(PREFIX)/lib + $(INSTALL) $(IFLAGS) src/voro++.hh $(PREFIX)/include/voro++ + $(INSTALL) $(IFLAGS) src/c_loops.hh $(PREFIX)/include/voro++ + $(INSTALL) $(IFLAGS) src/cell.hh $(PREFIX)/include/voro++ + $(INSTALL) $(IFLAGS) src/common.hh $(PREFIX)/include/voro++ + $(INSTALL) $(IFLAGS) src/config.hh $(PREFIX)/include/voro++ + $(INSTALL) $(IFLAGS) src/container.hh $(PREFIX)/include/voro++ + $(INSTALL) $(IFLAGS) src/container_prd.hh $(PREFIX)/include/voro++ + $(INSTALL) $(IFLAGS) src/rad_option.hh $(PREFIX)/include/voro++ + $(INSTALL) $(IFLAGS) src/pre_container.hh $(PREFIX)/include/voro++ + $(INSTALL) $(IFLAGS) src/unitcell.hh $(PREFIX)/include/voro++ + $(INSTALL) $(IFLAGS) src/v_base.hh $(PREFIX)/include/voro++ + $(INSTALL) $(IFLAGS) src/v_compute.hh $(PREFIX)/include/voro++ + $(INSTALL) $(IFLAGS) src/wall.hh $(PREFIX)/include/voro++ + $(INSTALL) $(IFLAGS) src/worklist.hh $(PREFIX)/include/voro++ + +# Uninstall the executable, man page, and shared library +uninstall: + rm -f $(PREFIX)/bin/voro++ + rm -f $(PREFIX)/man/man1/voro++.1 + rm -f $(PREFIX)/lib/libvoro++.a + rm -f $(PREFIX)/include/voro++/voro++.hh + rm -f $(PREFIX)/include/voro++/c_loops.hh + rm -f $(PREFIX)/include/voro++/cell.hh + rm -f $(PREFIX)/include/voro++/common.hh + rm -f $(PREFIX)/include/voro++/config.hh + rm -f $(PREFIX)/include/voro++/container.hh + rm -f $(PREFIX)/include/voro++/container_prd.hh + rm -f $(PREFIX)/include/voro++/pre_container.hh + rm -f $(PREFIX)/include/voro++/rad_option.hh + rm -f $(PREFIX)/include/voro++/unitcell.hh + rm -f $(PREFIX)/include/voro++/v_base.hh + rm -f $(PREFIX)/include/voro++/v_compute.hh + rm -f $(PREFIX)/include/voro++/wall.hh + rm -f $(PREFIX)/include/voro++/worklist.hh + rmdir $(PREFIX)/include/voro++ diff --git a/contrib/voro++/NEWS b/contrib/voro++/NEWS new file mode 100644 index 0000000000000000000000000000000000000000..1a251ef1b8f48b661e7d49abe6d743256c11d09b --- /dev/null +++ b/contrib/voro++/NEWS @@ -0,0 +1,317 @@ +Version 0.4.5 (...) +=================== +* Fixed an error in the check_facets diagnostic routine. Thanks to Tristan + Carrier-Baudouin (Université catholique de Louvain) for pointing this out. + +Version 0.4.4 (January 17th 2012) +================================= +* Fixed an error in pointer arithmetic that was introduced in version 0.4, + which would occur in cases where the delete stack was extended when a large + number of vertices were being removed. Thanks to Jeff Johnson (Lawrence + Berkeley Laboratory) and Matt Freeman (Texas A&M University) for pointing + this out. + +Version 0.4.3 (November 12th 2011) +================================== +* Removed spurious Gnuplot output line from torus.cc example +* More changes for better Visual C++ compatibility +* Fixed indexing error in worklist generation routine. This had no effect + on the generated worklists, but would become apparent in other situations. +* Added rad_option.hh to the list of files included by voro++.hh for + completeness +* Fix errors in Gnuplot commands in the basic examples README file. Thanks to + William-Fernando Oquendo (National University of Colombia) for pointing this + out. +* Fixed memory allocation issue in face_freq_table routine - thanks to Lingti + Kong for pointing this out +* Minor cleanups and optimizations to wall classes + +Version 0.4.2 (September 23rd 2011) +=================================== +* Fixed a bug in the put_remap routine where a z periodic boolean was + switched to an x periodic boolean. This would only be noticed when using + mixed periodic boundary conditions and importing particles that need to be + remapped. +* The pid function in the c_loop_base class was mistakenly labeled as double + instead of int - this is now fixed. Thanks to William-Fernando Oquendo + (National University of Colombia) for pointing this out. +* Fixed an extremely subtle bounds checking issue that would only materialize + for the radical Voronoi tessellation with large particle radii. Thanks to + Richard Martin and Maciej Haranczyk (Lawrence Berkeley Laboratory) for + pointing out the original problem. +* Fixed other problems with the radical tessellation. Originally, the + algorithms were concieved for with hard spheres in mind, where the particles + would not overlap, and an assumption was used in the cutoff procedure that + made use of this, but would not be true in general. +* Removed more bracket initializations like "double a(3);" for better + consistency, and more compatibility with older versions of MS Visual C++. + Thanks to Martin Brehm for help with this. +* Factored out the regular/radical inline routines into separate classes, so + that they don't have to be duplicated in the container_periodic classes +* Fixed problems with the container_periodic classes referencing the wrong + loop classes. Thanks to Wang Chuncheng (Nanyang Technological University) for + pointing this out. +* Added c_loop_order_periodic class for doing ordered loops with the periodic + container classes +* Updated the README file in the src directory. The detailed description of + each file has been removed since this is difficult to maintain and this + information is already present in the class reference manual. +* Fixed an error in the pre_container selection of the optimal computational + grid size +* Code comment cleanups, particularly in wall.hh +* Minor man page reformatting +* Updated Doxyfile to version 1.7.5.1 + +Version 0.4.1 (September 7th 2011) +================================== +* Fixed bug in command-line utility that would give incorrect results when + using the "-c" option for custom output. Thanks to Prof. Aldo Romero + (CINVESTAV-Unidad Queretaro) for pointing this out. +* Added some additional documentation about neighbor information + +Version 0.4 (August 30th 2011) +============================== +* New classes called container_periodic and container_periodic_poly that carry + out Voronoi computations in 3D periodic parallelepiped unit cells have been + added. This adds significant complexity to the computation, and the memory + organization of these classes is different, requiring allocation for ghost + regions. Currently these classes cannot be accessed by the command-line + utility, but will be integrated further in future releases. These classes are + currently mainly exploited by a sister software project Zeo++ for chemical + informatics (Maciej Haranczyk, Chris Rycroft, Thomas Willems, Richard Martin) + to be released in late 2011. +* As part of the new container_periodic classes, a new class called unitcell + has been added, which will compute the Voronoi cell for a single particle in + a 3D periodic parallelepiped class. The Voronoi cell is formed by the + influences of the periodic images of itself only. This turns out to be an + important component of the calculations done by the container_periodic + classes but can also be used independently. +* The container classes now have a routine called find_voronoi_cell that will + take a given position vector and return the Voronoi cell which is contained + within. For the regular Voronoi tessellation, this is just the Voronoi cell + corresponding to the closest particle (by definition). For the radical + Voronoi tessellation, this is weighted by the particle radii. +* The library is now enclosed within the "voro" namespace. This requires + specifying "using namespace voro;" in the preamble of codes or prepending + "voro::" to access functions. This greatly minimizes the possiblity of naming + conflicts when using multiple libraries, particularly since many of the + classes iin the library have fairly generic names (eg. "container"). Thanks to + Allan Johns (Dr. D Studios) for suggesting this. +* Voro++ can now be built as a static library that can be installed and linked + to. As part of this, the .cc and .hh files have been significantly revised + with some small inline functions and template code being written into the + header files. +* Previously, all of the voronoicell output routines sent data to an output + stream. However, input and output are now carried out using the STL vector + class, allowing for programs to directly link to and use Voro++ output. The + STL vector class has been chosen since it the simplest and most standard + mechanism for returning a variable amount of data. Several new examples are + provided to demonstrate this functionality, for both the voronoicell class + and the container class. +* A common issue has been that the order of particles in the output file does + not match the input file, since Voro++ internally sorts particles according + to their position. A new class called voro_order has been provided, which can + link to particles as they are stored, allowing for the Voronoi computation to + be carried out in the same order as the input file. The core computation + routines can be run with a variety of different loops, and a new example + "loops.cc" is provided to demonstrate this. +* The order of parameters to certain functions have been changed to take + advantage of the C++ default parameter mechanism wherever possible +* The container and container_poly classes are now derived from a base class, + rather than being different instances of a template. This simplifies the code + and stops common routines from being duplicated. The core Voronoi computation + routine is now held within a voro_compute class, which can be instantiated on + any container with the correct access functions. +* The voronoicell and voronoicell_neighbor classes are now derived from a + common base class, rather than being different instances of a template. This + simplifies the code and stops common routines from being duplicated. The core + nplane routine is now a function template that can be instantiated on the + parent class itself. +* All output routines have been switched from using C++ iostreams to using the C + cstdio library. This has been done for increased performance. In general the + cstdio routines run significantly faster than the comparable iostream + routines: for one file import test, using fscanf from cstdio was five times + as fast as the comparable << operator from iostream. As another example, + the program "cylinder.cc", which uses both file import and export, runs + approximately twice as fast before. Since many people use Voro++ to batch + process large numbers of input files, this increase in input/output speed + seemed desirable. +* The Gnuplot output routines now merge individual lines into contiguous paths + wherever possible, resulting in a ~15% reduction in their file size and a + noticeable improvement in rendering speed +* Previously, the POV-Ray output routines could create cylinders where the start + and end points matched. This was a benign problem, due to the fact the vertex + positions within Voro++ were held to higher precision than the POV-Ray output + file, meaning that distinct vertices could appear to be at the same position; + a perl script was provided to post-process and remove these. However, Voro++ + now scans each cylinder before saving to file to automatically remove these + cases from consideration. +* Pointer arithmetic is now used within a number of critical cell computation + routines, and gives a speedup of 10%-20% in many cases. On some typical + problems on typical machines, Voro++ currently computes around 50,000 + cells/second. New machines can achieve upwards of 70,000 cells/second. +* A new pre-container mechanism is provided, which can read in a file of + unknown length, and then make a guess at the correct computational grid size + to use. This removes the need for specifying a length scale with the + command-line utility. However, a length scale or grid decomposition can still + be manually specified. +* Removed the option to compile in single-precision. This was a highly + specialized feature, and it appears better to allow users who wish to do this + to make their own modifications. This option also conflicted with building + Voro++ as a standard static library. +* Fixed a benign bug in the block computation list that would cause it to get + extended prematurely +* Numerous small improvements to memory allocation routines +* Added routines to copy a Voronoi cell +* Created a new wall_list class to handle a list of walls. This simplifies the + command-line utility code. +* Labels in the worklist that are used in the transition from the radius search + to the block search have been optimized +* The command-line utility can now produce POV-Ray output. Also, the main loop + in the utility has been combined so that the Voronoi tessellation is only + carried out once, even if POV-Ray and Gnuplot output is also required. +* The command-line utility does range checking on the filename to prevent + buffer overruns +* The routines that put particles into a container now do so more reliably for + periodic cases, remapping them into the primary domain if necessary +* A number of the POV-Ray header files have been altered to directly make use + of a right-handed coordinate system in which the z axis points upwards. This + matches the Gnuplot style, and the style used in many scientific simulations. + It avoids the need for a rotation or matrix transformation when rendering + many of the particle packings. Some of the test particle packings have been + transformed to ensure consistency with previous renderings. +* Some POV-Ray files have been cleaned up and there are additional comments +* Fixed a bug in the print_all_custom() routine, affecting "%P" output. Thanks + to David Waroquiers (Université Catholique de Louvain, Belgium) for pointing + this out. +* Fixed a bug that caused the neighbor list not to be outputted in the same + order as the other plane diagnostic routines. Thanks to Olufemi Olorode + (Texas A&M University) for pointing this out. +* Removed the add_vertex() and init_test() routines, which were mainly used for + debugging +* Updated Doxyfile to version 1.7.4 + +Version 0.3.1 (September 29, 2009) +================================== +* Carried out a major overhaul of the source code comments that are used by + Doxygen. Several errors in the documentation were fixed. +* Additional comments in the Makefiles, and added the "phony target" keyword +* Many code cleanups and standardizations. Some double and triple loops + were concatenated into one to reduce the amount of indentation. +* Fixed the import.cc example program +* Updated Doxyfile to version 1.6.1 + +Version 0.3 (August 17, 2009) +============================= +* In response to feedback from several people, the routines for computing + statistics about computed Voronoi cells have been significantly revised, + extended, and put within a common framework. The voronoicell class now has a + large number of routines of the form output_...() that will print cell + information to an output stream. There are also a number of new, simple + routines for computing basic statistics such as the number of edges and faces + of each cell. All of these routines can now be used during the container + analysis, by making use of the new print_custom() routine, which can output + according to a given format string, that uses control sequences similar to + the standard C printf() routine. +* Renamed the "radical" example directory to "custom", and added two + new programs called "cell_statistics.cc" and "custom_output.cc" for + demonstrating the new output routines for the voronoicell and container + classes respectively +* Added a routine for computing the centroid of a Voronoi cell +* Added new routines for computing neighbor normals, in response to a + request from Dave Greenwood +* Removed unnecessary trailing tabs and spaces in the source code +* Fixed a few text justification problems, and altered some of the comments + in the example programs +* Improved the command-line utility, allowing it to specify custom information + in the output. Implemented better error checking on command-line arguments. +* Removed the facets() routine, since this has been superseded by the new + output_...() routines. This also rendered some functions in the neighbor_none + and neighbor_track classes obsolete, and they have also been removed. +* Some reorganization of the cell.hh and container.hh header files to group + similar functions together +* Added torus.cc example that shows how to write custom walls as derived + classes +* Updated Doxyfile to version 1.5.9 + +Version 0.2.7 (March 25, 2009) +============================== +* Added some missing cstdlib and cstring header files that cause compilation + errors on some systems +* Some text cleanups in the main README file and cmd_line.cc +* The worklist_gen.pl script was in DOS format. It has been switched to Unix + format to match the rest of the code. +* Fixed some incorrect inequalities in degenerate2.cc +* Improved some error messages in container.cc + +Version 0.2.6 (March 23, 2009) +============================== +* Significantly improved the error messages generated by the code. It now + makes use of the exit() routine rather than throwing errors, and it returns + various status codes (defined in config.hh) for different types of abnormal + behavior. +* Changed two occurences of "cin" to "cout" in the draw_particles routines +* Corrected error in comment in the tetrahedron example +* Minor comment cleanups of the worklist_gen.pl script +* Updated Doxyfile to version 1.5.8 +* Added a routine print_facet_information() in response to a problem + from Hengxing Lan +* Many of the cell based statistics routines (like number_of_faces() and + facets()) internally track their progress by temporarily flipping the edge + table entries to negative values, so that they know where they have already + been. The common code that was used at the end of each of these functions for + resetting the edges back to positive has now been made into a private inline + function called reset_edges(). +* Fixed a missing initialization of max_radius to zero in the radius_poly + class. This should not have ever caused any errors, as max_radius would + always have been big enough. However if max_radius was initially set to a + large value, it could have potentially made the code run slower. +* Fixed the code layout in the suretest class header +* Added some additional checks in the command-line utility to screen out + invalid command-line arguments. Switched the test on the number of + computational blocks to use floating point arithmetic, because integers + could potentially overflow and become negative. +* Included several more of the POV-Ray header files that were used to create + the example images on the website +* Removed a "cout" statement in the wall_cone class +* Cleanup of the README files for the basic examples and the wall examples + +Version 0.2.5 (January 1, 2009) +=============================== +* Added the DOE acknowledgements to the code overview document + +Version 0.2.4 (December 14, 2008) +================================= +* Added the code overview PDF document to the package, in the docs directory +* Fixed some spelling errors in the comments +* Many more documentation updates + +Version 0.2.3 (December 9, 2008) +================================ +* Removed an unused variable that was reported by the Portland C compiler +* Documentation updates +* Added the import.pov script +* Added some simple functions to solve the problem from Stefan Eibl of counting + faces +* Renamed the facets_loop to voropp_loop + +Version 0.2.2 (November 19, 2008) +================================= +* Main README file updated + +Version 0.2.1 (November 3, 2008) +================================ +* Much more documentation +* Brief Doxygen class comments +* Updated Doxyfile to version 1.5.7 + +Version 0.2 (October 31, 2008) +============================== +* Updated some occurrences of char* with const char* for compatability with + version 4.2 of the GNU C++ compiler +* Making use of default parameters in the wall classes +* The command-line utility can now add walls + +Version 0.1 (August 22, 2008) +============================= +* Initial version uploaded to the web diff --git a/contrib/voro++/README b/contrib/voro++/README new file mode 100644 index 0000000000000000000000000000000000000000..338ebcb32118b5f16fe0a7e5bee2999852add5ec --- /dev/null +++ b/contrib/voro++/README @@ -0,0 +1,153 @@ +Voro++, a 3D cell-based Voronoi library (http://math.lbl.gov/voro++/) +By Chris H. Rycroft (UC Berkeley / Lawrence Berkeley Laboratory) +================================================================ +Voro++ is a software library for carrying out three-dimensional computations +of the Voronoi tessellation. A distinguishing feature of the Voro++ library +is that it carries out cell-based calculations, computing the Voronoi cell +for each particle individually, rather than computing the Voronoi +tessellation as a global network of vertices and edges. It is particularly +well-suited for applications that rely on cell-based statistics, where +features of Voronoi cells (eg. volume, centroid, number of faces) can be +used to analyze a system of particles + +Voro++ comprises of several C++ classes that can be built as a static library +and linked to. A command-line utility is also provided that can analyze text +files of particle configurations and use most of the features of the code. +Numerous examples are provided to demonstrate the library's features and all of +these are discussed in detail on the library website. + + +Compilation - Linux / Mac OS / Windows with Cygwin +================================================== +The code is written in ANSI C++, and compiles on many system architectures. The +package contains the C++ source code, example files, miscellaneous utilities +and documentation. On Linux, Mac OS, and Windows (using Cygwin), the +compilation and installed can be carried out using GNU Make. + +To begin, the user should review the file "config.mk" in the top level +directory, to make sure that the compilation and installation settings are +appropriate for their system. Typing "make" will then compile the static +library, command-line utility, and examples. The command-line utility and +library will appear within the "src" directory. + +Following successful compilation, the library, command-line utility, and +documentation can be installed by typing "sudo make install". By default, the +program files are installed into /usr/local, and it may be necessary to modify +your environment variables in order to access the installed files: + +- to use the command-line utility, the variable PATH should contain + /usr/local/bin. +- to access the Voro++ man page, the variable MANPATH should contain + /usr/local/man. +- to access the Voro++ header files, code compilation should include + the flag '-I/usr/local/include/voro++'. +- to link to the static library, code compilation should include the + flags '-L/usr/local/lib' to tell the linker where to look, and then + '-lvoro++' to link to the library. + +The library website contains additional notes on setting environment variables, +and many guides are available on the Internet. + +The code can later be uninstalled with "sudo make uninstall". It is also +possible to use the library and command-line utility without installation by +calling the files directly once they have been compiled. On systems where the +user does not have root privileges to install into /usr/local, the "config.mk" +file can be modified to install into the user's home directory by setting +PREFIX=$(HOME). Voro++ supports parallel compilation by using the "make -j <n>" +command where n is the number of threads. + + +Compilation - Windows without Cygwin +==================================== +On a Windows machine without a terminal environment like Cygwin, it is possible +to import and compile the library in many standard C++ development +environments. Users have reported success in building the library with +Microsoft Visual C++ Express and Code::Blocks. + + +Related programs +================ +No external dependencies are required to compile and run the code, but several +programs may be useful for analyzing the output: + +- The freeware plotting program Gnuplot (available at www.gnuplot.info) can be + used for rapid 2D and 3D visualization of the program output. + +- The freeware raytracer POV-Ray (available at www.povray.org) can be used for + high-quality renderings of the program output. + +- The reference manual is generated from comments in the source code using + Doxygen (available at www.doxygen.org). This package is only required if the + library files are being developed and the reference manuals need to be + regenerated. The complete reference manual to the current code is available + online at http://math.lbl.gov/voro++/doc/refman/ + + +Contents +======== +examples - many documented examples making use of the library +html - an HTML-based reference manual (generated by Doxygen) +man - contains the man page that is installed with the program +scripts - miscellaneous helper scripts +src - source code files + + +Usage +===== +Voro++ is released as free software through the Lawrence Berkeley National +Laboratory - a detailed copyright notice is provided below, and the complete +terms of the license can be found in the LICENSE file. + +I am very interested to hear from users of the software, so if you find this +useful, please email me at chr@alum.mit.edu. Also, if you plan to publish an +academic paper using this software, please consider citing one of the following +publications: + +- Chris H. Rycroft, "Voro++: A three-dimensional Voronoi cell library in C++", + Chaos 19, 041111 (2009). + +- Chris H. Rycroft, Gary S. Grest, James W. Landry, and Martin Z. Bazant, + "Analysis of Granular Flow in a Pebble-Bed Nuclear Reactor", + Phys. Rev. E 74, 021306 (2006). + +- Chris H. Rycroft, "Multiscale Modeling in Granular Flow", PhD thesis + submitted to the Massachusetts Institute of Technology, September 2007. + (http://math.berkeley.edu/~chr/publish/phd.html) + +The first reference contains a one-page overview of the library. The second +reference contains some of the initial images that were made using a very early +version of this code, to track small changes in packing fraction in a large +particle simulation. The third reference discusses the use of 3D Voronoi cells, +and describes the algorithms that were employed in the early version of this +code. Since the publication of the above references, the algorithms in Voro++ +have been significantly improved, and a paper specifically devoted to the +current code architecture will be published during 2012. + + +Copyright Notice +================ +Voro++ Copyright (c) 2008, The Regents of the University of California, through +Lawrence Berkeley National Laboratory (subject to receipt of any required +approvals from the U.S. Dept. of Energy). All rights reserved. + +If you have questions about your rights to use or distribute this software, +please contact Berkeley Lab's Technology Transfer Department at TTD@lbl.gov. + +NOTICE. This software was developed under partial funding from the U.S. +Department of Energy. As such, the U.S. Government has been granted for itself +and others acting on its behalf a paid-up, nonexclusive, irrevocable, worldwide +license in the Software to reproduce, prepare derivative works, and perform +publicly and display publicly. Beginning five (5) years after the date +permission to assert copyright is obtained from the U.S. Department of Energy, +and subject to any subsequent five (5) year renewals, the U.S. Government is +granted for itself and others acting on its behalf a paid-up, nonexclusive, +irrevocable, worldwide license in the Software to reproduce, prepare derivative +works, distribute copies to the public, perform publicly and display publicly, +and to permit others to do so. + + +Acknowledgments +=============== +This work was supported by the Director, Office of Science, Computational and +Technology Research, U.S. Department of Energy under Contract No. +DE-AC02-05CH11231. diff --git a/contrib/voro++/config.mk b/contrib/voro++/config.mk new file mode 100644 index 0000000000000000000000000000000000000000..4f74162a83a83b107a0126f69ac9b01d81e4b483 --- /dev/null +++ b/contrib/voro++/config.mk @@ -0,0 +1,30 @@ +# Voro++, a 3D cell-based Voronoi library +# +# Author : Chris H. Rycroft (LBL / UC Berkeley) +# Email : chr@alum.mit.edu +# Date : August 28th 2011 + +# This a common configuration file that includes definitions used by all +# the Makefiles. + +# C++ compiler +CXX=g++ + +# Flags for the C++ compiler +CFLAGS=-Wall -ansi -pedantic -O3 + +# Relative include and library paths for compilation of the examples +E_INC=-I../../src +E_LIB=-L../../src + +# Installation directory +PREFIX=/usr/local + +# Install command +INSTALL=install + +# Flags for install command for executable +IFLAGS_EXEC=-m 0755 + +# Flags for install command for non-executable files +IFLAGS=-m 0644 diff --git a/contrib/voro++/examples/Makefile b/contrib/voro++/examples/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..dc289f5e744362bab813907f068e36974f54e4fe --- /dev/null +++ b/contrib/voro++/examples/Makefile @@ -0,0 +1,36 @@ +# Voro++ makefile +# +# Author : Chris H. Rycroft (LBL / UC Berkeley) +# Email : chr@alum.mit.edu +# Date : August 30th 2011 + +# Makefile rules +all: ex_basic ex_walls ex_custom ex_extra ex_degenerate ex_interface + +ex_basic: + $(MAKE) -C basic + +ex_walls: + $(MAKE) -C walls + +ex_custom: + $(MAKE) -C custom + +ex_extra: + $(MAKE) -C extra + +ex_degenerate: + $(MAKE) -C degenerate + +ex_interface: + $(MAKE) -C interface + +clean: + $(MAKE) -C basic clean + $(MAKE) -C walls clean + $(MAKE) -C custom clean + $(MAKE) -C extra clean + $(MAKE) -C degenerate clean + $(MAKE) -C interface clean + +.PHONY: all ex_basic ex_walls ex_custom ex_extra ex_degenerate clean diff --git a/contrib/voro++/examples/README b/contrib/voro++/examples/README new file mode 100644 index 0000000000000000000000000000000000000000..c00d68c69e5cf86ef17a66551f3ec528f4095b21 --- /dev/null +++ b/contrib/voro++/examples/README @@ -0,0 +1,29 @@ +Voro++ example directory +======================== +These directories contain example programs that make use of the Voro++ code, +and they are divided into six sections: + +basic - this contains several simple scripts that introduce this basic classes +and carry out simple operations, such as constructing a single cell, or making +a Voronoi tessellation for a small number of a random particles in a box. + +walls - these programs demonstrate the use of wall objects, to calculate the +Voronoi cells in non-standard geometries. + +custom - these programs demonstrate how to customize the output of the library +to contain a variety of different statistics about the computed Voronoi cells. +The radical tessellation for a polydisperse packing of particles is also +demonstrated. + +interface - these programs demonstrate features of the library's C++ interface. + +extra - this contains miscellaneous additional applications of the library for +non-standard usage. It also includes an example of using a wall object to +approximately deal with a case of an irregular boundary. + +degenerate - these codes demonstrate cases when "degenerate" vertices of order +bigger than 3 are created, when the cutting planes are aligned to existing +vertices within the numerical tolerance. + +timing - these programs and scripts can be used to test the performance of the +code under different configurations. diff --git a/contrib/voro++/examples/basic/Makefile b/contrib/voro++/examples/basic/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..0b042f986d8a8b8c71b04ff8a4b693b0a6f13d13 --- /dev/null +++ b/contrib/voro++/examples/basic/Makefile @@ -0,0 +1,31 @@ +# Voro++ makefile +# +# Author : Chris H. Rycroft (LBL / UC Berkeley) +# Email : chr@alum.mit.edu +# Date : August 30th 2011 + +# Load the common configuration file +include ../../config.mk + +# List of executables +EXECUTABLES=single_cell platonic random_points import + +# Makefile rules +all: $(EXECUTABLES) + +single_cell: single_cell.cc + $(CXX) $(CFLAGS) $(E_INC) $(E_LIB) -o single_cell single_cell.cc -lvoro++ + +platonic: platonic.cc + $(CXX) $(CFLAGS) $(E_INC) $(E_LIB) -o platonic platonic.cc -lvoro++ + +random_points: random_points.cc + $(CXX) $(CFLAGS) $(E_INC) $(E_LIB) -o random_points random_points.cc -lvoro++ + +import: import.cc + $(CXX) $(CFLAGS) $(E_INC) $(E_LIB) -o import import.cc -lvoro++ + +clean: + rm -f $(EXECUTABLES) + +.PHONY: all clean diff --git a/contrib/voro++/examples/basic/README b/contrib/voro++/examples/basic/README new file mode 100644 index 0000000000000000000000000000000000000000..b8da51075ad02131f64ce7234b6f129d12d2ba34 --- /dev/null +++ b/contrib/voro++/examples/basic/README @@ -0,0 +1,44 @@ +Voro++ basic example codes +========================== +These programs demonstrate some basic usage of the Voro++ library. + +1. single_cell.cc introduces the basic voronoicell class. It creates a simple +cell by cutting it with a number of random planes. It outputs the cell to a file +called single_cell.gnu, which can be visualized in gnuplot using the following +commands: + +set style data lines +splot 'single_cell.gnu' + +2. platonic.cc uses the voronoicell class to make the five Platonic solids, +which are output to files that can be visualized in gnuplot. + +3. random_points.cc introduces the container class, for holding particle +positions in a box. After creating a container, it adds a small number of +random points to the box. It then calculates the sum of the volumes of the +Voronoi cells, and compares it to the container volume - since the cells should +perfectly partition the container, these two should be identical to within +numerical accuracy. The code then saves the particle positions to +"random_points_p.gnu" and the Voronoi cells to "random_points_v.gnu". These can +be visualized in gnuplot using the command: + +splot 'random_points_p.gnu' u 2:3:4 with points, 'random_points_v.gnu' with lines + +4. import.cc demonstrates the ability of the code to import a list of particles +from a text file. The code imports a text file called 'pack_ten_cube' which +contains a thousand particles in a cube of side length 10. Each line of this +file has the form: + +<Numerical ID> <x coordinate> <y coordinate> <z coordinate> + +The code imports the particles into the container, and then saves the particles +and Voronoi cells in gnuplot and POV-Ray formats. To visualize the particles in +gnuplot, use the command: + +splot 'pack_ten_cube' u 2:3:4 with points, 'pack_ten_cube.gnu' with lines + +To create a POV-Ray rendering of the particles, the scene header file +import.pov must be used, which includes the output from the program. To render +an 800x600 image with antialiasing, use the command: + +povray +W800 +H600 +A0.01 +Oimport.png import.pov diff --git a/contrib/voro++/examples/basic/import.cc b/contrib/voro++/examples/basic/import.cc new file mode 100644 index 0000000000000000000000000000000000000000..0f5662686d7a38f06e57278421fe2f0656c5d782 --- /dev/null +++ b/contrib/voro++/examples/basic/import.cc @@ -0,0 +1,36 @@ +// File import example code +// +// Author : Chris H. Rycroft (LBL / UC Berkeley) +// Email : chr@alum.mit.edu +// Date : August 30th 2011 + +#include "voro++.hh" +using namespace voro; + +// Set up constants for the container geometry +const double x_min=-5,x_max=5; +const double y_min=-5,y_max=5; +const double z_min=0,z_max=10; + +// Set up the number of blocks that the container is divided into +const int n_x=6,n_y=6,n_z=6; + +int main() { + + // Create a container with the geometry given above, and make it + // non-periodic in each of the three coordinates. Allocate space for + // eight particles within each computational block + container con(x_min,x_max,y_min,y_max,z_min,z_max,n_x,n_y,n_z, + false,false,false,8); + + //Randomly add particles into the container + con.import("pack_ten_cube"); + + // Save the Voronoi network of all the particles to text files + // in gnuplot and POV-Ray formats + con.draw_cells_gnuplot("pack_ten_cube.gnu"); + con.draw_cells_pov("pack_ten_cube_v.pov"); + + // Output the particles in POV-Ray format + con.draw_particles_pov("pack_ten_cube_p.pov"); +} diff --git a/contrib/voro++/examples/basic/import.pov b/contrib/voro++/examples/basic/import.pov new file mode 100644 index 0000000000000000000000000000000000000000..f6a5ce2dae9209c5430946c707e228da3f36acfe --- /dev/null +++ b/contrib/voro++/examples/basic/import.pov @@ -0,0 +1,35 @@ +#version 3.6; + +// Right-handed coordinate system in which the z-axis points upwards +camera { + location <30,-50,25> + sky z + right -0.24*x*image_width/image_height + up 0.24*z + look_at <0,0,4.5> +} + +// White background +background{rgb 1} + +// Two lights with slightly different colors +light_source{<-8,-20,30> color rgb <0.77,0.75,0.75>} +light_source{<25,-12,12> color rgb <0.38,0.40,0.40>} + +// Radius of the Voronoi cell network +#declare r=0.08; + +// Radius of the particles +#declare s=0.5; + +// Particles +union{ +#include "pack_ten_cube_p.pov" + pigment{rgb 0.95} finish{reflection 0.1 specular 0.3 ambient 0.42} +} + +// Voronoi cells +union{ +#include "pack_ten_cube_v.pov" + pigment{rgb <1,0.4,0.45>} finish{specular 0.5 ambient 0.42} +} diff --git a/contrib/voro++/examples/basic/pack_ten_cube b/contrib/voro++/examples/basic/pack_ten_cube new file mode 100644 index 0000000000000000000000000000000000000000..6f3f3945ae15441b08f43dcffffc3bd5618ed404 --- /dev/null +++ b/contrib/voro++/examples/basic/pack_ten_cube @@ -0,0 +1,1000 @@ +23 1.777747557 -3.492096799 0.4999833772 +9 -1.504573524 4.5003357507 0.499881119 +14 -3.593346295 -4.079478798 0.4996447752 +16 -2.504448341 4.5004712224 0.4999803344 +10 -3.579038981 -0.110447005999999 0.4997721172 +8 -4.5000910941 2.497038418 0.4999033242 +18 -0.892068133 -1.124158881 0.4999412306 +11 -4.5007521028 4.4964495223 0.499349178 +17 2.496184614 3.63520192 1.3650818592 +7 3.500609988 4.5002518564 0.4995491064 +12 -2.670897425 0.385134808 0.4996563098 +19 4.130861187 -2.031997472 1.3420844832 +13 -4.4994016039 -0.502308366 0.4996701882 +6 3.634643031 1.868396401 0.4995850472 +21 0.495264667999999 4.5003315776 0.4998162976 +20 2.612941495 -2.942271588 0.4999589272 +5 3.410513879 -2.716031302 1.2309531604 +1 1.855321249 -0.697359048 0.4998681664 +3 1.492483294 2.701456337 0.4999731858 +2 -2.004772133 3.634556374 0.4999603508 +24 3.494539851 0.878346363 0.4998479288 +15 -3.593218603 -3.07978668 0.4997078944 +22 1.296120489 -1.525888167 0.498931062 +4 -2.965881239 -4.500569906 1.1540947224 +33 2.699604467 -1.232172013 0.4998971756 +31 -1.004070822 4.5000802154 1.365885387 +48 0.995216749 3.63429996 0.4997774642 +41 4.500214804 0.368378753 0.4999298238 +36 -4.5005298974 0.497388109 0.4995623988 +28 -1.210613696 -4.500396777 0.4997212104 +44 0.841361402 -4.50011141 0.4999100322 +42 3.506519854 -3.390711975 0.4995787316 +47 0.495526024 3.634097707 1.365928512 +38 -0.0244284950000004 -2.905790942 0.4994271714 +46 -3.949344308 -4.500313615 1.3338999244 +39 4.500720286 2.367827033 0.4996029004 +30 -0.705081046 -3.638151806 0.4995762636 +35 4.500116126 3.500099301 0.499782779 +37 0.777966276999999 -3.502235602 0.499960099 +25 -3.579944942 2.888322594 0.500023417 +32 -1.711925821 -3.632955825 0.49997382 +27 -0.00470451999999977 3.634687389 0.4999528096 +45 1.260617033 -2.584861871 0.49997382 +40 1.01129435 1.005628177 0.4997598924 +26 -1.0045196 3.634691976 0.4993728864 +29 3.635551758 2.868165015 0.499953135 +43 -0.50464489 4.5004659768 0.4997416176 +34 4.50004539 2.933594663 1.3237734196 +53 3.500139667 -4.500042015 0.499974295 +61 4.500151467 0.895418571 1.3803060668 +59 -3.246288172 3.830518911 0.4996174914 +71 4.500304424 4.500089931 0.499564145 +70 -0.158606368 -4.500008857 0.4998872312 +49 1.341105719 -4.500230172 1.365996031 +56 2.494542208 4.5006202551 0.499429341 +50 3.637530743 -0.136830733 0.499908515 +69 -2.210299451 -4.500076456 0.4996615122 +67 -2.711808232 2.384844711 0.4995786946 +55 -1.811976822 1.817448551 0.4999563366 +57 2.688580494 1.838608993 0.8205807256 +51 1.710861975 0.291709271999999 0.499505978 +64 -4.4812325308 3.496714039 0.4998743278 +52 2.503588045 2.76715736 0.499479061 +68 -4.5001843169 -1.502057664 0.4998231866 +62 -4.5001178548 -4.500587194 0.49963454 +60 -2.736305691 -2.562451455 0.4991955282 +65 -4.5002010247 1.4972494 0.4995872804 +54 1.841558913 -4.498511809 0.49997382 +66 4.500069843 -4.500076453 0.4997955272 +58 -0.504977848 2.76901692 0.4997757722 +63 2.996851285 3.636710386 0.4996950258 +72 -2.712988674 1.384654202 0.4998680854 +82 4.500287117 -1.641758177 0.4993995768 +87 -3.580218361 1.888721627 0.499693982 +78 4.130169439 -2.570692439 0.4994981638 +92 4.500259802 -3.500135416 0.4999033004 +77 0.494756016 2.768820502 0.4996955318 +74 2.003045388 -1.378555139 1.2170813804 +93 -2.708534174 3.207675447 1.0678208324 +81 1.495024384 4.5001698629 0.4997080546 +95 0.633004209 -2.808436977 1.2462371128 +79 -1.504843748 2.768860181 0.4997729994 +96 -4.5003281499 -2.501635229 0.499386617 +91 4.500389849 4.5002917992 1.4991542496 +89 4.500208985 1.36815892 0.4996067374 +94 2.495136557 0.911856452 0.4995224186 +90 -2.712338356 -3.568244486 0.49997382 +85 -4.4987421448 -0.00233840299999954 1.3655003356 +83 3.766877984 3.766931671 1.1248614478 +73 -0.684847553 -4.500064627 1.3501098464 +75 -3.58040719 -1.110081582 0.4999535498 +88 0.995403566 4.5001783001 1.3656873432 +86 2.446839006 -4.500229587 1.2963521604 +76 -0.00435931400000023 4.5001105015 1.3659861412 +84 2.639791263 -0.0775123239999997 0.4996600504 +80 4.500452682 -0.641528804 0.4996760284 +106 4.211839246 1.394959232 2.197062694 +116 -1.710473549 -4.227311273 1.3216228844 +107 0.0941037260000002 -0.94456352 0.4991886178 +98 -4.5002660347 3.979923517 1.3750259878 +101 2.997558649 4.5001802284 1.3633823704 +105 -1.812641939 -2.179851109 0.4998001296 +103 2.671453487 -3.940487596 0.4993790516 +108 0.91130271 -0.368489469 0.4999002862 +119 -1.890096007 -1.182957596 0.4995949714 +114 -4.5004553765 -1.002117033 1.3656490896 +115 4.500031621 1.896596281 1.3814991902 +104 -0.767264107 0.81918975 0.4999102538 +117 -4.5001162131 -3.501093176 0.499877364 +97 -4.5006343585 -3.679862011 1.4835837344 +99 -3.261197572 0.392705993 1.3063596088 +120 0.421595997000001 -2.010787226 0.4999765368 +102 4.500284972 -2.960886587 1.3418948266 +100 -0.812303012 1.817821788 0.499505001 +109 3.278430681 -2.047177263 0.499730762 +112 2.802184805 -3.494420012 1.3846319146 +113 1.995426386 3.62883435 0.4996833242 +118 -4.500281243 0.997410902 1.3651986086 +110 -1.767180584 0.812667594 0.4995394068 +111 -3.603484861 -2.094871991 0.6703225308 +127 2.140523091 -2.061175684 0.4996442096 +126 -0.576463007 -2.072604187 0.4993084496 +141 -0.0313528619999994 -3.581744633 1.2358153446 +133 1.995260637 4.500371952 1.3654872112 +137 -4.5001839683 -2.672437967 1.484272491 +124 3.667146964 -1.141442717 0.7344138754 +129 1.750572668 1.71020664 0.4996383334 +135 1.765489562 0.999828323 1.2030925006 +123 0.698631663 -1.228974698 1.243191352 +144 -3.581020005 0.889141449 0.4996759462 +140 -1.645382879 2.900072086 2.031263698 +134 0.238727658 0.371198172 0.499697031 +125 -3.695426488 4.5003383969 1.090343807 +131 -4.3168225703 1.996864452 1.3461892288 +132 -1.226514515 -1.761951501 1.193650347 +142 3.069250797 2.817005969 1.3224607634 +143 -1.808378593 -0.186378457 0.4998849562 +136 -1.501375607 3.632677896 1.366387764 +138 -4.5003096549 -4.50000161 2.168133636 +128 -2.003804301 4.5000235884 1.3661159716 +121 -1.134544705 -2.814756391 0.8696309272 +130 1.996608137 2.769331423 1.3609315758 +139 4.280009854 3.653156508 1.981972591 +122 3.182500997 -4.495087451 1.9735000802 +156 -2.71233203 -0.613908198999999 0.4998614262 +151 -2.255435742 -4.500084897 2.114410936 +149 2.173441932 0.101653963 1.3656702836 +146 -3.561981699 1.342475677 1.3906297338 +162 -2.059640522 2.42311195 1.2563787496 +158 -3.526923035 -3.462068954 1.4210739232 +157 -0.603843041 -0.167041875000001 0.499967501 +168 -4.4976438421 2.979942081 1.3755233632 +155 3.63408854 0.3957996 1.3643386924 +145 0.0754208270000003 1.35776895 0.4998093568 +153 -3.662134043 -1.531565572 1.4942674356 +161 4.50046085 -4.50061776 1.4996214942 +148 -0.300329123 0.513236683000001 1.3294805396 +152 3.634464185 1.395822741 1.3806850922 +163 -3.053859523 -2.448390049 1.4398418208 +154 -0.265167837 -1.494226064 1.25251521 +150 4.500179583 2.471009293 2.210236748 +164 -3.616523335 -0.536800793999999 1.403396945 +167 -1.265489684 0.291831187 1.1901975712 +165 0.849230963999999 1.915537289 0.8801813144 +166 4.500265854 -3.66604119 2.049991876 +159 -3.976947411 4.500062613 2.049832606 +160 1.495412568 3.634404282 1.365473769 +147 1.030055693 0.322907859 1.2308602108 +171 -2.317534663 1.470039517 1.4142359414 +174 -2.084524488 -2.96042299 1.144455757 +183 -0.621796841 -0.346885018 1.7246326334 +173 -3.632010846 3.484374545 1.354638395 +192 3.689981903 4.5003333236 2.084319288 +182 0.341176119 -4.500264821 1.3660463856 +187 -2.317546595 3.738350032 1.9332114072 +169 -1.418091529 -0.720567794 1.2496502312 +189 -2.265379793 0.0608718990000003 1.3542777464 +190 2.034900038 -2.683768129 1.2747548346 +177 -0.503786356 4.5001552217 2.232299622 +180 -1.049079218 2.372949286 1.296765799 +188 3.690967475 -3.945824515 1.3103487146 +178 3.282014766 3.593558621 1.9817586164 +179 -0.461787573 1.408622673 1.74363394 +191 -0.323480439 -2.504356536 1.365036985 +170 0.854753563 -4.500284139 2.267274804 +172 -2.753903301 -1.584923616 0.8020130848 +185 -2.573607983 -3.700017679 1.60595243 +175 -0.502908707 3.580274365 1.3652348842 +181 4.500012277 -2.687753003 2.30384576 +184 -3.943627367 0.498900728000001 2.029374094 +176 4.499850483 -0.104376991000001 1.3810178372 +186 1.437726468 -0.574320216999999 1.40004188 +213 -0.0976026660000002 2.11203256 1.1337010554 +214 0.392312953 -1.980956817 1.826852113 +210 -0.990210471 -3.562132264 1.5181266224 +199 2.022282108 -2.002256417 2.00904205 +212 1.819362169 -3.633034126 1.5029243416 +202 -1.309506163 1.333791989 1.2191527316 +198 1.325311624 -2.83082991 1.9671561974 +197 1.269748303 -2.044776016 1.3523619866 +208 -0.185169608 -4.144877282 2.139863712 +207 -1.275751328 -2.53943922 1.8205217068 +193 -2.932693934 4.5007005685 1.7353248614 +203 3.030920623 -0.584074115 1.2677265098 +196 4.499884569 -0.0162513410000003 3.15720918 +206 2.771337973 0.897436633 1.4601604012 +211 2.576331928 2.061831686 1.7883802418 +194 -1.257008405 -4.500012931 2.170182048 +200 0.995816812 2.768424279 1.3810452308 +195 0.495985162 4.5001679697 2.231810466 +216 2.284791612 -0.724089899 1.9184577632 +204 2.746083369 -2.691260395 1.9775348552 +205 -4.5000352646 -0.276885755 2.32679172 +201 2.84520848 -1.890208139 1.3872109968 +215 0.262135113999999 -0.316524595 1.2586576224 +209 1.996035729 3.634882499 2.23082913 +240 -3.230497328 2.284759836 1.348379412 +231 1.481117548 -4.500065801 3.046688492 +225 4.500320741 -1.10410475 1.3859997494 +235 3.576167709 -1.290386258 1.7188783698 +238 2.498421541 4.4995242839 2.22956777 +224 -1.775888214 -3.358314928 2.101862236 +239 0.47634328 1.140205177 1.3894778276 +230 -1.78598231 0.774267898 1.8970256626 +221 -2.668366269 -0.846827915 1.4712391412 +232 -4.1611452534 1.462931492 2.181899866 +229 -4.0557037128 -3.176904996 2.22394784 +220 -0.830430341 0.519886315 2.177344696 +237 -1.889867853 -1.202487026 1.9880344432 +233 -0.892318192 -1.269949654 1.997448484 +217 1.557519304 1.899924518 1.5852360964 +219 3.569595418 2.217510905 1.946834384 +234 -3.310861252 -4.211408229 2.046926432 +227 -2.151780487 -2.018247931 1.4724039644 +226 0.157910516 0.668294419 2.211336888 +218 0.0366332099999997 2.853725871 1.790630227 +236 0.842645457 -3.668571901 1.7128028854 +228 1.288669767 -1.323783531 2.044946728 +222 1.946633935 -4.500424222 2.161808896 +223 4.500061612 0.39635578 2.24656381 +248 0.114008786 -0.961123707 2.008527708 +245 3.615938247 -2.238928523 2.173689456 +249 2.867698366 -1.595590791 2.354541452 +259 3.134973217 1.373524021 2.260639338 +263 2.77971978 0.180387241 2.156809096 +255 -0.190266819 -3.145067502 2.121078486 +264 4.500263573 -0.694555401 2.362729858 +260 -1.612839289 1.902020798 1.9835160558 +242 1.173505203 0.871725746 2.054097222 +256 -2.79259332 -4.197787507 2.901796974 +241 3.622598914 -0.343689999 2.037181602 +253 4.082967441 -4.500739127 2.408140654 +246 0.737341444 -0.141696229 2.120953014 +251 -4.500018223 4.4995642996 2.902082526 +261 -2.862620643 -1.663944394 2.079790078 +243 -0.155773676 -0.199229292 2.59686147 +262 1.487183913 -3.672365345 2.481849414 +257 2.038885853 -2.846844354 2.666936934 +254 -3.060976866 -3.076882855 2.217388824 +252 -4.5003222607 -1.798407794 1.969946276 +247 4.500416579 4.4865323259 2.66933217 +250 1.714293333 0.0275625509999999 2.250898994 +258 0.995958743999999 3.634169969 2.231693794 +244 2.098864228 1.245782293 2.113027318 +283 -1.503672472 4.5000223677 2.23203126 +286 -3.262303978 3.715763007 2.259421124 +266 4.500262885 -1.990539132 3.153037236 +277 1.68240875 2.688525586 2.30660506 +279 -2.771431399 0.846515226999999 2.050750732 +274 2.000023771 -1.32895498 2.773741498 +288 -1.540530664 -0.177446281 2.080137338 +280 -0.990489497 3.626835076 2.237386528 +275 1.372659006 -2.107489262 2.762251866 +272 1.495759333 4.5003144117 2.231551952 +270 3.599080154 -3.232943785 2.065843782 +269 -2.867681897 1.835779108 2.164864312 +284 -3.049959991 -0.140103577000001 2.125370364 +281 0.567740954 2.010522135 1.8732039758 +268 -2.275302176 -2.473565267 2.354082168 +278 -4.5000000325 3.480360825 2.24128665 +276 0.547626692 -2.636885095 2.56497051 +282 4.500206244 -1.681521679 2.20233429 +267 2.660370512 2.894930187 2.334182926 +265 -0.679650392999999 2.290715223 2.222179834 +271 -3.651042962 -2.26288055 2.219455682 +273 4.500033214 -3.472702199 3.030666962 +285 -0.623961733 -4.50011844 2.965147376 +287 1.242563149 -0.677107479 2.806195548 +301 -2.644305348 2.794541699 1.9776623782 +309 3.762765011 1.955826483 2.892417732 +306 3.514555412 -2.156828791 3.164924244 +297 -3.646773494 2.808450181 2.091250428 +304 3.743944132 -1.286733101 2.723849606 +298 -3.631075258 -0.955775228 2.311259214 +290 3.719198805 2.950459535 2.610450168 +311 -2.289074661 -0.54755645 2.629552856 +292 -2.130408834 2.350946731 2.711675846 +305 1.633775745 3.56557901 3.160241996 +291 3.002089739 -2.973790555 2.901771286 +312 -0.936793761 -3.637094334 2.568748462 +300 1.28216256 1.802842057 2.541212378 +296 3.566102199 -0.353354324000001 3.035519154 +294 -0.000402970000000558 4.3927355435 3.093120692 +308 -2.432971954 4.5000403202 2.600850882 +303 -0.372324593 -1.200766201 2.848719136 +289 -2.305919986 -1.511178251 2.896055422 +299 3.584808436 0.554588558 2.61687858 +302 0.73013901 1.064992812 2.929074776 +310 -0.484464369 -2.137624369 2.281312514 +293 -3.643889999 0.0963722300000001 2.894035152 +307 3.396977821 -3.885855126 2.795708114 +295 -4.5002642788 1.67308786 3.098541668 +329 3.221998484 4.5004501865 2.96759099 +332 -0.337478279 0.821022334 3.066441442 +315 2.908266358 -1.177733801 3.262128172 +334 -4.5000379728 -1.180078324 2.755789892 +321 -1.37507058 -0.91598724 2.79770368 +316 -0.592790246 3.594296256 3.20052041 +326 0.714108195 2.729867027 2.552203436 +331 -2.407056715 -3.276264401 2.946741806 +317 -1.517219576 -2.822357414 2.90509973 +320 -1.938219797 0.38452046 2.805203662 +319 -0.00324743899999991 3.649371132 2.394827862 +318 -1.440428544 -1.886023441 2.562972744 +325 -3.628812253 2.072959488 2.768430122 +333 -0.0156802989999996 1.647963227 2.605495808 +313 1.999094411 4.4992097939 3.095611256 +330 -4.5000219753 0.708926359 2.833262832 +324 0.5616068 -1.526021211 2.700939504 +328 0.361118249 -4.500022128 3.136877208 +314 4.500038151 0.978872463 3.059349046 +327 -0.827449532999999 -1.93562572 3.351500218 +322 4.50013304 3.519628524 2.947874356 +335 -1.798073341 -4.067485493 2.891367634 +336 -3.665269681 -1.663523894 3.019130394 +323 2.2714932 2.006120203 2.739105982 +344 -1.271204388 -4.499304315 3.72729126 +351 -0.988100228 1.41514921 2.59372529 +342 -3.792345356 -4.500299951 2.874070708 +339 2.387674308 0.712193288 2.907227268 +345 2.635126552 3.691759021 2.997507948 +350 -4.5001706355 -3.792185593 2.874474006 +349 2.483446808 -3.670921474 2.315866348 +348 -1.291638895 0.893006517 3.39062114 +358 0.378564914 -0.830053421 3.395265636 +356 -3.890319669 3.587832299 3.026661222 +359 -1.04022185 -0.000130146000000053 3.018233788 +355 -4.500453354 2.380629114 2.386954854 +360 2.956549248 1.476527814 3.239065088 +340 2.714203335 4.500050223 3.82879752 +346 4.032753249 4.5000404384 3.552932696 +338 -3.540152302 -3.54094501 2.999088074 +354 -1.003990361 4.5000362118 3.098206566 +341 -0.5228433 -2.823753608 3.007610022 +347 0.503029524 -3.631893649 2.652539068 +343 1.186720035 -1.431250197 3.475059086 +357 1.660303428 1.274066829 3.300616796 +337 2.398160473 -0.415977469 2.86275796 +353 -3.43446006 1.090207167 2.758536066 +352 -1.936655782 4.500346735 3.468427182 +368 -1.155839085 -3.50891938 3.535978904 +370 4.500030037 2.55381397 3.206728502 +375 -0.841147404 -0.798639602 3.63503649 +365 -3.916020775 -3.759990954 3.91279992 +361 -1.632031825 -1.410236977 3.627690652 +374 1.213191868 -3.026349461 3.201204634 +367 3.604057597 0.798389376 3.586458372 +364 -4.500396291 -0.190302288000001 3.322818526 +379 2.516376059 -2.106023126 3.13901294 +383 -0.184344901999999 -1.466595389 3.984795788 +371 -2.812933497 0.501572726 3.275018202 +363 -4.5001609926 -4.500249588 3.580212924 +362 -4.5001283384 2.836010698 3.277040186 +377 -1.175173555 2.834577638 2.911288958 +378 -2.131555793 1.351096876 2.637179218 +381 0.633807274 3.570134948 3.161539634 +372 -2.073483596 3.343532917 2.818422512 +380 -3.199384064 -2.55851261 3.061047886 +384 -4.5002486112 -1.778475514 3.556919384 +373 -0.185836818999999 -3.69034385 3.374612914 +376 -4.5000012281 -2.441495471 2.73555709 +366 -1.842991902 -0.39483127 3.511190634 +382 -0.207939275999999 -0.026783043 3.580375308 +369 1.650012208 0.127064764 3.243855902 +390 -4.5001487484 -3.041671148 3.535277372 +405 2.115980288 -3.649165911 3.2587385 +394 -2.272031625 -2.380328121 3.389382758 +385 2.864047206 0.126280145 3.561877528 +406 2.615721165 -4.500102914 2.904763286 +391 -2.270632944 -4.500318965 3.699003844 +388 3.714162609 -1.432582925 3.824364534 +403 -1.41504493 -2.571112271 3.86746528 +408 -3.994409447 0.589566986 3.690917066 +399 -3.270157577 -4.500182284 3.726718532 +396 -0.138075073 -0.56692461 4.418806532 +392 -1.502415296 1.868030785 3.32169728 +404 1.541675912 2.442253825 3.265495036 +401 -0.510093449999999 1.872688273 3.445126938 +386 3.581018276 3.637829719 3.323606628 +400 2.608180815 2.746322445 3.321081858 +393 -3.04785124 2.959503761 2.87758162 +398 2.150233096 -4.500142197 3.789722876 +395 -3.789462578 -2.415284887 3.855319686 +402 -3.087581223 -0.857236157 3.144868024 +389 4.500040204 -4.500109657 3.316878514 +397 -1.121953608 0.0841875510000003 4.011254666 +387 -3.597553294 2.584954069 3.626600902 +407 0.631184329 2.028829797 3.26551508 +414 4.500840419 -0.374730156 4.090573378 +426 4.500121016 -1.003800727 3.313616024 +430 -2.927212631 -1.688961502 3.69307688 +420 -3.939975294 -0.946629618 3.659472636 +415 -1.311161931 2.66955365 3.888114236 +422 -1.509054418 3.606430915 3.6005369 +429 -2.81085591 1.963155843 3.33299753 +412 0.661672273000001 0.0821063200000003 3.098992812 +432 -0.186312545 2.706247328 2.986137424 +428 1.705698448 -2.305728978 3.688916042 +411 3.574035741 2.668311606 3.568103224 +421 -2.100206386 -3.529078631 3.864031492 +413 0.996238367 4.4999524561 3.097653032 +424 -0.463577189 4.5000176191 3.97279011 +416 0.965801743 -3.887046257 3.645319676 +427 2.813841022 3.51445511 3.965231242 +409 -1.057907605 -1.776812997 4.359721236 +410 -3.397449421 4.500100511 2.864659982 +417 -2.205471256 1.22330576 3.62617068 +419 4.500069459 -3.759356838 3.98844643 +431 3.508624231 -0.476452775 4.030680386 +418 -2.79450004 -3.972806165 4.430588016 +425 3.67086349 -3.30902625 3.565025662 +423 1.948638383 -0.81218127 3.66296925 +447 0.146063317 -2.163821629 3.348790206 +441 -3.663316042 1.530804938 3.626573156 +450 4.500087396 1.709342107 3.742161656 +440 -3.340143707 -0.156793547 3.812251634 +456 2.403862811 0.952297215 3.886692382 +437 -2.603369421 -0.800607444 4.01797447 +433 1.910150786 3.048426176 3.97027214 +435 3.535847412 1.767464788 4.000398272 +442 0.221810375 1.266212785 3.766038552 +434 -2.448212392 2.994593471 3.676981176 +438 0.0464725159999997 3.628546612 3.968709456 +445 4.500637328 -2.786463497 3.757752622 +449 -4.5004564553 -1.271956087 4.420625352 +452 -3.052697752 -3.229104047 3.814153096 +453 -2.094292234 -1.88064952 4.37862513 +444 -2.939443618 -2.414372299 4.382264502 +454 2.061291298 0.0517852880000005 4.153400082 +439 2.244658198 1.932792502 3.773925268 +451 -2.755108117 3.879904421 3.31599915 +446 -0.42837059 -2.652284639 4.005155918 +448 -2.367941225 0.201311239 4.118479728 +455 0.48359156 -3.044382679 3.884782812 +436 2.514471645 -2.888085142 3.770512134 +443 -4.4087285298 2.123818149 3.986366358 +468 1.064034295 -0.309471648000001 3.926481844 +472 -2.035185723 -2.854142358 4.598831684 +476 -0.296261452 -4.500624825 3.949308558 +464 3.531978375 -4.500068883 3.573087076 +470 -2.132627204 2.124195142 4.054421656 +473 4.500146489 0.620348453 3.992803652 +459 -1.231802133 1.751928119 4.277266076 +475 2.52808728 -1.863691739 4.10890359 +458 -3.022194137 0.959332081 4.139007628 +477 3.514566847 4.2322800797 4.365003608 +479 -4.5000439569 1.184159587 4.31597554 +480 4.50001619 3.631723431 3.941269128 +471 3.278268351 -1.589914122 4.710427318 +478 0.664761114 2.841800001 3.846039496 +461 -0.315668394 2.696532261 3.977533546 +460 -1.975068718 -4.500190651 4.654190116 +467 0.536302738 4.5001032628 3.985416662 +462 -3.099537623 2.024684534 4.2882503 +466 4.012294291 -4.500093433 4.450129994 +463 -3.674088801 4.5002617841 3.825440006 +457 -0.861884992 3.448611669 4.346081492 +469 -3.573436452 -1.644696858 4.454763888 +474 -0.377326424 -3.588822972 4.35114761 +465 3.685611859 3.247180436 4.375787394 +483 0.096201239 4.4963452052 4.88325619 +503 -0.645465129 0.951861082 4.151345406 +494 0.223265213 0.450974252 4.345657386 +497 1.645321897 -3.285326217 4.065014872 +490 1.032908748 0.682829065 3.806798024 +481 0.617963438 -4.50039983 4.353851566 +499 1.741906319 4.5006988661 4.061647452 +491 -3.462828967 3.528470271 3.928700638 +487 4.500230427 -1.902703194 4.224944152 +493 1.180992006 2.024090566 4.100639404 +485 2.873465773 -3.817034205 3.8892338 +501 -4.5002564683 3.944604575 3.733959622 +482 4.500206068 1.794634429 4.738442876 +498 -4.5000445082 -2.537190451 4.548202442 +488 1.583443435 -4.499526236 4.613386732 +489 3.618816281 -2.471197656 4.10845877 +496 2.853472211 2.563761868 4.27269262 +500 -1.716670011 -0.882428308 4.4727759 +502 1.762400473 1.343579211 4.546447926 +484 -1.395262286 4.3230681195 4.289788436 +492 0.810762874 -2.120453882 4.094195088 +495 0.7027494 -1.153126235 4.32347949 +486 -3.658610284 -3.075553586 4.594681508 +504 -4.50005695 -0.113076903 4.319684674 +507 1.140219078 3.703798901 4.018856976 +517 1.605539265 -1.580536146 4.370634764 +522 0.0320110979999999 -2.127916908 4.720987574 +513 -2.173549175 3.687780286 4.343259734 +509 -3.654704937 0.34875015 4.615393848 +518 2.736726483 1.595360209 4.576262758 +521 3.847564781 1.046457537 4.61917976 +515 0.767159287 1.265702381 4.604151944 +505 -3.495739104 -2.300708461 5.205395586 +508 -0.249806467 1.819279619 4.452636658 +524 -2.409214209 1.494958811 4.780702348 +528 1.032733144 -2.853155295 4.737272384 +526 -4.5001124736 -4.500141367 4.579998182 +520 -1.360399634 -3.589338699 4.533833884 +516 -1.651788787 0.849922854 4.375775178 +525 -2.811554623 -3.232485069 5.102442118 +510 3.611332399 -3.5869681 4.523752266 +527 -4.5001005331 3.957741897 4.733785438 +511 1.957288292 -2.482920111 4.64797571 +523 1.878714532 3.738238103 4.693533166 +512 -1.042953038 -2.677542469 4.793698322 +519 2.883459258 -2.856445573 4.699334164 +514 -1.652810482 -1.59453981 5.228668696 +506 4.480236308 2.666029949 4.200189168 +548 -0.611140806 0.243236777 4.85591581 +547 4.144974808 -1.091789303 4.689642744 +550 -0.700583798 -3.749792169 5.283635138 +530 2.323974316 -3.685071352 4.714072658 +549 1.347176791 0.45213074 4.727515088 +541 1.427934521 -3.669933792 5.157425992 +535 1.961731151 2.31769244 4.652080088 +545 2.308903464 0.610448927 4.951026498 +544 -2.712424497 4.5000109102 4.099324908 +539 2.895071323 -4.500277725 4.618751442 +551 -4.5002451574 2.375704127 4.949727302 +532 -0.853560343 -1.005434112 4.962376812 +536 3.155412318 0.33550387 4.495274196 +533 2.641361805 4.5000032104 4.826099436 +534 4.499902876 -2.838620768 4.756048386 +542 -4.5000267152 -4.500084388 5.579883974 +543 4.500044379 0.115452456 4.961611298 +537 -3.665154365 4.5002205638 4.825290794 +540 -0.989441229 1.164658839 5.065785974 +529 -4.5002959673 0.464039317 5.136212834 +538 -0.975707129 -4.500157442 4.68261065 +552 0.320473119 2.58519749 4.749000854 +546 2.641186142 -0.825707551 4.383647332 +531 -2.752505577 -4.500035126 5.283023432 +570 -1.581354273 0.00705784799999964 4.909182842 +571 -2.735892591 -1.296873985 4.875903496 +564 -4.4999960436 3.085321237 4.245321808 +554 0.209218084 1.683348646 5.330335484 +560 -3.710508522 -0.663638281 4.590539722 +569 -2.8503999 0.663795605 5.118992802 +563 0.466830515 -3.664766103 4.88158725 +555 -3.631177777 -4.164538246 4.943461478 +556 0.563468843 3.552453997 4.82146681 +562 1.604951595 -0.640646784999999 4.711838956 +557 1.102189874 2.068286595 5.097705032 +561 4.499939634 4.5000643216 4.437091474 +568 1.304538839 1.151195212 5.44117232 +575 4.500105784 -3.811544776 4.986818406 +567 -2.817934959 -0.300523856 4.8568749 +566 -0.886065815 2.542255259 4.784222934 +558 -2.834725238 2.938052616 4.597232776 +565 3.673009429 -2.411472929 5.121696606 +572 1.089267929 4.4029824613 4.812861718 +553 3.633265054 0.399604982 5.371346506 +574 0.945406086 -1.904794324 5.061201518 +576 2.339599819 -1.511082764 5.045884826 +573 -3.700828076 0.805083918999999 5.630452642 +559 -2.919359655 3.854449902 4.988114572 +582 -2.082029476 -0.707435164 5.397803236 +585 0.690512449 -0.281817058 4.90030231 +578 -4.5001696331 -3.542081257 4.866196334 +587 2.81726835 3.525443121 4.965136966 +595 -2.484055719 -2.193606719 5.244696558 +579 4.500148229 -1.859044258 5.22385731 +597 2.76886636 2.340489444 5.243573994 +586 -1.976147453 -3.742530682 5.306688532 +591 -3.735131142 3.284713004 4.85934223 +581 -3.647033134 1.366639274 4.804886164 +583 -3.524081968 2.297794291 5.151115238 +593 0.476029634000001 0.609339302 5.30005482 +580 4.500165715 -0.700982819 5.538728296 +599 3.374895152 -0.545632405000001 5.019214462 +588 -1.49027648 3.714172453 5.077146874 +590 -2.731135558 -0.0803307740000001 5.828278576 +598 0.816332976 4.500098247 5.769919174 +584 3.668988344 2.345771668 4.808228602 +596 2.040315406 3.014702318 5.364230074 +577 -0.714087131 -1.915784823 5.351673588 +594 0.154559739 -1.23591751 5.155698844 +589 -4.5000192745 -1.812504186 5.261834864 +592 3.575821489 -4.399398782 5.34411851 +600 2.146228768 -3.043756527 5.46040375 +618 4.500263837 2.681436285 5.250774138 +624 1.856882755 4.5000118252 5.446227254 +614 -4.5002565033 -0.649916645 5.203473746 +606 3.377696241 1.552357625 5.342446988 +611 -1.896040398 0.852751215 5.349820466 +609 0.207104652 -2.84637044 5.394033166 +604 -3.657036775 -0.179958241 5.464115386 +622 -3.664447241 -1.275941445 5.379805428 +617 2.236063847 -4.500081877 5.37079768 +610 2.418704508 -0.343333603 5.230572992 +602 -0.0614521229999996 -4.500030932 5.087333886 +608 -0.361698308999999 3.644246718 5.1894059 +616 1.691413507 0.21107957 5.634847776 +615 -2.89022918 4.5001507637 5.751024198 +619 -2.149830503 4.5000438901 4.925971746 +620 0.428889157 2.190178761 6.16390027 +601 2.810215228 0.77067975 5.801287854 +603 -1.708186408 -2.754819246 5.538477576 +605 -1.078053364 0.415526657 5.72307053 +621 -3.024750601 1.539239637 5.569377016 +607 4.500067014 3.632181358 4.941048088 +623 -3.548707469 -4.499946143 5.887999696 +612 0.285245316 3.031558199 5.642993352 +613 1.072904303 -1.004094333 5.476354718 +635 -4.5000513974 -1.169619394 6.057728914 +643 -1.38797007 -4.500154619 5.593458768 +641 -4.5001390459 1.446909688 5.320103162 +626 -1.849175686 2.819092791 4.717636618 +637 -0.111885717 -0.33590093 5.500154462 +642 -2.28251564 3.309724702 5.533675134 +636 1.290754582 3.662672443 5.498840974 +644 4.372099313 1.893906428 5.853470682 +647 -0.424294169 -0.401743008 6.447786444 +630 4.500167391 1.024799464 5.376541136 +640 -1.323986676 -3.614916687 6.053803504 +632 -2.743974191 -1.368213355 5.873170092 +639 -1.372372859 2.867190909 5.595320982 +646 -3.695146178 -3.371361629 5.5490094 +631 -2.494261641 2.353236597 5.333232112 +627 -4.5001011126 4.500270634 5.573635174 +625 2.234837349 1.517677264 5.437569766 +645 -0.536673557999999 1.390367601 5.928298724 +634 1.147645147 -2.899180893 5.729540862 +648 -2.251498467 1.815087493 6.140243212 +629 0.904082978 -4.500143593 5.347170198 +638 3.506122364 4.5000732528 5.32826828 +628 3.685735275 3.247822821 5.375774288 +633 -1.587978894 1.956194067 5.18895512 +656 3.648176935 -0.405297296000001 5.970813486 +671 -2.870955758 -3.767569334 5.953397052 +653 -1.178271364 -0.575877348000001 5.804928304 +665 4.500061511 4.5001594684 5.43744047 +661 -0.874180015 4.5002702541 5.124345944 +657 1.766882045 -2.127243789 5.585997808 +658 1.558307507 -4.156866392 6.021049766 +663 -0.144234508 0.482312728 6.073975906 +664 -0.733043509 -2.857801319 5.734511342 +668 2.790931095 -1.083856556 5.829139842 +650 -1.833347839 0.0315979220000004 6.254183842 +667 -0.432765816 -4.500101041 6.015634192 +672 -4.500083278 -2.778949176 5.518518706 +666 4.435092301 0.211537065 5.954787598 +660 -0.451219894 2.355451965 5.665110814 +669 -1.577570671 1.087749292 6.269265044 +670 3.723841087 -1.330384411 5.567031502 +651 -2.253448874 -2.168674546 6.217377426 +662 3.769379833 -3.339995714 5.480137958 +654 -4.4975225584 -0.0429850160000003 5.998072724 +652 4.498754693 -1.533838325 6.169398506 +659 -3.692307206 3.914311982 5.635034532 +649 1.925375979 0.983980534000001 6.224494418 +655 -4.4956595562 -4.500108517 6.579824322 +678 -1.629331791 4.5000355718 5.779740342 +692 -4.1772543963 2.446732834 5.893394892 +684 3.518972057 2.413221423 5.900751314 +673 0.69504651 3.662179678 6.302016962 +694 2.773284588 -2.268316092 5.533907584 +688 -0.180497878 4.4731247882 5.843913568 +691 -0.624828604 3.622988766 6.153767374 +695 -4.5002259281 3.308539058 5.50240493 +675 0.197408713 -3.743558725 5.841265954 +680 4.500307234 -4.500282217 5.711484208 +679 -4.500044417 0.67405253 6.694966612 +682 -2.219091001 -4.500043756 6.149422616 +677 -3.914597269 -1.980276893 6.05496275 +686 0.985504273 -1.778276798 6.10297032 +690 -4.5000382647 1.596385092 6.308785416 +689 -1.792199817 -1.277458499 6.166569584 +685 -2.472075877 2.767037723 6.351984888 +676 -3.221023249 3.039972801 5.748448442 +696 2.712649864 4.1446993244 5.822057706 +681 4.500088011 3.636246626 5.940973448 +683 2.856651464 -3.739906611 5.562612526 +687 -3.019226637 -2.756634206 5.957017552 +674 1.878273251 -0.70709146 5.989158288 +693 4.5002002 -2.71216935 5.74774071 +700 -3.289131137 2.194089247 6.277257586 +718 -0.402635868 -3.72039097 6.640873892 +708 3.727153719 -2.180575558 6.09330177 +701 -1.622107939 3.604341609 6.224287748 +709 -2.628835414 3.754484372 6.363752594 +713 -4.5004143972 -3.634176959 6.079916582 +717 -3.470645786 -0.78586951 6.23740935 +720 2.717827943 -4.500196226 6.246909452 +698 3.812226133 1.066875083 6.100898596 +714 0.305078756 -1.003497741 6.116916572 +712 -1.254973937 -4.500042221 6.5845269 +705 1.214516583 2.724211282 5.84746386 +707 -2.046869696 4.5000512419 6.688295582 +704 4.494020803 -3.615303846 6.176877582 +703 -2.171003647 -3.15915351 6.327263018 +702 -1.275318403 2.031535104 6.135742196 +715 4.500037295 2.736169156 6.376593132 +699 4.500110408 -0.602629113000001 6.533775302 +711 -3.894293627 -2.912952758 6.414986382 +706 0.649247921000001 -4.50000853 6.314132898 +710 -3.112420417 -1.88684571 6.644642002 +719 0.788755044 -0.137615957 5.886702162 +716 0.568522327999999 1.182083191 6.1172764 +697 1.875824189 -2.71281267 6.389064744 +736 4.500102998 1.418380508 6.735809434 +737 -3.714668902 -3.867544357 6.652483614 +738 -3.578037373 1.265402521 6.509592776 +728 2.854928227 3.160376799 5.92526928 +721 -2.538561288 0.857627275 6.116060878 +743 0.0321560310000004 -2.061770867 6.000825382 +732 2.194160682 2.314636299 6.06133092 +744 -4.5001729178 3.856546687 6.338751414 +733 -3.501254908 0.200111290000001 6.401171598 +727 -0.946387889 4.5001152333 6.510176304 +742 -3.039861974 -3.162558531 6.870620084 +726 -4.5000502067 2.055175278 7.197261876 +740 1.820711305 0.0657459669999998 6.621054686 +731 3.12228586 -2.974863285 6.149303928 +724 -0.636723587 -1.33635758 6.162900858 +725 1.970494862 3.524222107 6.221598216 +730 2.93465313 1.664643845 6.23176208 +739 -3.74218383 4.5001365828 6.443810142 +734 -4.5001758281 -2.232609773 6.827065586 +722 -1.256028632 -2.12142271 6.166342454 +729 1.90508762 -1.594200927 6.449785266 +735 4.500105829 -2.413084338 6.701806746 +723 0.71541812 1.666313337 6.979689998 +741 1.113094007 -0.719036822 6.632832398 +745 0.383646521999999 -1.6348607 6.888379016 +765 1.348875055 1.80077058 6.206744622 +751 0.384520017 -2.9192041 6.37542954 +754 -4.500063994 -0.557184997 6.855668942 +747 3.602720576 -1.304614308 6.559261866 +763 1.150623016 0.779658062 6.823705658 +755 -2.498913377 -0.701240125 6.57675132 +756 2.683351987 -1.01058857 6.820571256 +746 -2.959112025 -4.500099339 6.821957842 +759 -1.006195591 -2.925888366 6.704817074 +757 0.00918382199999979 2.993911479 6.603282796 +760 2.688462991 -0.150895073 6.173944332 +761 -2.632342419 0.237331179 6.89470687 +748 1.957372608 -4.439459423 6.89331799 +752 3.618879297 -3.599135676 6.75221732 +767 3.250211485 0.491529388 6.69482937 +768 -2.968212267 4.4986126719 7.07686839 +753 3.62529875 -0.393438024 6.970466134 +764 -0.915656022 0.446529009 6.709245636 +758 3.714235651 -4.500145693 6.3292602 +762 -3.582826064 3.518458156 6.548436518 +749 0.402406352 0.0484632070000002 6.790010428 +750 2.838701235 -1.94984366 6.489746384 +766 -3.954880818 -1.39536305 6.86500964 +774 0.058287687 4.5000781934 6.814494156 +777 0.39623866 -0.761901808999999 7.375739638 +780 2.755069206 3.549165509 6.841094054 +785 -1.834460129 2.260725836 6.932370698 +770 -1.331120378 -0.646764559 6.790605466 +776 -2.041210127 3.300423882 7.079803032 +787 -4.5001250207 2.927535157 6.708493986 +769 -0.520020427 -1.111856455 7.145286392 +786 2.907605645 2.554969379 6.719408086 +778 -1.862654027 -2.547782644 7.05612514 +779 -2.787004198 1.682198201 6.974201112 +773 -3.925289688 0.127414019 7.303830074 +771 -1.077931919 2.873943947 6.637054154 +782 1.067442656 -2.395883189 6.885051164 +781 -0.518140433 -2.063677276 6.838737782 +789 -1.319783216 -1.755727712 7.350984512 +784 -2.189281114 -3.513324625 7.262196206 +783 2.007767095 4.5001752947 6.43571023 +792 3.909289872 4.3870107206 6.236299094 +790 2.374837093 -3.578428037 6.426599892 +791 -0.430593966 2.098108975 6.666608554 +788 -2.241030297 -1.563140611 7.013211318 +772 -2.056428434 1.021086958 7.144580102 +775 3.614424856 -2.153994835 7.086827782 +798 0.529294953 -3.685131785 7.001604238 +811 -4.5000074447 -3.392154858 7.050165996 +804 -1.631228739 0.136353158 7.335106858 +802 -3.634865201 -2.46555738 7.270750968 +800 -4.5000131416 4.5000571179 7.10409178 +807 0.531687577 3.617418716 7.28754172 +803 2.389104129 0.807849632 7.092644592 +813 1.055525431 4.4999118985 6.740876826 +809 -0.149679597 -2.911198066 7.220713178 +795 1.626837394 2.753495101 6.75801434 +812 3.680111557 3.372316931 6.448748794 +793 -0.370673841 -0.120936745 7.406002416 +799 -4.4284171538 1.134092305 7.579935886 +814 1.306516678 -1.486845332 7.243588248 +810 -2.691916703 -2.279080571 7.546090634 +801 -0.45298569 3.703026197 7.13561967 +808 -3.610313203 2.67876364 7.09077885 +816 -1.137693913 1.511312254 7.061130874 +805 2.815860821 -2.759309121 7.076404106 +796 1.503946217 -3.482169426 6.90841816 +815 -2.265505052 -0.607794821 7.544582966 +806 4.500050826 -1.529154307 7.169336188 +794 4.500130131 -4.304063091 6.915491968 +797 2.093388622 1.737031234 6.87128393 +820 2.712914075 -0.120400215999999 7.27516145 +836 -4.5000461794 -4.500064369 7.579735042 +835 -0.031895295 -4.500173969 7.145133616 +837 0.688631677 -2.744774666 7.742137422 +832 4.500021099 -3.316252295 7.131055232 +830 4.500002908 0.436820857 6.926866418 +819 -3.372091334 -3.775587246 7.587418574 +829 -1.38716768 4.031059763 7.275439702 +823 -0.112781733999999 1.809160788 7.56963154 +826 4.500083959 4.5002933709 7.035053416 +838 -3.972326563 3.722706175 7.446498974 +839 2.824221178 -1.715955387 7.515243248 +833 3.031038874 4.5000336444 6.700849982 +840 3.811742685 2.139110924 6.816732284 +831 0.734417035 2.64255656 7.19512608 +821 -0.397101060000001 -1.954676104 7.825309098 +827 0.432402522 0.73343507 7.517947826 +817 -1.216749214 -3.744690247 7.238643562 +822 -2.696367125 1.344316825 8.044436962 +828 -0.145206744 1.151604706 6.816934868 +834 -2.662042909 2.581701691 7.392804248 +824 -2.036696026 -4.50005881 7.207925676 +818 -4.5001333706 -2.648935368 7.737050598 +825 0.291437026 4.500032667 7.78687256 +860 -1.320698302 -0.847804191 7.770092896 +849 -1.042692162 2.389846026 7.529264594 +861 0.542309327 -1.61563877 7.87551845 +858 -3.601921254 1.78544392 7.544407864 +848 -3.090446601 -1.104447465 7.274803884 +845 0.390638137 -0.0761148599999997 8.103457168 +856 1.149147808 0.00287958699999979 7.453464336 +841 1.648343742 3.793890916 7.128953188 +853 -0.820328323 -4.500084402 7.760220304 +850 -4.5000151681 2.914656754 7.70838282 +842 3.144772703 -4.500034702 7.151174262 +851 -2.976810152 3.534903658 7.343648238 +847 4.497970366 3.500679093 7.020833072 +852 -1.018013173 -2.745195226 7.68820907 +854 -2.65593619 -3.135152407 8.061641748 +857 -1.853651387 2.814489952 7.9333958 +859 -3.252450711 0.864543271000001 7.36585316 +846 4.500008143 -0.377001482 7.507958942 +843 1.531582036 2.172888465 7.574367998 +863 1.997774554 -2.209337903 7.244319732 +864 3.79467218 1.033585918 7.33466599 +844 1.875764798 -0.666687024 7.29961096 +855 -4.5000395368 4.5000231965 8.104069198 +862 -3.641372047 -2.979095895 8.128773278 +868 -4.5000482242 -1.65170272 7.66310154 +872 4.500038813 2.574279235 7.397058946 +878 -4.4941056291 -3.605851868 8.02715155 +883 -2.171560016 4.5000730601 7.68121363 +874 1.290300938 4.5000470858 7.739705472 +881 -2.440612713 0.394676500999999 7.86341641 +885 -0.170789183 -3.740022964 7.779783248 +882 1.037299676 -4.500079673 7.280155998 +888 -3.53759308 -1.71694688 7.92655647 +867 -0.298558207 -0.861874769 8.087866364 +870 -2.186277799 -1.489841229 8.008999892 +875 3.030243382 1.669149969 7.227068646 +879 -0.993920785 3.322923819 7.88581861 +886 1.619062448 1.177498233 7.612513956 +880 -2.757975414 -4.500026199 7.900476864 +865 2.306496576 4.5000415726 7.390026186 +873 -3.972815171 -0.802010408 7.669722366 +887 -2.382268318 3.637507873 8.141111346 +884 3.663627706 -1.177645932 7.589703146 +866 -0.662358136 0.814869929 7.603716792 +877 -4.5000382744 0.286925249 8.106404342 +871 -4.3603052935 1.931392337 8.179659346 +876 -0.707177983999999 4.5000312098 7.838983956 +869 3.458008969 3.070713853 7.375905948 +908 1.177728778 -0.837308031 7.9949883 +905 -1.202937683 -1.661279458 8.33961044 +909 1.353035474 3.127318807 7.813342162 +899 2.325687148 2.891296129 7.459822636 +894 -1.037393538 0.0395562070000004 8.133811346 +892 1.014350959 -3.680653535 7.876022126 +898 -1.633916995 -3.423920757 8.08893289 +890 1.984919807 -1.427246013 7.975833038 +896 3.649053574 -3.027573027 7.572163936 +903 3.02756401 3.897546801 7.737902346 +904 1.515063842 -2.321096808 8.11289426 +902 3.615669544 0.166253343 7.799029808 +910 -1.736191165 -4.500012934 8.161674702 +893 4.500159332 1.627996872 7.720151158 +891 -1.874708145 -2.435621804 8.10065476 +889 2.015299628 0.290280181 7.862239966 +900 -3.518964841 4.4832205367 7.911339426 +901 -3.71306876 -4.500010918 8.196642922 +907 2.082198108 3.773223742 8.039132626 +906 0.767551732 1.558710805 7.972456446 +911 0.488964547 -0.857521522 8.719652342 +897 -1.843343924 1.819970372 7.829865648 +895 1.101634341 0.610810532 8.253654436 +912 2.385902643 1.838984949 7.972588194 +917 -3.519786843 3.037109236 8.01992552 +923 -2.893530301 -2.197059781 8.522089796 +930 -4.5000536786 -1.072437272 8.47819437 +914 4.500044161 0.61962328 7.910000468 +935 2.973524526 0.926749614 7.89525906 +927 2.845547449 -3.636138473 7.556199224 +915 -1.043987024 -0.75173253 8.745217026 +924 2.007508638 -3.106286294 7.686279266 +936 3.824823897 4.5000522267 7.772526714 +934 3.98266385 -0.593385609 8.335912344 +920 2.809643203 -0.828063051 7.975006304 +933 -0.180806030999999 -2.8450739 8.225783452 +913 -3.342986173 0.0430036569999999 8.112332108 +916 2.381311388 -4.500023521 7.796954404 +932 3.832278313 3.121435582 8.301797848 +929 -1.574822716 0.873478889 8.008451204 +925 3.872567816 -4.000392298 7.63233322 +922 -2.942347999 -0.865057446000001 8.234291382 +919 3.659829518 2.18971347 7.8038071 +921 -0.161039828 2.858394688 7.58426761 +926 -2.009118863 -0.635725981 8.510734076 +928 1.997707654 -0.508552419 8.46350999 +931 -3.682734254 1.075130547 8.243614446 +918 2.83271746 3.092347504 8.29794074 +939 1.244210345 -1.551770023 8.691469242 +957 4.500001987 -1.431832611 8.164561762 +953 -0.0447779710000002 1.102518981 8.33568698 +958 1.474292655 -4.50004874 8.217940572 +951 -2.406245422 -3.944144817 8.65362229 +950 -1.104916092 2.59005781 8.55706819 +954 0.432157187 -4.500005795 8.07621793 +941 -2.508296746 -1.388738666 8.967293542 +943 -0.917579026 1.614129718 8.14776863 +955 3.270281032 -4.500021343 8.254877612 +952 -2.933145135 2.279775667 8.306757084 +946 4.500007653 -2.492901142 7.69858211 +948 1.597915614 1.576211766 8.52934013 +945 2.826265053 0.0741679069999996 8.405924108 +940 0.565346663000001 -2.282567971 8.620269664 +959 -0.380841692000001 -4.500003442 8.6584417 +947 1.959880776 2.621568508 8.426467632 +944 -4.1093307448 -1.96352487 8.709013894 +938 4.500014821 3.791491479 7.977550156 +937 -1.967634154 0.333620169 8.75286636 +942 0.6436857 2.528095443 8.184378384 +956 2.333293816 -3.712701544 8.411603176 +949 -3.939863543 0.392838922 8.92796115 +960 -3.849896791 -3.703614863 8.78570905 +968 4.500018116 2.380983547 8.378169182 +979 0.704751386 3.732001275 8.275964954 +972 -3.092484314 -3.074165673 8.959233326 +970 2.757226355 -2.555918791 8.053722098 +983 0.0430873330000008 -2.90961653 9.198236842 +984 -4.2605204315 3.580336293 8.41511519 +965 3.27018164 -1.605456454 8.403431664 +981 -1.207740982 -3.960549039 8.817194668 +976 -0.305495859000001 0.0197453599999999 8.814907058 +967 -4.5000215675 -2.883960968 8.719086854 +962 2.501901536 1.200537702 8.733451414 +980 2.820030212 2.220991853 8.78840032 +982 -0.163949455 4.3007167674 8.654549792 +973 -3.702343254 -0.571862096 8.814301596 +961 -0.907839867 0.815435966 8.75123593 +974 -1.139153363 -2.786859825 8.67995375 +966 -0.167266826 -1.611865152 8.73613229 +978 0.354789528 -3.669330875 8.627567008 +963 3.778031965 -2.466782555 8.38998981 +971 3.766498138 1.345233043 8.337987978 +969 -2.722483171 4.500002406 8.51574715 +977 -2.925147256 3.139554055 8.817346002 +975 -1.496692274 4.085964062 8.291971632 +964 1.885377245 0.421156348999999 8.845065948 +991 -1.789775634 -2.081210015 9.031871422 +988 3.785201814 2.084266046 9.011382054 +986 1.511429039 3.43856569 8.788925344 +1000 -0.20067931 2.163537647 8.576889586 +998 -0.831590021 -2.080974616 9.317990532 +994 -2.093629351 -3.021839841 8.880745724 +989 4.500002198 -3.39950078 8.1275595 +996 -1.980374672 1.424254016 8.737942194 +993 4.500010695 3.509580542 8.936973656 +997 3.930587835 0.431726975 8.710245516 +990 -0.183949164 3.317686018 8.472233888 +999 -2.786339984 -0.200038612 8.964692098 +992 0.553129847 1.620738631 8.947201684 +985 4.297770052 4.5000146144 8.65360408 +995 3.369822948 -3.515511354 8.399149886 +987 2.642179778 4.5000268747 8.436795444 diff --git a/contrib/voro++/examples/basic/platonic.cc b/contrib/voro++/examples/basic/platonic.cc new file mode 100644 index 0000000000000000000000000000000000000000..4e8aa5bd92255a3485943781c427d342251c94ca --- /dev/null +++ b/contrib/voro++/examples/basic/platonic.cc @@ -0,0 +1,86 @@ +// Platonic solids example code +// +// Author : Chris H. Rycroft (LBL / UC Berkeley) +// Email : chr@alum.mit.edu +// Date : August 30th 2011 + +#include "voro++.hh" +using namespace voro; + +// Golden ratio constants +const double Phi=0.5*(1+sqrt(5.0)); +const double phi=0.5*(1-sqrt(5.0)); + +int main() { + voronoicell v; + + // Create a tetrahedron + v.init(-2,2,-2,2,-2,2); + v.plane(1,1,1); + v.plane(1,-1,-1); + v.plane(-1,1,-1); + v.plane(-1,-1,1); + + v.draw_gnuplot(0,0,0,"tetrahedron.gnu"); + + // Create a cube. Since this is the default shape + // we don't need to do any plane cutting. + v.init(-1,1,-1,1,-1,1); + v.draw_gnuplot(0,0,0,"cube.gnu"); + + // Create an octahedron + v.init(-2,2,-2,2,-2,2); + v.plane(1,1,1); + v.plane(-1,1,1); + v.plane(1,-1,1); + v.plane(-1,-1,1); + v.plane(1,1,-1); + v.plane(-1,1,-1); + v.plane(1,-1,-1); + v.plane(-1,-1,-1); + + v.draw_gnuplot(0,0,0,"octahedron.gnu"); + + // Create a dodecahedron + v.init(-2,2,-2,2,-2,2); + v.plane(0,Phi,1); + v.plane(0,-Phi,1); + v.plane(0,Phi,-1); + v.plane(0,-Phi,-1); + v.plane(1,0,Phi); + v.plane(-1,0,Phi); + v.plane(1,0,-Phi); + v.plane(-1,0,-Phi); + v.plane(Phi,1,0); + v.plane(-Phi,1,0); + v.plane(Phi,-1,0); + v.plane(-Phi,-1,0); + + v.draw_gnuplot(0,0,0,"dodecahedron.gnu"); + + // Create an icosahedron + v.init(-2,2,-2,2,-2,2); + v.plane(1,1,1); + v.plane(-1,1,1); + v.plane(1,-1,1); + v.plane(-1,-1,1); + v.plane(1,1,-1); + v.plane(-1,1,-1); + v.plane(1,-1,-1); + v.plane(-1,-1,-1); + v.plane(0,phi,Phi); + v.plane(0,phi,-Phi); + v.plane(0,-phi,Phi); + v.plane(0,-phi,-Phi); + v.plane(Phi,0,phi); + v.plane(Phi,0,-phi); + v.plane(-Phi,0,phi); + v.plane(-Phi,0,-phi); + v.plane(phi,Phi,0); + v.plane(phi,-Phi,0); + v.plane(-phi,Phi,0); + v.plane(-phi,-Phi,0); + + v.draw_gnuplot(0,0,0,"icosahedron.gnu"); + +} diff --git a/contrib/voro++/examples/basic/random_points.cc b/contrib/voro++/examples/basic/random_points.cc new file mode 100644 index 0000000000000000000000000000000000000000..cc4a5acfbb98b66d025e1fbfb61913b1bb55d529 --- /dev/null +++ b/contrib/voro++/examples/basic/random_points.cc @@ -0,0 +1,54 @@ +// Voronoi calculation example code +// +// Author : Chris H. Rycroft (LBL / UC Berkeley) +// Email : chr@alum.mit.edu +// Date : August 30th 2011 + +#include "voro++.hh" +using namespace voro; + +// Set up constants for the container geometry +const double x_min=-1,x_max=1; +const double y_min=-1,y_max=1; +const double z_min=-1,z_max=1; +const double cvol=(x_max-x_min)*(y_max-y_min)*(x_max-x_min); + +// Set up the number of blocks that the container is divided into +const int n_x=6,n_y=6,n_z=6; + +// Set the number of particles that are going to be randomly introduced +const int particles=20; + +// This function returns a random double between 0 and 1 +double rnd() {return double(rand())/RAND_MAX;} + +int main() { + int i; + double x,y,z; + + // Create a container with the geometry given above, and make it + // non-periodic in each of the three coordinates. Allocate space for + // eight particles within each computational block + container con(x_min,x_max,y_min,y_max,z_min,z_max,n_x,n_y,n_z, + false,false,false,8); + + // Randomly add particles into the container + for(i=0;i<particles;i++) { + x=x_min+rnd()*(x_max-x_min); + y=y_min+rnd()*(y_max-y_min); + z=z_min+rnd()*(z_max-z_min); + con.put(i,x,y,z); + } + + // Sum up the volumes, and check that this matches the container volume + double vvol=con.sum_cell_volumes(); + printf("Container volume : %g\n" + "Voronoi volume : %g\n" + "Difference : %g\n",cvol,vvol,vvol-cvol); + + // Output the particle positions in gnuplot format + con.draw_particles("random_points_p.gnu"); + + // Output the Voronoi cells in gnuplot format + con.draw_cells_gnuplot("random_points_v.gnu"); +} diff --git a/contrib/voro++/examples/basic/single_cell.cc b/contrib/voro++/examples/basic/single_cell.cc new file mode 100644 index 0000000000000000000000000000000000000000..e2d4788bf711057232333881ea43b0a6d8e5d5b2 --- /dev/null +++ b/contrib/voro++/examples/basic/single_cell.cc @@ -0,0 +1,36 @@ +// Single Voronoi cell example code +// +// Author : Chris H. Rycroft (LBL / UC Berkeley) +// Email : chr@alum.mit.edu +// Date : August 30th 2011 + +#include "voro++.hh" +using namespace voro; + +// This function returns a random floating point number between 0 and 1 +double rnd() {return double(rand())/RAND_MAX;} + +int main() { + double x,y,z,rsq,r; + voronoicell v; + + // Initialize the Voronoi cell to be a cube of side length 2, centered + // on the origin + v.init(-1,1,-1,1,-1,1); + + // Cut the cell by 250 random planes which are all a distance 1 away + // from the origin, to make an approximation to a sphere + for(int i=0;i<250;i++) { + x=2*rnd()-1; + y=2*rnd()-1; + z=2*rnd()-1; + rsq=x*x+y*y+z*z; + if(rsq>0.01&&rsq<1) { + r=1/sqrt(rsq);x*=r;y*=r;z*=r; + v.plane(x,y,z,1); + } + } + + // Output the Voronoi cell to a file, in the gnuplot format + v.draw_gnuplot(0,0,0,"single_cell.gnu"); +} diff --git a/contrib/voro++/examples/custom/Makefile b/contrib/voro++/examples/custom/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..e2726e19b82bc451543c0c5087fee6dfe2ade472 --- /dev/null +++ b/contrib/voro++/examples/custom/Makefile @@ -0,0 +1,28 @@ +# Voro++ makefile +# +# Author : Chris H. Rycroft (LBL / UC Berkeley) +# Email : chr@alum.mit.edu +# Date : August 30th 2011 + +# Load the common configuration file +include ../../config.mk + +# List of executables +EXECUTABLES=cell_statistics custom_output radical + +# Makefile rules +all: $(EXECUTABLES) + +cell_statistics: cell_statistics.cc + $(CXX) $(CFLAGS) $(E_INC) $(E_LIB) -o cell_statistics cell_statistics.cc -lvoro++ + +custom_output: custom_output.cc + $(CXX) $(CFLAGS) $(E_INC) $(E_LIB) -o custom_output custom_output.cc -lvoro++ + +radical: radical.cc + $(CXX) $(CFLAGS) $(E_INC) $(E_LIB) -o radical radical.cc -lvoro++ + +clean: + rm -f $(EXECUTABLES) + +.PHONY: all clean diff --git a/contrib/voro++/examples/custom/README b/contrib/voro++/examples/custom/README new file mode 100644 index 0000000000000000000000000000000000000000..b0dd6d3a504341fc48b8616b941d3a0649f7f2df --- /dev/null +++ b/contrib/voro++/examples/custom/README @@ -0,0 +1,27 @@ +Customized output examples +========================== +The output of Voro++ can be customized to contain a variety of statistics about +the Voronoi cells. Voro++ can also calculated the radical Voronoi tessellation +for polydisperse packings where the cutting plane positions are displaced +according to the particle radii. + +1. cell_statistics.cc constructs a simple Voronoi cell, and then demonstrates +the large number of routines in the voronoicell class that will compute +different statistics about the cell. + +2. custom_output.cc loads in a small monodisperse packing in a cube of side +length six from the file pack_six_cube. It then uses the basic output routine +print_all() to save the particle positions and Voronoi volumes to the file +packing.standard. The routine print_all_neighbor() is also demonstrated, saving +the particle positions, Voronoi volumes and neighbors to the file +packing.neighbor. Three customized outputs are then created using the +print_all_custom() routine. + +3. radical.cc loads in a small monodisperse packing from the file +pack_six_cube, and saves the Voronoi tessellation to pack_six_cube.gnu. It then +loads in a polydisperse packing in the same geometry from the file +pack_six_cube_poly, and it saves the radical Voronoi tessellation to +pack_six_cube_poly.gnu. These can be overlaid in gnuplot using the commands: + +set style data lines +splot 'pack_six_cube.gnu', 'pack_six_cube_poly.gnu' diff --git a/contrib/voro++/examples/custom/cell_statistics.cc b/contrib/voro++/examples/custom/cell_statistics.cc new file mode 100644 index 0000000000000000000000000000000000000000..a96df2a6d4264a72143f5d574162221883275a0b --- /dev/null +++ b/contrib/voro++/examples/custom/cell_statistics.cc @@ -0,0 +1,52 @@ +// Simple cell statistics demonstration code +// +// Author : Chris H. Rycroft (LBL / UC Berkeley) +// Email : chr@alum.mit.edu +// Date : August 30th 2011 + +#include "voro++.hh" +using namespace voro; + +// This function returns a random floating point number between 0 and 1 +double rnd() {return double(rand())/RAND_MAX;} + +int main() { + double x,y,z; + voronoicell v; + + // Initialize the Voronoi cell to be a cube of side length 2, centered + // on the origin + v.init(-1,1,-1,1,-1,1); + + // Remove one edge of the cell with a single plane cut + v.plane(1,1,0,2); + + // Output the Voronoi cell to a file in gnuplot format + v.draw_gnuplot(0,0,0,"simple_cell.gnu"); + + // Output vertex-based statistics + printf("Total vertices : %d\n",v.p); + printf("Vertex positions : ");v.output_vertices();puts(""); + printf("Vertex orders : ");v.output_vertex_orders();puts(""); + printf("Max rad. sq. vertex : %g\n\n",0.25*v.max_radius_squared()); + + // Output edge-based statistics + printf("Total edges : %d\n",v.number_of_edges()); + printf("Total edge distance : %g\n",v.total_edge_distance()); + printf("Face perimeters : ");v.output_face_perimeters();puts("\n"); + + // Output face-based statistics + printf("Total faces : %d\n",v.number_of_faces()); + printf("Surface area : %g\n",v.surface_area()); + printf("Face freq. table : ");v.output_face_freq_table();puts(""); + printf("Face orders : ");v.output_face_orders();puts(""); + printf("Face areas : ");v.output_face_areas();puts(""); + printf("Face normals : ");v.output_normals();puts(""); + printf("Face vertices : ");v.output_face_vertices();puts("\n"); + + // Output volume-based statistics + v.centroid(x,y,z); + printf("Volume : %g\n" + "Centroid vector : (%g,%g,%g)\n",v.volume(),x,y,z); + +} diff --git a/contrib/voro++/examples/custom/custom_output.cc b/contrib/voro++/examples/custom/custom_output.cc new file mode 100644 index 0000000000000000000000000000000000000000..2f3944242bc6a7579e70e93afc26e6a781700239 --- /dev/null +++ b/contrib/voro++/examples/custom/custom_output.cc @@ -0,0 +1,52 @@ +// Custom output example code +// +// Author : Chris H. Rycroft (LBL / UC Berkeley) +// Email : chr@alum.mit.edu +// Date : August 30th 2011 + +#include "voro++.hh" +using namespace voro; + +// Set up constants for the container geometry +const double x_min=-3,x_max=3; +const double y_min=-3,y_max=3; +const double z_min=0,z_max=6; + +// Set up the number of blocks that the container is divided +// into. +const int n_x=3,n_y=3,n_z=3; + +int main() { + + // Create a container with the geometry given above, and make it + // non-periodic in each of the three coordinates. Allocate space for + // eight particles within each computational block. + container con(x_min,x_max,y_min,y_max,z_min,z_max,n_x,n_y,n_z, + false,false,false,8); + + // Import the monodisperse test packing and output the Voronoi + // tessellation in gnuplot and POV-Ray formats. + con.import("pack_six_cube"); + + // Do a custom output routine to store the number of vertices, edges, + // and faces of each Voronoi cell + con.print_custom( + "ID=%i, pos=(%x,%y,%z), vertices=%w, edges=%g, faces=%s", + "packing.custom1"); + + // Do a custom output routine to store a variety of face-based + // statistics. Store the particle ID and position, the number of faces + // the total face area, the order of each face, the areas of each face, + // the vertices making up each face, and the neighboring particle (or + // wall) corresponding to each face. + con.print_custom("%i %q %s %F %a %f %t %l %n","packing.custom2"); + + // Do a custom output routine that outputs the particle IDs and + // positions, plus the volume and the centroid position relative to the + // particle center + con.print_custom("%i %q %v %c","packing.custom3"); + + // Also create POV-Ray output of the Voronoi cells for use in the + // rendering + con.draw_cells_pov("pack_six_cube_v.pov"); +} diff --git a/contrib/voro++/examples/custom/custom_output.pl b/contrib/voro++/examples/custom/custom_output.pl new file mode 100644 index 0000000000000000000000000000000000000000..3daf6b1f8fff79c6d49d2f9594110df941781892 --- /dev/null +++ b/contrib/voro++/examples/custom/custom_output.pl @@ -0,0 +1,24 @@ +#!/usr/bin/perl + +# Open the custom output from the custom_output.cc program +open A,"packing.custom1" or die "Can't open file \"packing.custom1\"\n"; + +# Open the POV-Ray file +open B,">custom_output_p.pov" or die "Can't open output file\n"; + +# Loop over all lines in the packing.custom1 file +while(<A>) { + + # Use a regular expression to get the particle position and the number + # of faces of the Voronoi cell. These will be stored in the variables + # $1 and $2. + m/pos=\((.*)\).*faces=(\d*)/; + + # Print a sphere to the POV-Ray file, giving it a different texture + # depending on the number of faces of the Voronoi cell + print B "sphere{<$1>,0.5 texture{t$2}}\n"; +} + +# Close the two files +close A; +close B; diff --git a/contrib/voro++/examples/custom/custom_output.pov b/contrib/voro++/examples/custom/custom_output.pov new file mode 100644 index 0000000000000000000000000000000000000000..dac853cc5f7e9357c1529f097a2ff6d40bd75fd3 --- /dev/null +++ b/contrib/voro++/examples/custom/custom_output.pov @@ -0,0 +1,56 @@ +#version 3.6; +#include "colors.inc" +#include "metals.inc" +#include "textures.inc" + +// Increase tracing level for more accurate reflections +global_settings { + max_trace_level 64 +} + +// Right-handed coordinate system where the z-axis points upwards +camera { + location <30,-50,25> + sky z + right -0.15*x*image_width/image_height + up 0.15*z + look_at <0,0,2.8> +} + +// White background +background{rgb 1} + +// Two lights with slightly different colors +light_source{<-8,-20,30> color rgb <0.77,0.75,0.75>} +light_source{<25,-12,12> color rgb <0.43,0.45,0.45>} + +// The radius of the cylinders to be used when drawing the Voronoi cells +#declare r=0.06; + +// The radius of the particles +#declare s=0.5; + +// Different colors for the particles +#declare f1=finish{reflection 0.17 specular 0.3 ambient 0.42} +#declare t8=texture{pigment{rgb <0.6,0.6,0.6>} finish{f1}} +#declare t9=texture{pigment{rgb <0.7,0.3,1>} finish{f1}} +#declare t10=texture{pigment{rgb <0.3,0.7,1>} finish{f1}} +#declare t11=texture{pigment{rgb <0.2,0.9,0.9>} finish{f1}} +#declare t12=texture{pigment{rgb <0.3,1,0.7>} finish{f1}} +#declare t13=texture{pigment{rgb <0.7,1,0.3>} finish{f1}} +#declare t14=texture{pigment{rgb <0.9,0.9,0.2>} finish{f1}} +#declare t15=texture{pigment{rgb <1,0.7,0.3>} finish{f1}} +#declare t16=texture{pigment{rgb <1,0.3,0.7>} finish{f1}} +#declare t17=texture{pigment{rgb <0.9,0.2,0.9>} finish{f1}} +#declare t18=texture{pigment{rgb <1,1,1>} finish{f1}} + +// The particle packing +union{ +#include "custom_output_p.pov" +} + +// The computed Voronoi cells +union{ +#include "pack_six_cube_v.pov" + texture{T_Silver_4B} +} diff --git a/contrib/voro++/examples/custom/pack_six_cube b/contrib/voro++/examples/custom/pack_six_cube new file mode 100644 index 0000000000000000000000000000000000000000..066f2067f01d48db8eb779015d8f3652213280d7 --- /dev/null +++ b/contrib/voro++/examples/custom/pack_six_cube @@ -0,0 +1,216 @@ +1 -1.633531566 1.0081779456 0.4997643894 +2 -2.3175495108 2.50004343396 0.4998098766 +3 -0.0883292022000002 2.49998487024 0.49997382 +4 -0.5905249392 2.1141400272 1.2739520638 +5 -1.6354550196 0.00777687119999992 0.4998135702 +6 2.50024371 1.7052004254 1.1066620646 +7 1.6163377164 0.378218796 0.4996352686 +8 0.6450816684 1.8136706778 0.4991881638 +9 1.3723354464 2.50001343222 0.4998503506 +10 -2.49477600042 -2.4994533834 0.49997382 +11 0.1591747386 -0.8623052892 0.4997612252 +12 0.6018432558 2.50085393652 1.2236191762 +13 2.4993970962 2.50004979816 0.499958425 +14 2.5002306354 -0.5891871372 1.3656871624 +15 2.4996763188 0.910593138 0.4998442324 +16 0.1555379868 -2.1140856714 0.499808302 +17 1.7917374258 -2.5001865732 1.2081198644 +18 -2.1690769116 -1.9332698928 1.3393934932 +19 1.7064470976 1.5487702458 0.49997382 +20 -0.7669637874 -2.5000096794 0.4999680968 +21 2.5000711542 -1.0890633102 0.4997243732 +22 -1.630300629 -1.9954333962 0.4995576534 +23 1.7914606536 -1.7945441268 0.4997721152 +24 -2.50023339174 -0.4939926774 0.4998565634 +25 -2.5002228639 0.5096527854 0.4998286406 +26 -2.49973398858 1.5167884392 0.4998730372 +27 -1.09231806 2.50004601528 0.4999122966 +28 -0.7664081604 1.506191607 0.4998754028 +29 -2.49994466028 -1.4976897942 0.49997382 +30 -1.6351530756 -0.9955213908 0.4999588934 +31 2.5000470594 -2.5000639944 0.4999611072 +32 1.0827185856 -2.500004454 0.4999501042 +33 0.121049223 0.962177124 0.4998840514 +34 -0.731239728 -1.4928565722 0.499907191 +35 2.5000148538 -1.7942863308 1.208330482 +36 1.4293900734 -0.60411936 0.4998811682 +37 1.693914078 -1.1739451596 1.2777368674 +38 -0.7702945434 -0.4936272762 0.4995237402 +39 2.5001273412 0.4105916904 1.3657870828 +40 -0.2151642102 -0.4489046268 1.3296380976 +41 -0.7687151904 0.5062139106 0.4999055828 +42 2.500152618 -0.0892589747999999 0.4997650116 +43 1.0009049868 1.008280419 0.972585352 +44 -1.5086934072 0.9974863356 1.4916875348 +45 -0.1906878174 -2.5001610756 1.3546498898 +46 1.9350760212 2.50015141518 1.3263206044 +47 0.7680680142 -0.613803066 1.2529781652 +48 -0.520322322 0.9840571992 1.3423839878 +49 -1.7049937512 1.8781106406 0.987517195 +50 0.2890163712 1.5679785972 1.4005698552 +51 -2.5001055165 -0.9902666664 1.3677983936 +52 0.6718107054 0.0485346384000001 0.4998990378 +53 0.8828891958 -1.4903279178 0.7856231914 +54 1.6971075462 -1.8794484798 1.986236625 +55 0.7785745614 -1.5429397554 1.778749626 +56 2.498355582 -2.5002474342 1.9162502768 +57 1.8163510674 1.118761185 1.5402656292 +58 -2.49028043208 0.00966293040000021 1.3657617934 +59 -1.0465593666 -1.9851376494 1.3111443026 +60 1.6230277242 -0.109344417 1.3725323044 +61 0.803677725 -2.4904980648 1.4601558584 +62 2.500174548 -1.291019802 2.077806292 +63 -0.4406783868 -1.0295588292 2.111380354 +64 -1.0593921888 -0.9853736058 1.3206667652 +65 -1.0862456712 0.0421811507999998 1.334589922 +66 -0.0664300529999999 -1.4875173498 1.246881552 +67 0.2975538384 0.4089966312 1.3541999206 +68 -2.0563739124 1.7171792856 1.9181011058 +69 -1.5021759366 -2.5002090786 2.037012458 +70 1.2004706514 1.8826223166 1.7322744688 +71 -2.50018854048 1.0131918204 1.3636933196 +72 -0.6610079004 -1.996969944 2.233624626 +73 0.3572570658 -0.4242221946 2.149145084 +74 -2.50015722168 2.5001806872 1.4828326074 +75 -1.7654338962 -0.4966383762 1.832939586 +76 2.5001148054 1.8908456178 2.089239758 +77 -1.5156057486 -1.498156245 2.047882108 +78 -0.0249709901999999 2.50011927126 2.002554182 +79 2.500335852 0.901840926 2.23670456 +80 -2.50033055412 -2.5002094542 2.093220108 +81 -2.50007568966 -1.5087105342 2.222856128 +82 0.2019219258 -2.5001781654 2.2742338 +83 2.500074618 -0.1030437882 2.239501644 +84 1.306372176 -0.7329475686 2.087233828 +85 -0.9572314386 1.6112582586 2.05661196 +86 0.8603279154 0.9694525734 1.9616903498 +87 -1.4114044692 2.50004378976 1.713374457 +88 -2.5000006182 2.49931211886 2.482805848 +89 -1.020675462 -0.3572734878 2.57123686 +90 -0.4044797454 0.2263507242 2.042403434 +91 -2.50015066302 -0.0762997092000002 2.3660063 +92 2.5000666632 -0.6377540202 3.084536714 +93 1.635820743 0.3998132112 2.232930018 +94 0.787044012 2.3196010806 2.557182368 +95 1.7880996756 -1.270196802 2.779504834 +96 -2.5000149498 0.9308964468 2.36020607 +97 2.50006086 1.4990173908 3.038728388 +98 2.5000002036 -2.0009185842 2.782437742 +99 2.4973597854 0.4018063872 3.102688092 +100 -0.0847238868 1.1548315362 2.230957046 +101 -1.6189831278 0.38758413 2.276164892 +102 -1.3109302698 -1.529630028 3.0261821 +103 -0.8621444616 2.50007941956 2.548976818 +104 -2.5003575921 -2.1906193686 3.043995226 +105 1.737794406 2.50023188418 2.306502354 +106 1.1607421194 -2.5001894034 2.557490476 +107 -0.5515943472 -2.5000711818 3.090821674 +108 0.7581635106 0.305805486 2.70258895 +109 -0.129270348 -0.0804334734000003 2.953362524 +110 1.5702057348 -0.2965035672 2.947395472 +111 -1.5907955166 0.297198915 3.271622288 +112 -1.6352174376 1.2855549804 2.715570616 +113 0.2365862016 -1.5621519012 2.618913636 +114 2.5001485044 -1.4752385472 3.632918874 +115 -2.50003414566 0.7085497368 3.335106492 +116 0.693198909 -0.7706072304 3.02499245 +117 -1.977290892 -0.837825789 2.748661152 +118 -0.0904186877999997 1.9400047344 2.850126046 +119 0.7424979096 1.3708776012 2.869705454 +120 2.5001771184 2.49786273384 2.953357364 +121 -0.460913031 -1.0102788876 3.1107298 +122 -1.5499088826 -2.5003303314 3.035766602 +123 1.0563693948 -1.7172623304 3.2938531 +124 0.4360463934 -2.5001018958 3.246364772 +125 0.0342889535999999 0.8326700802 3.326329174 +126 1.8144590976 -2.498344152 3.31403944 +127 1.4937454758 0.7565635794 3.208225078 +128 1.6727590014 1.420657209 2.482601878 +129 0.9063634374 -0.0106950330000002 3.63948294 +130 1.6212776142 2.0992148076 3.215117466 +131 -0.8136720582 0.7230042144 2.807794018 +132 -1.315108014 -0.6402926916 3.483977248 +133 -2.50004255652 -0.2892251556 3.401060322 +134 0.1195260084 -1.6342581966 3.633549956 +135 0.9584037636 1.636359729 3.809100648 +136 -1.7019079596 2.2670358852 3.038768934 +137 0.4485449298 2.50002773754 3.480648292 +138 -0.5629460556 2.50007656902 3.530567852 +139 -2.068160793 -2.5000301934 3.890959658 +140 1.8860334708 0.0716001041999998 3.821883252 +141 -2.50019618556 1.6650778878 3.043689132 +142 -2.50008791622 -1.2873252654 3.47288578 +143 0.1086245172 -0.5872844136 3.815345888 +144 1.6639765482 -0.932813649 3.712928374 +145 -0.1833273246 -2.5000925064 4.03160142 +146 -0.8962851474 1.5809637768 3.320864614 +147 -0.7169574816 0.1400516334 3.731676664 +148 2.500011852 2.0721063306 3.85816837 +149 2.5001365008 -0.6344300454 4.174079146 +150 -1.7707348866 1.2864253152 3.70626387 +151 1.2513762864 0.7556992416 4.181294142 +152 1.089643938 -2.5001485434 4.002974924 +153 2.50008954 -2.499974847 4.041819504 +154 -1.0940190246 -2.1313022424 3.845642176 +155 2.1776722896 1.0541972718 3.87428099 +156 -0.0395331882000001 1.6972500684 3.823106582 +157 2.5000338774 0.3867181632 4.54549633 +158 2.5001497122 1.3073891742 4.960181558 +159 1.3717521018 2.50027781286 4.096333292 +160 -1.6955078352 -1.3622797578 4.061873346 +161 1.6724483508 1.6405378734 4.508968746 +162 -1.5883062366 2.50004191788 4.004525984 +163 -2.50011644388 0.2717493792 4.23459531 +164 -0.7107997986 -1.1884793388 4.062312162 +165 0.8285435406 -1.2029877876 4.191307692 +166 -1.55143851 -0.0437593109999996 4.25096113 +167 -2.50013461182 2.50003897878 3.594022786 +168 0.0734856906000001 2.50008308844 4.408358144 +169 -0.914548509 1.0255301358 4.152194222 +170 -1.6341264246 -2.500034877 4.79181139 +171 1.4748712236 -0.4511699232 4.568599668 +172 0.1489712184 0.3411368382 4.189539116 +173 1.406735919 0.986367417 5.217013654 +174 0.4877848422 -0.430742853 4.727390504 +175 -2.5000717353 1.7276144418 4.229072872 +176 -1.7937201336 0.8688761202 4.61458745 +177 -2.50005687384 -1.8015027882 4.461473774 +178 -0.8057804424 2.0077339104 4.385534408 +179 -2.5000002933 -0.726109998 4.300541254 +180 -2.2475473872 -1.145362248 5.172585892 +181 -0.5008551234 -0.354949131 4.573265494 +182 0.8966084802 2.50000754118 4.976206068 +183 1.7559791976 -1.7879098968 4.223069524 +184 -0.0969458190000001 -1.2325570164 4.850439668 +185 2.5000228332 -2.5000156716 5.04177638 +186 -0.0943493447999999 1.8364560702 5.137311674 +187 2.500007484 -0.422753251200001 5.151382112 +188 0.4431724908 1.22235765 4.55945736 +189 -0.955181808 1.3287034494 5.104253614 +190 -0.9722254404 -1.7524120296 4.845562498 +191 0.4668761538 -2.0274797958 4.626421886 +192 0.5609288028 0.4537067568 5.188170966 +193 1.5196347156 0.0203280810000002 5.449296672 +194 1.2386247156 -1.5352518792 5.04064475 +195 -1.057892532 0.3365646498 5.033092932 +196 -1.3577205258 -0.8297695788 4.837965486 +197 2.3955945402 0.4951880454 5.534080218 +198 2.1694818594 2.50002353358 4.699335376 +199 -1.7074444422 1.9173469206 4.808416404 +200 2.5000456284 -1.4262992286 4.784752276 +201 0.7982982492 1.698849276 5.566507768 +202 1.5086419476 -2.500001286 4.91091146 +203 -0.5057618832 -2.5000529898 5.318127822 +204 -1.6643472924 -1.859715171 5.559303806 +205 1.7791669638 -0.9293853702 5.624343356 +206 0.4425652998 -1.510152669 5.645313296 +207 0.7376718042 -0.5556371952 5.687557738 +208 -0.3174564174 0.724506156 5.58195597 +209 0.476099514 -2.5000387746 5.50763995 +210 1.7492949126 1.983260724 5.445238122 +211 -0.2060036316 -0.2676090414 5.524777266 +212 2.3083762086 -1.7742526776 5.702449874 +213 1.3510895334 -2.1388098024 5.829978542 +214 -2.1305990952 -0.1588704822 5.057989534 +215 -2.50001512608 1.3339185534 5.148295084 +216 -1.0131713934 2.5000168179 5.230870194 diff --git a/contrib/voro++/examples/custom/pack_six_cube.pov b/contrib/voro++/examples/custom/pack_six_cube.pov new file mode 100644 index 0000000000000000000000000000000000000000..84364abce4d4ca2fbfa037fe8cc11a985667e95c --- /dev/null +++ b/contrib/voro++/examples/custom/pack_six_cube.pov @@ -0,0 +1,35 @@ +#version 3.6; + +// Right-handed coordinate system where the z-axis points upwards +camera { + location <30,-50,25> + sky z + right -0.15*x*image_width/image_height + up 0.15*z + look_at <0,0,2.8> +} + +// White background +background{rgb 1} + +// Two lights with slightly different colors +light_source{<-8,-20,30> color rgb <0.77,0.75,0.75>} +light_source{<25,-12,12> color rgb <0.43,0.45,0.45>} + +// The radius of the cylinders to be used when drawing the Voronoi cells +#declare r=0.08; + +// The radius of the particles +#declare s=0.5; + +// The particle packing +union{ +#include "pack_six_cube_p.pov" + pigment{rgb <0.92,0.65,1>} finish{reflection 0.17 specular 0.3 ambient 0.42} +} + +// The computed Voronoi cells +union{ +#include "pack_six_cube_v.pov" + pigment{rgb <0.7,0.95,1>} finish{specular 0.5 ambient 0.42} +} diff --git a/contrib/voro++/examples/custom/pack_six_cube_poly b/contrib/voro++/examples/custom/pack_six_cube_poly new file mode 100644 index 0000000000000000000000000000000000000000..73bcdf20d0a2cd0c0bdbaa385d67beb49f773e7f --- /dev/null +++ b/contrib/voro++/examples/custom/pack_six_cube_poly @@ -0,0 +1,159 @@ +1 2.2943224014 -1.0464559164 0.705670375 0.7060563124 +2 -2.2131251616 -0.2534282466 0.4179088816 0.4179333901 +3 0.4986979062 -2.2939091778 0.7059446546 0.7062197784 +4 -1.1363949942 2.51662017456 0.4833167708 0.4835316314 +5 2.5828525206 -2.5704232026 0.4170765074 0.4171853937 +6 2.5312613994 0.0813363383999999 0.4686585474 0.4687482872 +7 0.5270681202 0.1822394328 0.4566503184 0.4566702648 +8 -1.8090864528 -2.4784758522 0.5213700014 0.5215540739 +9 1.5172336578 -2.5995934452 0.400239651 0.4004180139 +10 -2.73541260294 -0.665141415 0.264585664 0.2646419567 +11 2.3288409102 1.3275844698 0.6712796186 0.671305465 +12 -2.3449237668 -1.3998745674 0.653114676 0.6537050365 +13 -0.273720192 0.98136621 0.5832515002 0.5835425632 +14 -2.2730510436 0.8475503082 0.7267395712 0.7271867217 +15 -1.085860644 -2.713778256 0.2766961708 0.2767006077 +16 1.3479684156 2.42613314088 0.5737740954 0.5739094414 +17 0.8679249744 1.362694794 0.5918476524 0.5923292094 +18 2.4884923332 2.48855293056 0.5114622224 0.5115241628 +19 -1.2926150898 -0.6855962928 0.6186114574 0.6186510622 +20 -0.0560958545999997 2.1992913546 0.6555111342 0.6559432277 +21 -0.3722640066 -1.390832787 0.5430032632 0.5434405502 +22 1.5403470072 -0.3978432918 0.3501305128 0.3504226441 +23 -1.4918790522 0.2174364522 0.3453688136 0.345726593 +24 -1.6062643146 1.5734729928 0.3338806088 0.3339006782 +25 -2.287521294 2.2873168098 0.7127836958 0.7128691615 +26 -1.20882963 0.9761847042 0.3286489024 0.3286563375 +27 -2.65328715 -2.3745858984 0.3469818514 0.3469938136 +28 2.4560289282 2.47977454422 1.540497065 0.518089035 +29 1.5203646228 0.459011676 0.5245273472 0.524557466 +30 -2.2683050202 -2.2685845308 1.7291921848 0.7317004607 +31 -2.2389258816 -0.3545632704 1.5777711886 0.7463444395 +32 1.3274025204 0.870454446 1.3818432376 0.4457722249 +33 -0.8200048704 1.682402946 0.3146065552 0.3146130774 +34 2.037405963 -2.734891422 0.7927691996 0.2653537674 +35 0.7446510036 -0.9449665488 0.665534172 0.6657401609 +36 0.252108156 1.4342595378 1.6692793032 0.6510015351 +37 -0.232995339 -0.3789234516 0.4790476876 0.4790707157 +38 -1.182695493 0.3412997304 1.1881339314 0.5607946756 +39 0.7342458606 2.48273619588 1.4745929916 0.5176415568 +40 1.4495150124 -1.7657545758 0.4065028532 0.4065169232 +41 2.4072350574 -2.1788555046 1.331500264 0.5929448755 +42 1.9710933996 2.74890964128 1.0075394556 0.25109367 +43 2.3634119148 0.3264172704 1.4397791162 0.5468590664 +44 -0.7944022698 -2.3604619842 1.0731014692 0.6398110513 +45 -2.61750025026 1.5823487454 1.4837685658 0.3828216219 +46 -1.3934448894 -1.4557962264 1.4245323334 0.5007351387 +47 2.0516104722 -0.5976729528 1.8291002472 0.5032897309 +48 -1.1662107612 1.580801847 1.2476943158 0.68038851 +49 -2.62275320286 2.62274544918 1.6943357446 0.3772760844 +50 1.427421291 1.7820856302 1.393223335 0.4714230179 +51 1.511602665 -0.286772143799999 1.1251421486 0.4330516084 +52 -0.00495156840000011 0.1458958272 1.4742242634 0.6673832361 +53 1.4580859176 -1.3409557974 1.518765968 0.4972881764 +54 2.6241844452 -1.3095172254 1.7018651874 0.3759083213 +55 -0.118992429 -1.2628323378 1.7735270244 0.7194916347 +56 1.5647497962 2.46394055646 2.121833662 0.5359769328 +57 -1.5032832552 2.59377415992 1.4501380794 0.4063930172 +58 -0.5839557306 1.0057908114 2.610664932 0.6791948278 +59 1.3074553278 -2.4040604262 1.7243671778 0.5964918599 +60 0.8814832356 -0.5611616082 1.7601448296 0.5026682898 +61 -2.48310263682 0.8266609542 1.9533304434 0.5170110188 +62 2.297113395 1.3967461578 2.081742634 0.7030393739 +63 -1.0195599864 -0.4111505676 1.9681311576 0.5352429558 +64 -0.5175275088 2.4823593312 1.69677395 0.5176595874 +65 -1.5489189312 0.4950305808 2.168855308 0.4975790562 +66 0.333337215 -0.0583095054 2.827392692 0.7423505541 +67 0.0674296854000001 -2.4833591418 1.8344001122 0.5167676635 +68 0.2775952626 2.3842496988 2.507242568 0.6160387592 +69 2.4017613972 -2.4018615012 2.501486212 0.5984231387 +70 -1.9955052906 1.9651018854 2.311247106 0.7211789759 +71 -2.53302155544 -1.2633035634 2.325987884 0.4670032313 +72 1.0254797076 -1.3689550506 2.699984766 0.7453434186 +73 2.7366543312 -0.255166959 1.8627578132 0.2633667332 +74 -1.5932869332 -1.161104781 2.33654568 0.4783428461 +75 -1.009793352 -2.3145221832 2.379841524 0.6857252069 +76 0.693340893 -2.7334615248 2.233459154 0.2665414081 +77 1.4664561702 0.2494399638 2.198538934 0.5896736187 +78 1.0609126104 1.346259048 2.764337228 0.7100030833 +79 2.5104461586 0.288508614 2.469325808 0.4902809103 +80 2.2333125396 -1.3321437648 2.468530976 0.4850812043 +81 -2.53682629722 -2.0202472632 2.866756044 0.4632815554 +82 1.39206234 -2.5243049766 2.847264012 0.4759385864 +83 -2.2724829138 -0.1098747342 3.030753202 0.7278689558 +84 2.017225557 -0.4654244676 3.2605051 0.7088141325 +85 -0.8802476718 2.2941084036 3.138807084 0.706319733 +86 -0.628079403 -1.2303917862 3.026510666 0.6333826584 +87 -2.3580815088 1.2015017298 3.469933122 0.6423476731 +88 2.4394649826 2.43914405052 2.782663268 0.5611360678 +89 0.0625357709999999 1.567985091 3.457187126 0.5253053479 +90 -1.539161295 0.7417340322 3.027584724 0.3961963631 +99 -2.72525501652 2.7252550677 2.33003352 0.2747456695 +92 0.0712955964000002 -2.1279171366 2.760670462 0.4755996786 +93 -1.6729430694 -2.2970374674 3.599943258 0.703232669 +94 2.3386638444 1.4752735164 3.527299472 0.6613443566 +95 -1.434656622 1.4247232644 3.255650254 0.3315953156 +96 1.4645618112 2.40960447342 3.394721712 0.5906045429 +97 1.3760703144 0.6001459458 3.91326855 0.6957628841 +98 -0.9462140538 -0.0427487088 3.336492874 0.6348952769 +100 0.1827398208 2.53982076702 3.56794066 0.4602070182 +101 -0.457002639 -2.4730137114 3.539548678 0.5270570418 +102 -0.931419198 1.310320869 4.181737976 0.7285273468 +103 -2.0616432114 -1.381992453 2.96886929 0.338965935 +104 0.3262376142 -1.1104806558 3.891426076 0.6602407423 +105 2.603218266 0.4692112902 3.333852194 0.3969569889 +106 0.621550263600001 -2.5866908208 3.286851976 0.4133731777 +107 -1.6503699132 -0.9780887094 3.900764794 0.6499567157 +108 2.5553042898 0.5974451142 4.164302548 0.4447202462 +109 1.093439955 -1.9843021254 3.772229138 0.4928106182 +110 2.2235607966 -1.7856976272 3.593621548 0.6684564056 +111 -1.8611431338 0.263821821 4.322428632 0.6784407082 +112 -0.714751794 -1.7696935824 4.568625748 0.7458394563 +113 0.0386044164000001 0.2095397208 4.263319014 0.7410307389 +114 2.6686634316 -0.9488247192 3.911576604 0.3313563455 +115 2.2284709422 2.44392245922 4.203874322 0.52275482 +116 1.6157859984 1.0711117986 4.785981628 0.324507904 +117 2.6962586916 2.69148775836 3.569067278 0.3038361345 +118 2.3010754314 -2.3010362742 4.857805072 0.6990378129 +119 1.5263534148 -1.0151841486 4.39882278 0.646307023 +120 2.5098680544 -0.286387857 4.293648972 0.4497013899 +121 -2.299556475 -1.9016876682 4.792048206 0.7005884521 +122 0.9244959174 1.6753165404 3.841476996 0.4245743159 +123 -2.195684046 2.3733634644 3.92901905 0.627024797 +124 2.029463979 0.3068333046 4.912229852 0.5146686515 +125 2.413782231 1.5097724478 4.772127442 0.5862580388 +126 -0.9412554102 -0.4929830346 4.75320165 0.5604422166 +127 0.3372408174 -2.552452671 4.098775276 0.4476288123 +128 1.595908398 1.800843726 3.997430578 0.2760586876 +129 -1.1690519448 2.54118940104 4.240150194 0.4588777615 +130 0.9204879588 2.5114852107 4.32092078 0.4885296669 +131 0.659912373 1.3331246274 4.845102632 0.6684164081 +132 2.671829979 2.67183193236 4.893475244 0.3281755811 +133 -2.2910456076 1.4532497628 4.8927943 0.7089778106 +134 -1.076059968 0.5908148568 5.408126698 0.7007406601 +135 -2.3840496972 -0.6255172758 5.10418547 0.6160086477 +136 1.0821373314 -0.0702869808000002 4.884508576 0.5053602451 +137 -0.1570730478 2.3498492814 4.651425962 0.6502238281 +138 0.2317918764 0.4511463576 5.732392164 0.6539508916 +139 -1.3545203652 -2.270521377 5.800060516 0.7295653254 +140 -0.9624893322 -2.7356211324 4.088993036 0.2643819056 +141 -1.5216895236 -0.3565353498 5.43671559 0.3466350961 +142 -1.2907235904 2.2917439416 5.332687914 0.6684343677 +143 0.8866195422 -2.0804987466 5.0460502 0.7449337414 +144 1.6203390714 2.41392403836 5.130579106 0.5861366337 +145 1.296612102 0.664002732 5.135460666 0.2998035487 +146 -2.53747613442 0.4097391504 5.36465084 0.4625465899 +147 0.1716290718 -0.8312932698 5.267659842 0.7114849333 +148 1.654186005 1.321091574 5.765267432 0.6781646288 +149 2.378105925 -0.7080846654 5.286799656 0.6219566767 +150 1.7460546672 -1.5505974858 5.104615992 0.2664296597 +151 -2.5832557326 -1.4049308712 5.751830462 0.4167636988 +152 1.5354658446 -0.00829035900000008 5.96063277 0.6640629242 +153 -1.7109245526 -1.0595021664 5.944676482 0.5411024747 +154 2.6796552096 2.1823488846 5.31882093 0.3203466498 +155 -0.3250549086 1.5328440306 5.45032619 0.5047825301 +156 -1.026100956 1.520969247 6.202284836 0.5233534934 +157 1.2170797572 -0.7873677756 5.30232077 0.3354648203 +158 0.5536985856 2.295029025 5.731413028 0.6438728258 +159 2.5065769272 0.6006610446 6.121709486 0.4934687094 +160 -2.0501973498 -0.0777889722000005 6.039149584 0.501875366 diff --git a/contrib/voro++/examples/custom/pack_six_cube_poly.pov b/contrib/voro++/examples/custom/pack_six_cube_poly.pov new file mode 100644 index 0000000000000000000000000000000000000000..40c3b67391c6bccd25e9fe6699903879d17d9271 --- /dev/null +++ b/contrib/voro++/examples/custom/pack_six_cube_poly.pov @@ -0,0 +1,33 @@ +#version 3.6; + +// Right-handed coordinate system where the z-axis points upwards +camera { + location <30,-50,25> + sky z + right -0.15*x*image_width/image_height + up 0.15*z + look_at <0,0,2.8> +} + +// White background +background{rgb 1} + +// Two lights with slightly different colors +light_source{<-8,-20,30> color rgb <0.77,0.75,0.75>} +light_source{<25,-12> color rgb <0.43,0.45,0.45>} + +// The radius of the cylinders to be used when drawing the Voronoi cells +#declare r=0.08; + +// The polydisperse particle packing +union{ +#include "pack_six_cube_poly_p.pov" + pigment{rgb <0.92,0.65,1>} finish{reflection 0.17 specular 0.3 ambient 0.42} +} + +// The Voronoi cells for the packing, computed using the radical Voronoi +// tessellation +union{ +#include "pack_six_cube_poly_v.pov" + pigment{rgb <0.7,0.95,1>} finish{specular 0.5 ambient 0.42} +} diff --git a/contrib/voro++/examples/custom/radical.cc b/contrib/voro++/examples/custom/radical.cc new file mode 100644 index 0000000000000000000000000000000000000000..8ce9bd7326ec9c6f677126b691488f3ecbf00f21 --- /dev/null +++ b/contrib/voro++/examples/custom/radical.cc @@ -0,0 +1,43 @@ +// Radical Voronoi tessellation example code +// +// Author : Chris H. Rycroft (LBL / UC Berkeley) +// Email : chr@alum.mit.edu +// Date : August 30th 2011 + +#include "voro++.hh" +using namespace voro; + +// Set up constants for the container geometry +const double x_min=-3,x_max=3; +const double y_min=-3,y_max=3; +const double z_min=0,z_max=6; + +// Set up the number of blocks that the container is divided +// into. +const int n_x=3,n_y=3,n_z=3; + +int main() { + + // Create a container with the geometry given above, and make it + // non-periodic in each of the three coordinates. Allocate space for + // eight particles within each computational block. Import + // the monodisperse test packing and output the Voronoi + // tessellation in gnuplot and POV-Ray formats. + container con(x_min,x_max,y_min,y_max,z_min,z_max,n_x,n_y,n_z, + false,false,false,8); + con.import("pack_six_cube"); + con.draw_cells_gnuplot("pack_six_cube.gnu"); + con.draw_cells_pov("pack_six_cube_v.pov"); + con.draw_particles_pov("pack_six_cube_p.pov"); + + // Create a container for polydisperse particles using the same + // geometry as above. Import the polydisperse test packing and + // output the Voronoi radical tessellation in gnuplot and POV-Ray + // formats. + container_poly conp(x_min,x_max,y_min,y_max,z_min,z_max,n_x,n_y,n_z, + false,false,false,8); + conp.import("pack_six_cube_poly"); + conp.draw_cells_gnuplot("pack_six_cube_poly.gnu"); + conp.draw_cells_pov("pack_six_cube_poly_v.pov"); + conp.draw_particles_pov("pack_six_cube_poly_p.pov"); +} diff --git a/contrib/voro++/examples/degenerate/Makefile b/contrib/voro++/examples/degenerate/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..61bad1c3bc24fd4f46a7522c3f560140c1f87c53 --- /dev/null +++ b/contrib/voro++/examples/degenerate/Makefile @@ -0,0 +1,25 @@ +# Voro++ makefile +# +# Author : Chris H. Rycroft (LBL / UC Berkeley) +# Email : chr@alum.mit.edu +# Date : August 30th 2011 + +# Load the common configuration file +include ../../config.mk + +# List of executables +EXECUTABLES=degenerate degenerate2 + +# Makefile rules +all: degenerate degenerate2 + +degenerate: $(SOURCE) degenerate.cc + $(CXX) $(CFLAGS) $(E_INC) $(E_LIB) -o degenerate degenerate.cc -lvoro++ + +degenerate2: $(SOURCE) degenerate2.cc + $(CXX) $(CFLAGS) $(E_INC) $(E_LIB) -o degenerate2 degenerate2.cc -lvoro++ + +clean: + rm -f $(EXECUTABLES) + +.PHONY: all clean diff --git a/contrib/voro++/examples/degenerate/README b/contrib/voro++/examples/degenerate/README new file mode 100644 index 0000000000000000000000000000000000000000..f81b2977c70b04e45486b26c3a6698127d9598ea --- /dev/null +++ b/contrib/voro++/examples/degenerate/README @@ -0,0 +1,21 @@ +Examples of degenerate vertex support +===================================== +Voronoi cells are irregular polyhedra whose faces are made by random plane cuts +due to neighboring particles, and typically all the vertices of these polyhedra +have order 3, since creating higher order vertices can only occur if a plane +cut intersects an existing vertex. + +In order to make the code robust for handling very large systems, Voro++ +correctly handles these cases, by taking the approach that if a plane is within +a particular numerical tolerance of an existing vertex, it treats the plane as +perfectly intersecting that vertex, and it recomputes the cell topology +accordingly, allowing it to have perfect representations of objects such as an +octahedron. These example codes demonstrate this support: + +1. higher_test.cc - this code creates an object by cutting with planes aligned +in a conical arragement along the positive and negative axes in the x, y, and z +directions. This results in six very high order vertices, and often many order +four vertices. + +2. higher_test2.cc - this code creates an approximation to a sphere, by cutting +with many different planes aligned in locally random conical arrangements. diff --git a/contrib/voro++/examples/degenerate/degenerate.cc b/contrib/voro++/examples/degenerate/degenerate.cc new file mode 100644 index 0000000000000000000000000000000000000000..c997b02a00f2ad19736b9cbf2f7ee385d344451a --- /dev/null +++ b/contrib/voro++/examples/degenerate/degenerate.cc @@ -0,0 +1,48 @@ +// Degenerate Voronoi cell example code +// +// Author : Chris H. Rycroft (LBL / UC Berkeley) +// Email : chr@alum.mit.edu +// Date : August 30th 2011 + +#include "voro++.hh" +using namespace voro; + +const double pi=3.1415926535897932384626433832795; + +// The number of planes to be cut around each coordinate axis +const int n=32; +const double step=2*pi/n; + +// The angle (in radians) of the cutting planes from horizontal +const double theta=pi/4-0.25; + +int main() { + double x,y,z,phi; + voronoicell v; + + // Initialize the Voronoi cell to be a cube of side length 2, centered + // on the origin + v.init(-1,1,-1,1,-1,1); + + // Plane cutting + for(phi=0;phi<2*pi-0.5*step;phi+=step) { + x=cos(theta);y=cos(phi)*sin(theta);z=sin(phi)*sin(theta); + v.plane(x,y,z,1); + v.plane(-x,y,z,1); + v.plane(y,x,z,1); + v.plane(y,-x,z,1); + v.plane(y,z,x,1); + v.plane(y,z,-x,1); + } + + // Check that the relation table is correct, and that there are no + // duplicate edges + v.check_relations(); + v.check_duplicates(); + + // Output the Voronoi cell to a file in Gnuplot format + v.draw_gnuplot(0,0,0,"degenerate.gnu"); + + // Output the Voronoi cell to a file in POV-Ray format + v.draw_pov(0,0,0,"degenerate_v.pov"); +} diff --git a/contrib/voro++/examples/degenerate/degenerate.pov b/contrib/voro++/examples/degenerate/degenerate.pov new file mode 100644 index 0000000000000000000000000000000000000000..74edc85293a1bd9001aa2488cff97411b3555633 --- /dev/null +++ b/contrib/voro++/examples/degenerate/degenerate.pov @@ -0,0 +1,33 @@ +#version 3.6; + +#include "colors.inc" +#include "metals.inc" +#include "textures.inc" + +global_settings { + max_trace_level 64 +} + +camera { + location <15,10,-30> + right 0.04*x*image_width/image_height + up 0.04*y + look_at <0,0,0> +} + +background{rgb 1} + +light_source{<-4,35,-20> color rgb <0.72,0.7,0.7>} +light_source{<20,5,-10> color rgb <0.4,0.42,0.42>} + +#declare r=0.01; + +union{ +#include "degenerate_v.pov" + texture{T_Gold_3C} +} + +sphere{<0,0,0>,0.5-r + pigment{rgb <0.1,0.15,0.4>} + finish{reflection 0.25 specular 0.4 ambient 0.6} +} diff --git a/contrib/voro++/examples/degenerate/degenerate2.cc b/contrib/voro++/examples/degenerate/degenerate2.cc new file mode 100644 index 0000000000000000000000000000000000000000..6165d605d14516390afd4ca3aaf698e75669809b --- /dev/null +++ b/contrib/voro++/examples/degenerate/degenerate2.cc @@ -0,0 +1,64 @@ +// Degenerate vertex example code +// +// Author : Chris H. Rycroft (LBL / UC Berkeley) +// Email : chr@alum.mit.edu +// Date : August 30th 2011 + +#include "voro++.hh" +using namespace voro; + +const double pi=3.1415926535897932384626433832795; + +// The total number of points to create as degenerate vertices +const int points=100; + +// The number of planes that will be cut around each point +const int n=64; +const double step=2*pi/n; + +// The angle (in radians) of the cutting planes from horizontal +const double theta=0.04; + +// This function returns a random floating point number between 0 and 1 +double rnd() {return double(rand())/RAND_MAX;} + +int main() { + double x,y,z,rsq,r,phi; + voronoicell v; + int n=0; + + // Initialize the Voronoi cell to be a cube of side length 2, centered on + // the origin + v.init(-1,1,-1,1,-1,1); + + // Plane cutting + while(n<points) { + + // Choose a random point + x=2*rnd()-1; + y=2*rnd()-1; + z=2*rnd()-1; + + // Skip it if it's outside the unit sphere or too close to the + // origin + rsq=x*x+y*y+z*z; + if(rsq<0.01||rsq>1) continue; + + // Rescale the point so that it has modulus 1, and then apply + // plane cuts around this point + r=1/sqrt(rsq);x*=r;y*=r;z*=r; + rsq=sqrt(x*x+y*y);r=z/rsq; + for(phi=rnd()*step;phi<2*pi;phi+=step) + v.plane(x*cos(theta)+sin(theta)*(-y*cos(phi)/rsq-x*r*sin(phi)), + y*cos(theta)+sin(theta)*(x*cos(phi)/rsq-y*r*sin(phi)), + z*cos(theta)+sin(theta)*rsq*sin(phi),1); + n++; + } + + // Output the Voronoi cell to a file in Gnuplot format + v.draw_gnuplot(0,0,0,"degenerate2.gnu"); + + // Optional POV-Ray output + v.draw_pov(0,0,0,"degenerate2_v.pov"); + v.draw_pov_mesh(0,0,0,"degenerate2_m.pov"); +} diff --git a/contrib/voro++/examples/degenerate/degenerate2.pov b/contrib/voro++/examples/degenerate/degenerate2.pov new file mode 100644 index 0000000000000000000000000000000000000000..a734a5ea1c5eb8713d576be761e3d60f2a2c324b --- /dev/null +++ b/contrib/voro++/examples/degenerate/degenerate2.pov @@ -0,0 +1,32 @@ +#version 3.6; +#include "colors.inc" +#include "metals.inc" +#include "textures.inc" + +global_settings { + max_trace_level 64 +} + +camera { + location <1,2.5,-5> + right 0.2*x*image_width/image_height + up 0.2*y + look_at <0,0,0> +} + +background{rgb 1} + +light_source{<-0.8,3,-2> color rgb <0.77,0.75,0.75>} +light_source{<2.5,1.2,-1.2> color rgb <0.38,0.40,0.40>} + +#declare r=0.002; + +union{ +#include "degenerate2_m.pov" + pigment{rgb <1,0.2,0.25>} finish{specular 0.2 ambient 0.42} +} + +union{ +#include "degenerate2_v.pov" + texture{T_Gold_3C} +} diff --git a/contrib/voro++/examples/extra/Makefile b/contrib/voro++/examples/extra/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..89e6517affe0023d0036ed7b5f31feedc272ad46 --- /dev/null +++ b/contrib/voro++/examples/extra/Makefile @@ -0,0 +1,34 @@ +# Voro++ makefile +# +# Author : Chris H. Rycroft (LBL / UC Berkeley) +# Email : chr@alum.mit.edu +# Date : August 30th 2011 + +# Load the common configuration file +include ../../config.mk + +# List of executables +EXECUTABLES=box_cut cut_region superellipsoid irregular + +# Makefile rules +all: $(EXECUTABLES) + +box_cut: box_cut.cc + $(CXX) $(CFLAGS) $(E_INC) $(E_LIB) -o box_cut box_cut.cc -lvoro++ + +cut_region: cut_region.cc + $(CXX) $(CFLAGS) $(E_INC) $(E_LIB) -o cut_region cut_region.cc -lvoro++ + +superellipsoid: superellipsoid.cc + $(CXX) $(CFLAGS) $(E_INC) $(E_LIB) -o superellipsoid superellipsoid.cc -lvoro++ + +irregular: irregular.cc + $(CXX) $(CFLAGS) $(E_INC) $(E_LIB) -o irregular irregular.cc -lvoro++ + +finite_sys: finite_sys.cc + $(CXX) $(CFLAGS) $(E_INC) $(E_LIB) -o finite_sys finite_sys.cc -lvoro++ + +clean: + rm -f $(EXECUTABLES) + +.PHONY: all clean diff --git a/contrib/voro++/examples/extra/README b/contrib/voro++/examples/extra/README new file mode 100644 index 0000000000000000000000000000000000000000..85ce45a944deed0d4697546a1153cd87ba577b33 --- /dev/null +++ b/contrib/voro++/examples/extra/README @@ -0,0 +1,27 @@ +Extra examples +============== +This directory contains miscellaneous extra examples of the code. + +box_cut.cc - this creates a large Voronoi cell, and then cuts the cell by a +group of points within a small box, to demonstrate space that particles within +a block can possibly affect. Different topologies are visible depending on +whether a face, edge, or corner of the box is aligned with the cell. + +cut_region.cc - this program demonstrates the plane_intersects() routine for +determining whether a plane has any intersection with a Voronoi cell. The +program creates a test Voronoi cell, saves it to "cell.gnu", and then maps out +the region of space which can possibly influence it and saves an outline of it +to "cell_cut_region.gnu". These can be visualized in gnuplot using: + +splot 'cell.gnu' with lines, 'cell_cut_region.gnu' with dots + +superellipsoid.cc - this creates a cell in the shape of a superellipsoid +(satisfying the equation x^4+y^4+z^4=1) and outputs the results in gnuplot +format to "superellipsoid.gnu". + +irregular.cc - this code makes use of a wall class as a method of handling a +Voronoi tessellation for an irregular group of particles. Each Voronoi cell is +initialized to be a dodecahedron surronding the particle, which is then cut. +This stops Voronoi cells from extending a long way out to the computational +boundaries. The output can be visualized using the POV-Ray header file +irregular.pov. diff --git a/contrib/voro++/examples/extra/box_cut.cc b/contrib/voro++/examples/extra/box_cut.cc new file mode 100644 index 0000000000000000000000000000000000000000..7eb0916c5e93c7042045cdeed25853ab576abd19 --- /dev/null +++ b/contrib/voro++/examples/extra/box_cut.cc @@ -0,0 +1,32 @@ +// Box cutting example code +// +// Author : Chris H. Rycroft (LBL / UC Berkeley) +// Email : chr@alum.mit.edu +// Date : August 30th 2011 + +#include "voro++.hh" +using namespace voro; + +// Parameters controlling the center of the test box +const double cx=1.5,cy=1.5,cz=1.5; + +int main() { + double x,y,z; + voronoicell v; + + // Initialize the Voronoi cell to be a cube of side length 16, centered + // on the origin + v.init(-8,8,-8,8,-8,8); + + // Cut by a grid of points in a box of width one, centered on + // (cx,cy,cz) + for(x=cx-0.5;x<cx+0.55;x+=0.1) for(y=cy-0.5;y<cy+0.55;y+=0.1) + for(z=cz-0.5;z<cz+0.55;z+=0.1) v.plane(x,y,z); + + // Output the Voronoi cell in gnuplot format + v.draw_gnuplot(0,0,0,"box_cut.gnu"); + + // Now make a small file that contains the test box + v.init(cx-0.5,cx+0.5,cy-0.5,cy+0.5,cz-0.5,cz+0.5); + v.draw_gnuplot(0,0,0,"box_cut.points"); +} diff --git a/contrib/voro++/examples/extra/cut_region.cc b/contrib/voro++/examples/extra/cut_region.cc new file mode 100644 index 0000000000000000000000000000000000000000..3b8b10bcf70b4029a4033d6cf44e57b34ea51ed2 --- /dev/null +++ b/contrib/voro++/examples/extra/cut_region.cc @@ -0,0 +1,72 @@ +// Cell cutting region example code +// +// Author : Chris H. Rycroft (LBL / UC Berkeley) +// Email : chr@alum.mit.edu +// Date : August 30th 2011 + +#include "voro++.hh" +using namespace voro; + +const double pi=3.1415926535897932384626433832795; + +// This constant sets the tolerance in the bisection search algorithm +const double tolwidth=1e-7; + +// This constant determines the density of points to test +const double theta_step=pi/200; + +int main() { + double x,y,z,r,rmin,rmax; + double theta,phi,phi_step; + voronoicell v; + FILE *fp=safe_fopen("cell_cut_region.gnu","w"); + + // Initialize the Voronoi cell to be an octahedron and make a single + // plane cut to add some variation + v.init_octahedron(1); + v.plane(0.4,0.3,1,0.1); + + // Output the cell in gnuplot format + v.draw_gnuplot(0,0,0,"cell.gnu"); + + // Now test over direction vectors from the center of the sphere. For + // each vector, carry out a search to find the maximum distance along + // that vector that a plane will intersect with cell, and save it to + // the output file. + for(theta=theta_step*0.5;theta<pi;theta+=theta_step) { + phi_step=2*pi/(int(2*pi*sin(theta)/theta_step)+1); + for(phi=phi_step*0.5;phi<2*pi;phi+=phi_step) { + + // Calculate a direction to look along + x=sin(theta)*cos(phi); + y=sin(theta)*sin(phi); + z=cos(theta); + + // Now carry out a bisection search. Here, we initialize + // a minimum and a maximum guess for the distance + // along this vector. Keep multiplying rmax by two until + // the plane no longer makes a cut. + rmin=0;rmax=1; + while (v.plane_intersects(x,y,z,rmax)) rmax*=2; + + // We now know that the distance is somewhere between + // rmin and rmax. Test the point halfway in-between + // these two. If it intersects, then move rmin to this + // point; otherwise, move rmax there. At each stage the + // bounding interval is divided by two. Exit when the + // width of the interval is smaller than the tolerance. + while (rmax-rmin>tolwidth) { + r=(rmax+rmin)*0.5; + if (v.plane_intersects(x,y,z,r)) rmin=r; + else rmax=r; + } + + // Output this point to file + r=(rmax+rmin)*0.5; + x*=r;y*=r;z*=r; + fprintf(fp,"%g %g %g\n",x,y,z); + } + } + + fclose(fp); +} diff --git a/contrib/voro++/examples/extra/irregular.cc b/contrib/voro++/examples/extra/irregular.cc new file mode 100644 index 0000000000000000000000000000000000000000..3f9dd9df1bbab8b992eb9c49bfdff30a6655ac4c --- /dev/null +++ b/contrib/voro++/examples/extra/irregular.cc @@ -0,0 +1,70 @@ +// Irregular packing example code +// +// Author : Chris H. Rycroft (LBL / UC Berkeley) +// Email : chr@alum.mit.edu +// Date : August 30th 2011 + +#include "voro++.hh" +using namespace voro; + +// Set up constants for the container geometry +const double x_min=-6,x_max=6; +const double y_min=-6,y_max=6; +const double z_min=-3,z_max=9; + +// Golden ratio constants +const double Phi=0.5*(1+sqrt(5.0)); +const double phi=0.5*(1-sqrt(5.0)); + +// Set up the number of blocks that the container is divided +// into. +const int n_x=5,n_y=5,n_z=5; + +// Create a wall class that, whenever called, will replace the Voronoi cell +// with a prescribed shape, in this case a dodecahedron +class wall_initial_shape : public wall { + public: + wall_initial_shape() { + + // Create a dodecahedron + v.init(-2,2,-2,2,-2,2); + v.plane(0,Phi,1);v.plane(0,-Phi,1);v.plane(0,Phi,-1); + v.plane(0,-Phi,-1);v.plane(1,0,Phi);v.plane(-1,0,Phi); + v.plane(1,0,-Phi);v.plane(-1,0,-Phi);v.plane(Phi,1,0); + v.plane(-Phi,1,0);v.plane(Phi,-1,0);v.plane(-Phi,-1,0); + }; + bool point_inside(double x,double y,double z) {return true;} + bool cut_cell(voronoicell &c,double x,double y,double z) { + + // Set the cell to be equal to the dodecahedron + c=v; + return true; + } + bool cut_cell(voronoicell_neighbor &c,double x,double y,double z) { + + // Set the cell to be equal to the dodecahedron + c=v; + return true; + } + private: + voronoicell v; +}; + +int main() { + + // Create a container with the geometry given above. This is bigger + // than the particle packing itself. + container con(x_min,x_max,y_min,y_max,z_min,z_max,n_x,n_y,n_z, + false,false,false,8); + + // Create the "initial shape" wall class and add it to the container + wall_initial_shape(wis); + con.add_wall(wis); + + // Import the irregular particle packing + con.import("pack_irregular"); + + // Save the particles and Voronoi cells in POV-Ray format + con.draw_particles_pov("irregular_p.pov"); + con.draw_cells_pov("irregular_v.pov"); +} diff --git a/contrib/voro++/examples/extra/irregular.pov b/contrib/voro++/examples/extra/irregular.pov new file mode 100644 index 0000000000000000000000000000000000000000..ac461b267ba015a9c1049eb9661422b96f183de4 --- /dev/null +++ b/contrib/voro++/examples/extra/irregular.pov @@ -0,0 +1,34 @@ +#version 3.6; +#include "colors.inc" +#include "metals.inc" +#include "textures.inc" + +camera { + location <0,-50,15> + sky z + right -0.25*x*image_width/image_height + up 0.25*y + look_at <0,0,0> +} + +background{rgb 1} + +light_source{<-16,-30,30> color rgb <0.77,0.75,0.75>} +light_source{<25,-16,8> color rgb <0.43,0.45,0.45>} + +#declare r=0.05; +#declare s=0.5; + +#declare particles=union { +#include "irregular_p.pov" + pigment{rgb 0.9} finish{reflection 0.2 specular 0.25 ambient 0.28 metallic} +} + +union{particles translate <-4,0,0>} +union{particles translate <4,0,0>} + +union{ +#include "irregular_v.pov" + translate <4,0,0> + pigment{rgb <0.7,0.3,0.9>} finish{specular 0.5 ambient 0.42} +} diff --git a/contrib/voro++/examples/extra/pack_irregular b/contrib/voro++/examples/extra/pack_irregular new file mode 100644 index 0000000000000000000000000000000000000000..a9e845351a36a30a2351280f93afbb0b73afcb0c --- /dev/null +++ b/contrib/voro++/examples/extra/pack_irregular @@ -0,0 +1,90 @@ +72 -0.147483 -0.558693 -3.18934 +9 -2.41157 -1.29774 -1.06982 +80 -1.47859 -1.8335 -1.36336 +65 -0.711941 -2.41131 -1.64334 +64 -0.4797 -1.21197 -2.50408 +20 -1.42529 -0.939487 -1.80822 +40 -1.23958 0.407091 -1.66298 +79 -2.15132 0.907402 -1.59593 +66 -1.53942 -0.324634 -1.02788 +0 -0.413499 0.327672 -2.81041 +7 0.539113 0.879889 -1.70334 +10 -0.531341 -0.241038 -1.12169 +22 -0.697165 -0.321415 -2.10456 +59 0.392636 -0.224244 -2.07623 +67 0.763622 0.563918 -2.62516 +36 -0.30969 0.754975 -1.08361 +45 1.579 0.889521 -1.4745 +47 1.4156 -0.647419 -1.48749 +84 2.28022 0.210077 -1.69046 +15 0.77776 1.81164 -1.68825 +42 -0.18009 1.616 -1.8986 +54 0.560998 2.64828 -1.1852 +23 -1.87416 -2.33337 0.0595857 +41 -1.44546 -1.42998 0.0496244 +3 0.648987 -2.47874 -0.114855 +5 -0.539766 -1.84268 0.146595 +52 0.0605186 -2.7285 0.762346 +87 0.506043 -1.30521 0.122018 +56 0.125353 -1.8152 -0.649339 +27 1.23838 -1.98443 0.524113 +11 -1.7844 -0.395658 0.171453 +13 -1.56182 0.417102 0.228077 +53 -1.05622 0.840323 0.989743 +21 -1.73028 0.613184 -0.737932 +24 -2.70227 0.360208 -0.694108 +43 -2.26163 0.0972097 0.905263 +2 -0.846054 0.37304 -0.320826 +8 0.881191 0.180836 -0.691522 +83 0.220646 -0.586568 -0.560328 +32 -0.929809 -0.630924 -0.2915 +57 -0.740037 -0.0210996 0.59228 +50 0.224453 -0.1255 0.328453 +49 -0.337601 -0.932723 0.508691 +74 2.15102 -0.586216 -0.812645 +85 2.74671 0.216964 -0.805714 +82 1.07437 0.400501 0.359586 +55 -1.95062 2.07317 0.607831 +86 -1.52454 1.40705 -0.00434567 +69 -2.21193 1.06183 0.646364 +89 -0.387785 2.20094 -0.16407 +61 -0.849347 1.52048 -0.733213 +68 -0.635487 1.68349 0.655008 +70 0.495467 2.5636 0.133158 +18 0.305068 1.94276 0.946142 +76 0.987675 1.2686 -0.403397 +14 1.59053 2.0932 0.386613 +26 1.08147 2.78732 0.911973 +44 1.96939 1.24919 -0.592929 +46 2.94129 1.02209 0.994683 +19 1.18461 2.24248 -0.516429 +88 2.2082 1.30683 0.376432 +39 -1.12068 -1.89589 2.01622 +37 -1.35954 -1.23596 1.02763 +17 -0.390062 -2.44346 1.60836 +78 0.309306 -1.49032 2.25291 +71 0.465111 -1.82342 1.13741 +60 -2.51128 -0.741988 1.52195 +62 -2.26236 0.132924 1.93737 +77 -1.58329 0.16374 2.79988 +16 -1.40954 -0.246268 1.30018 +34 -1.34135 -0.920726 2.03534 +28 0.465115 0.780311 1.96134 +31 -0.530333 0.808298 2.08415 +35 -0.443838 -0.132428 2.41211 +51 0.76714 0.0380576 2.56075 +63 0.424234 -0.520687 1.23131 +73 -0.487922 -0.869208 1.49529 +29 -0.0885648 0.57667 1.05946 +1 1.53919 -0.840006 2.01191 +12 1.61355 -0.981671 1.0564 +75 1.46049 0.694938 1.91717 +58 -1.67927 1.51233 1.39003 +33 -1.05848 1.00787 2.90952 +4 -0.110568 1.67679 1.82049 +6 -0.822763 1.82494 1.80562 +81 0.694696 2.26858 2.02688 +25 0.235788 1.78411 2.77166 +30 0.783889 1.06523 1.04789 +38 2.09077 1.30555 1.4377 +48 1.28628 1.88704 1.31663 diff --git a/contrib/voro++/examples/extra/superellipsoid.cc b/contrib/voro++/examples/extra/superellipsoid.cc new file mode 100644 index 0000000000000000000000000000000000000000..d81978d64ec414d7e82761997f6c47e1a23da4d3 --- /dev/null +++ b/contrib/voro++/examples/extra/superellipsoid.cc @@ -0,0 +1,41 @@ +// Superellipsoid example code +// +// Author : Chris H. Rycroft (LBL / UC Berkeley) +// Email : chr@alum.mit.edu +// Date : August 30th 2011 + +#include "voro++.hh" +using namespace voro; + +// This function returns a random floating point number between 0 and 1 +double rnd() {return double(rand())/RAND_MAX;} + +int main() { + double x,y,z,rsq,r; + voronoicell v; + + // Initialize the Voronoi cell to be a cube of side length 2, centered + // on the origin + v.init(-1,1,-1,1,-1,1); + + // Cut the cell by 5000 random planes that are scaled to create a + // superellipsoid + for(int i=0;i<5000;i++) { + x=2*rnd()-1; + y=2*rnd()-1; + z=2*rnd()-1; + rsq=x*x*x*x+y*y*y*y+z*z*z*z; + if(rsq>0.01&&rsq<1) { + r=1/sqrt(sqrt(rsq)); + x*=r;y*=r;z*=r; + v.plane(x*x*x,y*y*y,z*z*z,x*x*x*x+y*y*y*y+z*z*z*z); + } + } + + // Output the Voronoi cell to a file, in the gnuplot format + v.draw_gnuplot(0,0,0,"superellipsoid.gnu"); + + // Output the Voronoi cell to a file in POV-Ray formats + v.draw_pov(0,0,0,"superellipsoid_v.pov"); + v.draw_pov_mesh(0,0,0,"superellipsoid_m.pov"); +} diff --git a/contrib/voro++/examples/extra/superellipsoid.pov b/contrib/voro++/examples/extra/superellipsoid.pov new file mode 100644 index 0000000000000000000000000000000000000000..4429e89bde478e2ce588b5e1169f19a1fc8e09f5 --- /dev/null +++ b/contrib/voro++/examples/extra/superellipsoid.pov @@ -0,0 +1,32 @@ +#version 3.6; +#include "colors.inc" +#include "metals.inc" +#include "textures.inc" + +global_settings { + max_trace_level 64 +} + +camera { + location <1,2.5,-5> + right 0.23*x*image_width/image_height + up 0.23*y + look_at <0,0,0> +} + +background{rgb 1} + +light_source{<-0.8,3,-2> color rgb <0.77,0.75,0.65>} +light_source{<2.5,1.2,-1.2> color rgb <0.38,0.30,0.40>} + +#declare r=0.006; + +union{ +#include "superellipsoid_m.pov" + texture{T_Gold_3C} +} + +union{ +#include "superellipsoid_v.pov" + texture{T_Silver_3C} +} diff --git a/contrib/voro++/examples/interface/Makefile b/contrib/voro++/examples/interface/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..3522ac04339bf77e8dcd401bf11834f17ab8c20b --- /dev/null +++ b/contrib/voro++/examples/interface/Makefile @@ -0,0 +1,31 @@ +# Voro++ makefile +# +# Author : Chris H. Rycroft (LBL / UC Berkeley) +# Email : chr@alum.mit.edu +# Date : August 30th 2011 + +# Load the common configuration file +include ../../config.mk + +# List of executables +EXECUTABLES=loops polygons odd_even find_voro_cell + +# Makefile rules +all: $(EXECUTABLES) + +loops: loops.cc + $(CXX) $(CFLAGS) $(E_INC) $(E_LIB) -o loops loops.cc -lvoro++ + +polygons: polygons.cc + $(CXX) $(CFLAGS) $(E_INC) $(E_LIB) -o polygons polygons.cc -lvoro++ + +odd_even: odd_even.cc + $(CXX) $(CFLAGS) $(E_INC) $(E_LIB) -o odd_even odd_even.cc -lvoro++ + +find_voro_cell: find_voro_cell.cc + $(CXX) $(CFLAGS) $(E_INC) $(E_LIB) -o find_voro_cell find_voro_cell.cc -lvoro++ + +clean: + rm -f $(EXECUTABLES) + +.PHONY: all clean diff --git a/contrib/voro++/examples/interface/README b/contrib/voro++/examples/interface/README new file mode 100644 index 0000000000000000000000000000000000000000..85e358f5b6921e36744cf6dca3b9556ffcae60ee --- /dev/null +++ b/contrib/voro++/examples/interface/README @@ -0,0 +1,52 @@ +C++ interface output examples +============================= +Since version 0.4, Voro++ has contained many routines that allow for programs +to directly analyze features of a single Voronoi cell, and Voronoi cells in a +particle packing. These example codes demonstrate this functionality. + +1. odd_even.cc constructs a single Voronoi cell using random planes, in the +same manner as the basic single_cell.cc example. It then calls several routines +to gain information about the computed cell's faces. Using this information it +constructs a POV-Ray scene in which the faces are colored white or black +depending on whether the have an odd or even number of sides. The POV-Ray +header file odd_even.pov can be used to visualize the result. + +2. loops.cc demonstrates the loop classes, that can be used to iterate over a +certain subset of particles within a container. It demonstrates the +c_loop_order class, which can loop over a specific pre-computed list of +particles. It also demonstrates the c_loop_subset class, which can loop over +particles in a certain region of the container. These classes are used to +compute Voronoi cells in two interlocking tori. The POV-Ray header file +loops.pov can be used to visualize the result. + +3. polygons.cc demonstrates how routines can be used to find all faces in a +Voronoi tessellation that have a specific number of sides. The routine also +demonstrates the pre_container class, that can aid in correctly configuring the +underlying grid that the code uses, in cases whether the amount of input data +is not known a priori. When run, the code generates POV-Ray scenes of all +quadrilateral, pentagonal, and hexagonal faces in a Voronoi tessellation. The +can be visualized using the POV-Ray header files polygons4.pov, polygons5.pov, +and polygons6.pov. + +4. find_voro_cell.cc demonstrates the find_voronoi_cell routine. For a given +position vector, this routine will return the Voronoi cell that the vector is +within. The code creates a unit cube and randomly adds twenty particles to it. +It carries out a number of find_voronoi_cell calls for a slice through the +cube, creating a file with vectors from each sample point to the particle whose +Voronoi cell contains the point. The results can be visualized in Gnuplot with + +splot 'find_voro_cell_v.gnu' w l t 'Voronoi cells', 'find_voro_cell.vec' w vec t 'Voronoi cell vectors', 'find_voro_cell_p.gnu' w p u 2:3:4 t 'Particles' + +The example also uses the find_voronoi_cell routine to estimate the size of +each Voronoi cell. It scans a grid covering the entire container, making +find_voronoi_cell calls at each location. The number of times each Voronoi cell +is returned gives an estimate of its volume. These sampled volumes, as well as +the exact calculated voulmes are saved to 'find_voro_cell.vol'. A graph +comparing the two can be plotted in Gnuplot with + +set xlabel 'Calculated volume' +set ylabel 'Sampled volume' +plot [0:0.1] [0:0.1] 'find_voro_cell.vol' u 5:6 + +Altering the size of scanning grid alters who accurate the sampled volumes will +match the calculated results. diff --git a/contrib/voro++/examples/interface/find_voro_cell.cc b/contrib/voro++/examples/interface/find_voro_cell.cc new file mode 100644 index 0000000000000000000000000000000000000000..096a51df55773708ad9f19e54ad0b997b1dddba5 --- /dev/null +++ b/contrib/voro++/examples/interface/find_voro_cell.cc @@ -0,0 +1,89 @@ +// Example code demonstrating find_voronoi_cell function +// +// Author : Chris H. Rycroft (LBL / UC Berkeley) +// Email : chr@alum.mit.edu +// Date : August 30th 2011 + +#include "voro++.hh" +using namespace voro; + +// The sampling distance for the grids of find_voronoi_cell calls +const double h=0.05; + +// The cube of the sampling distance, corresponding the amount of volume +// associated with a sample point +const double hcube=h*h*h; + +// Set the number of particles that are going to be randomly introduced +const int particles=20; + +// This function returns a random double between 0 and 1 +double rnd() {return double(rand())/RAND_MAX;} + +int main() { + int i; + double x,y,z,r,rx,ry,rz; + + // Create a container with the geometry given above, and make it + // non-periodic in each of the three coordinates. Allocate space for + // eight particles within each computational block + container con(0,1,0,1,0,1,5,5,5,false,false,false,8); + + // Randomly add particles into the container + for(i=0;i<particles;i++) { + x=rnd(); + y=rnd(); + z=rnd(); + con.put(i,x,y,z); + } + + // Output the particle positions in gnuplot format + con.draw_particles("find_voro_cell_p.gnu"); + + // Scan a 2D slice in the container, and for each point in the slice, + // find the Voronoi cell that the point is in. Store a vector + FILE *f1=safe_fopen("find_voro_cell.vec","w"); + for(x=0.5*h;x<1;x+=h) for(y=0.5*h;y<1;y+=h) { + if(con.find_voronoi_cell(x,y,0.5,rx,ry,rz,i)) + fprintf(f1,"%g %g %g %g %g %g %g\n",x,y,0.5,rx-x,ry-y,rz-0.5, + sqrt((rx-x)*(rx-x)+(ry-y)*(ry-y)+(rz-0.5)*(rz-0.5))); + else fprintf(stderr,"# find_voronoi_cell error for %g %g 0.5\n",x,y); + } + fclose(f1); + + // Create a blank array for storing the sampled Voronoi volumes + int samp_v[particles]; + for(i=0;i<particles;i++) samp_v[i]=0; + + // Scan over a grid covering the entire container, finding which + // Voronoi cell each point is in, and tallying the result as a method + // of sampling the volume of each Voronoi cell + for(z=0.5*h;z<1;z+=h) for(y=0.5*h;y<1;y+=h) for(x=0.5*h;x<1;x+=h) { + if(con.find_voronoi_cell(x,y,z,rx,ry,rz,i)) samp_v[i]++; + else fprintf(stderr,"# find_voronoi_cell error for %g %g %g\n",x,y,z); + } + + // Output the Voronoi cells in gnuplot format and a file with the + // comparisons between the Voronoi cell volumes and the sampled volumes + f1=safe_fopen("find_voro_cell.vol","w"); + FILE *f2=safe_fopen("find_voro_cell_v.gnu","w"); + c_loop_all cla(con); + voronoicell c; + if(cla.start()) do if (con.compute_cell(c,cla)) { + + // Get the position and ID information for the particle + // currently being considered by the loop. Ignore the radius + // information. + cla.pos(i,x,y,z,r); + + // Save and entry to the .vol file, storing both the computed + // Voronoi cell volume, and the sampled volume based on the + // number of grid points that were inside the cell + fprintf(f1,"%d %g %g %g %g %g\n",i,x,y,z,c.volume(),samp_v[i]*hcube); + + // Draw the Voronoi cell + c.draw_gnuplot(x,y,z,f2); + } while (cla.inc()); + fclose(f1); + fclose(f2); +} diff --git a/contrib/voro++/examples/interface/loops.cc b/contrib/voro++/examples/interface/loops.cc new file mode 100644 index 0000000000000000000000000000000000000000..2fa3c38cd7a32b9717742e30f8cf94f4d2dca890 --- /dev/null +++ b/contrib/voro++/examples/interface/loops.cc @@ -0,0 +1,81 @@ +// Example code demonstrating the loop classes +// +// Author : Chris H. Rycroft (LBL / UC Berkeley) +// Email : chr@alum.mit.edu +// Date : August 30th 2011 + +#include "voro++.hh" +using namespace voro; + +// Constants determining the configuration of the tori +const double dis=1.25,mjrad=2.5,mirad=0.95,trad=mjrad+mirad; + +// Set the number of particles that are going to be randomly introduced +const int particles=100000; + +// This function returns a random double between 0 and 1 +double rnd() {return double(rand())/RAND_MAX;} + +int main() { + int i; + double x,y,z,r; + voronoicell c; + + // Create a container as a non-periodic 10 by 10 by 10 box + container con(-5,5,-5,5,-5,5,26,26,26,false,false,false,8); + particle_order po; + + // Randomly add particles into the container + for(i=0;i<particles;i++) { + x=10*rnd()-5; + y=10*rnd()-5; + z=10*rnd()-5; + + // If the particle lies within the first torus, store it in the + // ordering class when adding to the container + r=sqrt((x-dis)*(x-dis)+y*y); + if((r-mjrad)*(r-mjrad)+z*z<mirad) con.put(po,i,x,y,z); + else con.put(i,x,y,z); + } + + // Compute Voronoi cells for the first torus. Here, the points + // previously stored in the ordering class are looped over. + FILE *f1=safe_fopen("loops1_m.pov","w"); + FILE *f2=safe_fopen("loops1_v.pov","w"); + c_loop_order clo(con,po); + if(clo.start()) do if(con.compute_cell(c,clo)) { + + // Get the position of the current particle under consideration + clo.pos(x,y,z); + + // Save a POV-Ray mesh to one file and a cylinder/sphere + // representation to the other file + c.draw_pov_mesh(x,y,z,f1); + c.draw_pov(x,y,z,f2); + } while (clo.inc()); + fclose(f1); + fclose(f2); + + // Compute Voronoi cells for the second torus. Here, the subset loop is + // used to search over the blocks overlapping the torus, and then each + // particle is individually tested. + f1=safe_fopen("loops2_m.pov","w"); + f2=safe_fopen("loops2_v.pov","w"); + c_loop_subset cls(con); + cls.setup_box(-dis-trad,-dis+trad,-mirad,mirad,-trad,trad,false); + if(cls.start()) do { + + // Get the position of the current particle under consideration + cls.pos(x,y,z); + + // Test whether this point is within the torus, and if so, + // compute and save the Voronoi cell + r=sqrt((x+dis)*(x+dis)+z*z); + if((r-mjrad)*(r-mjrad)+y*y<mirad&&con.compute_cell(c,cls)) { + c.draw_pov_mesh(x,y,z,f1); + c.draw_pov(x,y,z,f2); + } + } while (cls.inc()); + fclose(f1); + fclose(f2); +} diff --git a/contrib/voro++/examples/interface/loops.pov b/contrib/voro++/examples/interface/loops.pov new file mode 100644 index 0000000000000000000000000000000000000000..953b2918622b3b7facae70acaa6812823fc60093 --- /dev/null +++ b/contrib/voro++/examples/interface/loops.pov @@ -0,0 +1,44 @@ +#version 3.6; +#include "colors.inc" +#include "metals.inc" +#include "textures.inc" + +global_settings { + max_trace_level 64 +} + +camera { + location <2,-40,30> + sky z + right -0.155*x*image_width/image_height + up 0.155*z + look_at <0,0,0> +} + +background{rgb 1} + +light_source{<-8,-20,30> color rgb <0.79,0.75,0.75>} +light_source{<25,-12,12> color rgb <0.36,0.40,0.40>} + +#declare r=0.02; +#declare s=0.2; + +union{ +#include "loops1_m.pov" + pigment{rgb <0.9,0.6,0.3>} finish{reflection 0.185 specular 0.3 ambient 0.42} +} + +union{ +#include "loops1_v.pov" + pigment{rgb <0.9,0.4,0.45>} finish{specular 0.5 ambient 0.42} +} + +union{ +#include "loops2_m.pov" + pigment{rgb <0.5,0.65,0.75>} finish{reflection 0.185 specular 0.3 ambient 0.42} +} + +union{ +#include "loops2_v.pov" + pigment{rgb <0.42,0.42,0.75>} finish{specular 0.5 ambient 0.42} +} diff --git a/contrib/voro++/examples/interface/odd_even.cc b/contrib/voro++/examples/interface/odd_even.cc new file mode 100644 index 0000000000000000000000000000000000000000..be08b16260fbb37f9aaec70929f3636ef9e51824 --- /dev/null +++ b/contrib/voro++/examples/interface/odd_even.cc @@ -0,0 +1,53 @@ +// Odd/even face coloring code +// +// Author : Chris H. Rycroft (LBL / UC Berkeley) +// Email : chr@alum.mit.edu +// Date : August 30th 2011 + +#include "voro++.hh" +using namespace voro; + +// This function returns a random floating point number between 0 and 1 +double rnd() {return double(rand())/RAND_MAX;} + +int main() { + unsigned int i; + double x,y,z,rsq,r; + voronoicell v; + + // Initialize the Voronoi cell to be a cube of side length 2, centered + // on the origin + v.init(-1,1,-1,1,-1,1); + + // Cut the cell by 250 random planes which are all a distance 1 away + // from the origin, to make an approximation to a sphere + for(i=0;i<250;i++) { + x=2*rnd()-1; + y=2*rnd()-1; + z=2*rnd()-1; + rsq=x*x+y*y+z*z; + if(rsq>0.01&&rsq<1) { + r=1/sqrt(rsq);x*=r;y*=r;z*=r; + v.plane(x,y,z,1); + } + } + + // Calculate the orders of the faces and the normal vectors + vector<int> f_vert; + vector<double> nor; + v.face_orders(f_vert); + v.normals(nor); + + // Output POV-Ray planes with textures based on whether a face is + // composed of an odd or even number of edges + const char* parity[2]={"even","odd"}; + FILE *fp=safe_fopen("odd_even_pl.pov","w"); + for(i=0;i<f_vert.size();i++) + fprintf(fp,"plane{<%g,%g,%g>,0.5 texture{t_%s}}\n" + ,nor[3*i],nor[3*i+1],nor[3*i+2] + ,parity[f_vert[i]&1]); + fclose(fp); + + // Save the Voronoi cell as a spheres and cylinders + v.draw_pov(0,0,0,"odd_even_v.pov"); +} diff --git a/contrib/voro++/examples/interface/odd_even.pov b/contrib/voro++/examples/interface/odd_even.pov new file mode 100644 index 0000000000000000000000000000000000000000..669ede81c34c21c484fdf1eeb6c6d425f37ca8e1 --- /dev/null +++ b/contrib/voro++/examples/interface/odd_even.pov @@ -0,0 +1,38 @@ +#version 3.6; + +#include "colors.inc" +#include "metals.inc" +#include "textures.inc" + +global_settings { + max_trace_level 64 +} + +camera { + location <15,-30,10> + sky z + right -0.033*x*image_width/image_height + up 0.033*y + look_at <0,0,0> +} + +background{rgb 1} + +light_source{<-4,-20,35> color rgb <0.72,0.7,0.7>} +light_source{<20,-10,5> color rgb <0.4,0.42,0.42>} + +#declare r=0.01; + +#declare f1=finish{reflection 0.17 specular 0.3 ambient 0.42} +#declare t_odd=texture{pigment{rgb <0.8,0.8,0.8>} finish{f1}} +#declare t_even=texture{pigment{rgb <0.2,0.2,0.2>} finish{f1}} + +intersection{ +#include "odd_even_pl.pov" +} + +union{ +#include "odd_even_v.pov" + pigment{rgb <0.9,0.1,0.15>} + finish{reflection 0.25 specular 0.4 ambient 0.3} +} diff --git a/contrib/voro++/examples/interface/pack_six_cube b/contrib/voro++/examples/interface/pack_six_cube new file mode 100644 index 0000000000000000000000000000000000000000..066f2067f01d48db8eb779015d8f3652213280d7 --- /dev/null +++ b/contrib/voro++/examples/interface/pack_six_cube @@ -0,0 +1,216 @@ +1 -1.633531566 1.0081779456 0.4997643894 +2 -2.3175495108 2.50004343396 0.4998098766 +3 -0.0883292022000002 2.49998487024 0.49997382 +4 -0.5905249392 2.1141400272 1.2739520638 +5 -1.6354550196 0.00777687119999992 0.4998135702 +6 2.50024371 1.7052004254 1.1066620646 +7 1.6163377164 0.378218796 0.4996352686 +8 0.6450816684 1.8136706778 0.4991881638 +9 1.3723354464 2.50001343222 0.4998503506 +10 -2.49477600042 -2.4994533834 0.49997382 +11 0.1591747386 -0.8623052892 0.4997612252 +12 0.6018432558 2.50085393652 1.2236191762 +13 2.4993970962 2.50004979816 0.499958425 +14 2.5002306354 -0.5891871372 1.3656871624 +15 2.4996763188 0.910593138 0.4998442324 +16 0.1555379868 -2.1140856714 0.499808302 +17 1.7917374258 -2.5001865732 1.2081198644 +18 -2.1690769116 -1.9332698928 1.3393934932 +19 1.7064470976 1.5487702458 0.49997382 +20 -0.7669637874 -2.5000096794 0.4999680968 +21 2.5000711542 -1.0890633102 0.4997243732 +22 -1.630300629 -1.9954333962 0.4995576534 +23 1.7914606536 -1.7945441268 0.4997721152 +24 -2.50023339174 -0.4939926774 0.4998565634 +25 -2.5002228639 0.5096527854 0.4998286406 +26 -2.49973398858 1.5167884392 0.4998730372 +27 -1.09231806 2.50004601528 0.4999122966 +28 -0.7664081604 1.506191607 0.4998754028 +29 -2.49994466028 -1.4976897942 0.49997382 +30 -1.6351530756 -0.9955213908 0.4999588934 +31 2.5000470594 -2.5000639944 0.4999611072 +32 1.0827185856 -2.500004454 0.4999501042 +33 0.121049223 0.962177124 0.4998840514 +34 -0.731239728 -1.4928565722 0.499907191 +35 2.5000148538 -1.7942863308 1.208330482 +36 1.4293900734 -0.60411936 0.4998811682 +37 1.693914078 -1.1739451596 1.2777368674 +38 -0.7702945434 -0.4936272762 0.4995237402 +39 2.5001273412 0.4105916904 1.3657870828 +40 -0.2151642102 -0.4489046268 1.3296380976 +41 -0.7687151904 0.5062139106 0.4999055828 +42 2.500152618 -0.0892589747999999 0.4997650116 +43 1.0009049868 1.008280419 0.972585352 +44 -1.5086934072 0.9974863356 1.4916875348 +45 -0.1906878174 -2.5001610756 1.3546498898 +46 1.9350760212 2.50015141518 1.3263206044 +47 0.7680680142 -0.613803066 1.2529781652 +48 -0.520322322 0.9840571992 1.3423839878 +49 -1.7049937512 1.8781106406 0.987517195 +50 0.2890163712 1.5679785972 1.4005698552 +51 -2.5001055165 -0.9902666664 1.3677983936 +52 0.6718107054 0.0485346384000001 0.4998990378 +53 0.8828891958 -1.4903279178 0.7856231914 +54 1.6971075462 -1.8794484798 1.986236625 +55 0.7785745614 -1.5429397554 1.778749626 +56 2.498355582 -2.5002474342 1.9162502768 +57 1.8163510674 1.118761185 1.5402656292 +58 -2.49028043208 0.00966293040000021 1.3657617934 +59 -1.0465593666 -1.9851376494 1.3111443026 +60 1.6230277242 -0.109344417 1.3725323044 +61 0.803677725 -2.4904980648 1.4601558584 +62 2.500174548 -1.291019802 2.077806292 +63 -0.4406783868 -1.0295588292 2.111380354 +64 -1.0593921888 -0.9853736058 1.3206667652 +65 -1.0862456712 0.0421811507999998 1.334589922 +66 -0.0664300529999999 -1.4875173498 1.246881552 +67 0.2975538384 0.4089966312 1.3541999206 +68 -2.0563739124 1.7171792856 1.9181011058 +69 -1.5021759366 -2.5002090786 2.037012458 +70 1.2004706514 1.8826223166 1.7322744688 +71 -2.50018854048 1.0131918204 1.3636933196 +72 -0.6610079004 -1.996969944 2.233624626 +73 0.3572570658 -0.4242221946 2.149145084 +74 -2.50015722168 2.5001806872 1.4828326074 +75 -1.7654338962 -0.4966383762 1.832939586 +76 2.5001148054 1.8908456178 2.089239758 +77 -1.5156057486 -1.498156245 2.047882108 +78 -0.0249709901999999 2.50011927126 2.002554182 +79 2.500335852 0.901840926 2.23670456 +80 -2.50033055412 -2.5002094542 2.093220108 +81 -2.50007568966 -1.5087105342 2.222856128 +82 0.2019219258 -2.5001781654 2.2742338 +83 2.500074618 -0.1030437882 2.239501644 +84 1.306372176 -0.7329475686 2.087233828 +85 -0.9572314386 1.6112582586 2.05661196 +86 0.8603279154 0.9694525734 1.9616903498 +87 -1.4114044692 2.50004378976 1.713374457 +88 -2.5000006182 2.49931211886 2.482805848 +89 -1.020675462 -0.3572734878 2.57123686 +90 -0.4044797454 0.2263507242 2.042403434 +91 -2.50015066302 -0.0762997092000002 2.3660063 +92 2.5000666632 -0.6377540202 3.084536714 +93 1.635820743 0.3998132112 2.232930018 +94 0.787044012 2.3196010806 2.557182368 +95 1.7880996756 -1.270196802 2.779504834 +96 -2.5000149498 0.9308964468 2.36020607 +97 2.50006086 1.4990173908 3.038728388 +98 2.5000002036 -2.0009185842 2.782437742 +99 2.4973597854 0.4018063872 3.102688092 +100 -0.0847238868 1.1548315362 2.230957046 +101 -1.6189831278 0.38758413 2.276164892 +102 -1.3109302698 -1.529630028 3.0261821 +103 -0.8621444616 2.50007941956 2.548976818 +104 -2.5003575921 -2.1906193686 3.043995226 +105 1.737794406 2.50023188418 2.306502354 +106 1.1607421194 -2.5001894034 2.557490476 +107 -0.5515943472 -2.5000711818 3.090821674 +108 0.7581635106 0.305805486 2.70258895 +109 -0.129270348 -0.0804334734000003 2.953362524 +110 1.5702057348 -0.2965035672 2.947395472 +111 -1.5907955166 0.297198915 3.271622288 +112 -1.6352174376 1.2855549804 2.715570616 +113 0.2365862016 -1.5621519012 2.618913636 +114 2.5001485044 -1.4752385472 3.632918874 +115 -2.50003414566 0.7085497368 3.335106492 +116 0.693198909 -0.7706072304 3.02499245 +117 -1.977290892 -0.837825789 2.748661152 +118 -0.0904186877999997 1.9400047344 2.850126046 +119 0.7424979096 1.3708776012 2.869705454 +120 2.5001771184 2.49786273384 2.953357364 +121 -0.460913031 -1.0102788876 3.1107298 +122 -1.5499088826 -2.5003303314 3.035766602 +123 1.0563693948 -1.7172623304 3.2938531 +124 0.4360463934 -2.5001018958 3.246364772 +125 0.0342889535999999 0.8326700802 3.326329174 +126 1.8144590976 -2.498344152 3.31403944 +127 1.4937454758 0.7565635794 3.208225078 +128 1.6727590014 1.420657209 2.482601878 +129 0.9063634374 -0.0106950330000002 3.63948294 +130 1.6212776142 2.0992148076 3.215117466 +131 -0.8136720582 0.7230042144 2.807794018 +132 -1.315108014 -0.6402926916 3.483977248 +133 -2.50004255652 -0.2892251556 3.401060322 +134 0.1195260084 -1.6342581966 3.633549956 +135 0.9584037636 1.636359729 3.809100648 +136 -1.7019079596 2.2670358852 3.038768934 +137 0.4485449298 2.50002773754 3.480648292 +138 -0.5629460556 2.50007656902 3.530567852 +139 -2.068160793 -2.5000301934 3.890959658 +140 1.8860334708 0.0716001041999998 3.821883252 +141 -2.50019618556 1.6650778878 3.043689132 +142 -2.50008791622 -1.2873252654 3.47288578 +143 0.1086245172 -0.5872844136 3.815345888 +144 1.6639765482 -0.932813649 3.712928374 +145 -0.1833273246 -2.5000925064 4.03160142 +146 -0.8962851474 1.5809637768 3.320864614 +147 -0.7169574816 0.1400516334 3.731676664 +148 2.500011852 2.0721063306 3.85816837 +149 2.5001365008 -0.6344300454 4.174079146 +150 -1.7707348866 1.2864253152 3.70626387 +151 1.2513762864 0.7556992416 4.181294142 +152 1.089643938 -2.5001485434 4.002974924 +153 2.50008954 -2.499974847 4.041819504 +154 -1.0940190246 -2.1313022424 3.845642176 +155 2.1776722896 1.0541972718 3.87428099 +156 -0.0395331882000001 1.6972500684 3.823106582 +157 2.5000338774 0.3867181632 4.54549633 +158 2.5001497122 1.3073891742 4.960181558 +159 1.3717521018 2.50027781286 4.096333292 +160 -1.6955078352 -1.3622797578 4.061873346 +161 1.6724483508 1.6405378734 4.508968746 +162 -1.5883062366 2.50004191788 4.004525984 +163 -2.50011644388 0.2717493792 4.23459531 +164 -0.7107997986 -1.1884793388 4.062312162 +165 0.8285435406 -1.2029877876 4.191307692 +166 -1.55143851 -0.0437593109999996 4.25096113 +167 -2.50013461182 2.50003897878 3.594022786 +168 0.0734856906000001 2.50008308844 4.408358144 +169 -0.914548509 1.0255301358 4.152194222 +170 -1.6341264246 -2.500034877 4.79181139 +171 1.4748712236 -0.4511699232 4.568599668 +172 0.1489712184 0.3411368382 4.189539116 +173 1.406735919 0.986367417 5.217013654 +174 0.4877848422 -0.430742853 4.727390504 +175 -2.5000717353 1.7276144418 4.229072872 +176 -1.7937201336 0.8688761202 4.61458745 +177 -2.50005687384 -1.8015027882 4.461473774 +178 -0.8057804424 2.0077339104 4.385534408 +179 -2.5000002933 -0.726109998 4.300541254 +180 -2.2475473872 -1.145362248 5.172585892 +181 -0.5008551234 -0.354949131 4.573265494 +182 0.8966084802 2.50000754118 4.976206068 +183 1.7559791976 -1.7879098968 4.223069524 +184 -0.0969458190000001 -1.2325570164 4.850439668 +185 2.5000228332 -2.5000156716 5.04177638 +186 -0.0943493447999999 1.8364560702 5.137311674 +187 2.500007484 -0.422753251200001 5.151382112 +188 0.4431724908 1.22235765 4.55945736 +189 -0.955181808 1.3287034494 5.104253614 +190 -0.9722254404 -1.7524120296 4.845562498 +191 0.4668761538 -2.0274797958 4.626421886 +192 0.5609288028 0.4537067568 5.188170966 +193 1.5196347156 0.0203280810000002 5.449296672 +194 1.2386247156 -1.5352518792 5.04064475 +195 -1.057892532 0.3365646498 5.033092932 +196 -1.3577205258 -0.8297695788 4.837965486 +197 2.3955945402 0.4951880454 5.534080218 +198 2.1694818594 2.50002353358 4.699335376 +199 -1.7074444422 1.9173469206 4.808416404 +200 2.5000456284 -1.4262992286 4.784752276 +201 0.7982982492 1.698849276 5.566507768 +202 1.5086419476 -2.500001286 4.91091146 +203 -0.5057618832 -2.5000529898 5.318127822 +204 -1.6643472924 -1.859715171 5.559303806 +205 1.7791669638 -0.9293853702 5.624343356 +206 0.4425652998 -1.510152669 5.645313296 +207 0.7376718042 -0.5556371952 5.687557738 +208 -0.3174564174 0.724506156 5.58195597 +209 0.476099514 -2.5000387746 5.50763995 +210 1.7492949126 1.983260724 5.445238122 +211 -0.2060036316 -0.2676090414 5.524777266 +212 2.3083762086 -1.7742526776 5.702449874 +213 1.3510895334 -2.1388098024 5.829978542 +214 -2.1305990952 -0.1588704822 5.057989534 +215 -2.50001512608 1.3339185534 5.148295084 +216 -1.0131713934 2.5000168179 5.230870194 diff --git a/contrib/voro++/examples/interface/polygons.cc b/contrib/voro++/examples/interface/polygons.cc new file mode 100644 index 0000000000000000000000000000000000000000..205a6e4e1219a37031cf7feadffd4a88a292506c --- /dev/null +++ b/contrib/voro++/examples/interface/polygons.cc @@ -0,0 +1,104 @@ +// Direct C++ interface example code +// +// Author : Chris H. Rycroft (LBL / UC Berkeley) +// Email : chr@alum.mit.edu +// Date : August 30th 2011 + +#include "voro++.hh" +using namespace voro; + +void draw_polygon(FILE *fp,vector<int> &f_vert,vector<double> &v,int j); + +int main() { + unsigned int i,j; + int id,nx,ny,nz; + double x,y,z; + voronoicell_neighbor c; + vector<int> neigh,f_vert; + vector<double> v; + + // Create a pre-container class to import the input file and guess the + // best computational grid size to use. + pre_container pcon(-3,3,-3,3,0,6,false,false,false); + pcon.import("pack_six_cube"); + pcon.guess_optimal(nx,ny,nz); + + // Set up the container class and import the particles from the + // pre-container + container con(-3,3,-3,3,0,6,nx,ny,nz,false,false,false,8); + pcon.setup(con); + + // Open the output files + FILE *fp4=safe_fopen("polygons4_v.pov","w"), + *fp5=safe_fopen("polygons5_v.pov","w"), + *fp6=safe_fopen("polygons6_v.pov","w"); + + // Loop over all particles in the container and compute each Voronoi + // cell + c_loop_all cl(con); + if(cl.start()) do if(con.compute_cell(c,cl)) { + cl.pos(x,y,z);id=cl.pid(); + + // Gather information about the computed Voronoi cell + c.neighbors(neigh); + c.face_vertices(f_vert); + c.vertices(x,y,z,v); + + // Loop over all faces of the Voronoi cell + for(i=0,j=0;i<neigh.size();i++) { + + // Draw all quadrilaterals, pentagons, and hexagons. + // Skip if the neighbor information is smaller than + // this particle's ID, to avoid double counting. This + // also removes faces that touch the walls, since the + // neighbor information is set to negative numbers for + // these cases. + if(neigh[i]>id) { + switch(f_vert[j]) { + case 4: draw_polygon(fp4,f_vert,v,j); + break; + case 5: draw_polygon(fp5,f_vert,v,j); + break; + case 6: draw_polygon(fp6,f_vert,v,j); + } + } + + // Skip to the next entry in the face vertex list + j+=f_vert[j]+1; + } + } while (cl.inc()); + + // Close the output files + fclose(fp4); + fclose(fp5); + fclose(fp6); + + // Draw the outline of the domain + con.draw_domain_pov("polygons_d.pov"); +} + +void draw_polygon(FILE *fp,vector<int> &f_vert,vector<double> &v,int j) { + static char s[6][128]; + int k,l,n=f_vert[j]; + + // Create POV-Ray vector strings for each of the vertices + for(k=0;k<n;k++) { + l=3*f_vert[j+k+1]; + sprintf(s[k],"<%g,%g,%g>",v[l],v[l+1],v[l+2]); + } + + // Draw the interior of the polygon + fputs("union{\n",fp); + for(k=2;k<n;k++) fprintf(fp,"\ttriangle{%s,%s,%s}\n",s[0],s[k-1],s[k]); + fputs("\ttexture{t1}\n}\n",fp); + + // Draw the outline of the polygon + fputs("union{\n",fp); + for(k=0;k<n;k++) { + l=(k+1)%n; + fprintf(fp,"\tcylinder{%s,%s,r}\n\tsphere{%s,r}\n", + s[k],s[l],s[l]); + } + fputs("\ttexture{t2}\n}\n",fp); +} + diff --git a/contrib/voro++/examples/interface/polygons4.pov b/contrib/voro++/examples/interface/polygons4.pov new file mode 100644 index 0000000000000000000000000000000000000000..ae3ac1475115ab5c841d39b1b205ef17a9abf23c --- /dev/null +++ b/contrib/voro++/examples/interface/polygons4.pov @@ -0,0 +1,38 @@ +#version 3.6; +#include "colors.inc" +#include "metals.inc" +#include "textures.inc" + +global_settings { + max_trace_level 64 +} + +camera { + location <30,-50,25> + sky z + up 0.15*z + right -0.15*x*image_width/image_height + look_at <0,0,2.8> +} + +background{rgb 1} + +light_source{<-8,-20,30> color rgb <0.77,0.75,0.75>} +light_source{<25,-12,12> color rgb <0.43,0.45,0.45>} + +#declare r=0.06; +#declare rr=0.08; + +#declare f1=finish{reflection 0.15 specular 0.3 ambient 0.42} + +#declare t1=texture{pigment{rgbft <0.9,0.5,0.3,0,0.4>} finish{f1}} +#declare t2=texture{pigment{rgb <0.9,0.35,0.25>} finish{f1}} + +union{ +#include "polygons4_v.pov" +} + +union{ +#include "polygons_d.pov" + texture{T_Silver_4B} +} diff --git a/contrib/voro++/examples/interface/polygons5.pov b/contrib/voro++/examples/interface/polygons5.pov new file mode 100644 index 0000000000000000000000000000000000000000..3c0159e3f88b9e83d053c614f72a5c073ae8a67e --- /dev/null +++ b/contrib/voro++/examples/interface/polygons5.pov @@ -0,0 +1,38 @@ +#version 3.6; +#include "colors.inc" +#include "metals.inc" +#include "textures.inc" + +global_settings { + max_trace_level 64 +} + +camera { + location <30,-50,25> + sky z + up 0.15*z + right -0.15*x*image_width/image_height + look_at <0,0,2.8> +} + +background{rgb 1} + +light_source{<-8,-20,30> color rgb <0.77,0.75,0.75>} +light_source{<25,-12,12> color rgb <0.43,0.45,0.45>} + +#declare r=0.06; +#declare rr=0.08; + +#declare f1=finish{reflection 0.15 specular 0.3 ambient 0.42} + +#declare t1=texture{pigment{rgbft <0.3,0.9,0.7,0,0.4>} finish{f1}} +#declare t2=texture{pigment{rgb <0.1,0.5,0.3>} finish{f1}} + +union{ +#include "polygons5_v.pov" +} + +union{ +#include "polygons_d.pov" + texture{T_Silver_4B} +} diff --git a/contrib/voro++/examples/interface/polygons6.pov b/contrib/voro++/examples/interface/polygons6.pov new file mode 100644 index 0000000000000000000000000000000000000000..b70bc0b96e13fcccdb87400628cdb17c26f76749 --- /dev/null +++ b/contrib/voro++/examples/interface/polygons6.pov @@ -0,0 +1,38 @@ +#version 3.6; +#include "colors.inc" +#include "metals.inc" +#include "textures.inc" + +global_settings { + max_trace_level 64 +} + +camera { + location <30,-50,25> + sky z + up 0.15*z + right -0.15*x*image_width/image_height + look_at <0,0,2.8> +} + +background{rgb 1} + +light_source{<-8,-20,30> color rgb <0.77,0.75,0.75>} +light_source{<25,-12,12> color rgb <0.43,0.45,0.45>} + +#declare r=0.06; +#declare rr=0.08; + +#declare f1=finish{reflection 0.15 specular 0.3 ambient 0.42} + +#declare t1=texture{pigment{rgbft <0.3,0.7,0.9,0,0.4>} finish{f1}} +#declare t2=texture{pigment{rgb <0.3,0.4,0.9>} finish{f1}} + +union{ +#include "polygons6_v.pov" +} + +union{ +#include "polygons_d.pov" + texture{T_Silver_4B} +} diff --git a/contrib/voro++/examples/no_release/Makefile b/contrib/voro++/examples/no_release/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..b839abec7fae98edcc1b00b0d2f647e9f1f38167 --- /dev/null +++ b/contrib/voro++/examples/no_release/Makefile @@ -0,0 +1,58 @@ +# Voro++ makefile +# +# Author : Chris H. Rycroft (LBL / UC Berkeley) +# Email : chr@alum.mit.edu +# Date : August 30th 2011 + +# Load the common configuration file +include ../../config.mk + +# List of executables +EXECUTABLES=rad_test finite_sys cylinder_inv single_cell_2d period sphere_mesh lloyd_box import_rahman import_nguyen polycrystal_rahman random_points_10 random_points_200 import_freeman + +# Makefile rules +all: $(EXECUTABLES) + +rad_test: rad_test.cc + $(CXX) $(CFLAGS) $(E_INC) $(E_LIB) -o rad_test rad_test.cc -lvoro++ + +finite_sys: finite_sys.cc + $(CXX) $(CFLAGS) $(E_INC) $(E_LIB) -o finite_sys finite_sys.cc -lvoro++ + +cylinder_inv: cylinder_inv.cc + $(CXX) $(CFLAGS) $(E_INC) $(E_LIB) -o cylinder_inv cylinder_inv.cc -lvoro++ + +single_cell_2d: single_cell_2d.cc + $(CXX) $(CFLAGS) $(E_INC) $(E_LIB) -o single_cell_2d single_cell_2d.cc -lvoro++ + +period: period.cc + $(CXX) $(CFLAGS) $(E_INC) $(E_LIB) -o period period.cc -lvoro++ + +sphere_mesh: sphere_mesh.cc + $(CXX) $(CFLAGS) $(E_INC) $(E_LIB) -o sphere_mesh sphere_mesh.cc -lvoro++ + +lloyd_box: lloyd_box.cc + $(CXX) $(CFLAGS) $(E_INC) $(E_LIB) -o lloyd_box lloyd_box.cc -lvoro++ + +import_rahman: import_rahman.cc + $(CXX) $(CFLAGS) $(E_INC) $(E_LIB) -o import_rahman import_rahman.cc -lvoro++ + +import_nguyen: import_nguyen.cc + $(CXX) $(CFLAGS) $(E_INC) $(E_LIB) -o import_nguyen import_nguyen.cc -lvoro++ + +import_freeman: import_freeman.cc + $(CXX) $(E_INC) $(E_LIB) -o import_freeman import_freeman.cc + +polycrystal_rahman: polycrystal_rahman.cc + $(CXX) $(CFLAGS) $(E_INC) $(E_LIB) -o polycrystal_rahman polycrystal_rahman.cc -lvoro++ + +random_points_10: random_points_10.cc + $(CXX) $(CFLAGS) $(E_INC) $(E_LIB) -o random_points_10 random_points_10.cc -lvoro++ + +random_points_200: random_points_200.cc + $(CXX) $(CFLAGS) $(E_INC) $(E_LIB) -o random_points_200 random_points_200.cc -lvoro++ + +clean: + rm -f $(EXECUTABLES) + +.PHONY: all clean diff --git a/contrib/voro++/examples/no_release/cylinder_inv.cc b/contrib/voro++/examples/no_release/cylinder_inv.cc new file mode 100644 index 0000000000000000000000000000000000000000..93e4d00048c3cc9a4440e47cafff8eeb51ea0c01 --- /dev/null +++ b/contrib/voro++/examples/no_release/cylinder_inv.cc @@ -0,0 +1,77 @@ +// Cylindrical wall example code +// +// Author : Chris H. Rycroft (LBL / UC Berkeley) +// Email : chr@alum.mit.edu +// Date : August 30th 2011 + +#include "voro++.hh" +using namespace voro; + +// Set up constants for the container geometry +const double x_min=-6,x_max=6; +const double y_min=-6,y_max=6; +const double z_min=-6,z_max=6; + +// Set the computational grid size +const int n_x=6,n_y=6,n_z=6; + +struct wall_cylinder_inv : public wall { + public: + wall_cylinder_inv(double xc_,double yc_,double zc_,double xa_,double ya_,double za_,double rc_,int w_id_=-99) + : w_id(w_id_), xc(xc_), yc(yc_), zc(zc_), xa(xa_), ya(ya_), za(za_), + asi(1/(xa_*xa_+ya_*ya_+za_*za_)), rc(rc_) {} + bool point_inside(double x,double y,double z) { + double xd=x-xc,yd=y-yc,zd=z-zc; + double pa=(xd*xa+yd*ya+zd*za)*asi; + xd-=xa*pa;yd-=ya*pa;zd-=za*pa; + return xd*xd+yd*yd+zd*zd>rc*rc; + } + template<class v_cell> + bool cut_cell_base(v_cell &c,double x,double y,double z) { + double xd=x-xc,yd=y-yc,zd=z-zc; + double pa=(xd*xa+yd*ya+zd*za)*asi; + xd-=xa*pa;yd-=ya*pa;zd-=za*pa; + pa=xd*xd+yd*yd+zd*zd; + if(pa>1e-5) { + pa=2*(sqrt(pa)*rc-pa); + return c.nplane(-xd,-yd,-zd,-pa,w_id); + } + return true; + } + bool cut_cell(voronoicell &c,double x,double y,double z) {return cut_cell_base(c,x,y,z);} + bool cut_cell(voronoicell_neighbor &c,double x,double y,double z) {return cut_cell_base(c,x,y,z);} + private: + const int w_id; + const double xc,yc,zc,xa,ya,za,asi,rc; +}; + +int main() { + int i;double x,y,z; + + // Create a container with the geometry given above, and make it + // non-periodic in each of the three coordinates. Allocate space for + // eight particles within each computational block. + container con(x_min,x_max,y_min,y_max,z_min,z_max,n_x,n_y,n_z, + false,false,false,8); + + // Add a cylindrical wall to the container + wall_cylinder_inv cyl(0,0,0,0,1,0,4.2); + con.add_wall(cyl); + + // Place particles in a regular grid within the frustum, for points + // which are within the wall boundaries + for(z=-5.5;z<6;z+=1) for(y=-5.5;y<6;y+=1) for(x=-5.5;x<6;x+=1) + if (con.point_inside(x,y,z)) {con.put(i,x,y,z);i++;} + + // Output the particle positions in POV-Ray format + con.draw_particles_pov("cylinder_inv_p.pov"); + + // Output the Voronoi cells in POV-Ray format + con.draw_cells_pov("cylinder_inv_v.pov"); + + // Output the particle positions in gnuplot format + con.draw_particles("cylinder_inv.par"); + + // Output the Voronoi cells in gnuplot format + con.draw_cells_gnuplot("cylinder_inv.gnu"); +} diff --git a/contrib/voro++/examples/no_release/cylinder_inv.pov b/contrib/voro++/examples/no_release/cylinder_inv.pov new file mode 100644 index 0000000000000000000000000000000000000000..a9c33b5e81f827cb5cdbecd3e6ac57aa10bbfb1d --- /dev/null +++ b/contrib/voro++/examples/no_release/cylinder_inv.pov @@ -0,0 +1,37 @@ +#version 3.6; + +#include "colors.inc" +#include "metals.inc" +#include "textures.inc" + +// Right-handed coordinate system in which the z axis points upwards +camera { + location <20,-50,20> + sky z + right -0.34*x*image_width/image_height + up 0.34*z + look_at <0,0,0> +} + +// White background +background{rgb 1} + +// Two lights with slightly different colors +light_source{<-8,-20,30> color rgb <0.77,0.75,0.75>} +light_source{<20,-15,5> color rgb <0.38,0.40,0.40>} + +// Radius of the Voronoi cell network, and the particle radius +#declare r=0.06; +#declare s=0.48; + +// Particles +union{ +#include "cylinder_inv_p.pov" + pigment{rgb <0.5,0.8,0.7>} finish{reflection 0.12 specular 0.3 ambient 0.42} +} + +// Voronoi cells +union{ +#include "cylinder_inv_v.pov" + pigment{rgb <0.1,0.3,0.9>} finish{specular 0.3 ambient 0.42} +} diff --git a/contrib/voro++/examples/no_release/finite_sys.cc b/contrib/voro++/examples/no_release/finite_sys.cc new file mode 100644 index 0000000000000000000000000000000000000000..04926d869edfaf8b25c702f73297057fd83919d5 --- /dev/null +++ b/contrib/voro++/examples/no_release/finite_sys.cc @@ -0,0 +1,110 @@ +// Irregular packing example code +// +// Author : Chris H. Rycroft (LBL / UC Berkeley) +// Email : chr@alum.mit.edu +// Date : August 30th 2011 + +#include "voro++.hh" +using namespace voro; + +// Set up constants for the container geometry +const double x_min=-15,x_max=15; +const double y_min=-7,y_max=7; +const double z_min=-15,z_max=15; + +// Golden ratio constants +const double Phi=0.5*(1+sqrt(5.0)); +const double phi=0.5*(1-sqrt(5.0)); + +// Set up the number of blocks that the container is divided +// into. +const int n_x=8,n_y=8,n_z=8; + +// ID for dodecahedron faces +const int wid=-10; + +// Create a wall class that, whenever called, will replace the Voronoi cell +// with a prescribed shape, in this case a dodecahedron +class wall_initial_shape : public wall { + public: + wall_initial_shape() { + + // Create a dodecahedron with neighbor information all + // set to -10 + v.init(-2,2,-2,2,-2,2); + v.nplane(0,Phi,1,wid);v.nplane(0,-Phi,1,wid);v.nplane(0,Phi,-1,wid); + v.nplane(0,-Phi,-1,wid);v.nplane(1,0,Phi,wid);v.nplane(-1,0,Phi,wid); + v.nplane(1,0,-Phi,wid);v.nplane(-1,0,-Phi,wid);v.nplane(Phi,1,0,wid); + v.nplane(-Phi,1,0,wid);v.nplane(Phi,-1,0,wid);v.nplane(-Phi,-1,0,wid); + }; + bool point_inside(double x,double y,double z) {return true;} + bool cut_cell(voronoicell &c,double x,double y,double z) { + + // Just ignore this case + return true; + } + bool cut_cell(voronoicell_neighbor &c,double x,double y,double z) { + + // Set the cell to be equal to the dodecahedron + c=v; + return true; + } + private: + voronoicell_neighbor v; +}; + +// Determines whether any of the sides in the neighbor information are from the +// initial dodecahedron +bool has_dodec_sides(vector<int> &vi) { + for(unsigned int i=0;i<vi.size();i++) if(vi[i]==wid) return true; + return false; +} + +int main() { + + // Create a container with the geometry given above. This is bigger + // than the particle packing itself. + container con(x_min,x_max,y_min,y_max,z_min,z_max,n_x,n_y,n_z, + false,false,false,8); + + // Create the "initial shape" wall class and add it to the container + wall_initial_shape(wis); + con.add_wall(wis); + + // Import the irregular particle packing + con.import("pack_semicircle"); + + // Open files to save the "inside" and "outside" particles + FILE *finside=safe_fopen("finite_sys_in.pov","w"), + *foutside=safe_fopen("finite_sys_out.pov","w"); + + // Loop over all particles + double x,y,z; + vector<int> vi; + voronoicell_neighbor c; + c_loop_all cl(con); + if(cl.start()) do { + + // Get particle position + cl.pos(x,y,z); + + // Remove half of the particles to see a cross-section + if(y<0) continue; + + if(con.compute_cell(c,cl)) { + + // Get the neighboring IDs of all the faces + c.neighbors(vi); + + // Depending on whether any of the faces are + // from the original dodecahedron, print to + // the "inside" or "outside" file + fprintf(has_dodec_sides(vi)?foutside:finside, + "sphere{<%g,%g,%g>,s}\n",x,y,z); + } + } while(cl.inc()); + + // Close the output files + fclose(finside); + fclose(foutside); +} diff --git a/contrib/voro++/examples/no_release/finite_sys.pov b/contrib/voro++/examples/no_release/finite_sys.pov new file mode 100644 index 0000000000000000000000000000000000000000..8cc7a01840dd482e0774e49e8010c06ef85d525d --- /dev/null +++ b/contrib/voro++/examples/no_release/finite_sys.pov @@ -0,0 +1,30 @@ +#version 3.6; +#include "colors.inc" +#include "metals.inc" +#include "textures.inc" + +camera { + location <5,-50,0> + sky z + right -0.62*x*image_width/image_height + up 0.62*y + look_at <5,0,0> +} + +background{rgb 1} + +light_source{<-16,-30,30> color rgb <0.77,0.75,0.75>} +light_source{<25,-16,8> color rgb <0.43,0.45,0.45>} + +#declare r=0.05; +#declare s=0.5; + +union { +#include "finite_sys_out.pov" + pigment{rgb <0.9,0.9,0.3>} finish{reflection 0.2 specular 0.25 ambient 0.28 metallic} +} + +union{ +#include "finite_sys_in.pov" + pigment{rgb <0.3,0.5,0.9>} finish{reflection 0.2 specular 0.25 ambient 0.28 metallic} +} diff --git a/contrib/voro++/examples/no_release/import_freeman.cc b/contrib/voro++/examples/no_release/import_freeman.cc new file mode 100644 index 0000000000000000000000000000000000000000..fc2651610445651106a8cb3e770104a3b7b429fa --- /dev/null +++ b/contrib/voro++/examples/no_release/import_freeman.cc @@ -0,0 +1,50 @@ +// File import example code +// +// Author : Chris H. Rycroft (LBL / UC Berkeley) +// Email : chr@alum.mit.edu +// Date : August 30th 2011 + +#include "voro++.cc" +using namespace voro; + +// Set up constants for the container geometry +const double x_min=-50000,x_max=50000; +const double y_min=-50000,y_max=50000; +const double z_min=-50000,z_max=50000; + +// Set up the number of blocks that the container is divided into +const int n_x=6,n_y=6,n_z=6; + +int main() { + FILE * outputFile; + int id; + double x,y,z; + voronoicell c; + // Create a container with the geometry given above, and make it + // non-periodic in each of the three coordinates. Allocate space for + // eight particles within each computational block + container con(x_min,x_max,y_min,y_max,z_min,z_max,n_x,n_y,n_z, + false,false,false,8); + + //Randomly add particles into the container + con.import("pointlist.txt"); + + // Save the Voronoi network of all the particles to text files + // in gnuplot and POV-Ray formats + /* con.draw_cells_gnuplot("pack_ten_cube.gnu"); + con.draw_cells_pov("pack_ten_cube_v.pov"); + + // Output the particles in POV-Ray format + con.draw_particles_pov("pack_ten_cube_p.pov");*/ + + outputFile = fopen("MESH2","w"); + printf("STARING FIRST LOOP"); + c_loop_all cl(con); + //FIRST LOOP START + if(cl.start()) do if(con.compute_cell(c,cl)) { + cl.pos(x,y,z);id=cl.pid(); + printf("%d %e %e %e\n", id,x,y,z); + fflush(stdout); + fprintf(outputFile,"%d %e %e %e\n", id,x,y,z); + } while (cl.inc()); +} diff --git a/contrib/voro++/examples/no_release/import_nguyen.cc b/contrib/voro++/examples/no_release/import_nguyen.cc new file mode 100644 index 0000000000000000000000000000000000000000..571fb2eb3016a9414d47ef97ae21b236a20e39d1 --- /dev/null +++ b/contrib/voro++/examples/no_release/import_nguyen.cc @@ -0,0 +1,47 @@ +// File import example code +// +// Author : Chris H. Rycroft (LBL / UC Berkeley) +// Email : chr@alum.mit.edu +// Date : August 30th 2011 + +#include "voro++.hh" +using namespace voro; + +// Set up constants for the container geometry +const double x_min=-5,x_max=5; +const double y_min=-5,y_max=5; +const double z_min=-5,z_max=5; + +// Set up the number of blocks that the container is divided into +const int n_x=6,n_y=6,n_z=6; + +int main() { + + // Construct container + container con(-5,5,-5,5,0,10,6,6,6,false,false,false,8); + + // Import particles + con.import("../basic/pack_ten_cube"); + + // Loop over all the particles and compute the Voronoi cell for each + unsigned int i; + int id; + double x,y,z; + vector<double> vd; + voronoicell c; + c_loop_all cl(con); + if(cl.start()) do if(con.compute_cell(c,cl)) { + + // Get particle position and ID + cl.pos(x,y,z);id=cl.pid(); + + // Get face areas + c.face_areas(vd); + + // Output information (additional diagnostics could be done + // here) + printf("ID %d (%.3f,%.3f,%.3f) :",id,x,y,z); + for(i=0;i<vd.size();i++) printf(" %.3f",vd[i]); + puts(""); + } while (cl.inc()); +} diff --git a/contrib/voro++/examples/no_release/import_rahman.cc b/contrib/voro++/examples/no_release/import_rahman.cc new file mode 100644 index 0000000000000000000000000000000000000000..2a0b86f0319112f9d53228cb7ed822b34756e3a0 --- /dev/null +++ b/contrib/voro++/examples/no_release/import_rahman.cc @@ -0,0 +1,49 @@ +// Voronoi method to generate nanocrystalline grain boundaries +// Oct 18, 2011 +#include "voro++.hh" +using namespace voro; + +// Box geometry +const double x_min=-10,x_max=10; +const double y_min=-10,y_max=10; +const double z_min=-10,z_max=10; +const double cvol=(x_max-x_min)*(y_max-y_min)*(x_max-x_min); + +// Number of blocks that the Box is divided into +const int n_x=5,n_y=5,n_z=4; + +// Total no of particles + +const int particles=10000; + +// Function for random double between 0 and 1 +double rnd() {return double(rand())/RAND_MAX;} + +int main() { + int i; + double x,y,z; + + // Creating Box and allcating 100 particles within each block + + container con(x_min,x_max,y_min,y_max,z_min,z_max,n_x,n_y,n_z, + false,false,false,100); + + // Set up particle order class + particle_order po; + + // Add particles into the Box + for(i=1;i<particles;i++) { + x=x_min+rnd()*(x_max-x_min); + y=y_min+rnd()*(y_max-y_min); + z=z_min+rnd()*(z_max-z_min); + con.put(po,i,x,y,z); + } + + // Setup an ordered loop class + c_loop_order cl(con,po); + + // Customize output for LAMMPS, preserving ordering + FILE *fp=safe_fopen("lammps_input","w"); + con.print_custom(cl,"%i 1 %x %y %z",fp); + fclose(fp); +} diff --git a/contrib/voro++/examples/no_release/lloyd_box.cc b/contrib/voro++/examples/no_release/lloyd_box.cc new file mode 100644 index 0000000000000000000000000000000000000000..75cd7f22bc8afad17105e5f4f6d7fc10b9097fdd --- /dev/null +++ b/contrib/voro++/examples/no_release/lloyd_box.cc @@ -0,0 +1,86 @@ +// Voronoi calculation example code +// +// Author : Chris H. Rycroft (LBL / UC Berkeley) +// Email : chr@alum.mit.edu +// Date : August 30th 2011 + +#include "voro++.hh" +using namespace voro; + +// Set up constants for the container geometry +const double boxl=1; + +// Set up the number of blocks that the container is divided into +const int bl=10; + +// Set the number of particles that are going to be randomly introduced +const int particles=4000; + +// Set the number of Voronoi faces to bin +const int nface=40; + +// This function returns a random double between 0 and 1 +double rnd() {return double(rand())/RAND_MAX;} + +int main() { + int i,l; + double x,y,z,r,dx,dy,dz; + int faces[nface],*fp; + double p[3*particles]; + + // Create a container with the geometry given above, and make it + // non-periodic in each of the three coordinates. Allocate space for + // eight particles within each computational block + container con(-boxl,boxl,-boxl,boxl,-boxl,boxl,bl,bl,bl,false,false,false,8); + + // Randomly add particles into the container + for(i=0;i<particles;i++) { + x=boxl*(2*rnd()-1); + y=boxl*(2*rnd()-1); + z=boxl*(2*rnd()-1); + con.put(i,x,y,z); + } + + for(l=0;l<=200;l++) { + c_loop_all vl(con); + voronoicell c; + for(fp=faces;fp<faces+nface;fp++) *fp=0; + if(vl.start()) do if(con.compute_cell(c,vl)) { + vl.pos(i,x,y,z,r); + c.centroid(dx,dy,dz); + p[3*i]=x+dx; + p[3*i+1]=y+dy; + p[3*i+2]=z+dz; + + i=c.number_of_faces()-4; + if(i<0) i=0;if(i>=nface) i=nface-1; + faces[i]++; + } while (vl.inc()); + con.clear(); + for(i=0;i<particles;i++) con.put(i,p[3*i],p[3*i+1],p[3*i+2]); + printf("%d",l); + for(fp=faces;fp<faces+nface;fp++) printf(" %d",*fp); + puts(""); + } + + // Output the particle positions in gnuplot format + con.draw_particles("sphere_mesh_p.gnu"); + + // Output the Voronoi cells in gnuplot format + con.draw_cells_gnuplot("sphere_mesh_v.gnu"); + + // Output the neighbor mesh in gnuplot format + FILE *ff=safe_fopen("sphere_mesh.net","w"); + vector<int> vi; + voronoicell_neighbor c; + c_loop_all vl(con); + if(vl.start()) do if(con.compute_cell(c,vl)) { + i=vl.pid(); + c.neighbors(vi); + for(l=0;l<(signed int) vi.size();l++) if(vi[l]>i) + fprintf(ff,"%g %g %g\n%g %g %g\n\n\n", + p[3*i],p[3*i+1],p[3*i+2], + p[3*vi[l]],p[3*vi[l]+1],p[3*vi[l]+2]); + } while (vl.inc()); + fclose(ff); +} diff --git a/contrib/voro++/examples/no_release/pack_semicircle b/contrib/voro++/examples/no_release/pack_semicircle new file mode 100644 index 0000000000000000000000000000000000000000..8cc73ff6438d5e523639dde0288cc1a5572ffa26 --- /dev/null +++ b/contrib/voro++/examples/no_release/pack_semicircle @@ -0,0 +1,2000 @@ +1077 1.86256 -3.99411 -11.0596 +422 1.82319 -3.25751 -12.0501 +427 1.39439 -3.11596 -11.1579 +988 0.398536 -3.03205 -11.193 +1656 2.39746 -3.21127 -10.7417 +785 2.7407 -3.11823 -11.6776 +31 0.328468 -1.1719 -13.0094 +53 -0.432162 -1.79162 -11.6202 +59 1.71208 -1.14889 -11.0747 +69 -0.594367 -1.30255 -13.3717 +111 0.208524 -2.54024 -12.6186 +133 0.793107 -2.1486 -11.4457 +369 0.730158 -2.03454 -13.3168 +1612 -1.42138 -1.11499 -12.7004 +863 -0.823659 -1.11651 -10.7807 +829 2.07862 -1.82708 -13.5423 +1080 1.85954 -2.6845 -13.0762 +1173 1.39837 -1.95275 -12.5744 +101 0.404336 -1.45639 -12.0537 +1565 1.75017 -2.2978 -11.7042 +1548 1.4981 -2.21368 -10.7394 +7 4.73782 -1.83343 -10.8948 +91 3.22187 -1.43201 -12.1272 +363 4.05809 -1.57666 -11.5982 +611 2.48892 -1.90148 -12.6195 +1566 2.98366 -1.02422 -13.0087 +1856 3.81017 -2.8435 -11.9609 +1841 2.4742 -1.64003 -11.4966 +848 4.94322 -1.66815 -12.0545 +920 2.71967 -2.99217 -12.6694 +1066 4.06088 -1.09508 -13.399 +592 3.2198 -2.29743 -11.3666 +1293 4.07005 -1.68575 -12.5922 +1580 5.33913 -2.93074 -10.7944 +1424 6.66276 -1.88429 -11.1585 +377 7.42486 -2.5174 -10.8808 +778 8.12203 -1.26839 -11.4204 +1712 8.99936 -1.07882 -10.9796 +1007 -2.29502 0.395917 -12.1398 +14 2.1213 0.0640332 -13.7118 +74 -0.79349 0.68511 -12.5151 +1936 0.717473 -0.0918085 -12.932 +208 0.7329 0.128672 -11.9567 +305 1.99063 -0.503975 -12.0484 +563 1.84936 -0.897162 -13.2547 +597 -0.0673235 0.71445 -11.8283 +1803 1.70503 0.0869068 -12.8029 +725 1.83932 0.973085 -11.9826 +810 1.67198 -0.135804 -11.1749 +866 0.919127 -0.764516 -11.5474 +915 -0.760401 -0.282117 -12.7669 +1737 -1.55701 -0.278491 -12.1624 +113 0.403819 0.145568 -10.9996 +1198 1.14593 0.755206 -11.2958 +1720 -0.0340367 -0.71933 -11.2484 +1676 0.0421263 -0.541009 -12.2294 +1284 -1.53841 -0.139982 -10.989 +1349 -0.892489 0.600414 -11.275 +1507 0.949744 -0.736141 -13.6606 +1563 1.21467 -0.974365 -12.4794 +161 2.66893 0.43577 -12.1343 +216 3.64419 0.310984 -12.4397 +270 3.37034 -0.15093 -13.882 +386 4.61313 0.363455 -12.0999 +401 3.02176 -0.474705 -11.9187 +500 4.04412 -0.816855 -10.9363 +893 6.11731 0.138405 -10.9162 +718 3.78835 -0.674703 -12.5288 +817 4.7083 -0.0540283 -13.0036 +873 5.3441 -0.954022 -11.4807 +907 5.3392 -0.374185 -12.2968 +935 4.23387 0.187158 -11.0157 +1095 2.61839 0.914091 -11.2577 +1942 5.20666 0.129278 -11.3299 +1214 2.59664 -0.683894 -11.0381 +1226 6.19754 -0.0569021 -11.8936 +1370 3.24084 0.0777258 -11.1102 +164 4.56564 0.987353 -12.8799 +1583 6.33404 -0.957517 -11.34 +1597 2.88564 0.203187 -13.0823 +1822 4.4751 -0.5829 -11.8078 +831 2.61632 -0.890231 -13.9291 +21 7.25053 -0.75275 -11.6836 +594 7.33252 0.159423 -11.2821 +1136 6.85686 0.501498 -12.3971 +1376 8.19259 -0.320602 -11.1095 +614 8.4007 0.657415 -11.0966 +792 9.1767 -0.0854512 -10.8875 +852 -3.20614 1.02119 -11.7188 +654 0.630099 1.57025 -11.5596 +795 0.606605 2.70798 -11.3278 +917 1.10524 1.47964 -12.4348 +1475 1.76754 2.80786 -11.3027 +1118 -1.62774 1.24113 -10.8842 +1128 1.23986 2.04651 -10.9261 +1373 -0.299791 1.54626 -12.6389 +350 -0.319594 2.47559 -11.0309 +950 2.07227 1.74476 -11.3908 +118 2.91817 2.23937 -12.6599 +273 5.59911 1.09335 -10.9658 +737 2.90161 2.24625 -11.1445 +886 3.79869 2.0095 -12.2454 +1145 4.41303 2.75589 -11.9207 +1158 5.17236 1.98846 -10.8368 +1220 3.27235 2.78645 -11.9 +1885 5.05235 1.20853 -11.7951 +1264 5.78747 2.07174 -11.6435 +1496 2.35344 1.11527 -13.4856 +1521 2.95399 1.4787 -12.0117 +1706 6.04917 1.02579 -11.8562 +1710 4.38994 1.87371 -11.4505 +1968 5.50879 1.29344 -12.6808 +1991 5.31785 2.878 -11.2838 +260 3.82856 2.61682 -11.0864 +591 3.59627 1.00066 -10.9624 +1104 3.95545 1.08739 -11.8917 +816 4.5827 1.10731 -10.8379 +488 7.20904 2.23337 -11.3733 +580 6.99453 1.69992 -12.3687 +1408 7.86854 1.50019 -11.2074 +1323 7.05559 1.06721 -11.5968 +1541 6.44896 2.62633 -10.8557 +44 8.92118 1.87173 -10.9355 +1951 6.45862 1.64326 -11.0386 +37 -0.154986 3.26176 -11.6644 +1416 1.88485 3.16009 -12.2312 +367 1.13507 3.36594 -10.7656 +742 2.27266 3.8492 -10.9665 +1341 2.69303 3.59924 -11.8387 +1258 3.96378 3.55577 -11.4027 +225 1.29973 -3.35809 -9.17249 +1009 1.95261 -3.52651 -8.43399 +1955 1.44198 -3.89181 -10.0872 +1041 -0.0646834 -3.39165 -10.381 +292 0.785446 -3.05449 -9.9766 +4 2.98046 -3.17448 -9.02904 +22 4.36261 -3.55222 -9.00022 +42 5.81862 -3.44192 -7.12282 +181 4.80572 -4.16573 -8.25063 +293 3.81579 -4.0438 -8.32252 +991 6.04415 -3.40647 -10.2684 +1611 5.15303 -3.43953 -9.60233 +1558 3.0437 -3.90045 -10.0815 +1616 5.59088 -4.0291 -8.92365 +1662 5.52995 -3.49802 -8.07855 +1714 4.03737 -3.66464 -9.98748 +954 4.91161 -3.81177 -6.82406 +1421 4.01478 -3.12271 -6.88506 +364 4.66574 -3.27146 -7.62942 +1031 2.15834 -3.26905 -9.77248 +1423 6.08701 -4.11962 -6.43825 +543 2.16138 -3.02584 -7.59392 +289 6.31316 -3.03086 -8.48861 +168 6.6808 -3.641 -9.52959 +515 9.17994 -3.67962 -7.92695 +738 9.67431 -3.66638 -7.00112 +1303 7.60227 -3.97165 -7.75888 +180 8.64564 -3.26914 -7.18807 +1272 7.02578 -3.32358 -10.4403 +1411 6.533 -4.06282 -8.5901 +1420 6.76124 -3.43501 -7.69122 +1787 7.67651 -3.69411 -6.80105 +1750 6.7716 -3.39336 -6.49999 +1698 7.40792 -3.37771 -8.89562 +1790 8.16577 -3.3054 -8.24724 +1674 10.0746 -3.03798 -7.91671 +8 1.1777 -1.70178 -9.23575 +139 1.62806 -1.67549 -8.3433 +235 -0.832148 -1.22192 -7.21967 +506 -0.99154 -2.74718 -9.67609 +511 -1.05109 -1.45938 -9.47331 +1766 2.00874 -2.82381 -6.62654 +709 0.475096 -2.5079 -8.91391 +832 1.30815 -2.62653 -8.37361 +840 -0.132078 -1.81357 -9.30021 +1874 -0.805883 -1.81208 -8.56131 +1028 0.256171 -1.36975 -7.19078 +1224 1.02525 -1.84097 -6.75899 +1227 -1.72037 -1.27543 -10.3676 +1283 -2.05003 -2.70555 -10.498 +1417 1.58129 -2.21633 -7.50348 +1868 0.514064 -1.62174 -10.6422 +1634 0.6485 -2.79702 -7.64165 +1854 0.677125 -1.70275 -8.03497 +1134 1.55979 -2.45732 -9.76782 +487 1.3679 -1.40172 -10.1705 +464 2.00046 -1.62819 -6.69863 +380 1.94858 -1.06534 -9.26185 +1382 0.416786 -1.12783 -9.77821 +98 5.49635 -2.45587 -8.53316 +121 3.89263 -2.81233 -10.5431 +1642 4.42446 -2.16714 -6.79148 +798 3.63429 -1.04916 -10.0521 +265 5.57509 -2.05159 -10.3786 +277 3.04339 -1.22524 -7.57558 +1615 3.5691 -2.32255 -7.28635 +312 2.6269 -1.64614 -8.3814 +1273 2.49635 -2.21805 -10.6808 +441 5.08947 -1.57258 -7.24322 +1735 4.56546 -2.19785 -8.79125 +530 6.08511 -2.84245 -9.44377 +242 5.55382 -1.02152 -6.49302 +1999 3.98692 -1.52353 -7.71843 +599 2.16719 -2.61067 -8.8852 +632 4.63074 -2.28513 -7.79016 +641 2.70036 -1.3257 -10.2783 +647 3.79933 -2.96119 -8.02065 +652 5.14659 -2.85113 -6.67647 +1644 6.08734 -1.02141 -10.34 +807 2.58941 -2.09016 -7.36167 +1665 5.55843 -2.56264 -7.54084 +957 5.16399 -2.44089 -9.55435 +1032 5.26174 -1.27435 -9.83263 +1045 3.62488 -1.15277 -8.57362 +1073 5.95217 -1.85431 -9.36934 +1948 4.451 -1.85385 -9.93751 +1828 2.92369 -1.2867 -9.27387 +1194 3.58856 -2.40641 -8.82935 +1167 4.43726 -1.23791 -9.15035 +1253 3.0646 -2.90497 -9.98882 +1335 5.81758 -1.53993 -8.29286 +1827 3.76242 -1.82105 -10.6748 +1727 2.49001 -2.10077 -9.68251 +1757 6.03921 -1.2742 -7.33625 +1510 3.81012 -1.30528 -6.75876 +1536 3.48178 -1.983 -9.72881 +1574 4.82819 -1.40289 -8.2451 +1684 4.2121 -2.76202 -9.5942 +1589 2.86564 -2.61056 -8.16958 +1633 2.84683 -1.11033 -6.57451 +137 9.00039 -1.43678 -6.91078 +1437 6.58628 -1.98159 -7.83022 +1974 7.5548 -1.86093 -10.1377 +481 9.68075 -1.66733 -7.60628 +554 7.35484 -2.58417 -6.56915 +601 7.20464 -2.65791 -8.2319 +666 8.47778 -1.75721 -9.74938 +687 9.47103 -1.89662 -8.5567 +446 9.95063 -1.48334 -6.5985 +963 7.68089 -1.41481 -9.25181 +986 8.51407 -1.67025 -8.73799 +1063 6.82565 -1.95465 -8.89293 +491 8.49896 -2.29621 -7.00971 +1384 7.63292 -1.90933 -7.32534 +1446 7.35067 -2.73612 -9.69911 +1520 9.97439 -2.41857 -6.95174 +1911 7.91942 -2.48389 -8.91628 +1587 7.61302 -1.74892 -8.31169 +1609 8.34318 -2.35402 -7.99575 +1614 9.24445 -2.567 -7.61868 +264 6.45812 -2.67325 -7.11885 +1682 8.67708 -2.73485 -9.5187 +1537 7.05488 -1.12897 -7.59914 +1954 6.97135 -1.09158 -9.87779 +1775 7.74125 -2.91717 -7.42905 +1852 8.3849 -1.32253 -7.69871 +1892 10.397 -1.5949 -9.15687 +1809 6.76536 -1.76022 -6.85171 +1817 9.41447 -2.04115 -9.54454 +1247 6.54719 -1.94961 -10.1674 +1231 10.0567 -1.11258 -8.34974 +747 8.05608 -1.53266 -6.50133 +1632 11.3547 -1.82743 -6.71811 +1147 10.9107 -2.72166 -6.77436 +533 -3.35119 0.191611 -9.13151 +1244 -3.03011 -0.951272 -10.0236 +1268 -2.71248 -0.624681 -7.88796 +1816 -2.49337 0.276346 -9.76747 +1207 -2.3406 0.78505 -8.27055 +110 1.2201 -0.8135 -8.04242 +1075 1.81843 0.0378929 -7.27011 +215 -0.490999 -0.56074 -9.17626 +226 -0.624735 0.474877 -7.02878 +330 0.886328 -0.322695 -7.23764 +1754 -0.213154 0.63052 -7.92675 +1438 -1.79378 -0.947655 -9.03396 +383 1.99015 -0.622539 -10.2454 +409 1.44178 0.733565 -7.99365 +485 1.77178 0.112712 -9.6038 +1242 1.20215 0.312425 -10.401 +1571 1.54255 -0.71905 -6.58743 +731 0.169479 -0.729044 -8.44453 +762 -0.0067644 0.536099 -10.1756 +784 -0.0382038 -0.316542 -6.85667 +1995 -1.55007 0.48147 -9.5065 +906 0.600064 -0.123363 -9.73205 +1989 1.72296 -0.206015 -8.65727 +972 -1.09624 -0.593657 -9.97178 +996 1.32617 0.682557 -6.68537 +1832 -0.977267 0.338536 -10.3136 +1137 0.971934 -0.742937 -9.04095 +1695 0.72732 0.051891 -8.15128 +926 0.878824 -0.620628 -10.5587 +1412 -1.43963 0.713747 -7.84257 +1433 0.633564 0.733796 -7.40485 +1441 1.04886 0.459249 -9.00608 +1442 -0.154376 -0.475143 -10.2862 +1533 0.0579267 0.311788 -9.01323 +205 2.11352 -0.910488 -7.38572 +12 3.99106 0.938839 -7.51036 +75 5.1286 0.039425 -8.42402 +147 2.93226 0.703453 -6.65891 +1850 4.24743 0.621081 -9.59001 +923 2.4172 0.224364 -10.5621 +1144 3.34815 0.727623 -9.1659 +452 5.89388 0.678688 -10.1049 +459 3.9214 0.7693 -6.52732 +678 6.33581 -0.966681 -9.11602 +617 2.60113 0.0715789 -9.04669 +648 5.34325 -0.8506 -8.92841 +651 6.42178 0.785076 -9.26239 +658 2.34588 0.314037 -8.07335 +1083 2.17394 0.95312 -8.84616 +844 3.26995 0.686149 -8.15521 +503 2.56812 0.832471 -9.78278 +927 3.51159 -0.332282 -9.13384 +1388 4.99722 0.325766 -10.3721 +1043 4.99512 -0.653919 -10.593 +1056 3.42417 0.458085 -10.1401 +1097 4.21218 -0.23528 -10.1098 +1129 2.90593 -0.375123 -9.92834 +1998 5.53815 -0.313409 -9.82567 +1287 4.36408 -0.607228 -7.85129 +1347 2.90953 -0.308096 -7.20027 +1392 4.72914 0.269178 -7.53846 +1395 2.52514 -0.657344 -8.26393 +1431 4.50693 -0.240675 -9.15454 +1436 5.423 -0.143877 -6.95306 +1445 3.86698 -0.0287229 -7.12897 +1451 4.1822 0.359747 -8.40064 +938 6.3097 -0.690668 -8.10186 +1591 5.75756 0.825366 -8.51594 +1595 3.4417 -0.299743 -8.08498 +1613 5.96522 -0.0514587 -8.96074 +1971 5.20177 0.509636 -9.30331 +1641 5.89158 0.159493 -7.7824 +1733 6.40863 0.56976 -7.03138 +1652 5.41096 0.860487 -7.10751 +1745 5.36111 -0.693384 -7.7854 +1756 4.63226 -0.753283 -6.89739 +1836 8.61826 0.872488 -6.53966 +170 10.1457 0.972058 -7.88449 +177 7.67871 0.700188 -8.6472 +218 9.9172 -0.742321 -9.36397 +1994 7.59972 -0.410873 -9.46259 +253 8.01917 -0.976005 -10.1729 +283 6.52397 -0.41886 -7.12726 +1820 7.39578 0.412514 -7.00317 +385 7.35353 0.629227 -9.58997 +423 6.75112 0.610334 -8.02303 +428 6.83471 0.672279 -10.4437 +486 9.04133 -0.533973 -7.45418 +535 9.32382 0.311677 -6.97262 +577 7.82357 0.987315 -7.70044 +558 10.2821 0.0271182 -6.99865 +636 7.66751 0.0547427 -10.3457 +642 9.51091 -0.585598 -6.57278 +675 8.35894 0.147769 -9.12848 +707 8.49236 -0.831304 -9.28164 +1625 9.82792 -0.000908218 -10.0641 +835 8.35305 0.130771 -7.15537 +1291 7.63943 -0.557114 -7.02367 +964 10.2799 -0.90811 -7.35243 +916 8.51302 -0.644249 -6.54443 +1103 6.95346 0.0436818 -8.85002 +1109 8.6129 -0.105422 -10.0619 +1148 10.1332 0.531543 -8.9377 +1154 6.87381 -0.469326 -10.6545 +1181 9.41665 0.293041 -7.96797 +1731 9.17428 -0.93108 -10.0062 +1189 8.4321 0.282538 -8.1404 +1250 6.56791 -0.180348 -9.74763 +1236 10.2892 -0.188479 -8.04667 +1696 9.32546 -0.093434 -8.8857 +1896 9.33455 0.678625 -9.52117 +1297 9.00535 0.97934 -8.57145 +1321 7.16979 -0.89104 -8.57013 +1340 7.36407 -0.170748 -7.9039 +1391 8.11692 -0.636742 -8.37531 +1894 9.07607 -0.918995 -8.37876 +507 10.9996 -0.891738 -8.07244 +1064 12.3419 0.556219 -7.04416 +1311 11.7127 -0.258973 -7.34967 +365 11.3948 0.466184 -6.73614 +664 11.0067 -0.609202 -6.73412 +84 11.0101 0.383547 -7.65546 +984 10.9391 -0.0805075 -8.79898 +708 0.638427 1.19822 -10.5568 +478 1.06049 1.87788 -9.95687 +556 -0.750963 2.41276 -9.02437 +569 1.47084 1.77714 -7.28578 +1939 -0.804932 1.48526 -7.88645 +616 -0.0606027 2.04085 -8.25698 +691 0.738619 2.8221 -10.0259 +756 -0.743435 1.64973 -10.6582 +758 -1.22289 1.41375 -8.81461 +759 1.63357 2.76049 -7.45792 +1890 -0.449759 1.32921 -9.75768 +772 0.540217 1.11879 -9.55951 +892 0.117739 2.00241 -10.2662 +1779 0.510952 1.64595 -7.01381 +1282 1.79218 2.50375 -8.42401 +1402 2.00897 1.96235 -10.2836 +140 1.95296 1.93738 -9.23231 +1502 0.319055 1.1728 -8.57685 +1546 0.241309 2.5145 -7.42964 +590 1.61187 1.09817 -9.66039 +1638 1.69833 2.75161 -9.75396 +1647 1.04085 2.30622 -9.05351 +1675 0.118412 1.96725 -9.23807 +1806 1.28274 1.39142 -8.72975 +1703 0.923241 2.05596 -8.07469 +512 1.84488 1.0413 -10.6368 +1627 4.80251 1.43198 -6.55692 +1773 5.20482 1.80213 -7.39422 +1504 4.00281 1.30412 -8.67612 +163 5.01538 2.77046 -7.2222 +609 6.03822 1.35059 -7.71266 +243 2.87073 1.49571 -10.4845 +250 5.32142 2.24421 -9.83717 +254 5.43635 2.20858 -6.51036 +1607 2.89704 1.80706 -9.53479 +769 2.45108 2.9421 -10.5853 +303 4.2281 1.93925 -7.19915 +347 3.79088 1.42816 -9.96423 +405 6.09188 1.66506 -10.1087 +417 3.64092 1.96925 -8.00792 +448 3.2986 2.32391 -7.13761 +450 2.73236 2.78795 -9.63815 +466 4.75302 1.95512 -9.04237 +477 2.49615 2.33653 -7.73393 +1812 2.18557 1.39688 -7.87736 +665 5.66869 2.76618 -7.9791 +696 3.07561 1.33572 -7.42026 +786 2.77715 2.51325 -8.67772 +818 5.49711 1.86061 -8.38108 +1539 5.99757 2.33388 -9.10598 +732 4.85104 1.09362 -8.18996 +1618 4.78996 1.3999 -9.90449 +1016 2.94223 1.53253 -8.57442 +1062 5.57362 1.43771 -9.28451 +1556 3.78041 2.12946 -9.19505 +1126 3.91052 2.81124 -8.47518 +1927 6.19469 1.60319 -6.75124 +1192 3.38141 2.32226 -10.2418 +1277 4.34421 2.39859 -9.98269 +1360 4.60829 2.21045 -8.08514 +1428 6.29566 2.55655 -7.11009 +1440 4.05467 2.8848 -7.47446 +1185 8.81494 1.01346 -7.57245 +45 7.19042 2.22082 -6.45253 +1767 6.46258 2.17138 -8.10336 +182 8.05036 2.47201 -6.89681 +1649 9.60284 1.30179 -7.02849 +339 7.15773 1.48212 -8.30594 +354 9.20922 1.82565 -8.00241 +390 8.30534 2.53623 -9.08378 +397 8.58404 1.94206 -9.98651 +437 9.86788 1.47106 -8.70518 +526 6.61466 2.48611 -9.87958 +1513 8.42265 1.08565 -9.46938 +622 7.73582 1.81236 -9.47317 +640 6.77857 1.71695 -9.20089 +653 7.22859 2.3016 -7.44845 +1839 8.26579 1.88381 -7.67602 +688 8.1888 1.55918 -8.61844 +859 8.63809 2.76679 -10.5493 +922 7.64291 2.35497 -8.35691 +1098 9.57407 2.48687 -9.61755 +1114 7.55953 2.7673 -9.71172 +1886 6.96403 1.34397 -7.33489 +1165 6.91521 2.6993 -8.95001 +1248 9.91917 2.41982 -8.38046 +1802 7.77576 2.24958 -10.5459 +1858 7.76337 1.35304 -6.73468 +1432 7.08566 1.6108 -10.2057 +241 7.89936 1.03959 -10.3204 +1486 8.9824 2.08575 -7.00861 +1491 10.3029 1.87997 -7.44752 +1859 8.91228 1.06658 -10.3411 +1549 9.7658 2.68163 -7.18509 +1762 9.0228 1.8374 -9.09411 +298 10.6229 1.04042 -7.00852 +872 10.5359 1.8651 -6.44979 +57 11.0573 1.36651 -7.99961 +561 11.9064 1.34835 -7.4718 +871 11.4024 2.27871 -7.16226 +1301 11.4363 1.45538 -6.59573 +682 10.8323 1.46411 -8.96907 +344 1.92732 3.90278 -9.08648 +1405 1.13212 3.29854 -9.13685 +498 -0.10703 3.22665 -10.3741 +704 1.74517 3.70568 -10.0498 +1150 0.575323 3.78481 -9.81028 +1499 1.35419 3.50255 -8.18341 +1528 0.153691 3.27331 -8.93182 +1940 5.88587 4.61631 -8.21136 +1012 4.50984 3.576 -6.91318 +142 2.73412 3.75139 -9.90601 +419 6.11265 3.66119 -8.02098 +813 3.08908 3.98137 -8.48077 +898 3.98152 3.96455 -9.21341 +951 3.42172 3.29449 -10.4724 +1489 4.04835 3.8737 -8.21979 +78 5.6148 3.56832 -7.1587 +1691 2.32639 3.34647 -8.35767 +238 4.89551 3.28295 -9.73277 +62 3.68784 3.06483 -9.53624 +109 4.52517 3.1916 -10.6571 +1673 3.15709 3.07409 -7.87231 +1952 2.83406 3.15634 -6.8356 +60 4.77395 3.19715 -8.09483 +259 5.38225 3.08922 -8.88106 +1115 5.67448 3.01978 -10.3604 +522 6.72187 3.47707 -9.79906 +1992 8.21986 3.93422 -7.01526 +213 9.43764 3.30157 -7.90003 +1119 6.61314 3.6245 -7.14868 +1135 6.8928 3.80251 -8.68765 +598 7.73687 3.30515 -10.5359 +1371 7.90712 3.29892 -8.55438 +1309 7.53335 3.24844 -7.25695 +1460 8.80487 3.07306 -7.1602 +115 6.91209 3.06049 -8.01757 +1683 6.18313 -3.45462 -5.69386 +646 5.64381 -3.49582 -4.85281 +1105 5.28233 -3.02193 -5.65838 +68 7.82849 -4.12477 -4.78643 +313 10.0273 -4.01427 -3.98527 +359 9.59923 -3.95397 -4.94972 +700 6.62324 -3.68375 -4.76335 +755 8.13508 -3.61231 -2.43324 +766 9.10277 -4.22287 -3.6662 +804 7.89742 -3.70635 -3.40002 +949 9.04723 -3.66228 -2.84002 +1620 8.72552 -3.79788 -4.489 +1666 10.35 -3.66497 -5.54372 +1400 7.30527 -3.58759 -5.57241 +175 8.93592 -3.72579 -6.32937 +1470 9.18548 -3.21426 -5.50715 +867 9.88354 -3.08457 -6.21132 +774 8.22377 -3.34019 -5.26397 +961 10.3103 -3.36481 -2.54422 +1793 7.06099 -4.33737 -6.34195 +579 9.60376 -3.1239 -4.15216 +1387 7.25044 -3.04337 -2.16137 +1670 8.22957 -3.01813 -6.31412 +1871 7.90906 -3.00822 -4.11726 +1884 10.3333 -3.00827 -3.47818 +1305 11.1496 -3.41893 -3.88422 +366 11.2395 -3.16414 -2.85455 +1535 1.6495 -1.80973 -5.78003 +581 -0.253162 -1.59613 -6.36003 +19 5.27262 -1.95167 -6.25852 +149 2.9272 -1.67152 -5.51602 +337 2.42818 -2.53792 -5.49907 +381 4.37581 -2.7927 -6.01286 +451 3.71228 -2.62303 -5.28174 +1949 4.42509 -2.19391 -4.49395 +1889 5.68595 -2.31119 -3.04228 +685 6.05409 -1.82645 -3.87164 +729 5.95268 -2.7294 -4.28964 +911 6.01145 -2.62465 -6.225 +941 5.29428 -1.6195 -4.51028 +990 4.99126 -2.1288 -5.31559 +839 3.34915 -1.06157 -4.56561 +1153 5.18299 -1.53124 -3.41469 +1211 6.3167 -2.01745 -4.89015 +1807 3.89843 -1.64376 -5.19619 +1514 4.46949 -1.40814 -6.01402 +768 5.98516 -1.47899 -2.57545 +1375 6.21724 -1.7245 -5.84107 +1677 3.70714 -2.05402 -6.10402 +306 4.28762 -1.23038 -4.26443 +280 5.43314 -1.23612 -5.4581 +1021 6.37785 -2.36526 -2.32233 +1984 2.75978 -2.20988 -6.38362 +715 6.11707 -1.05169 -4.5122 +10 9.05985 -2.47233 -6.20128 +77 7.2987 -2.03203 -2.63054 +107 7.10596 -1.24429 -5.14034 +602 10.276 -1.20986 -2.46376 +1902 10.6226 -2.0125 -5.10982 +214 8.04519 -1.48034 -5.5029 +255 8.57359 -1.49983 -2.71093 +279 6.83271 -2.45634 -3.90116 +393 9.36364 -2.24317 -3.66322 +1975 8.78159 -1.17209 -4.90143 +1482 7.4468 -2.83448 -3.20848 +1529 9.79072 -1.61565 -5.49764 +605 9.35398 -1.84681 -2.17329 +583 7.86037 -2.4606 -5.57063 +631 7.61899 -1.92007 -3.57512 +703 8.8217 -2.08262 -5.3121 +726 10.4536 -1.57657 -3.37669 +763 9.51226 -1.43277 -3.06927 +457 8.28347 -1.17334 -3.6105 +794 9.2325 -1.28086 -4.01649 +855 6.44195 -2.95976 -3.1306 +694 6.75536 -1.42579 -3.21092 +881 10.4524 -2.24844 -4.11727 +1722 9.07913 -2.68074 -2.65163 +753 8.09696 -2.61402 -2.47607 +1023 7.16331 -2.8422 -4.76241 +1036 9.60023 -2.04472 -4.61435 +1139 8.78166 -2.80905 -4.62631 +1837 10.1908 -1.301 -4.30113 +702 6.9471 -1.50561 -4.18874 +1199 8.44362 -2.54361 -3.41136 +1315 7.21763 -1.80215 -5.96164 +1324 10.3676 -2.21269 -6.0557 +1345 8.50811 -1.94291 -4.20814 +1801 7.65214 -1.9708 -4.7241 +1791 6.86241 -2.70101 -5.70548 +1004 7.64634 -1.11859 -2.84179 +1410 9.97538 -2.29684 -2.87369 +1413 10.0109 -2.80347 -5.11997 +1736 8.94265 -1.29855 -5.92204 +876 11.1032 -1.08307 -3.95496 +396 12.6828 -1.68384 -4.92391 +527 11.3794 -1.89642 -4.46684 +608 11.9305 -2.87175 -3.58304 +1959 11.1607 -1.21388 -5.95274 +884 11.5263 -2.08064 -5.54301 +887 12.4835 -2.67879 -2.27358 +1024 11.935 -1.8 -3.64108 +1111 10.9118 -1.98144 -2.46089 +1127 12.229 -2.42211 -4.42488 +1265 11.904 -1.87358 -2.39877 +1372 11.3745 -1.27551 -3.00037 +1203 12.0964 -1.23908 -5.60088 +1367 11.1221 -2.32018 -3.37791 +1721 13.3478 -1.67651 -3.27579 +1794 12.4862 -1.23335 -3.02874 +546 10.928 -2.8962 -4.71232 +439 13.4344 -2.12814 -2.21727 +1584 10.9901 -2.91484 -5.7102 +735 12.7078 -1.07201 -4.13333 +83 -0.125265 0.64162 -6.17865 +779 1.81534 0.066649 -6.03223 +1631 0.749266 0.0204014 -6.20714 +333 0.603846 -0.959891 -6.34083 +76 5.67594 0.234762 -3.48236 +200 5.81524 0.527454 -5.26226 +233 3.72193 -0.313931 -5.11522 +1899 6.41171 -0.549808 -5.32439 +288 5.49342 -0.605319 -2.69305 +860 2.76649 -0.179145 -6.219 +342 4.5001 -0.521241 -2.77177 +471 5.12406 -0.709475 -4.09434 +473 5.93833 -0.888677 -3.54249 +531 4.54491 -0.879473 -5.16855 +710 4.14593 -0.238015 -6.19182 +1715 3.76239 -0.253375 -4.09809 +1953 4.38694 0.420275 -5.47887 +1498 4.1276 0.836716 -3.891 +841 3.55625 -0.970293 -5.85142 +1914 6.2727 0.511268 -4.37319 +856 5.08593 -0.388725 -5.86769 +1831 2.48626 0.758559 -5.76557 +896 4.59106 -0.0443867 -4.61732 +903 5.43538 0.397906 -2.52559 +944 6.034 -0.167973 -6.16507 +1015 4.60973 0.00262709 -3.61648 +1813 5.49909 -0.370874 -4.95723 +1124 4.86618 0.883433 -3.2185 +1171 3.42169 0.405895 -5.74107 +853 5.87492 0.81705 -6.22282 +1452 2.77657 -0.630367 -5.32556 +1637 3.56605 0.573086 -4.68059 +1477 5.27959 0.615939 -4.31754 +1174 4.85449 0.443287 -6.37554 +71 6.34729 0.210192 -2.16107 +24 7.39077 -0.735982 -3.72962 +27 7.00821 -0.314841 -4.55829 +1926 8.57932 0.212152 -2.3082 +1915 9.19687 -0.799592 -2.363 +136 8.96441 0.557117 -3.19303 +158 9.4274 -0.595693 -5.40156 +272 10.2409 -0.0595628 -5.17735 +1742 6.81228 0.602891 -5.36631 +362 9.52865 0.488468 -4.17893 +430 10.0394 -0.657812 -3.41773 +1142 6.65451 -0.942834 -6.28564 +480 7.37701 -0.238825 -2.45029 +529 8.12237 -0.166692 -3.11297 +547 8.67742 -0.467943 -4.19974 +550 8.00387 0.152054 -6.2187 +557 9.97854 0.699786 -6.32404 +1636 7.76534 0.79018 -4.82449 +669 7.88159 -0.773532 -4.72121 +1121 9.40769 0.772237 -2.31502 +1573 7.6085 -0.763364 -6.04571 +720 9.07474 -0.432097 -3.28385 +1864 9.93695 0.342102 -3.27797 +808 8.44016 -0.499675 -5.55779 +837 7.83322 0.0638851 -4.14061 +875 9.05545 0.134354 -6.02591 +373 10.6123 0.81771 -3.84109 +1778 6.85129 0.521682 -2.96655 +1072 9.60671 0.681722 -5.3964 +1131 6.58504 -0.136617 -3.67044 +1923 10.7137 0.0811389 -6.04695 +1182 10.0207 -0.243592 -2.4723 +1219 9.64909 -0.471151 -4.43439 +1269 7.12994 0.736207 -3.91006 +1295 7.57615 -0.0472915 -5.337 +1310 10.2495 -0.799069 -5.93334 +1389 10.5552 -0.101739 -4.22955 +1401 8.87937 0.161277 -4.94976 +1457 6.48963 -0.567155 -2.77303 +1592 7.01308 0.0314488 -6.16174 +1600 8.60644 0.859336 -4.28814 +1880 7.7252 0.696275 -2.51318 +1921 8.02644 0.773232 -3.46343 +72 10.9712 -0.302927 -3.34364 +129 11.4453 0.792861 -3.28892 +224 11.0486 0.715388 -4.73807 +275 12.0059 -0.794529 -2.26955 +1709 12.3226 0.528244 -5.9943 +411 12.4212 0.302673 -3.67339 +442 11.793 0.839939 -2.35264 +555 11.6704 -0.239711 -6.08375 +1699 12.9234 -0.672193 -5.02451 +1970 10.8542 0.407129 -2.5274 +877 11.0422 0.962318 -5.70694 +971 12.6341 -0.476953 -5.96162 +992 11.2898 -0.157081 -5.16279 +1661 11.8752 -0.00925133 -2.87467 +1263 11.9479 -0.651129 -3.63802 +1308 13.087 0.260472 -4.41832 +332 11.0402 -0.564247 -2.38249 +1414 12.9087 0.962173 -3.10135 +1419 11.5089 0.151153 -4.05316 +1466 12.8962 0.84064 -5.21015 +1602 12.8256 -0.30807 -2.57129 +1814 12.1951 -0.0428012 -4.7538 +1648 12.7511 0.613537 -2.17746 +1664 11.7303 -0.938205 -4.72029 +108 10.7339 -0.983864 -5.07829 +1604 1.6306 1.56136 -6.318 +9 5.8178 1.19038 -3.20593 +97 5.51723 2.10993 -3.45909 +256 4.52593 2.08357 -5.06493 +336 2.66283 1.75132 -5.97721 +404 4.44381 2.25055 -6.07324 +578 6.29784 2.36746 -6.02619 +353 3.56412 1.69545 -6.40674 +773 4.86523 2.58136 -4.26677 +888 5.45062 1.47822 -4.80633 +945 5.41659 2.18663 -5.51098 +1453 6.15134 1.5052 -4.09463 +1588 6.1521 1.50108 -5.5485 +1621 5.95139 1.19276 -2.20554 +1723 4.73878 1.66066 -3.89745 +1471 3.21213 1.2916 -5.27942 +1988 4.13625 1.37429 -5.65233 +125 5.8644 2.5473 -4.28866 +905 6.32325 2.98665 -2.16944 +979 6.0174 2.99531 -5.29263 +1039 4.52165 1.11064 -4.76818 +1781 3.47272 2.67361 -6.21699 +806 6.31496 2.72641 -3.41409 +1374 5.09754 1.09956 -5.66138 +48 7.12877 2.70731 -5.57953 +49 10.1087 2.24739 -2.66931 +1996 7.85037 1.04162 -5.78845 +144 7.98119 1.75511 -5.07501 +316 8.94016 2.09588 -2.26887 +236 8.13947 1.9654 -6.03943 +1281 8.12001 2.79556 -5.48156 +247 8.77914 2.71024 -6.22871 +278 7.55693 2.57271 -4.68589 +307 9.56846 1.4795 -3.92893 +1639 9.69825 2.89447 -4.38788 +1206 10.3699 1.17796 -2.94037 +508 6.43031 2.10844 -2.63642 +668 8.99024 2.19101 -4.32774 +131 6.9344 1.33036 -4.6913 +805 8.20816 2.49113 -2.8232 +1925 10.1353 1.11584 -4.66757 +823 9.85647 2.34164 -5.22839 +825 6.77367 1.45585 -3.31424 +1997 10.1833 1.4728 -5.60029 +1956 6.89544 1.01719 -6.28117 +894 7.74439 1.51337 -4.13432 +895 8.61267 1.59934 -3.61609 +1005 8.70382 1.09225 -5.26987 +942 7.28568 2.5669 -3.21924 +1861 7.12939 1.70747 -5.59662 +983 8.07904 2.42227 -3.81269 +1462 6.93652 1.29798 -2.34091 +1838 8.87698 2.16252 -5.32059 +1035 7.27321 2.45638 -2.22549 +1052 9.73531 2.4177 -6.21814 +1601 9.12511 1.63052 -6.12982 +1928 8.51826 1.28384 -2.67221 +1312 6.53138 2.20813 -4.95198 +1605 9.07957 2.42865 -3.30944 +1143 10.0645 2.30714 -3.66633 +1581 7.73244 1.6753 -3.14812 +1190 9.44303 1.55208 -2.93994 +1463 6.93941 2.11924 -4.04365 +1777 13.2682 2.17952 -2.9263 +124 12.8748 2.00492 -3.82897 +134 11.632 2.44881 -3.87915 +196 11.2491 1.95939 -5.75269 +202 11.5753 2.47716 -4.87713 +219 11.9358 1.11048 -5.27925 +257 10.922 2.62456 -3.12797 +300 12.2227 2.166 -5.65542 +474 12.0633 1.56298 -3.44717 +681 12.4043 1.46212 -6.34391 +722 11.2252 1.69511 -2.918 +782 12.5344 1.74333 -4.73266 +1331 11.6792 1.38958 -4.35391 +1071 12.4873 1.6816 -2.54934 +1824 10.8911 1.77771 -3.85669 +1929 11.8681 2.44498 -2.76237 +1407 12.4489 2.85242 -3.46712 +54 10.8388 1.80108 -4.85477 +1629 10.7334 2.64508 -4.32841 +821 5.84422 3.98005 -5.27779 +1183 5.98078 3.78324 -6.25324 +1296 4.20352 3.18256 -5.76213 +672 5.2803 3.06556 -5.96781 +102 7.56737 3.68998 -5.47922 +106 8.25993 4.26633 -3.32085 +973 9.09006 3.93728 -4.55475 +1084 8.79881 3.70994 -6.21641 +1359 10.0664 3.88295 -4.34533 +1728 6.89654 3.53406 -3.31726 +1748 9.71603 3.49799 -5.86848 +1965 7.1751 4.09245 -4.46912 +1092 7.58648 3.3066 -4.00746 +1169 10.3575 3.21345 -5.06869 +1191 6.92369 3.45261 -6.21382 +246 8.80778 3.28638 -2.73988 +345 10.5298 3.42015 -3.58961 +701 9.55405 3.30364 -3.40499 +1906 7.84935 3.39682 -3.04695 +1404 9.11228 3.12199 -5.16556 +1223 7.90217 3.28098 -6.32806 +150 10.2738 3.23314 -2.64119 +1830 8.22575 3.47695 -4.75734 +1945 6.71797 3.0704 -4.44332 +995 8.77864 3.1142 -4.00727 +1050 11.2556 3.49612 -4.27316 +1256 11.2603 3.4028 -2.59896 +1707 9.7517 -4.05895 -0.794092 +582 9.60514 -4.14674 0.516917 +593 10.0907 -3.8604 1.36446 +882 7.29535 -3.39234 -1.06949 +1065 7.61322 -3.71251 -0.171991 +1093 8.61264 -3.65128 -1.55553 +1403 7.69821 -3.03017 0.553922 +1568 8.79691 -4.02304 2.13251 +166 10.5893 -3.84146 0.498175 +408 9.03963 -3.58893 -0.10354 +545 8.12673 -3.65848 1.4559 +1090 10.2252 -3.37973 -1.35479 +1743 10.6008 -3.48004 -0.433729 +637 9.12315 -3.50008 1.34514 +455 9.45411 -3.32937 -1.98941 +39 8.31163 -3.22964 -0.700236 +1765 9.68525 -3.15338 0.59441 +994 9.29747 -3.18833 -0.982689 +1492 9.72422 -3.33915 2.13474 +314 11.4988 -3.06902 -0.255366 +600 11.9818 -4.05492 -1.19269 +733 11.0589 -4.21417 1.29836 +1891 11.2154 -3.41327 -1.21969 +1356 11.5545 -3.86659 2.0943 +1362 12.4435 -3.08741 0.0719474 +1760 11.842 -3.16419 0.881399 +1140 10.8612 -3.14217 1.16249 +299 6.24819 -2.02584 -1.17488 +1930 6.41157 -1.72154 0.633523 +34 6.71541 -1.80758 -0.318254 +989 10.0529 -1.28004 1.57294 +1937 10.1302 -1.64568 -1.57603 +1981 8.56409 -1.91333 0.658982 +195 10.4712 -2.18817 1.57174 +1575 6.74951 -2.68983 0.890266 +268 8.89495 -2.56975 -1.6573 +297 8.22025 -1.84983 -1.84312 +1865 9.32681 -1.25959 0.889981 +343 6.5369 -2.96437 1.8983 +420 8.62373 -1.97044 -0.899968 +1761 7.34127 -1.44209 2.10234 +465 7.59284 -2.03427 -0.800944 +470 6.67142 -2.01291 1.62207 +1333 8.1844 -2.43781 -0.102989 +1725 7.37282 -2.10199 0.37509 +1655 6.97456 -1.00594 0.220322 +604 7.92394 -2.73555 -1.48585 +128 6.94438 -1.13064 1.2393 +1102 9.6837 -1.11518 -0.855945 +1302 9.65713 -2.15464 0.596003 +1157 8.00047 -1.16318 -1.14991 +1716 8.13117 -1.44389 -0.199107 +833 8.69456 -2.95319 0.586739 +870 10.2164 -2.57142 -1.94304 +880 7.88474 -1.96258 1.44394 +930 9.83805 -2.34887 -0.928532 +934 10.4492 -2.62485 0.207924 +1020 8.93235 -1.23562 -1.50367 +392 7.33917 -1.23149 -1.89686 +1882 9.21219 -2.58884 -0.186948 +1022 10.1078 -1.72453 -0.186147 +1076 7.50013 -2.88203 1.52276 +1427 7.79242 -1.26869 0.731275 +1857 8.88581 -1.81496 1.60058 +1132 8.50729 -2.73819 1.54479 +1138 10.5093 -1.6491 0.730491 +1797 7.10684 -2.18655 -1.66148 +1233 9.11638 -1.59493 -0.111449 +1260 7.09617 -2.78138 -0.303654 +1285 9.52058 -2.5928 1.48439 +94 11.3051 -1.33635 -1.80515 +157 13.1006 -1.29812 -0.488274 +921 13.2554 -1.87807 2.02398 +463 11.8883 -2.01018 0.641531 +780 13.4969 -1.74736 -1.28893 +908 12.2193 -1.89082 -0.729912 +997 11.5736 -1.5366 1.4639 +1123 12.8131 -1.83888 0.302144 +1188 12.2541 -2.26499 1.53711 +1246 12.8581 -2.87484 2.04987 +85 11.19 -2.01542 -0.0740403 +624 11.3363 -1.15466 0.413221 +1196 11.3527 -2.59985 1.84386 +1393 12.9133 -1.41904 1.20415 +1590 12.7832 -1.38639 -2.05796 +1916 11.318 -2.74035 -1.95219 +750 10.8046 -2.58718 -0.834506 +1579 10.8936 -1.59648 -0.932106 +1051 12.3377 -1.28514 2.05767 +1025 12.1636 -1.09139 -1.32796 +1769 5.11433 -0.449739 1.42162 +135 5.78842 0.0107723 -0.619676 +1511 5.97261 0.0303081 1.17119 +519 5.96586 0.45661 0.266778 +209 5.6843 -0.260499 -1.57898 +1562 5.96743 -0.968318 1.36958 +1322 6.12369 -0.93115 -0.522989 +435 6.01823 -0.639005 0.427345 +1386 6.08422 0.305107 2.12613 +584 6.12395 0.726628 -1.33465 +1730 6.38813 -0.926741 -1.84566 +2 7.84648 -0.337453 -0.0670314 +6 9.51609 -0.689713 0.0327419 +32 8.76306 -0.79135 -0.617203 +36 6.594 0.942534 -0.479211 +212 10.5585 -0.730627 -0.56271 +104 6.65876 -0.132255 -0.148693 +1425 9.47268 0.614688 1.39228 +130 7.32471 0.313893 -0.74549 +1686 9.69184 -0.0711778 2.11653 +340 10.2852 0.746595 1.95774 +1705 7.02904 -0.178983 0.780349 +1792 7.60174 -0.307015 -1.47841 +1763 6.59348 -0.224234 -1.16432 +1823 8.02971 0.137898 0.786469 +412 9.84279 -0.025935 -0.639712 +1172 10.1471 0.423819 -1.73917 +449 10.4472 -0.698492 0.427654 +454 8.22946 -0.759536 -2.11315 +461 7.16005 0.564595 -1.69887 +494 9.55536 -0.384807 -1.52742 +1241 10.6842 -0.165788 2.03905 +1456 8.86739 0.598397 0.496275 +628 9.2826 0.535767 -1.24936 +1488 8.07105 0.675782 -1.30255 +659 8.5885 -0.175509 -1.38529 +775 8.67017 0.206332 2.03004 +802 7.89754 0.705247 -0.025835 +924 6.9033 0.757531 0.453262 +933 10.4973 -0.716289 -1.55886 +1966 8.64646 0.190524 -0.444329 +1897 8.59874 -0.779456 0.409265 +1008 9.38214 0.875363 -0.314342 +1044 10.5904 0.357631 0.910793 +1719 9.15964 -0.874424 1.79758 +1125 8.91123 -0.169905 1.13551 +953 8.05604 -0.616586 1.44805 +1366 10.3742 0.784838 -0.396065 +1870 6.70677 0.658656 1.42835 +1212 9.88792 -0.372302 1.18597 +1479 7.63329 0.37203 1.66855 +141 6.79955 -0.283719 1.74979 +1327 9.78089 0.223687 0.339783 +1680 7.08935 -0.99928 -0.772905 +1266 11.4359 0.734351 -0.578104 +174 12.5006 -0.186369 -1.63228 +184 13.381 -0.64446 -1.75439 +230 13.4335 0.405905 1.86514 +143 10.898 -0.816476 1.31137 +375 12.2906 -0.94053 0.206065 +387 13.9839 -0.703898 1.6859 +421 14.0326 -0.55687 -0.160105 +429 11.0761 0.844092 -1.65582 +462 11.5568 -0.739038 -0.615687 +562 13.3466 -0.836564 0.511654 +634 11.9356 0.0207473 -0.0874041 +1552 11.3807 0.797606 0.48442 +761 11.4686 -0.202525 0.767838 +1826 13.1254 0.117681 -0.0323671 +842 11.5152 -0.325157 -1.53564 +1811 12.9964 -0.554767 1.73559 +371 10.7819 0.125419 -1.02684 +1029 12.315 0.249553 1.78078 +858 11.5739 -0.621401 2.02156 +1155 12.5848 -0.462119 -0.674823 +1259 12.023 0.660054 -1.39284 +1692 12.8699 0.611524 -0.863432 +1877 12.1617 -0.759871 1.2246 +1542 12.2774 0.384378 0.79078 +1205 11.3523 0.400615 1.55659 +1554 13.202 0.0444761 0.961974 +1585 13.573 -0.0970597 -0.919951 +1702 10.9351 0.0365389 -0.0429883 +1161 5.35794 1.12409 -0.162989 +123 5.91991 1.57919 -0.853652 +655 5.54424 1.29232 1.69617 +846 5.98677 1.83162 0.159344 +826 6.05812 2.13583 -1.70867 +1067 6.28152 1.47871 1.04712 +1508 6.38485 2.1292 1.82728 +40 10.3097 1.91724 -0.474526 +47 8.53088 2.87423 1.39201 +86 8.13111 2.73529 0.395991 +88 9.39405 1.91473 -0.0254472 +90 9.84346 2.07882 -1.72015 +65 7.74227 1.08904 0.884162 +165 7.14734 1.54895 1.54225 +198 6.76809 1.51353 -1.37908 +204 7.31198 2.54355 1.5992 +222 8.16576 2.70362 -1.84745 +228 8.66048 2.47421 -0.410766 +229 10.2551 1.28914 -1.25073 +1934 10.6559 1.63558 -2.09872 +630 10.6111 1.41954 0.338996 +187 7.81838 1.48787 -1.90934 +384 6.9748 2.13543 0.750865 +402 9.67993 2.58811 1.62304 +418 9.11072 2.24728 0.873037 +322 8.77134 1.26289 -1.70686 +453 7.41315 2.70044 -0.298884 +458 10.5114 2.59674 -1.1859 +460 9.35293 1.62185 -0.979067 +1758 8.00403 2.03024 1.09225 +603 8.50327 1.26152 -0.593959 +540 10.2944 2.08067 1.01756 +585 8.5688 1.54808 0.403809 +1958 10.6613 2.81771 1.58525 +1651 9.55635 1.60402 1.49561 +1789 6.80081 1.91861 -0.414759 +741 9.48907 2.93382 -2.09852 +1840 8.46643 1.91032 1.96979 +1626 10.4035 1.82856 1.97887 +890 7.65585 1.81285 0.0937988 +937 9.0042 2.48258 -1.34922 +1003 9.67412 1.18396 0.595984 +1700 8.11903 2.02081 -1.11857 +1094 9.66991 2.67039 -0.627725 +1883 7.2014 2.40225 -1.22957 +1353 6.45459 2.88539 1.1593 +1054 7.51428 1.29578 -0.75018 +1941 9.88693 2.6998 0.348034 +1406 8.64117 1.16599 1.32508 +81 12.8746 2.94559 1.21194 +82 11.7156 2.89841 1.5947 +315 11.465 1.82747 0.772103 +348 12.6524 1.42238 -1.59791 +376 12.9183 2.59688 -0.94855 +399 11.3671 1.97529 1.75597 +492 12.2196 1.35314 -0.699164 +509 11.6471 1.76974 -2.01494 +566 11.4057 1.67055 -0.213682 +751 11.1206 1.78169 -1.16521 +999 12.3547 2.09424 1.14231 +728 13.3473 1.3098 1.44342 +1364 13.0462 2.28422 -1.9174 +1365 11.7914 2.89649 -1.87344 +800 13.2828 1.04574 0.481074 +1319 11.9582 1.1651 1.33644 +1495 11.3284 2.58616 -0.609452 +1783 11.8551 2.57952 0.24082 +1943 12.8174 1.97007 -0.176004 +1972 12.0361 2.19901 -1.19989 +1074 10.8676 2.61206 -2.12955 +355 12.3048 1.25021 0.291713 +1531 10.8333 2.39015 0.236435 +1251 10.8434 1.24547 1.29509 +1010 9.92778 4.06249 -0.572533 +1193 8.85055 3.80022 1.19185 +1202 10.4571 4.02443 1.39421 +1377 8.2753 4.11381 -1.09234 +1478 8.19993 3.56116 -0.162923 +1599 9.69199 4.15586 0.394638 +1917 8.96383 4.18556 -0.325132 +1443 8.865 3.6627 -1.81534 +1960 9.89532 3.37622 -1.29905 +294 8.8785 3.34881 -0.866076 +1553 7.63048 3.90967 1.87008 +815 7.86627 3.20317 -1.03486 +1522 9.54596 3.8661 1.90744 +424 10.6862 3.26909 0.689999 +538 9.0192 3.19453 0.394755 +1122 7.66925 3.31248 1.06906 +657 10.4856 3.15481 -0.310847 +968 9.75611 3.40142 1.04753 +537 7.80663 3.60965 -2.07086 +50 11.6951 3.93398 -1.87185 +410 10.9108 3.94896 -0.744444 +919 12.189 3.42269 0.662105 +1924 11.3932 3.85497 1.08627 +1487 12.642 3.51397 -0.661255 +1493 11.4034 3.43076 -0.0259972 +1800 11.1138 3.59985 2.01736 +1746 10.8375 3.47202 -1.62024 +1976 11.7138 3.41245 -1.01902 +814 5.73351 -3.76725 4.55387 +1344 6.25401 -4.27096 5.87481 +850 5.71317 -3.47411 6.14341 +1560 5.29242 -3.1394 5.19497 +1689 6.39179 -3.00253 5.3909 +948 9.0253 -4.53115 5.07225 +1011 7.67474 -4.14723 3.64854 +1087 7.59867 -4.05059 4.98254 +1540 8.91257 -3.79797 5.8489 +1784 10.2827 -3.77324 5.13685 +1878 6.69718 -3.97224 3.76545 +1900 7.99544 -3.44234 5.6698 +1843 7.02768 -3.63935 5.82635 +1913 9.68209 -4.18835 2.661 +1932 8.60721 -3.6386 4.90379 +528 9.17886 -3.44393 3.09986 +1741 7.68751 -3.2504 3.20641 +1717 8.30114 -3.43872 3.97324 +765 6.71487 -3.66595 4.71693 +1091 10.202 -3.0335 2.95822 +1267 8.22397 -3.23681 2.36328 +1654 10.5032 -3.03086 5.77954 +1326 7.76805 -3.09395 4.74552 +1851 7.10081 -3.08707 3.99888 +1380 9.36705 -3.00989 4.73888 +1450 10.5361 -4.29549 2.14692 +80 9.50493 -3.00134 5.72918 +607 11.2007 -3.43923 4.77036 +697 10.7571 -3.41212 3.69873 +1543 11.5232 -3.06261 2.72574 +1909 10.7236 -3.31326 2.15242 +1141 1.16016 -1.61841 6.15828 +1329 2.12284 -1.87094 6.25527 +153 4.97678 -2.18497 4.65496 +249 4.26339 -2.8479 4.4285 +372 3.36125 -1.71936 6.00157 +1657 4.18587 -1.57908 4.23557 +854 5.91714 -2.78849 4.46318 +1815 5.5323 -2.45728 3.60172 +982 5.10428 -1.63522 5.69997 +1643 5.8714 -1.9825 5.05309 +1082 5.0513 -1.54595 2.5024 +1249 3.88926 -1.87575 5.14331 +1352 4.5785 -2.49601 5.51771 +1461 5.51029 -2.45039 2.60205 +1667 4.28424 -1.95444 6.30511 +925 5.87947 -1.61958 3.18022 +311 2.5783 -1.19594 5.66587 +1058 5.63444 -1.62697 4.14935 +588 4.87281 -2.90905 6.37947 +1078 6.04769 -1.54838 6.117 +847 5.66928 -2.51204 5.87595 +889 6.00169 -1.53648 2.19151 +1834 4.93233 -1.19944 4.81832 +1863 3.13236 -2.71489 6.03868 +114 4.22547 -1.00354 5.49798 +1559 5.78824 -1.0196 5.30891 +51 9.89616 -2.88941 3.89927 +67 7.84215 -2.00646 5.05365 +1527 6.82775 -2.42775 4.69871 +155 9.48654 -2.0432 6.0143 +1444 8.31539 -1.23631 2.19134 +325 8.71618 -1.73457 5.45694 +356 6.51491 -2.79432 3.14201 +389 6.5007 -2.05861 3.82903 +391 9.11669 -2.27434 4.01694 +394 8.31239 -2.65023 6.19092 +413 7.37036 -2.32191 3.41166 +484 7.88571 -1.72711 6.01291 +1342 10.0621 -1.07726 4.80374 +595 9.76177 -2.1268 5.05686 +613 6.52439 -1.3603 4.62321 +626 8.17266 -2.20987 2.36873 +674 8.19859 -1.774 3.29462 +727 6.77606 -1.81513 5.4868 +1325 8.78735 -1.10695 3.75087 +796 6.6134 -2.48042 6.21406 +1876 9.04876 -2.68122 2.46653 +910 9.66391 -1.93246 2.22137 +977 10.3947 -2.84763 4.77553 +980 7.33119 -2.70364 5.55601 +1964 8.13225 -2.36486 4.1664 +1608 7.29851 -2.68195 2.48151 +1100 10.5989 -2.26674 3.5559 +1378 9.04674 -1.46546 2.85458 +1217 10.5804 -2.13802 2.56444 +1503 9.906 -1.66009 3.96383 +1279 7.3618 -1.73022 4.22096 +1300 6.74184 -1.89905 2.75893 +284 10.4922 -1.34676 3.18063 +1659 10.7052 -1.89488 4.51654 +1334 10.5592 -1.70387 5.4871 +828 7.36237 -1.10211 5.10381 +1343 8.55075 -2.692 5.22073 +1957 7.28343 -1.28251 3.33034 +1564 7.00088 -1.49052 6.41293 +1455 8.17072 -1.22233 4.52929 +1805 9.65679 -2.22451 3.1773 +1523 8.52669 -2.71809 3.31806 +1524 9.16324 -1.46688 4.60443 +33 12.506 -1.82135 3.61675 +203 12.338 -1.91136 5.77793 +282 12.2514 -2.73348 3.93792 +370 11.2178 -2.40268 5.20874 +623 11.5439 -1.41866 5.42223 +719 11.2864 -2.63613 4.18083 +857 13.1619 -1.46833 2.94956 +1516 11.699 -1.78489 4.5049 +1108 11.5662 -2.07614 3.38935 +1330 12.1039 -2.84777 5.08033 +1355 13.4988 -1.86224 4.80051 +1469 13.2646 -1.3 4.00746 +1544 11.4765 -2.16932 6.28899 +1987 12.4961 -2.13784 2.62051 +1476 12.0055 -1.16597 3.04791 +271 12.6088 -1.42971 4.94445 +426 11.0232 -1.27842 6.26403 +548 11.5706 -1.81537 2.42415 +501 11.2109 -1.19887 3.85837 +1598 10.7951 -1.21368 2.23686 +1040 1.10644 -0.0185264 6.12785 +199 1.71448 -0.796205 6.28717 +64 4.06408 -0.477614 4.66363 +1593 4.19907 0.990578 5.76948 +154 5.2884 -0.814346 3.14339 +206 4.70055 -0.765194 3.94919 +35 4.85382 0.376404 6.20927 +317 4.88861 0.0204712 2.74944 +331 5.65168 0.786517 4.27745 +416 3.33698 0.447789 5.87071 +434 2.75046 0.725319 5.08991 +456 2.32711 -0.223814 5.67732 +472 3.41081 -0.592152 5.96607 +516 5.66384 -0.593612 2.24456 +541 5.41953 0.882064 2.59931 +1480 6.40935 -0.852621 3.55656 +650 3.92017 -0.0959229 3.75068 +836 4.86289 0.761171 3.42072 +1685 5.35706 -0.0299504 3.78099 +913 5.02629 -0.209347 4.71574 +1668 5.81228 0.237772 5.96231 +1085 4.1817 0.0133441 5.55832 +1526 5.05746 -0.451501 5.68688 +1177 3.21556 -0.159778 5.08582 +290 5.84145 -0.674975 4.37207 +639 6.04866 -0.0634499 3.05953 +1336 3.8924 0.504447 4.73668 +1107 5.99178 0.106047 4.98743 +1465 4.98109 0.633229 5.25155 +1474 4.2353 -0.781425 3.0646 +1059 6.40597 0.0568991 3.99278 +13 9.09156 0.629809 4.29065 +20 9.85626 -0.977425 2.50475 +28 7.57966 0.26235 5.66735 +52 7.42126 -0.666547 6.00155 +56 7.17399 -0.735734 4.19023 +66 7.97294 -0.324691 4.96017 +120 8.9938 -0.478098 2.70561 +227 6.6543 0.63448 5.59798 +245 8.07317 -0.361289 3.96644 +1660 10.7006 0.716708 3.01554 +1732 7.61634 -0.38763 2.31643 +328 10.0265 0.4138 3.71265 +1398 8.98932 -0.12843 3.64229 +400 9.7015 -0.810583 3.47859 +1918 7.01042 -0.0590875 4.90808 +1596 8.2426 0.713026 3.77028 +525 9.80725 -0.158338 4.50293 +549 6.59152 0.815228 4.61729 +1704 8.36624 -0.836739 5.72372 +610 10.0148 0.820917 4.62579 +1610 10.1648 -0.837026 5.79086 +176 8.12165 -0.802923 3.07126 +712 8.52941 0.0718835 6.10812 +721 9.82691 0.326545 5.47435 +1711 6.50274 -0.430149 5.6851 +748 7.1967 -0.105609 3.17947 +749 7.00938 0.529115 2.43018 +1422 8.22326 0.180992 2.92401 +262 8.02754 0.929319 6.26266 +1317 9.40616 0.432045 2.92934 +1887 8.74597 0.277169 5.15652 +239 9.14058 -0.989761 6.33779 +1808 9.27642 -0.50833 5.47213 +1116 9.16176 0.84212 6.01447 +1555 6.59858 0.760293 3.31005 +1213 6.76263 -0.810868 2.61881 +1230 7.36341 0.336325 4.0607 +1232 10.2705 -0.18266 2.94852 +1239 10.5421 -0.444804 3.87783 +1274 8.87334 -0.511592 4.55752 +25 12.7251 -0.249036 5.58265 +38 12.7311 0.396022 3.15041 +46 12.0051 -0.635093 5.00608 +221 11.1638 -0.631448 2.96024 +269 11.5671 0.95562 6.13915 +1623 11.4882 0.234162 2.5787 +319 11.5261 -0.125537 4.29178 +395 13.0115 0.611781 4.73719 +514 12.1698 -0.97492 4.02952 +812 11.85 -0.58679 5.99263 +869 12.4073 -0.406323 2.52968 +1740 11.035 -0.848125 4.77794 +1034 12.1172 0.647213 3.92737 +1070 13.441 0.089994 3.78672 +1298 12.3934 0.692508 5.64126 +1578 11.5625 0.19591 5.35711 +1485 12.8578 -0.621858 3.39571 +1795 12.804 -0.319942 4.43958 +1547 11.9445 -0.174723 3.38515 +1622 10.9643 0.638679 3.97661 +520 10.9207 -0.218087 6.00255 +822 10.7425 0.69526 5.63685 +1842 10.7148 0.100072 4.83379 +534 0.228442 2.16422 6.26943 +349 2.06139 1.902 6.31512 +73 5.70731 2.92254 6.03813 +901 6.33695 1.26163 2.3266 +194 2.65937 2.04711 5.46462 +431 5.57561 2.28426 3.64678 +513 4.66237 1.71797 3.6401 +673 5.34024 1.74792 4.4571 +739 3.46602 2.42745 6.07672 +1357 4.29244 2.97623 6.20175 +1306 3.32383 1.45105 5.91515 +327 5.19974 1.31422 5.95031 +1557 5.55476 2.583 4.96353 +1693 5.88648 1.99757 5.70322 +1759 4.94894 2.28603 5.89771 +1146 2.42548 1.02138 6.00523 +1855 3.89743 2.3084 5.18248 +1888 4.71512 2.5118 4.29752 +612 4.6551 1.65597 5.1791 +967 6.23075 1.24636 6.26597 +1237 3.51385 1.40846 4.93436 +1055 5.77168 1.30799 3.43267 +285 6.02322 2.19747 2.75691 +1243 3.82694 1.07704 3.85563 +1749 5.8543 1.1194 5.21988 +914 6.29432 1.78177 4.16232 +1385 4.67923 1.00271 4.37316 +15 6.70189 2.52392 3.63094 +16 6.93627 2.60431 2.52378 +1467 10.642 1.57175 4.13469 +58 8.15152 2.56392 4.27952 +162 7.14541 1.30505 3.94482 +1640 9.8419 1.56794 6.15312 +179 8.52837 2.39547 2.84159 +122 6.62387 2.66197 5.58204 +1222 9.96009 1.31547 2.71176 +263 10.2091 2.67939 2.46626 +1314 9.43781 1.20841 3.55567 +1081 9.12001 1.07881 2.22352 +320 7.43481 1.25474 5.52547 +407 10.3689 1.62939 5.09562 +1254 9.35706 2.04975 2.40157 +517 9.44945 2.74618 3.1129 +1905 9.6847 1.76557 4.34631 +1946 7.60853 2.39027 3.23248 +645 7.93592 1.99231 5.0737 +671 8.05783 2.55479 5.89 +679 8.96785 2.08134 3.68189 +606 8.7121 1.64793 4.54609 +684 7.48921 2.92702 5.15646 +1672 8.85477 2.33936 5.25434 +711 10.0361 1.99994 3.43756 +1846 9.54792 2.50148 5.95527 +1567 10.6635 2.89441 5.45077 +783 8.85627 1.7917 6.09082 +793 7.21999 2.04683 6.09774 +797 9.39234 1.4945 5.26314 +1397 7.82111 1.02765 4.62758 +878 8.05282 1.69433 3.79583 +1825 7.56501 1.83039 2.40572 +1208 8.44743 1.19892 5.39741 +1399 6.63803 1.7284 5.1015 +1238 6.83258 1.70348 3.07452 +939 8.61988 1.41655 3.02117 +1033 7.97836 2.9546 2.22114 +1950 7.57747 1.01988 3.09016 +1133 9.86262 2.49148 5.00824 +1159 10.2046 2.93567 3.74533 +1729 6.45963 2.81675 4.60793 +1180 7.20896 2.18276 4.41846 +1195 9.12471 2.76674 4.39235 +663 8.12319 1.01531 2.25292 +105 12.9866 1.65863 2.30839 +1550 12.1684 1.0839 2.31187 +444 12.0019 1.67945 3.94817 +497 11.8146 1.94946 2.70838 +568 12.5672 1.38203 3.17892 +572 11.4893 2.37129 5.71351 +656 12.4723 2.51276 2.20845 +676 12.4512 1.82476 5.47769 +705 11.9454 2.78724 3.2501 +843 12.1761 1.15921 4.7841 +1910 11.1792 1.10289 4.83552 +1110 12.5551 2.2579 4.54765 +1186 11.1728 1.11692 2.23061 +1338 12.9531 1.38136 4.10137 +1561 12.7981 2.83751 3.76986 +1833 11.5646 2.02375 4.77892 +743 11.2237 2.24923 3.68502 +1718 11.2082 2.69485 2.43202 +962 11.5957 1.1153 3.21422 +1379 10.8575 1.63912 5.9679 +1348 10.8401 1.80219 2.87738 +1037 10.7313 2.50931 4.51498 +1920 5.65687 3.873 6.34463 +1933 4.34963 3.92672 5.89648 +1517 5.66393 3.53511 5.24895 +1796 5.6435 3.22941 4.20374 +92 6.41304 3.92401 4.31544 +965 7.53001 3.27921 3.68293 +276 9.26592 4.08997 5.07136 +683 8.35693 3.53767 4.18276 +406 8.93647 4.40361 4.03606 +959 7.77011 4.24504 3.77908 +1160 10.1513 4.35233 4.64462 +1216 9.04425 4.3827 3.01936 +1318 7.26228 4.21295 6.14334 +1947 10.1614 3.93449 3.73567 +1435 7.86744 3.84442 5.43686 +1209 6.6618 3.59583 5.2267 +1881 7.92617 4.56713 2.7843 +258 8.4952 3.85733 2.36942 +969 8.74128 3.58127 6.06874 +1299 7.3955 3.73605 4.56199 +1179 9.73348 3.67375 2.8703 +291 10.7016 3.42695 2.91184 +706 9.88343 3.39177 4.57505 +574 7.32128 3.50828 2.73222 +757 6.54688 3.4384 6.20747 +1525 8.64548 3.30677 5.11194 +30 9.78219 3.39444 5.57103 +167 9.25693 3.50634 3.73318 +1001 7.52297 3.26821 6.34127 +1979 8.42099 3.3192 3.2091 +482 10.3177 3.10511 6.36508 +811 9.03154 3.02253 2.2473 +378 11.0548 4.18125 4.1108 +975 12.1016 3.54219 3.90468 +1635 11.5201 3.36987 5.67059 +188 11.1556 3.24186 3.78329 +1245 11.5281 3.0831 4.70325 +207 1.54148 -3.96536 9.899 +476 0.68598 -3.45942 10.0092 +1184 1.53678 -3.81327 8.66114 +1286 -0.150194 -3.55432 9.45159 +629 1.46489 -3.49858 7.07435 +159 3.15542 -4.19165 10.3556 +338 4.33343 -3.34709 9.44773 +542 2.38836 -3.56001 10.2432 +1713 5.11152 -3.77616 6.88264 +809 5.48535 -3.8789 8.31381 +1197 4.10737 -4.10251 10.0627 +1218 4.54798 -3.79333 7.97325 +1337 4.45894 -4.46636 7.1949 +1369 5.88579 -3.99904 9.3168 +1650 3.92141 -3.66097 6.94496 +1782 3.03165 -3.77035 9.42663 +1215 2.14854 -3.25193 9.31268 +217 6.13606 -3.56517 7.62192 +240 3.75292 -3.7401 8.73466 +771 3.77126 -3.15954 7.92071 +1912 5.22004 -3.1758 9.01824 +1658 5.60491 -3.30563 9.98033 +1931 2.87873 -3.02886 8.44217 +1505 3.15958 -3.04278 7.13836 +99 9.11654 -3.85291 8.08192 +261 10.4396 -3.29956 7.54363 +1280 8.37656 -3.89452 7.4106 +1497 7.84509 -3.7902 8.25119 +1922 7.88033 -3.91621 6.54274 +1785 7.13165 -3.74446 7.54706 +220 7.25027 -3.30978 9.57075 +1396 6.95209 -3.4884 8.58489 +1168 9.9186 -3.41351 6.69775 +1788 6.514 -3.33389 6.72563 +1201 7.43627 -3.02139 6.49788 +156 1.43105 -1.83914 8.30098 +190 0.562785 -2.45937 8.08861 +191 -0.0767958 -2.16149 8.8574 +234 0.662857 -1.5377 9.10999 +518 -2.05301 -2.09173 9.31314 +539 1.38551 -2.54182 6.46893 +744 0.488108 -1.46296 8.12822 +660 -0.118347 -1.92349 10.3711 +862 0.798799 -1.36691 7.06127 +1935 0.85685 -2.53205 10.6362 +970 -0.672522 -1.36576 8.74718 +1030 -1.2159 -1.60022 9.55327 +1774 -1.58273 -2.35466 8.45469 +1288 1.79012 -1.34053 10.3865 +1346 1.41585 -2.8406 8.46295 +1363 1.54445 -1.91882 9.38845 +1426 1.35529 -2.59797 7.49477 +1481 0.105551 -2.06051 7.25681 +1534 0.89251 -1.68298 10.1091 +1724 1.70973 -1.67727 7.33237 +1751 0.699948 -2.9417 9.15377 +745 1.69395 -2.83741 10.1477 +904 0.118375 -1.11029 9.83947 +1993 1.98156 -1.00622 8.24469 +819 -0.288373 -1.00545 7.54652 +0 4.64616 -2.57975 8.23363 +79 2.7342 -1.27177 10.0641 +116 4.16679 -1.53497 8.87843 +117 3.8522 -2.73357 8.82173 +151 4.71499 -2.97389 10.2933 +1606 6.29122 -1.04348 8.60427 +1681 5.80267 -1.29391 10.0349 +1617 4.03671 -2.3292 10.6458 +1459 6.26338 -1.34058 7.0711 +308 6.11457 -1.79351 7.97033 +324 4.2379 -2.35942 9.66505 +329 2.51823 -2.43017 9.75444 +358 3.07427 -2.78321 10.6894 +432 5.53253 -2.90389 7.13088 +495 6.21716 -2.00134 10.6072 +496 2.26525 -2.16799 10.6856 +499 5.58682 -2.90138 8.12937 +532 3.85645 -2.29519 7.14225 +571 2.90756 -1.33448 8.43093 +1320 5.22174 -1.44371 8.40325 +1977 4.66626 -1.16424 9.66309 +1973 6.35598 -2.33841 7.16907 +677 5.97904 -1.92382 8.96145 +686 4.19739 -1.71267 7.88005 +698 4.55515 -2.98696 7.32445 +740 5.65987 -2.31971 9.8225 +1849 3.83321 -1.53878 10.0682 +746 3.36905 -2.23499 8.08253 +1938 2.63382 -1.32159 7.4696 +820 2.22432 -2.3591 8.80131 +885 4.86643 -1.15053 7.37931 +1038 2.40248 -2.22671 7.82628 +1096 3.3568 -1.11698 9.29712 +1101 4.87923 -1.90995 10.2943 +1113 3.40105 -2.89979 9.75156 +1130 2.19446 -2.80786 6.99313 +1176 6.17923 -2.89862 9.07263 +1289 2.90795 -2.1297 6.81784 +1290 5.22117 -2.05495 7.6125 +801 5.28164 -1.01818 6.47952 +621 3.47108 -1.31068 6.92395 +1418 3.14716 -2.06817 9.06655 +1483 5.23224 -2.00681 6.61739 +1551 2.25718 -1.24741 9.18548 +1530 5.0137 -2.16301 9.06572 +23 7.71464 -2.59559 10.6675 +96 8.23584 -2.76736 8.75512 +100 7.80809 -2.12464 6.92693 +146 7.22414 -2.75492 7.43787 +1569 8.06527 -1.00951 6.6859 +189 8.50161 -1.96765 10.0834 +1829 6.69349 -1.63156 9.59717 +1755 9.40066 -2.01557 7.36683 +318 7.26099 -2.58499 8.88215 +351 8.8559 -1.9752 9.14811 +447 8.83542 -2.21382 8.17719 +1088 8.96068 -1.23881 8.35938 +502 6.55711 -2.66555 8.17677 +504 7.21591 -1.0119 8.98296 +692 9.18562 -2.73385 6.67191 +789 9.62908 -2.70994 8.52915 +928 8.21033 -2.99998 9.72735 +1415 8.83789 -1.18933 7.3688 +1086 8.72122 -1.84949 6.62759 +1919 10.3717 -1.39199 7.52132 +1163 7.03696 -1.76712 8.35297 +1390 7.80577 -1.23783 9.75796 +1234 7.18453 -1.75748 10.5402 +1252 9.23254 -2.96122 7.64458 +1271 8.22177 -1.19475 10.6662 +1361 7.59185 -2.21458 9.74982 +425 8.07635 -1.61312 7.85899 +1449 7.19376 -1.49626 7.40359 +1515 9.80517 -1.76414 8.25641 +1866 7.91044 -1.75018 8.83855 +1582 8.16789 -2.82978 7.75923 +1518 6.59849 -2.64582 9.94449 +192 10.2128 -2.46868 6.55387 +1738 10.0882 -1.4652 6.565 +1473 8.65327 -1.00508 9.28116 +374 12.1274 -1.34662 6.58049 +1228 11.6776 -1.23801 7.69561 +467 10.9388 -2.12742 7.15076 +1679 -3.06411 -0.362351 9.91628 +3 0.917169 -0.599733 10.4736 +1898 0.315967 -0.501258 6.92963 +1120 -0.528649 0.998192 7.89559 +186 -0.233742 -0.180748 9.73016 +1879 -0.449542 0.068673 8.75969 +1576 1.26966 0.324297 8.0805 +310 0.0899262 0.815456 10.4152 +323 0.495496 0.391648 8.70981 +415 -1.24402 0.284468 8.19207 +443 1.34973 -0.882059 9.61467 +469 -0.874117 0.511902 10.062 +553 1.10749 -0.730988 7.84444 +619 1.91407 -0.660722 7.25761 +573 1.37814 0.889183 9.70734 +589 1.51883 -0.319562 8.80536 +662 -1.70232 0.91607 9.67381 +689 0.219342 -0.480539 8.22966 +1978 -1.86362 0.893542 8.68716 +295 2.07435 0.338053 7.35125 +1014 -0.133123 0.151561 7.5396 +1053 -1.04404 0.413419 7.2208 +1178 0.540047 -0.491453 9.17676 +1200 -1.26672 -0.601539 9.54552 +1354 0.67714 0.199786 9.88971 +1358 1.16039 -0.010814 7.1447 +1472 1.62235 0.738105 6.52929 +1501 0.946615 0.952614 7.37286 +1570 1.61815 0.069751 10.2278 +281 1.5801 0.962966 10.6839 +1772 5.49264 -0.876923 9.18072 +1694 6.38417 0.947032 7.22889 +382 3.98915 0.441961 6.70614 +178 3.37991 -0.277656 7.03904 +1847 5.94501 -0.114306 8.47655 +244 3.86156 0.538529 10.2307 +248 3.99665 0.486827 9.23536 +251 2.63059 0.196603 6.53239 +61 6.10837 -0.47076 6.60257 +1747 4.48171 0.654035 8.37633 +1844 2.23541 0.33308 8.3392 +1875 3.55399 -0.876469 7.8208 +475 5.59062 0.758481 7.80506 +479 2.21337 0.493007 9.32599 +544 5.67992 0.0743226 9.42268 +620 4.68752 0.632118 7.39604 +633 2.97499 -0.01529 10.6044 +643 5.47266 0.903182 6.82019 +699 6.22628 0.908041 9.49648 +716 5.08055 -0.084511 7.97491 +799 4.28686 -0.927907 6.49246 +1872 2.47815 0.777029 10.2475 +824 4.35305 -0.300941 7.26777 +865 5.94923 -0.330374 10.2966 +900 2.92912 0.702173 7.72053 +918 3.74083 -0.359802 8.76897 +1653 2.66574 -0.817856 6.59452 +952 2.7211 -0.428162 8.81011 +1351 6.15525 -0.00158927 7.48452 +1645 4.878 0.745398 9.63047 +1099 5.41282 0.798849 8.78784 +1753 5.28489 -0.0630508 6.9965 +1151 3.74587 0.159143 7.91427 +1545 4.45782 -0.818607 8.24438 +1175 4.78608 -0.121241 8.92979 +1873 3.12573 0.205455 9.64126 +1983 5.73836 -0.86253 7.77501 +1770 5.64616 0.621768 10.2587 +1313 3.89858 -0.424029 9.77271 +1328 3.16935 0.455396 8.67462 +1339 2.70831 -0.344874 7.77661 +1468 2.34417 -0.411041 9.73618 +1538 4.86575 -0.219543 9.92332 +1619 6.53932 0.625992 8.16253 +89 8.43101 0.106948 7.99448 +1969 8.40471 -0.0399912 8.9866 +301 9.2462 0.526304 7.56188 +1963 9.30453 -0.378314 7.98364 +346 8.23267 0.590057 9.80063 +1835 7.12787 0.224525 7.46162 +398 7.8224 -0.554044 7.54239 +1771 10.6635 -0.593296 6.8968 +304 8.05722 -0.826083 8.47553 +551 9.22891 0.50625 8.83782 +661 10.0782 0.00194975 9.45883 +714 9.16031 0.216766 9.79249 +724 6.81648 0.241168 9.04282 +1690 7.63189 -0.123669 10.6192 +790 6.88232 -0.63372 7.91107 +861 8.33522 0.675657 7.17753 +736 7.69383 0.0720398 6.6523 +891 10.0235 0.245366 8.28988 +897 10.136 0.153625 7.30081 +899 6.74495 0.270539 10.374 +946 7.47491 -0.269434 9.60046 +993 8.38295 -0.376114 10.0095 +1112 6.72928 0.309777 6.54032 +185 10.3595 -0.958617 8.46589 +1049 6.98026 -0.809817 10.2966 +1068 9.52354 -0.63578 8.92457 +1221 7.83476 0.777391 8.90289 +1262 7.03976 -0.632788 6.92485 +1270 9.70656 -0.7469 7.1461 +1678 8.63988 -0.266639 7.04158 +931 7.70465 0.899976 7.91959 +505 6.45744 -0.585069 9.47522 +1434 7.50682 0.00430079 8.36016 +788 7.26283 0.823785 9.72169 +1047 9.4492 -0.0493442 6.47842 +1810 10.1492 0.662239 6.44041 +576 11.6594 -0.546603 6.97341 +713 11.013 -0.331957 7.79655 +1986 10.945 0.155668 8.66752 +1430 12.0119 0.388714 6.83974 +879 10.841 0.693429 7.76059 +1017 11.0134 0.341146 6.82629 +1307 -2.62726 1.01597 10.1429 +1726 -2.42907 2.00847 8.59371 +43 -0.895522 1.08672 8.8473 +119 1.06735 1.20657 8.61628 +127 0.937025 1.86152 7.78974 +252 -0.626796 2.14758 10.1737 +352 0.395747 2.07308 10.3479 +436 1.30511 2.17667 8.66448 +445 -1.43568 1.8958 8.61572 +644 0.19094 1.00624 6.72016 +536 -0.181741 2.19291 9.2793 +274 0.0740198 1.29836 8.72403 +1818 0.583328 1.47918 9.5654 +767 -1.59167 2.27244 10.4048 +777 1.21781 1.74685 6.82918 +787 -0.3939 1.30375 9.68472 +834 -0.53617 2.00098 7.97559 +1804 0.0430236 2.78341 7.66606 +960 0.766015 2.45655 9.4588 +1018 1.33707 1.78595 10.1705 +1048 1.81366 2.37253 9.51575 +1060 -0.431677 2.82433 8.54525 +1089 0.621783 2.90173 8.48512 +1786 1.82938 1.16892 7.96999 +1409 -1.03223 2.02227 7.07465 +1646 1.27282 2.83149 10.235 +1671 1.35999 2.83236 7.81422 +1708 1.9067 1.47229 9.09049 +1908 -1.44846 2.6773 7.70528 +1780 0.113175 1.8879 7.22355 +570 -0.781052 1.04067 6.48773 +138 1.97527 2.20385 7.33878 +1532 4.56873 1.51377 8.9862 +41 4.98692 1.88125 9.81686 +565 6.3439 2.30565 6.53734 +1381 3.30168 1.27413 10.612 +173 2.25955 1.28242 7.07461 +183 5.88389 1.58645 10.1462 +210 2.86585 1.26921 9.46631 +296 4.63062 2.42978 8.58989 +302 5.57805 2.40566 8.90818 +524 4.5911 1.22442 10.4598 +1572 2.67957 1.30445 8.47871 +1229 4.89212 1.45951 7.94887 +1764 3.83057 1.11191 7.58213 +1845 5.92211 2.85823 7.27709 +361 4.83384 2.81398 9.49047 +368 4.6476 2.31614 7.22762 +1255 3.75831 1.88493 6.95191 +1982 2.83778 2.25703 6.83578 +1980 3.7486 2.18034 9.02365 +1276 5.94794 1.5192 8.34662 +1275 2.33717 1.7642 10.1672 +596 3.86176 1.37267 9.6792 +667 3.2725 2.09482 10.0414 +670 2.23757 2.18379 8.30348 +730 5.84539 2.54621 9.86809 +1240 3.5145 2.74167 7.40609 +827 4.21317 2.41141 10.1634 +1368 6.34285 2.43243 8.24971 +29 6.11898 1.88978 7.42866 +1853 5.37727 2.33366 7.93133 +974 6.33343 1.88222 9.30178 +1688 3.63778 2.99596 9.59141 +1006 4.60101 1.38767 6.7472 +1013 2.75922 2.28714 9.20172 +1821 3.9922 2.03569 7.9289 +1042 5.42429 1.95395 6.7123 +1869 3.15523 2.58051 8.32526 +1106 3.06522 1.74931 7.67044 +1907 2.53328 2.74321 10.2232 +438 3.69261 1.299 8.55463 +1204 3.1931 1.03639 6.8155 +132 8.17176 2.92992 8.2557 +201 7.31428 2.47422 8.01614 +1170 8.67264 1.05853 8.18471 +232 9.04245 1.18289 10.0957 +403 9.59761 2.72389 8.73977 +468 7.23324 1.55898 10.3987 +559 10.6201 1.42356 8.40716 +625 10.2716 2.94381 7.53204 +627 9.97311 2.29151 6.8354 +635 6.93875 1.21931 8.86138 +690 7.82678 1.63499 9.56721 +770 9.98263 1.14871 7.29808 +1819 8.4568 2.13158 7.72536 +1577 7.15338 1.21668 6.65054 +851 7.22923 2.17062 8.96511 +379 6.92976 1.5309 7.89037 +1454 8.50766 2.43322 6.77379 +1586 8.00338 1.60246 7.00755 +985 9.12062 2.86679 7.86923 +1904 6.9563 2.38228 9.90331 +1069 9.73676 1.34799 9.22831 +1117 6.48571 2.85764 9.14348 +1776 8.26469 2.4052 9.103 +1225 9.02498 1.93317 8.52362 +1278 9.12241 2.0871 9.50685 +1350 7.84165 2.94937 7.312 +1768 7.14682 2.10996 7.10013 +1394 7.95635 1.69385 8.47175 +1439 8.27671 1.78214 10.4481 +1484 9.66285 1.18438 8.24463 +1512 8.66655 1.26222 9.17254 +1630 9.06195 1.32287 6.94949 +1669 9.4499 1.95639 7.61885 +5 10.8866 1.36036 6.92769 +172 11.2739 1.78853 7.74417 +148 -2.05493 3.00883 9.40541 +1000 -2.03329 3.386 10.3313 +849 1.95744 3.56001 10.2581 +1734 0.73341 3.4598 7.35201 +695 1.22372 3.39795 9.31089 +587 1.97804 3.03112 8.76653 +18 2.14754 4.1259 9.40201 +193 5.78642 3.8436 7.3788 +334 4.73809 4.05791 8.31474 +575 3.16689 3.54375 10.2829 +1848 4.30957 3.40925 10.206 +909 5.7228 4.23124 8.29838 +940 5.75375 3.238 8.18663 +976 5.59772 3.37172 9.16526 +1701 2.73338 3.93725 8.35789 +1799 4.90799 4.10477 6.96541 +1895 3.31672 4.43738 9.85986 +1961 5.81535 4.30379 9.45467 +912 3.46702 3.81314 9.02623 +1744 4.44454 3.68663 9.19564 +1187 3.39326 3.29139 6.57492 +868 6.35764 3.39828 9.97489 +1019 2.70141 3.29333 9.40521 +845 4.20082 3.42226 7.1499 +321 4.79844 3.14845 7.90344 +1002 5.29541 3.26561 10.2918 +103 2.40698 3.12862 6.60213 +1079 3.96064 3.15932 8.45282 +567 5.08435 3.1156 6.79607 +752 2.3764 3.04345 7.81202 +11 9.28063 3.06457 6.73365 +266 7.84267 3.88845 7.6554 +267 6.76485 3.31552 8.0452 +493 8.57633 3.74657 8.66726 +1061 7.57893 3.26323 10.1258 +1156 7.39108 3.91184 8.54728 +1594 8.09065 4.01158 6.69452 +1603 6.68764 4.304 7.9156 +1860 8.7762 3.65845 7.36462 +1332 6.55787 4.20197 6.85305 +680 6.44352 3.81284 8.85103 +791 8.62599 3.23493 9.52798 +1687 6.87744 3.07781 7.08051 +1903 7.50844 3.11469 9.13942 +764 1.72978 -3.80394 11.3069 +717 2.69174 -3.55143 11.2027 +197 3.9703 -3.20893 11.7374 +1304 4.76632 -3.4384 11.1773 +586 3.80379 -3.46214 10.7721 +1985 3.02245 -3.18246 12.0713 +112 1.99282 -2.53295 12.4506 +126 0.366803 -1.6418 13.072 +169 1.34772 -1.46573 11.4214 +335 -1.10775 -2.72085 11.1498 +523 -1.02159 -1.65867 10.7549 +564 -0.168945 -2.4496 11.3621 +615 1.72562 -2.38836 11.4979 +618 1.14746 -2.24226 12.8988 +883 0.467738 -1.36424 10.9574 +943 0.991917 -2.88916 11.957 +987 -1.08622 -1.63141 11.7525 +1210 -0.487166 -1.38749 13.6376 +1257 -0.428326 -1.80895 12.4891 +1506 0.576724 -1.96382 11.8181 +1893 -0.162049 -1.22566 11.7217 +1 4.9811 -2.64966 11.7533 +63 5.92996 -1.47913 11.9338 +93 4.13368 -1.25026 11.8759 +1261 6.13277 -1.06471 10.9505 +754 5.30966 -1.59436 11.1578 +830 2.25845 -1.65947 11.9685 +902 3.55624 -2.60327 12.7213 +956 3.34051 -1.67674 12.4132 +1944 4.0852 -2.22048 11.6386 +1429 3.0757 -2.27428 11.6564 +1447 4.98122 -1.72455 12.1328 +1798 2.60829 -1.77135 13.0876 +286 5.42086 -2.55026 10.8608 +1990 3.11349 -1.18279 11.5739 +1697 4.38772 -1.29385 10.9097 +223 3.18709 -1.79441 10.7864 +145 7.60732 -1.04445 11.4406 +958 6.79328 -1.62515 11.4508 +17 0.117303 -0.675929 13.1415 +287 0.88306 -0.107322 12.841 +489 1.13492 0.524609 11.4669 +638 -1.71655 -0.00749487 11.6543 +760 -1.81195 -0.195266 12.6319 +803 -0.729574 -0.125634 11.4712 +932 1.74881 -0.561206 11.5656 +1235 0.859089 -0.66354 12.0104 +1294 -0.392601 -0.0298402 12.5736 +1490 1.6471 0.15794 12.2529 +1624 -1.03528 0.716742 11.0275 +1628 -0.123526 0.915217 11.387 +1752 0.61739 0.461812 13.6192 +1967 0.978142 -0.405465 13.9681 +1316 -2.00289 0.857525 11.237 +95 -0.0284997 -0.385575 10.7186 +55 2.12792 0.225146 11.078 +152 2.69679 -0.286797 11.7267 +341 4.9064 0.704337 12.6966 +388 6.0002 -0.494774 11.7723 +490 2.43082 -0.295233 12.6906 +1867 2.3725 0.888998 12.5955 +560 5.23728 -0.238432 12.5979 +649 3.16348 0.540373 11.4139 +781 3.6943 -0.365568 11.7201 +838 3.92165 0.821371 12.8246 +936 4.11613 0.765349 11.2103 +978 4.56645 0.106387 11.8488 +440 5.15995 -0.666922 10.8089 +1026 5.015 -0.785485 11.791 +1162 5.49902 0.458084 11.9299 +1292 4.21346 -0.217883 12.7263 +1027 6.02582 0.250527 11.1061 +1663 3.17122 0.323494 12.39 +1739 3.34326 -0.695332 12.6049 +947 4.27463 -0.205292 10.7559 +1458 5.02764 0.404693 11.0134 +26 2.46065 -0.816023 10.9111 +1166 3.51188 -0.850901 10.7189 +734 7.02182 0.00220818 12.0841 +776 6.82042 -0.352966 11.1714 +1509 7.25033 0.623132 11.1637 +998 8.60067 -0.117696 10.9505 +981 6.49233 0.80847 11.7923 +966 8.35431 0.833679 10.7627 +237 -2.34492 1.73265 10.7806 +87 -0.401173 1.00443 12.3485 +1862 1.1053 2.25043 11.0314 +414 -1.36696 1.65139 11.1556 +1901 -0.630483 2.32785 11.1573 +510 0.975367 1.60772 12.893 +1519 1.10067 2.08177 12.0215 +693 0.708753 1.33277 11.0063 +1046 0.520907 1.26818 12.0654 +1149 1.40093 2.681 12.7637 +1464 -1.36179 1.51027 12.3116 +1383 1.65965 2.92685 11.6561 +723 2.0374 1.91723 12.6562 +1494 1.50852 1.14404 12.1613 +433 1.9475 1.98221 11.4991 +231 4.68349 1.32898 11.8106 +521 2.43152 1.17401 11.164 +864 2.73676 1.62958 12.0018 +874 5.05227 2.06011 12.3846 +955 5.74507 1.41936 12.0537 +1057 3.38199 2.38852 11.7586 +1448 4.52573 2.60057 11.605 +483 3.93718 1.85544 11.1201 +552 3.65957 1.24686 11.9584 +1962 2.81976 2.07885 10.9894 +357 5.49698 1.29954 11.0864 +360 4.90925 2.09654 10.8312 +326 5.93181 2.38286 10.8548 +1164 3.5231 2.76289 10.7961 +929 6.80799 1.90947 11.3079 +211 7.05305 2.75155 10.8275 +160 6.44596 1.11281 10.8241 +70 0.807955 3.45039 11.6777 +1500 1.71028 3.81205 11.1937 +171 3.82147 3.68739 11.0333 +309 3.21879 3.37581 11.7779 +1152 2.48611 3.14576 11.1374 diff --git a/contrib/voro++/examples/no_release/period.cc b/contrib/voro++/examples/no_release/period.cc new file mode 100644 index 0000000000000000000000000000000000000000..7653c3ee03d48fc0a4eb7a72e59ac7d645216375 --- /dev/null +++ b/contrib/voro++/examples/no_release/period.cc @@ -0,0 +1,50 @@ +#include "voro++.hh" +using namespace voro; + +// Set up constants for the container geometry +const double bx=10; +const double by=10; +const double bz=10; +const double bxy=0; +const double bxz=5; +const double byz=0; + +// Set up the number of blocks that the container is divided +// into +const int n_x=3,n_y=3,n_z=3; + +// Set the number of particles to add +const int particles=20; + +// This function returns a random double between 0 and 1 +double rnd() {return double(rand())/RAND_MAX;} + +int main() { + int i; + double x,y,z; + + // Create a container with the geometry given above, and make it + // non-periodic in each of the three coordinates. Allocate space for + // eight particles within each computational block. + container_periodic con(bx,bxy,by,bxz,byz,bz,n_x,n_y,n_z,8); + + // Add particles into the container at random positions + for(i=0;i<particles;i++) { + x=bx*rnd(); + y=by*rnd(); + z=bz*rnd(); + con.put(i,x,y,z); + } + + + // Output volume + double vvol=con.sum_cell_volumes(); + printf("Container volume : %g\n" + "Voronoi volume : %g\n",bx*by*bz,vvol); + + // Output particle positions, Voronoi cells, and the domain + con.draw_particles("particles_periodic.gnu"); + con.draw_cells_gnuplot("cells_periodic.gnu"); + con.draw_domain_gnuplot("domain_periodic.gnu"); + +} diff --git a/contrib/voro++/examples/no_release/polycry.gnuplot b/contrib/voro++/examples/no_release/polycry.gnuplot new file mode 100644 index 0000000000000000000000000000000000000000..0ffd6ce2fc9b9847a300342422d6d43bc5d0efca --- /dev/null +++ b/contrib/voro++/examples/no_release/polycry.gnuplot @@ -0,0 +1,10 @@ +set term pdf color solid +set pointsize 0.5 +set output 'polycry.pdf' +e=1e-9 +set key outside right +set xlabel 'x' +set ylabel 'y' +set zlabel 'z' +splot [-e:81+e] [-e:81+e] [-e:81+e] 'lammps_input' u 2:3:4 w p pt 7 t 'Particles', 'lammps_cells' lt 4 t 'Voronoi cells', 'lammps_generators' u 2:3:4 w p lt 3 pt 9 t 'Generators' +set output diff --git a/contrib/voro++/examples/no_release/polycrystal_rahman.cc b/contrib/voro++/examples/no_release/polycrystal_rahman.cc new file mode 100644 index 0000000000000000000000000000000000000000..383be72db69e8f8c6c724fd8e7150d47c4eeef43 --- /dev/null +++ b/contrib/voro++/examples/no_release/polycrystal_rahman.cc @@ -0,0 +1,112 @@ +// Voronoi method to generate nanocrystalline grain boundaries +// Nov 18, 2011 + +#include <cstdio> +#include <cstdlib> +#include <cmath> +using namespace std; + +#include "voro++.hh" +using namespace voro; + +const double pi=3.1415926535897932384626433832795; + +// Box geometry +const double x_min=0,x_max=81; +const double y_min=0,y_max=81; +const double z_min=0,z_max=81; +const double cvol=(x_max-x_min)*(y_max-y_min)*(x_max-x_min); + +// Total number of particles +const int particles=24; + +// Lattice size +const double h=4; + +// Function for random double between 0 and 1 +double rnd() {return double(rand())/RAND_MAX;} + +int main() { + int i,j=0,c_id; + double x,y,z,x1,y1,z1,x2,y2,z2,x3,y3,z3,xt,yt,zt,rx,ry,rz; + double theta,cth,sth,r,v,xc,yc,zc,vx,vy,vz; + + // Create the container class + container con(x_min,x_max,y_min,y_max,z_min,z_max,10,10,10, + false,false,false,8); + + // Add generators to the box + for(i=1;i<=particles;i++) { + x=x_min+rnd()*(x_max-x_min); + y=y_min+rnd()*(y_max-y_min); + z=z_min+rnd()*(z_max-z_min); + con.put(i,x,y,z); + } + + // Open the file for the particle positions + FILE *fp=safe_fopen("lammps_input","w"); + + // Create a loop class to iterate over all of the generators + // in the box + c_loop_all cl(con); + voronoicell c; + if(cl.start()) do if(con.compute_cell(c,cl)) { + + // Generate the first vector of an orthonormal basis + x1=2*rnd()-1;y1=2*rnd()-1;z1=2*rnd()-1;r=1/sqrt(x1*x1+y1*y1+z1*z1); + x1*=r;y1*=r;z1*=r; + + // Construct a second perpendicular vector + if(abs(x1)>0.5||abs(y1)>0.5) {r=1/sqrt(x1*x1+y1*y1);x2=-y1*r;y2=x1*r;z2=0;} + else {r=1/sqrt(x1*x1+z1*z1);x2=-z1*r;y2=0;z2=x1*r;} + + // Construct a third perpendicular vector using the vector product + x=y2*z1-z2*y1;y=z2*x1-x2*z1;z=x2*y1-y2*x1; + + // Take a random rotation of the second and third vectors + theta=2*pi*rnd();cth=cos(theta);sth=sin(theta); + x3=x*cth+x2*sth;x2=-x*sth+x2*cth; + y3=y*cth+y2*sth;y2=-y*sth+y2*cth; + z3=z*cth+z2*sth;z2=-z*sth+z2*cth; + + // Get a bound on how far to search + r=sqrt(0.25*c.max_radius_squared()); + v=(int(r/h)+2)*h; + + // Add small random displacement to lattice positioning, + // so that it's not always perfectly aligned with the generator + vx=-v+h*rnd();vy=-v+h*rnd();vz=-v+h*rnd(); + + // Print diagnostic information about this generator + c_id=cl.pid();cl.pos(xc,yc,zc); + printf("Generator %d at (%g,%g,%g), random basis:\n",c_id,xc,yc,zc); + printf("%g %g %g\n",x1,y1,z1); + printf("%g %g %g\n",x2,y2,z2); + printf("%g %g %g\n\n",x3,y3,z3); + + // Loop over a local region of points + for(z=vx;z<=v;z+=h) for(y=vy;y<=v;y+=h) for(x=vz;x<=v;x+=h) { + + // Construct points rotated into the random basis + xt=xc+x*x1+y*x2+z*x3; + yt=yc+x*y1+y*y2+z*y3; + zt=zc+x*z1+y*z2+z*z3; + + // Skip if this lies outside the container + if(xt<x_min||xt>x_max||yt<y_min||yt>y_max||zt<z_min||zt>z_max) continue; + + // Find the nearest generator + con.find_voronoi_cell(xt,yt,zt,rx,ry,rz,i); + + // If the nearest generator matches, then save this point + if(i==c_id) {fprintf(fp,"%d %g %g %g\n",j,xt,yt,zt);j++;} + } + } while(cl.inc()); + + // Close the output file + fclose(fp); + + // Output files for diagnosic purposes + con.draw_particles("lammps_generators"); + con.draw_cells_gnuplot("lammps_cells"); +} diff --git a/contrib/voro++/examples/no_release/rad_test.cc b/contrib/voro++/examples/no_release/rad_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..94986cf14a7d45922c9a31dface607296e96f8af --- /dev/null +++ b/contrib/voro++/examples/no_release/rad_test.cc @@ -0,0 +1,67 @@ +// Voronoi calculation example code +// +// Author : Chris H. Rycroft (LBL / UC Berkeley) +// Email : chr@alum.mit.edu +// Date : August 30th 2011 + +#include "voro++.hh" +using namespace voro; + +// Set up constants for the container geometry +const double x_min=-1,x_max=1; +const double y_min=-1,y_max=1; +const double z_min=-1,z_max=1; +const double cvol=(x_max-x_min)*(y_max-y_min)*(x_max-x_min); + +// Set up the number of blocks that the container is divided into +const int n_x=3,n_y=3,n_z=3; + +// Set the number of particles that are going to be randomly introduced +const int particles=1000; + +// This function returns a random double between 0 and 1 +double rnd() {return double(rand())/RAND_MAX;} + +int main() { + int i; + double pos[particles*4],*posp=pos; + + for(i=0;i<particles;i++) { + *(posp++)=x_min+rnd()*(x_max-x_min); + *(posp++)=y_min+rnd()*(y_max-y_min); + *(posp++)=z_min+rnd()*(z_max-z_min); + *(posp++)=rnd(); + } + + char buf[128]; + for(i=0;i<=200;i++) { + int j;double x,y,z,r,mul=i*0.01,vol=0; + + container_poly con(x_min,x_max,y_min,y_max,z_min,z_max,n_x,n_y,n_z, + false,false,false,8); + + posp=pos; + for(int j=0;j<particles;j++) { + x=*(posp++);y=*(posp++);z=*(posp++);r=*(posp++)*mul; + con.put(j,x,y,z,r); + } + + sprintf(buf,"rad_test_out/fr%d.pov",i); +// FILE *pf=safe_fopen(buf,"w"); + j=0; + c_loop_all cl(con); + voronoicell c; + cl.start(); + do { + if(con.compute_cell(c,cl)) { + vol+=c.volume(); + cl.pos(x,y,z); +// c.draw_pov(x,y,z,pf); + j++; + } + } while(cl.inc()); + + printf("%g %d %g %g\n",mul,j,vol,vol-8); +// fclose(pf); + } +} diff --git a/contrib/voro++/examples/no_release/rad_test.pl b/contrib/voro++/examples/no_release/rad_test.pl new file mode 100644 index 0000000000000000000000000000000000000000..54b1356806585efe791c01add1dafe18f59b2d94 --- /dev/null +++ b/contrib/voro++/examples/no_release/rad_test.pl @@ -0,0 +1,15 @@ +#!/usr/bin/perl + +foreach $f (0..200) { + open A,"rad_test.pov"; + open B,">temp.pov"; + + while(<A>) { + s/FRAME/rad_test_out\/fr$f.pov/; + print B; + } + + close A; + close B; + system "povray +H600 +W800 +A0.01 -J +R5 +Ofr_$f.png temp.pov"; +} diff --git a/contrib/voro++/examples/no_release/rad_test.pov b/contrib/voro++/examples/no_release/rad_test.pov new file mode 100644 index 0000000000000000000000000000000000000000..68584add904a030d0820aa1367452423c603f167 --- /dev/null +++ b/contrib/voro++/examples/no_release/rad_test.pov @@ -0,0 +1,26 @@ +#version 3.6; + +// Right-handed coordinate system in which the z-axis points upwards +camera { + location <30,-50,25> + sky z + right -0.05*x*image_width/image_height + up 0.05*z + look_at <0,0,0> +} + +// White background +background{rgb 1} + +// Two lights with slightly different colors +light_source{<-8,-20,30> color rgb <0.77,0.75,0.75>} +light_source{<25,-12,12> color rgb <0.38,0.40,0.40>} + +// Radius of the Voronoi cell network +#declare r=0.008; + +// Voronoi cells +union{ +#include "FRAME" + pigment{rgb <1,0.4,0.45>} finish{specular 0.5 ambient 0.42} +} diff --git a/contrib/voro++/examples/no_release/random_points_10.cc b/contrib/voro++/examples/no_release/random_points_10.cc new file mode 100644 index 0000000000000000000000000000000000000000..6c105eb80d3f5f0decf70972d03ddbcd330b72ab --- /dev/null +++ b/contrib/voro++/examples/no_release/random_points_10.cc @@ -0,0 +1,60 @@ +// Voronoi calculation example code +// +// Author : Chris H. Rycroft (LBL / UC Berkeley) +// Email : chr@alum.mit.edu +// Date : August 30th 2011 + +#include "voro++.hh" +#include <iostream> +#include <fstream> +using namespace voro; + +// Set up constants for the container geometry +const double x_min=-1,x_max=1; +const double y_min=-1,y_max=1; +const double z_min=-1,z_max=1; +const double cvol=(x_max-x_min)*(y_max-y_min)*(x_max-x_min); + +// Set up the number of blocks that the container is divided into +const int n_x=6,n_y=6,n_z=6; + +// Set the number of particles that are going to be randomly introduced +//const int particles=20; +const int particles=10; + +// This function returns a random double between 0 and 1 +double rnd() {return double(rand())/RAND_MAX;} + +int main() { + int i; + double x,y,z; + + // Create a container with the geometry given above, and make it + // non-periodic in each of the three coordinates. Allocate space for + // eight particles within each computational block + container con(x_min,x_max,y_min,y_max,z_min,z_max,n_x,n_y,n_z, + false,false,false,8); + + // Randomly add particles into the container + for(i=0;i<particles;i++) { + x=x_min+rnd()*(x_max-x_min); + y=y_min+rnd()*(y_max-y_min); + z=z_min+rnd()*(z_max-z_min); + con.put(i,x,y,z); + } + + // Sum up the volumes, and check that this matches the container volume + double vvol=con.sum_cell_volumes(); + printf("Container volume : %g\n" + "Voronoi volume : %g\n" + "Difference : %g\n",cvol,vvol,vvol-cvol); + + // Output the particle positions in gnuplot format + con.draw_particles("random_points_p.gnu"); + + // Output the Voronoi cells in gnuplot format + con.draw_cells_gnuplot("random_points_v.gnu"); + const char *vars = "%q %s %n %f %t %w %P %o"; + con.print_custom(vars,"test.txt"); + +} diff --git a/contrib/voro++/examples/no_release/random_points_200.cc b/contrib/voro++/examples/no_release/random_points_200.cc new file mode 100644 index 0000000000000000000000000000000000000000..b6ede7aac3a2e8228fb6334fa5b1e358602f0143 --- /dev/null +++ b/contrib/voro++/examples/no_release/random_points_200.cc @@ -0,0 +1,60 @@ +// Voronoi calculation example code +// +// Author : Chris H. Rycroft (LBL / UC Berkeley) +// Email : chr@alum.mit.edu +// Date : August 30th 2011 + +#include "voro++.hh" +#include <iostream> +#include <fstream> +using namespace voro; + +// Set up constants for the container geometry +const double x_min=-1,x_max=1; +const double y_min=-1,y_max=1; +const double z_min=-1,z_max=1; +const double cvol=(x_max-x_min)*(y_max-y_min)*(x_max-x_min); + +// Set up the number of blocks that the container is divided into +const int n_x=60,n_y=60,n_z=60; + +// Set the number of particles that are going to be randomly introduced +//const int particles=20; +const int particles=200; + +// This function returns a random double between 0 and 1 +double rnd() {return double(rand())/RAND_MAX;} + +int main() { + int i; + double x,y,z; + + // Create a container with the geometry given above, and make it + // non-periodic in each of the three coordinates. Allocate space for + // eight particles within each computational block + container con(x_min,x_max,y_min,y_max,z_min,z_max,n_x,n_y,n_z, + false,false,false,8); + + // Randomly add particles into the container + for(i=0;i<particles;i++) { + x=x_min+rnd()*(x_max-x_min); + y=y_min+rnd()*(y_max-y_min); + z=z_min+rnd()*(z_max-z_min); + con.put(i,x,y,z); + } + + // Sum up the volumes, and check that this matches the container volume + double vvol=con.sum_cell_volumes(); + printf("Container volume : %g\n" + "Voronoi volume : %g\n" + "Difference : %g\n",cvol,vvol,vvol-cvol); + + // Output the particle positions in gnuplot format + con.draw_particles("random_points_p.gnu"); + + // Output the Voronoi cells in gnuplot format + con.draw_cells_gnuplot("random_points_v.gnu"); + const char *vars = "%n"; + con.print_custom(vars,"test.txt"); + +} diff --git a/contrib/voro++/examples/no_release/single_cell_2d.cc b/contrib/voro++/examples/no_release/single_cell_2d.cc new file mode 100644 index 0000000000000000000000000000000000000000..3ac439cbb7b43496edd3c7869e14932f6eeffcf9 --- /dev/null +++ b/contrib/voro++/examples/no_release/single_cell_2d.cc @@ -0,0 +1,35 @@ +// Single Voronoi cell example code +// +// Author : Chris H. Rycroft (LBL / UC Berkeley) +// Email : chr@alum.mit.edu +// Date : August 30th 2011 + +#include "voro++.hh" +using namespace voro; + +// This function returns a random floating point number between 0 and 1 +double rnd() {return double(rand())/RAND_MAX;} + +int main() { + double x,y,rsq,r; + voronoicell v; + + // Initialize the Voronoi cell to be a square of side length 2 in the xy-plane. Set the + // cell to be 1 high in the z-direction. + v.init(-1,1,-1,1,-0.5,0.5); + + // Cut the cell by 250 random planes which are all a distance 1 away + // from the origin, to make an approximation to a sphere + for(int i=0;i<25;i++) { + x=2*rnd()-1; + y=2*rnd()-1; + rsq=x*x+y*y; + if(rsq>0.01&&rsq<1) { + r=1/sqrt(rsq);x*=r;y*=r; + v.plane(x,y,0,1); + } + } + + // Output the Voronoi cell to a file, in the gnuplot format + v.draw_gnuplot(0,0,0,"single_cell_2d.gnu"); +} diff --git a/contrib/voro++/examples/no_release/sphere_mesh.cc b/contrib/voro++/examples/no_release/sphere_mesh.cc new file mode 100644 index 0000000000000000000000000000000000000000..4e40595b64104fadbeadea44db6599a26841982a --- /dev/null +++ b/contrib/voro++/examples/no_release/sphere_mesh.cc @@ -0,0 +1,216 @@ +// Voronoi calculation example code +// +// Author : Chris H. Rycroft (LBL / UC Berkeley) +// Email : chr@alum.mit.edu +// Date : August 30th 2011 + +#include "voro++.hh" +using namespace voro; + +// Set up constants for the container geometry +const double boxl=1.2; + +// Set up the number of blocks that the container is divided into +const int bl=24; + +// Set the number of particles that are going to be randomly introduced +const int particles=20000; + +const int nface=11; + +// This function returns a random double between 0 and 1 +double rnd() {return double(rand())/RAND_MAX;} + +struct wall_shell : public wall { + public: + wall_shell(double xc_,double yc_,double zc_,double rc,double sc,int w_id_=-99) + : w_id(w_id_), xc(xc_), yc(yc_), zc(zc_), lc(rc-sc), uc(rc+sc) {} + bool point_inside(double x,double y,double z) { + double rsq=(x-xc)*(x-xc)+(y-yc)*(y-yc)+(z-zc)*(z-zc); + return rsq>lc*lc&&rsq<uc*uc; + } + template<class v_cell> + bool cut_cell_base(v_cell &c,double x,double y,double z) { + double xd=x-xc,yd=y-yc,zd=z-zc,dq=xd*xd+yd*yd+zd*zd,dq2; + if (dq>1e-5) { + dq2=2*(sqrt(dq)*lc-dq); + dq=2*(sqrt(dq)*uc-dq); + return c.nplane(xd,yd,zd,dq,w_id)&&c.nplane(-xd,-yd,-zd,-dq2,w_id); + } + return true; + } + bool cut_cell(voronoicell &c,double x,double y,double z) {return cut_cell_base(c,x,y,z);} + bool cut_cell(voronoicell_neighbor &c,double x,double y,double z) {return cut_cell_base(c,x,y,z);} + private: + const int w_id; + const double xc,yc,zc,lc,uc; +}; + + +int main() { + int i=0,j,k,l,ll,o; + double x,y,z,r,dx,dy,dz; + int faces[nface],*fp; + double p[3*particles]; + + // Create a container with the geometry given above, and make it + // non-periodic in each of the three coordinates. Allocate space for + // eight particles within each computational block + container con(-boxl,boxl,-boxl,boxl,-boxl,boxl,bl,bl,bl,false,false,false,8); + + wall_shell ws(0,0,0,1,0.00001); + con.add_wall(ws); + + // Randomly add particles into the container + while(i<particles) { + x=boxl*(2*rnd()-1); + y=boxl*(2*rnd()-1); + z=boxl*(2*rnd()-1); + r=x*x+y*y+z*z; + if(r>1e-5) { + r=1/sqrt(r);x*=r;y*=r;z*=r; + con.put(i,x,y,z); + i++; + } + } + + for(l=0;l<1000;l++) { + c_loop_all vl(con); + voronoicell c; + for(fp=faces;fp<faces+nface;fp++) *fp=0; + if(vl.start()) do if(con.compute_cell(c,vl)) { + vl.pos(i,x,y,z,r); + c.centroid(dx,dy,dz); + p[3*i]=x+dx; + p[3*i+1]=y+dy; + p[3*i+2]=z+dz; + + i=c.number_of_faces()-4; + if(i<0) i=0;if(i>=nface) i=nface-1; + faces[i]++; + } while (vl.inc()); + con.clear(); + double fac=0;//l<9000?0.1/sqrt(double(l)):0; + for(i=0;i<particles;i++) con.put(i,p[3*i]+fac*(2*rnd()-1),p[3*i+1]+fac*(2*rnd()-1),p[3*i+2]+fac*(2*rnd()-1)); + printf("%d",l); + for(fp=faces;fp<faces+nface;fp++) printf(" %d",*fp); + puts(""); + } + + // Output the particle positions in gnuplot format + con.draw_particles("sphere_mesh_p.gnu"); + + // Output the Voronoi cells in gnuplot format + con.draw_cells_gnuplot("sphere_mesh_v.gnu"); + + // Allocate memory for neighbor relations + int *q=new int[particles*nface],*qn=new int[particles],*qp; + for(l=0;l<particles;l++) qn[l]=0; + + // Create a table of all neighbor relations + vector<int> vi; + voronoicell_neighbor c; + c_loop_all vl(con); + if(vl.start()) do if(con.compute_cell(c,vl)) { + i=vl.pid();qp=q+i*nface; + c.neighbors(vi); + if(vi.size()>nface+2) voro_fatal_error("Too many faces; boost nface",5); + + for(l=0;l<(signed int) vi.size();l++) if(vi[l]>=0) qp[qn[i]++]=vi[l]; + } while (vl.inc()); + + // Sort the connections in anti-clockwise order + bool connect; + int tote=0; + for(l=0;l<particles;l++) { + tote+=qn[l]; + for(i=0;i<qn[l]-2;i++) { + o=q[l*nface+i]; + //printf("---> %d,%d\n",i,o); + j=i+1; + while(j<qn[l]-1) { + ll=q[l*nface+j]; + // printf("-> %d %d\n",j,ll); + connect=false; + for(k=0;k<qn[ll];k++) { + // printf("%d %d %d\n",ll,k,q[ll*nface+k]); + if(q[ll*nface+k]==o) {connect=true;break;} + } + if(connect) break; + j++; + } + + // Swap the connected vertex into this location + //printf("%d %d\n",i+1,j); + o=q[l*nface+i+1]; + q[l*nface+i+1]=q[l*nface+j]; + q[l*nface+j]=o; + } + + // Reverse all connections if the have the wrong handedness + j=3*l;k=3*q[l*nface];o=3*q[l*nface+1]; + x=p[j]-p[k];dx=p[j]-p[o]; + y=p[j+1]-p[k+1];dy=p[j+1]-p[o+1]; + z=p[j+2]-p[k+2];dz=p[j+2]-p[o+2]; + if(p[j]*(y*dz-z*dy)+p[j+1]*(z*dx-x*dz)+p[j+2]*(x*dy-y*dx)<0) { + for(i=0;i<qn[l]/2;i++) { + o=q[l*nface+i]; + q[l*nface+i]=q[l*nface+qn[l]-1-i]; + q[l*nface+qn[l]-1-i]=o; + } + } + } + + FILE *ff=safe_fopen("sphere_mesh.net","w"); + int *mp=new int[particles],*mpi=new int[particles]; + for(i=0;i<particles;i++) mp[i]=-1; + *mpi=0;*mp=0;l=1;o=0; + while(o<l) { + i=mpi[o]; + for(j=0;j<qn[i];j++) { + k=q[i*nface+j]; + if(mp[k]==-1) { + mpi[l]=k; + mp[k]=l++; + } + if(mp[i]<mp[k]) + fprintf(ff,"%g %g %g\n%g %g %g\n\n\n",p[3*i],p[3*i+1],p[3*i+2],p[3*k],p[3*k+1],p[3*k+2]); + } + o++; + } + fclose(ff); + + // Save binary representation of the mesh + FILE *fb=safe_fopen("sphere_mesh.bin","wb"); + + // Write header + int kk[3],sz=tote+particles+2,*red(new int[sz]),*rp=red; + *kk=1;kk[1]=sz;kk[2]=3*particles; + fwrite(kk,sizeof(int),3,fb); + + // Assemble the connections and write them + *(rp++)=particles;*(rp++)=tote; + for(l=0;l<particles;l++) *(rp++)=qn[mpi[l]]; + for(l=0;l<particles;l++) { + i=mpi[l];printf("%d",l); + for(j=0;j<qn[i];j++) {*(rp++)=mp[q[i*nface+j]];printf(" %d",*(rp-1));} + puts(""); + } + fwrite(red,sizeof(int),sz,fb); + + + double *pm=new double[3*particles],*a=pm,*b; + for(i=0;i<particles;i++) { + b=p+3*mpi[i]; + *(a++)=*(b++);*(a++)=*(b++);*(a++)=*b; + } + fwrite(pm,sizeof(double),3*particles,fb); + delete [] pm; + + // Free dynamically allocated arrays + delete [] red; + delete [] mpi; + delete [] mp; + delete [] qn; + delete [] q; +} diff --git a/contrib/voro++/examples/timing/README b/contrib/voro++/examples/timing/README new file mode 100644 index 0000000000000000000000000000000000000000..9afd47aaf7ac5e72336eadbda15244aed5a5b9a2 --- /dev/null +++ b/contrib/voro++/examples/timing/README @@ -0,0 +1,12 @@ +Timing examples +=============== +These codes and scripts can be used to test the code's performance. The program +timing_test.cc creates a container with 100000 particles, and then times the +computation of all the cells in the container, using the dummy function +compute_all_cells(). + +The code will compile and run in the usual way, but it can also be tuned using +the preprocessor macro NNN to configure the grid size. The perl script +timing_test.pl will compile and run the program multiple times for NNN in the +range 10 to 40. For each value of NNN, it carries out three runs, and prints a +mean and standard deviation of times. diff --git a/contrib/voro++/examples/timing/timing_test.cc b/contrib/voro++/examples/timing/timing_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..d889a240fd51c33b4c9c14482d66dcff2d124b13 --- /dev/null +++ b/contrib/voro++/examples/timing/timing_test.cc @@ -0,0 +1,60 @@ +// Timing test example code +// +// Author : Chris H. Rycroft (LBL / UC Berkeley) +// Email : chr@alum.mit.edu +// Date : August 30th 2011 + +#include <ctime> +using namespace std; + +#include "voro++.hh" +using namespace voro; + +// Set up constants for the container geometry +const double x_min=-1,x_max=1; +const double y_min=-1,y_max=1; +const double z_min=-1,z_max=1; + +// Set up the number of blocks that the container is divided into. If the +// preprocessor variable NNN hasn't been passed to the code, then initialize it +// to a good value. Otherwise, use the value that has been passed. +#ifndef NNN +#define NNN 26 +#endif +const int n_x=NNN,n_y=NNN,n_z=NNN; + +// Set the number of particles that are going to be randomly introduced +const int particles=100000; + +// This function returns a random double between 0 and 1 +double rnd() {return double(rand())/RAND_MAX;} + +int main() { + clock_t start,end; + int i;double x,y,z; + + // Create a container with the geometry given above, and make it + // periodic in each of the three coordinates. Allocate space for eight + // particles within each computational block. + container con(x_min,x_max,y_min,y_max,z_min,z_max,n_x,n_y,n_z, + true,true,true,8); + + //Randomly add particles into the container + for(i=0;i<particles;i++) { + x=x_min+rnd()*(x_max-x_min); + y=y_min+rnd()*(y_max-y_min); + z=z_min+rnd()*(z_max-z_min); + con.put(i,x,y,z); + } + + // Store the initial clock time + start=clock(); + + // Carry out a dummy computation of all cells in the entire container + con.compute_all_cells(); + + // Calculate the elapsed time and print it + end=clock(); + double runtime=double(end-start)/CLOCKS_PER_SEC; + printf("%g\n",runtime); +} diff --git a/contrib/voro++/examples/timing/timing_test.pl b/contrib/voro++/examples/timing/timing_test.pl new file mode 100644 index 0000000000000000000000000000000000000000..f1ff487f8e8bd3fbf22824a25c126692fa715620 --- /dev/null +++ b/contrib/voro++/examples/timing/timing_test.pl @@ -0,0 +1,42 @@ +#!/usr/bin/perl + +# The range of grid sizes to consider +@range=(10..40); + +# The number of trials to consider. If this is set to one, the time for a +# single trial will be outputted. For higher values, the mean of all the trials +# will be outputted, along with the standard deviation. +$tries=3; + +# The flags to pass for code optimization +$opt="-O3"; + +foreach $r (@range) { + + # Compile the code with the current grid size + system "g++ $opt -I../../src -DNNN=$r -o timing_test " + ."-L../../src timing_test.cc -lvoro++"; + + # Carry out the trials for this grid size + $st=$stt=0; + foreach $t (1..$tries) { + + # Run the code, and output the timing information to the + # "time_temp" file. + system "./timing_test >time_temp"; + + # Read the "time_temp" file to find the duration of the run + open F,"time_temp" or die "Can't open timing file: $!"; + ($t)=split ' ',<F>; + $st+=$t;$stt+=$t*$t; + close F; + } + + # Compute the mean and variance and print to standard output + $st/=$tries; + $stt=$stt/$tries-$st*$st;$stt=$stt>0?sqrt($stt):0; + print "$r $st $stt\n"; +} + +# Delete the temporary timing file +unlink "time_temp"; diff --git a/contrib/voro++/examples/walls/Makefile b/contrib/voro++/examples/walls/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..569605fd7ada03f57bbc01c2c97d1eb8ef3b857b --- /dev/null +++ b/contrib/voro++/examples/walls/Makefile @@ -0,0 +1,31 @@ +# Voro++ makefile +# +# Author : Chris H. Rycroft (LBL / UC Berkeley) +# Email : chr@alum.mit.edu +# Date : August 30th 2011 + +# Load the common configuration file +include ../../config.mk + +# List of executables +EXECUTABLES=cylinder tetrahedron frustum torus + +# Makefile rules +all: $(EXECUTABLES) + +cylinder: cylinder.cc + $(CXX) $(CFLAGS) $(E_INC) $(E_LIB) -o cylinder cylinder.cc -lvoro++ + +tetrahedron: tetrahedron.cc + $(CXX) $(CFLAGS) $(E_INC) $(E_LIB) -o tetrahedron tetrahedron.cc -lvoro++ + +frustum: frustum.cc + $(CXX) $(CFLAGS) $(E_INC) $(E_LIB) -o frustum frustum.cc -lvoro++ + +torus: torus.cc + $(CXX) $(CFLAGS) $(E_INC) $(E_LIB) -o torus torus.cc -lvoro++ + +clean: + rm -f $(EXECUTABLES) + +.PHONY: all clean diff --git a/contrib/voro++/examples/walls/README b/contrib/voro++/examples/walls/README new file mode 100644 index 0000000000000000000000000000000000000000..8903906dba6dc45eee127af8b7f78c12111b8604 --- /dev/null +++ b/contrib/voro++/examples/walls/README @@ -0,0 +1,47 @@ +Wall support +============ +The structure of Voro++ makes it easy to handle complicated boundary conditions +by adding in additional plane cuts due to walls. The code has built-in support +for plane, cylindrical, and spherical walls, and extra ones can be easily coded +as derived C++ classes. + +1. cylinder.cc - this example creates a cylinder wall object, and imports a +test packing from "pack_cylinder". It outputs POV-Ray files for particles at +cylinder_p.pov, and Voronoi cells at cylinder_v.pov. These can be rendered +using the scene file cylinder.pov with the command: + +povray +W600 +H800 +A0.3 +Ocylinder.png cylinder.pov + +2. frustum.cc - this example creates a frustum by making use of a cone wall +object. It fills the frustum with 500 random points, and outputs the +Voronoi cells in gnuplot format. Due to the conical wall being approximated +with plane cuts, some inaccuracies can be seen. + +3. tetrahedron.cc - this example creates a tetrahedron with four planes, and +randomly inserts particles into it, using the point_inside() function to +determine whether the points are within the walls. It outputs the particles to +tetrahedron_p.gnu, and the Voronoi cells to tetrahedron_v.gnu. These can be +visualized in gnuplot using: + +splot 'tetrahedron_p.gnu' with points, 'tetrahedron_v.gnu' with lines + +Currently, the curved walls are made by a single approximating plane cut. This +provides good results when particles are pressed against the walls, but is +inaccurate it the particles are sparse. It would be possible to improve this by +approximating the curved surface with a sequence of planes rather than just +one. + +The code currently only supports walls which lead to convex computational +domains, since a non-convex domain would lead to non-convex cells. To correctly +handle these cases, the easiest way would be to divide the domain into several +convex sub-domains, carry out a calculation in each, and then glue the cells +that cross the divisions. Native support for non-convex domains may be added in +a later version. + +4. torus.cc - this example shows how to create a custom wall object, derived +from the pure virtual "wall" class. A routine is written that can cut a Voronoi +cell in response to a torus centered on the origin that is aligned with the xy +plane. The program writes POV-Ray files of the particles and Voronoi cells, and +these can be rendered using the following command: + +povray +W800 +H600 +A0.3 +Otorus.png torus.pov diff --git a/contrib/voro++/examples/walls/cylinder.cc b/contrib/voro++/examples/walls/cylinder.cc new file mode 100644 index 0000000000000000000000000000000000000000..0e82d78345fe92aae8799aa67bdcf118cedca4a3 --- /dev/null +++ b/contrib/voro++/examples/walls/cylinder.cc @@ -0,0 +1,37 @@ +// Cylindrical wall example code +// +// Author : Chris H. Rycroft (LBL / UC Berkeley) +// Email : chr@alum.mit.edu +// Date : August 30th 2011 + +#include "voro++.hh" +using namespace voro; + +// Set up constants for the container geometry +const double x_min=-6.5,x_max=6.5; +const double y_min=-6.5,y_max=6.5; +const double z_min=0,z_max=18.5; + +// Set the computational grid size +const int n_x=7,n_y=7,n_z=14; + +int main() { + // Create a container with the geometry given above, and make it + // non-periodic in each of the three coordinates. Allocate space for + // eight particles within each computational block. + container con(x_min,x_max,y_min,y_max,z_min,z_max,n_x,n_y,n_z, + false,false,false,8); + + // Add a cylindrical wall to the container + wall_cylinder cyl(0,0,0,0,0,1,6); + con.add_wall(cyl); + + // Import the particles from a file + con.import("pack_cylinder"); + + // Output the particle positions in POV-Ray format + con.draw_particles_pov("cylinder_p.pov"); + + // Output the Voronoi cells in POV-Ray format + con.draw_cells_pov("cylinder_v.pov"); +} diff --git a/contrib/voro++/examples/walls/cylinder.pov b/contrib/voro++/examples/walls/cylinder.pov new file mode 100644 index 0000000000000000000000000000000000000000..d880e611cc9ad6a988282ca7410b65ec94315b25 --- /dev/null +++ b/contrib/voro++/examples/walls/cylinder.pov @@ -0,0 +1,35 @@ +#version 3.6; + +// Right-handed coordinate system in which the z axis points upwards +camera { + location <20,-50,30> + sky z + right -0.4*x*image_width/image_height + up 0.4*z + look_at <0,0,9.25> +} + +// White background +background{rgb 1} + +// Two lights with slightly different colors +light_source{<-8,-20,30> color rgb <0.77,0.75,0.75>} +light_source{<20,-15,5> color rgb <0.38,0.40,0.40>} + +// Radius of the Voronoi cell network, and the particle radius +#declare r=0.08; +#declare s=0.5; + +// Particles +union{ +#include "cylinder_p.pov" +scale <1,-1,1> + pigment{rgb <1,0.95,0.5>} finish{reflection 0.1 specular 0.3 ambient 0.42} +} + +// Voronoi cells +union{ +#include "cylinder_v.pov" +scale <1,-1,1> +pigment{rgb <0.5,0.8,1>} finish{specular 0.5 ambient 0.42} +} diff --git a/contrib/voro++/examples/walls/frustum.cc b/contrib/voro++/examples/walls/frustum.cc new file mode 100644 index 0000000000000000000000000000000000000000..925ded31fd42c730aacd917cbe2684ffed46b7b3 --- /dev/null +++ b/contrib/voro++/examples/walls/frustum.cc @@ -0,0 +1,49 @@ +// Frustum example code +// +// Author : Chris H. Rycroft (LBL / UC Berkeley) +// Email : chr@alum.mit.edu +// Date : August 30th 2011 + +#include "voro++.hh" +using namespace voro; + +const double pi=3.1415926535897932384626433832795; + +int main() { + int i=0; + double x,y,z,evol,vvol; + + // Create a container with the geometry given above, and make it + // non-periodic in each of the three coordinates. Allocate space for + // eight particles within each computational block. + container con(-1.2,1.2,-1.2,1.2,0,1,14,14,7, + false,false,false,8); + + // Add a cylindrical wall to the container + wall_cone cone(0,0,2,0,0,-1,atan(0.5)); + con.add_wall(cone); + + // Place particles in a regular grid within the frustum, for points + // which are within the wall boundaries + for(z=0.1;z<1;z+=0.2) for(y=-0.85;y<1;y+=0.2) for(x=-0.95;x<1;x+=0.2) { + if (con.point_inside(x,y,z)) { + con.put(i,x,y,z);i++; + } + } + + // Output the particle positions and Voronoi cells in Gnuplot format + con.draw_particles("frustum_p.gnu"); + con.draw_cells_gnuplot("frustum_v.gnu"); + + // Output the particle positions and Voronoi cells in POV-Ray format + con.draw_particles_pov("frustum_p.pov"); + con.draw_cells_pov("frustum_v.pov"); + + // Compute the volume of the Voronoi cells and compare it to the + // exact frustum volume + evol=pi*1*(0.5*0.5+0.5*1+1*1)/3; + vvol=con.sum_cell_volumes(); + printf("Exact frustum volume : %g\n" + "Voronoi cell volume : %g\n" + "Difference : %g\n",evol,vvol,vvol-evol); +} diff --git a/contrib/voro++/examples/walls/frustum.pov b/contrib/voro++/examples/walls/frustum.pov new file mode 100644 index 0000000000000000000000000000000000000000..b4b7a2b6d8fed75d4368389a65f698789dc3279f --- /dev/null +++ b/contrib/voro++/examples/walls/frustum.pov @@ -0,0 +1,35 @@ +#version 3.6; + +// Right-handed coordinate system in which the z-axis points upwards +camera { + location <20,-50,30> + sky z + right -0.3*x*image_width/image_height + up 0.3*z + look_at <0,0,3> +} + +// White background +background{rgb 1} + +// Two lights with slightly different colors +light_source{<-8,-20,30> color rgb <0.77,0.75,0.75>} +light_source{<20,-15,5> color rgb <0.38,0.40,0.40>} + +// Radius of the Voronoi cell network, and the particle radius +#declare r=0.025; +#declare s=0.1; + +// Particles +union{ +#include "frustum_p.pov" + scale 10 + pigment{rgb <0.4,0.85,0.95>} finish{reflection 0.1 specular 0.3 ambient 0.42 metallic} +} + +// Voronoi cells +union{ +#include "frustum_v.pov" + scale 10 + pigment{rgb <0.5,0.5,0.51>} finish{specular 0.3 ambient 0.42 reflection 0.4 metallic} +} diff --git a/contrib/voro++/examples/walls/pack_cylinder b/contrib/voro++/examples/walls/pack_cylinder new file mode 100644 index 0000000000000000000000000000000000000000..03ca8aefe2c810455002918d47e977109f3a442e --- /dev/null +++ b/contrib/voro++/examples/walls/pack_cylinder @@ -0,0 +1,2300 @@ +27 -4.82756807832 2.6359046352 1.36596377715 +8 -2.4000578652 1.3234302624 0.49927231629 +7 1.5086870196 -3.2432993736 0.499689806 +6 -1.5135912696 -4.4558817888 0.4995967223 +5 5.044296732 -2.1923010072 0.49923775718 +1 -0.5210734944 -4.5739418232 0.49954443708 +3 -4.2865799892 -3.4461795972 0.49977831224 +2 -0.533211255599999 5.47425601788 0.49973963199 +30 -4.5685881228 3.0624931488 0.49960011401 +11 3.5600928072 -4.1927254572 0.49977450203 +14 1.431874878 4.30573422 0.49942347601 +15 -2.377025352 -4.9599437592 0.49996009035 +16 -1.1346964632 -5.3816793432 0.4999606871 +12 2.6972184288 -3.6879129636 0.49897738198 +13 -5.49711132096 -0.1748429076 0.4995971284 +10 5.4003534468 -1.0368854544 0.49997381994 +17 2.3065028112 2.796064434 0.49997891417 +18 -4.5818936436 0.3106536048 0.49865922371 +19 -3.566639658 1.2211741248 0.49981849568 +40 3.3543153564 -1.4810292192 0.49942306619 +20 -3.6969162192 -0.154071994799999 0.49897073868 +24 0.4664313852 5.48039771076 0.49947573922 +31 0.1718622348 -4.5174163908 1.2177012691 +22 -4.0477431864 2.2014673788 0.49935606558 +23 2.9198698296 -2.381634162 0.49984508221 +21 -2.4495878352 3.8727044412 0.49956240902 +28 4.4584696272 -1.3819037604 0.4991401605 +35 4.086949974 3.6813563748 0.49981000664 +36 5.4709065324 0.5634425736 0.4996995369 +34 3.1501522728 3.3326422824 0.49936706035 +33 -4.4409467472 -1.6968773904 0.49985364813 +29 -3.0248734668 -1.9645869336 0.4997169434 +32 -1.51526622 5.28821715288 0.49974111968 +39 1.4507837688 5.305433001 0.49947581021 +25 4.5595061676 -3.0761306052 0.49976594231 +43 -2.4459917916 2.8728600036 0.49969120596 +41 -3.2866393056 -3.4495218012 0.49946366875 +44 -3.6042616548 -1.1495549532 0.49945708125 +42 2.7751255716 4.6230224892 1.36099863704 +37 0.447696708 4.4806850664 0.49940851944 +9 -0.5424095028 4.3425877224 0.49926750912 +49 0.8559951816 -5.4331006164 0.49954581534 +53 4.4876725908 0.933718145999999 0.4999590472 +45 1.82545941 -5.18861712 0.49955298471 +50 4.6858566612 2.88066954 0.49981951279 +62 5.2792122504 1.544618088 0.49950952395 +47 -1.7684627088 -5.207931894 1.25369791017 +46 -4.84010848188 -2.6135531448 0.49939133862 +52 1.0271822136 -1.563843318 0.49951012938 +54 2.695085616 -4.6949383824 0.49982101288 +51 4.3593919944 1.9360309128 0.49929595441 +59 -0.1950969396 -2.6245866528 0.49969461503 +57 -1.5407953248 4.289523528 0.49968389027 +38 5.49557724 -0.237633804 1.09707805012 +60 2.3872730904 4.9551357822 0.4998092676 +58 2.3684334096 3.9556374312 0.49902204709 +63 -0.602786716800001 -5.1479641632 1.31422721654 +55 -4.5625757352 1.3105017888 0.49984441354 +56 3.6523409868 0.384218219999999 0.49972374263 +61 4.098634566 -3.669256092 1.15970956786 +68 0.862766922 -4.4331339744 0.49987038751 +64 -5.437868595 0.8270015568 0.49964187473 +4 2.2926488064 -4.999477056 1.36302338065 +71 -2.788245306 -0.571576632000001 0.49985306006 +69 2.2967880456 -2.9479757076 1.03904322354 +65 -2.4468731016 4.92590615124 0.49948549988 +67 -3.298127562 4.4015486208 0.49970708509 +72 -1.0056730752 4.83882709692 1.2332740726 +66 1.440160578 3.3058394652 0.49988872122 +70 -5.34931126176 -1.2790430904 0.49977866967 +78 -0.397436432399999 -0.7296489552 0.49965853041 +74 -3.2358617592 -4.4479638108 0.49897979781 +76 -0.53480838 3.342755196 0.49909382139 +79 -1.24224639 -0.194837272799999 0.49990716002 +26 0.00459517800000064 -1.6450517712 0.49904925362 +75 -5.04754060068 2.1849766164 0.49963143269 +77 0.502700216400001 -3.4967203788 0.49957286935 +80 -5.45195624064 -0.7306245972 1.32932876734 +73 1.3461158376 -5.3329439964 1.36498047668 +48 3.247140606 4.4394042204 0.49914342139 +90 -0.00115514520000026 -3.5432784912 1.3618421272 +89 -0.141563204400001 -5.4986024532 0.49946617417 +85 -1.9871167932 5.12848792728 1.36679907959 +82 -3.4434939444 3.001800936 0.49935790667 +86 -3.7938110028 -3.9823203984 1.18476002368 +84 -5.49027274164 0.3271287204 1.36431641917 +88 4.7031910944 -0.118489278 0.499210794 +81 -4.5415567272 -0.6895133916 0.49967516718 +83 -2.9117331312 0.464714562 0.49962217268 +87 -4.5165308328 -2.033675808 2.01554341264 +97 3.160815924 -4.5010972656 1.36316692026 +98 3.420724812 2.3705728788 0.49927456565 +95 3.7827259008 1.9221847224 1.31538491867 +91 3.9814258164 -2.2603474992 0.49890585413 +93 2.433031926 -1.0811594148 0.49973107196 +99 3.546777 -3.16065042 0.49937608941 +92 3.827386668 -0.6004387956 0.49959285505 +94 -4.6006070772 0.8091428136 1.36409582162 +96 1.5081569664 2.1941461656 0.49960771242 +104 -5.12792975424 -1.9905007812 1.22593051267 +105 5.2536543864 -1.6276265352 1.2971535003 +107 -3.8436063444 -2.5384589436 0.49926873889 +103 -3.3612479772 -2.8686439152 1.30941990456 +108 4.8227682372 -2.6445842328 1.3624791245 +106 -1.4402386044 2.2958820912 0.49839057492 +101 4.8027084144 0.448941183600001 1.31594505519 +100 0.0832429727999999 1.8653360028 1.20282985889 +102 -2.8196694024 -4.722307206 1.3650639386 +111 -0.0336743843999994 5.50034896428 1.36516501503 +115 -2.4289625928 -2.93540721 0.49951251824 +109 -1.5375191244 3.2903701596 0.49947813087 +110 1.7748553764 -1.3510269684 1.20245800118 +113 -0.5062943988 -3.5745193608 0.49960521816 +114 0.9107915016 0.5191577748 0.49969907159 +117 3.903442698 0.9275476824 1.31150913344 +112 -2.3723475504 -3.9437455176 0.49943089276 +116 -0.9640980384 -4.0676030712 1.23937176888 +125 5.0276712984 2.2305449436 1.18211679163 +124 4.5660467652 1.7053890612 1.89686105964 +123 -0.872995056 -3.05693658 1.27224623813 +119 0.358410514800001 -5.4885662976 1.36496452191 +121 1.5125843016 -0.689559832800001 0.49993109636 +118 -5.28652871556 1.5186476076 1.20532571911 +122 1.048914054 2.0564809464 1.37672842981 +120 3.5312505984 1.3767645792 0.49932782582 +126 -4.3558708512 -2.7778018116 1.35872844938 +130 -0.872997444 0.7791336948 1.17351350609 +128 2.8107586128 -0.1554327816 0.49968638794 +133 -4.6929062544 -2.8691168388 2.53529152622 +127 -1.4992386588 -3.4560395112 0.49974585121 +131 0.697119279600001 1.4960777856 0.49997381994 +129 -3.055177572 2.0803141164 0.49960738785 +135 0.455587444799999 3.4807688424 0.49992904726 +132 -5.49566497992 -0.2308563756 2.19414111608 +134 2.6896432944 0.8374566204 0.49853372393 +137 -1.1877292944 -2.5058956296 0.49966055161 +139 -0.4387804356 2.347599666 0.49959802461 +143 -4.5488174196 -1.1881353036 1.36625492667 +140 1.8324896328 -4.1890699884 0.49947127181 +141 1.9266317904 5.15174784948 1.36510156051 +142 0.551348601600001 -0.4139517396 0.49953227888 +138 -4.3271050032 1.7706295512 1.35756165712 +144 1.8907375404 0.2361326424 0.49974568257 +136 1.902126312 4.1353882584 1.36468467344 +153 -0.0598663871999996 4.501244118 1.36022244509 +145 -1.4006105616 1.296082662 0.4996490906 +150 -4.3169057136 3.4087064124 1.74212007022 +151 2.806321836 2.4047528928 1.28751044934 +152 1.9833437976 -2.031119316 0.49978484642 +149 3.8266987896 -2.7299921844 1.36725943641 +148 0.8007283728 -2.5375973052 0.49952119948 +146 -3.9899923752 3.7856097816 0.87554314661 +147 2.9451378168 1.3763042148 1.30878411626 +155 -2.0251179648 -1.959903534 0.49928359781 +161 -3.8969797644 2.1252665868 2.21073580823 +158 -5.1267170916 1.9923659664 2.0708384462 +157 3.9273318372 2.937547962 1.14863016538 +160 0.96247338 5.41557453072 1.36482110103 +159 4.6240377504 -0.2246701092 2.09832625718 +156 1.768537956 1.228639272 0.49997381994 +154 -2.0012888244 4.0936608012 1.36540092875 +162 -1.99720002 3.0937508064 1.36525680913 +165 -3.0179912064 3.5186228568 1.2417681501 +166 0.551607378 2.4854378424 0.49995843464 +170 -2.8823071512 4.6828327152 1.36545201365 +164 -0.402103092 1.3473120336 0.49900208991 +168 -2.1616587228 2.0484558936 1.1442461026 +163 5.435289408 -0.8433013596 1.88980635926 +171 -0.9159294372 1.8288736128 1.20843842725 +169 1.7213414928 2.7932848488 1.31104420381 +167 -3.7166002392 -0.634411801200001 1.37478557735 +178 -0.3089733132 0.3030984816 0.4991428544 +176 -4.6119128292 -0.1903221552 1.36313818388 +177 4.6631031048 -0.766683754800001 1.25936314126 +173 -1.9445212416 0.470277048 0.75318836528 +174 -4.2061476408 -3.54472515 1.98274942993 +172 -3.6496356204 0.534825432 1.22198755571 +175 2.5773705144 1.8334495908 0.49938075212 +179 0.416929973999999 -2.0780282424 1.30013824199 +180 -3.8515894284 -1.9119294024 1.27849508607 +184 3.1429947804 -3.4594413096 1.36358969795 +183 -1.0339594368 -1.51752147 0.49970668612 +188 -3.8000623524 2.6425129356 1.36123336067 +181 2.1708131832 -0.432935113200001 1.21599851257 +189 3.9494509776 -0.0710126124000006 1.33878125045 +186 -2.5226460264 -2.3250859812 1.28589564415 +185 -1.2167373696 -5.3639376492 2.07317359932 +182 2.2984654368 -3.9948973824 1.36291894537 +187 4.6736475612 2.8995492696 1.83535760586 +191 -1.010847276 2.8392419844 1.21957180476 +197 -2.7369681132 0.9429092916 1.3602446817 +190 5.351976558 1.2713695236 1.45810141202 +193 0.9412388064 3.4159357536 1.37160729491 +192 -0.6453649248 -0.1876316532 1.30230127908 +198 -1.8718401696 -0.9717365196 0.49991744954 +195 3.4873520712 3.8628563124 1.27915891356 +196 -4.6078308108 -0.689468342400001 2.23085254275 +194 4.0425999732 -2.2790970156 2.23266866876 +207 2.7037052532 -1.7204988888 1.21910154158 +203 -1.0158183432 3.8390841984 1.22154449131 +201 3.9274563816 -1.6628025144 1.29832836093 +202 1.3157544276 0.0782366652000004 1.30215768832 +200 -1.955005674 -4.2201106452 1.36495530623 +206 1.5289789068 -0.6524938572 1.95061325358 +205 3.7446103488 -4.0283973168 2.02316213694 +199 -2.8351577772 2.6118944556 1.62134719068 +204 3.1100421468 -0.8070722196 1.19660183427 +209 3.057941316 0.379956565200001 1.30708885336 +210 -4.4376700104 1.284977994 2.22735015531 +216 2.4731611764 3.8809714296 2.14480749226 +213 0.3454701948 2.667260838 1.73907596694 +212 0.942378831600001 4.4159014836 1.36589443387 +214 -2.8515921372 -0.0532938180000002 1.35255688909 +215 2.7355803732 0.846698122799999 2.13011203154 +208 -0.228724741200001 -5.4952505316 2.17412607458 +211 1.3575650772 -4.333273902 1.3668409888 +220 5.4938874228 0.2612049552 2.0137384364 +221 -2.2385601408 -5.023980006 2.1200146762 +217 -3.02440599 -1.350086298 1.288265574 +219 0.857345478 -0.9609619512 1.27829017235 +225 -1.7519513424 1.1818536372 1.4287711086 +222 1.1749504452 1.0684628424 1.29207044146 +218 -0.1196082228 -1.1548809912 1.36091898192 +223 1.4593594716 -2.4421987776 1.24560109302 +224 1.0118831868 -3.3952775328 1.35399504884 +226 0.3436915008 -0.116950758 1.4313733912 +233 2.008965126 1.7834547972 1.32016668727 +231 -0.7339399848 4.2911698596 2.06761656009 +227 -0.0551330172000002 4.4463328152 2.7853405977 +228 -4.6554485628 0.3093350568 2.22774097882 +230 -0.0550007399999997 3.5017055124 1.36136731756 +229 -1.2697299456 5.35190032116 2.04967810939 +232 -0.47031081 -4.4863846728 2.05220208599 +234 0.2068478196 0.8753660796 1.13611256967 +236 -0.5894948196 -2.0520951096 1.21834833179 +239 2.538833652 3.3682971396 1.28930115287 +240 0.855588987600001 -5.4333798876 2.23040563807 +243 -0.890131011599999 -3.581541768 2.12307506905 +238 2.909652186 -2.5573974336 1.72522594907 +235 -2.8431379236 -3.7226819532 1.35295873465 +241 3.2864796264 3.1037571948 1.89759522799 +242 -2.0335882296 -1.4565340692 1.3626488743 +237 -5.31160311048 -1.42767228 2.03170450996 +250 -1.9784100996 -3.2206140936 1.34504265835 +251 3.7134363384 -0.7880345688 1.99377487536 +252 2.73438735 -4.772814852 2.23077303922 +248 -0.2706715368 0.4956799584 1.9279484877 +249 3.9042288216 2.3842543032 2.21321449662 +245 -0.149934394800001 -2.6863909188 1.85491994754 +244 -3.417664638 3.2345041464 2.14314502054 +246 -1.062272922 -2.603777562 2.25534941607 +247 -1.5317839056 -2.3194336032 1.41968695509 +256 -3.8130706068 -1.3273389696 2.08875130671 +261 2.3526627456 2.805436206 2.09399202659 +260 5.0396633196 -2.2051101216 2.23360357296 +255 2.4197919132 -1.1067318396 1.95567464404 +253 -2.6316159852 4.83012934872 2.32178965209 +258 -1.9039853364 -0.368200935599999 1.29653987049 +257 2.075338176 -2.04498441 1.92557871223 +254 -3.4372393224 1.0210240656 2.06953806843 +259 1.3756012068 5.32538993604 2.2707710056 +263 5.3267556588 1.3699455516 2.45233707095 +264 -3.3285748452 1.7614452216 1.4066580398 +265 1.5980992704 4.3508560008 2.29194342807 +270 4.4930702316 -0.8287895316 2.88418246772 +262 4.4177785272 -3.2769427248 2.02220902613 +266 -5.4026830776 1.0300929312 2.06999499603 +268 -4.7000576736 -0.1856543268 3.09456191366 +267 -3.4177610844 -4.309167132 2.05177734972 +269 1.8251303004 -5.1887924988 2.23033614661 +271 3.4846217712 -3.1025679384 2.33463088222 +279 3.6351997476 0.3925418868 2.16720973309 +277 0.83908206 -2.6529511476 2.00088601868 +275 -4.0959592716 -3.6717435444 3.8118285844 +274 -1.57273014 2.3565288396 1.89076131271 +273 0.6712923096 -4.46205687 2.0818142535 +272 3.3511631736 4.361357274 2.13515955384 +276 -2.442331584 -4.0278065412 2.21639424629 +278 -1.4540670048 -4.4025021492 2.2107756702 +284 -1.701986862 4.471045632 2.24143583208 +288 4.5618933912 0.763986864 2.23370542656 +287 2.1346131144 0.791440752 1.32774113272 +282 4.0884180552 3.6794034348 2.05661075936 +286 -3.7695143388 -2.6721992736 2.20035734086 +285 1.842167862 -4.189240098 2.23110114198 +281 -2.7606289392 -3.049342614 2.08725776174 +283 0.841347582 0.520981020000001 2.06271740038 +280 -3.0309122412 -0.692990071200001 2.09952355437 +291 -5.4202375224 -0.9358993092 2.89912558031 +294 -3.0126152208 2.4057005232 2.58344262621 +290 -3.9324084144 -1.9775794284 2.90058427322 +297 -3.8789408316 -3.8999365584 2.85778498719 +292 1.0673956488 -3.5664003036 2.33752619449 +296 -2.1073301364 -2.3076892296 2.23727002604 +293 0.408518988 -1.1009302152 2.20767916297 +289 -0.361965094799999 -1.7345800176 2.13870472345 +295 1.9138705704 -3.2434883544 1.91423834958 +298 -0.8821214292 1.2778657704 2.0399488806 +300 -3.6286477704 4.1335744812 1.74012226716 +304 -3.0573086616 -1.9849902012 2.05924001692 +301 4.9938736068 2.3050632588 2.57283223761 +299 1.5249551112 3.3596733396 2.18156816956 +302 2.3946682224 4.95154580544 2.22528432275 +305 1.9273434432 5.15150907156 3.08622096345 +303 -4.719545772 2.8244606268 2.44624179856 +306 -1.1145822024 -1.0657626564 1.38800616874 +309 -5.11916361924 -2.0111100996 2.82009857456 +313 4.5247555296 -1.3698546192 2.0443769609 +310 0.469655009999999 3.9268919352 2.09877983554 +311 -1.5588018456 -0.6610335876 2.1881697572 +312 -2.2706193216 0.379240032 2.04192532559 +315 -0.563590356 -0.7546083624 2.16229150466 +308 1.9192050408 0.2698368924 2.15202616559 +307 5.4859615128 -0.396388039200001 2.78255972472 +314 -2.6346565872 3.8549750628 2.10167049006 +321 -5.28684590328 1.5169619916 2.93561922082 +318 -1.9610308836 -4.2617678184 3.06094724563 +323 -1.2844219176 0.2636802552 1.92472373936 +319 0.5349592956 1.4707702944 2.00296748702 +320 -0.580296174 2.4022866192 2.00874916341 +317 1.1363387904 -1.70519568 1.88536963585 +322 0.2404404576 -0.156324055199999 2.48694495325 +316 1.0834099692 1.1231302776 2.87614050631 +324 -1.8001799388 1.1975419752 2.42728709129 +331 -4.2599321772 1.7146014984 3.1120145553 +328 -0.2035883616 1.7161472388 2.63041933274 +333 -4.467269046 -1.157885238 3.1029476164 +326 1.547912652 2.2272211608 2.22613661319 +325 2.7513986544 -3.773660766 2.22724611993 +330 1.7168032416 1.2483172668 2.11268091041 +332 -1.8136099236 -3.2589951312 2.33009811244 +327 4.6915947636 -2.8703780664 2.8937799183 +329 -1.3579526904 -1.6501963008 2.16186319254 +342 1.529480604 -2.4000431388 2.68398565812 +337 -5.47924018452 0.477430464 2.89985355114 +334 -1.4349020772 3.5226523992 2.07199888253 +338 -0.3180931632 5.49085150752 2.32339775849 +336 3.26436687 -1.6795567536 2.04607664564 +335 2.2612405392 3.3212833704 2.94557207989 +340 2.8405641552 -0.208939669199999 2.0850166248 +341 0.0770345472000002 -3.7027078872 2.34568226938 +339 -2.9469292344 -3.5471037444 2.93328036351 +347 5.470444284 0.570734134799999 3.03569257669 +344 -2.5365148044 1.73422788 2.01616892289 +348 -1.3771354224 2.9230015812 2.86944645528 +350 5.3239434168 -1.3819464528 2.72422991361 +349 -0.4399231044 3.3579436236 2.27277829838 +346 -3.4855023924 -0.426296986800001 2.94905207603 +343 2.2478880396 2.2904125884 2.94452601589 +351 1.720606968 -1.419310062 2.6448338448 +345 2.59799016 -1.88445054 2.76233631269 +354 4.5082232568 3.1506055116 2.79399367048 +352 1.3456684248 -5.3325749184 3.09578224354 +360 -3.9551690424 0.6639556104 2.84652229256 +356 0.144095808 0.7921371432 2.78784874446 +355 1.2082654368 -0.1218089376 2.73497589063 +353 0.4766566428 4.92670411992 2.08847979724 +359 -2.291587764 -1.3284656796 2.31966102748 +357 -2.2277362008 2.9707846788 2.33022980416 +358 3.5748151272 1.3901770224 2.13510112938 +364 -0.707228135999999 0.0644748503999999 2.7173836098 +369 2.4541719372 -4.0177001352 3.1497738666 +361 3.424961574 -0.4076072328 2.8716068149 +362 -4.1536882776 3.6056150808 2.70867196283 +363 -4.80782818992 -2.6711034948 3.5085301675 +367 3.5120096328 3.7064669592 2.87315565116 +366 4.2570666192 0.1405244676 2.95364581971 +365 0.4564060908 -1.996156482 2.64992254719 +368 4.5138869928 -1.886629404 3.0220635386 +375 -3.6941447796 0.0551835503999998 2.09801131423 +378 -0.2089497144 -1.1918788572 2.98865209262 +374 -1.6708368324 0.298995117600001 2.84595727447 +373 3.3611053332 -4.3535025612 2.88756220118 +371 0.5115784656 3.082756866 2.63281312763 +376 -0.708132132 -5.1295842672 2.97161552213 +370 -1.594846458 -1.2073333236 3.02633215738 +377 2.1401401848 -0.5155896852 2.72916257874 +372 2.548431708 -2.87004363 2.60292344161 +387 -0.96515079 4.85354259348 2.86113458617 +383 -3.4052538156 4.3191571992 2.69620409453 +385 2.3084828808 1.2912922296 2.91725368281 +381 0.3355637676 -5.4901181172 3.08218871192 +379 -1.1704614252 1.9572914352 2.71381294765 +382 3.631775334 0.9219069372 3.01605966537 +384 2.2890694596 -5.001878664 3.09596916207 +386 -2.0199178212 3.775569492 2.88621973502 +380 3.6586002516 -1.3789826676 2.91451040353 +388 -3.9098706756 -2.9448159684 3.1519543074 +390 -0.347032234799999 5.48950829604 3.3225652781 +392 -3.0368194008 -2.5307191308 2.89632070992 +393 4.0943600124 -3.6723699444 2.88963072175 +394 -2.9931233676 0.4165825032 2.73210726812 +391 -1.9147619784 5.15652895416 2.93740950089 +389 -2.6622755208 -0.923480602800001 3.5901525754 +395 -5.49354789672 -0.2726597148 3.6963309854 +396 -2.863522602 -4.6963537956 2.82848596463 +397 -0.2263844388 -2.8839316092 2.83192255953 +398 -0.814798506 1.017054948 3.00140015411 +405 -1.0239347268 3.8569724472 2.92007685653 +399 2.5987774608 1.8369786612 2.12562959646 +401 -2.151933378 2.0061584928 2.8988580221 +402 0.752140129199999 -2.9221855968 3.03433372021 +404 1.1640413592 -4.3607475612 2.9455884947 +403 3.1034798424 2.7950040792 2.83036014279 +400 5.2483774092 1.6460082468 3.4096754517 +408 -2.3400325104 -0.440351228399999 2.77644316308 +407 -3.1485277056 -1.3605749604 2.83446549914 +413 4.164449286 3.5929220628 3.6221805943 +411 4.9142379276 -0.2612438892 3.5913098023 +409 2.7689484372 4.3828558356 2.95702132353 +412 -3.2995240056 1.498475034 2.93703171939 +406 -2.3474319888 -1.8582903108 3.1653520765 +410 -0.734077224 -2.0422176708 3.01438394611 +414 3.1661207844 1.8041693016 2.94822527968 +420 -1.7017769736 -5.2304161704 2.93723427587 +418 -4.7095583676 0.8925373836 3.4611242793 +417 -1.5905436588 4.4158564524 3.5251982351 +422 0.0943170683999996 -4.5383094696 2.89441426448 +416 -0.4218662724 2.6392609332 2.96724255983 +423 1.7553015228 -3.3149197428 3.01813388715 +421 -2.424662994 1.0926152988 3.2008971012 +415 3.9362840376 2.3844769164 3.2121713145 +419 3.4313009328 -2.3745506028 3.01790900757 +425 1.3978021872 2.822130396 3.01563535225 +427 -0.0926380895999994 -0.297003651600001 3.4188743483 +424 -5.26223888424 -1.6005494604 3.7199373955 +431 0.917291629199999 4.5381344484 2.99946103436 +426 -4.94386940184 2.4107782392 3.328222 +429 2.7032312388 0.279557846399999 2.95217546739 +430 1.4457833676 1.8978980844 3.394023468 +428 4.4170347972 1.5227327568 2.86828052079 +432 -3.0767690448 2.2417755864 3.5674623889 +440 2.7782207904 -1.0498581924 3.2820342134 +435 -3.0549023688 3.4516792704 3.04933126322 +434 -3.7889137068 3.9870021828 3.5573525356 +437 1.5070787496 0.2211633312 4.1710997829 +439 -0.124749721200001 3.558509676 3.2394751287 +438 -2.7535669248 4.761376626 3.3115900536 +441 -2.2661744964 2.90318292 3.3268325986 +433 0.9075574236 -1.0141853736 3.06966678985 +436 4.9711268268 -1.2577377624 3.6505852836 +442 -2.1875855544 -2.9568296964 3.2066134268 +446 0.1478309052 -2.2993124592 3.5509753613 +443 -0.8192776404 -4.1360359416 2.95206704427 +449 -4.2990779688 -1.8485832696 3.8218945138 +447 3.19630365 -3.3563940408 3.2573371799 +445 4.866669786 2.563531998 3.5302232142 +448 -0.6124008444 1.8384118572 3.5342801656 +444 -1.5154815924 3.4371023244 3.7159132173 +450 0.6979675776 0.3157263996 3.4747979794 +457 -0.333232564799999 -5.4906028524 3.8249722155 +451 -2.1318107388 -0.036793276800001 3.6673707234 +453 2.5084591932 -2.7107798616 3.5885577804 +459 -1.6419848856 -3.408087042 3.9120727481 +452 0.5683385724 5.47138440084 2.92141914847 +454 -3.6428770728 -1.1054086572 3.6659280981 +458 3.7423493268 -4.030680594 3.7542823234 +456 -1.5353715816 -2.2867184712 3.5602081471 +455 -0.2135797932 0.6514393836 3.7107409076 +463 3.9853522416 -0.6087809892 3.7166656555 +462 1.3842769896 -5.3235122556 4.0944646519 +464 -1.2713420136 5.3512026126 3.677587877 +461 -3.3248448192 -2.0514159672 3.7251429062 +465 1.0695461952 -1.9295242572 3.4366898158 +468 4.3265160336 1.7042987988 3.8469344383 +466 -3.2251508868 -0.380379852000001 4.2129878416 +467 -4.585726278 -0.6644824884 3.9645413765 +460 0.7071566088 2.109739002 2.75416785764 +471 3.4467213456 4.2863960412 3.6849881784 +474 -3.8552264868 2.628178182 3.07308894774 +469 5.4567317772 -0.690051951600001 4.3147191125 +475 -3.3814022688 -4.3392389472 3.6055760643 +470 -1.8858731184 -1.437394968 3.9546935693 +477 0.9089210712 3.6142715796 3.3805578275 +472 -5.2421242266 1.6647929772 3.9234640918 +473 -1.144886454 -3.1980188256 3.07069085904 +476 0.332242108799999 -1.3530683136 3.8139287321 +486 -1.3208388936 -5.3391739788 3.8551703168 +479 4.66570191 0.801909852 3.5821948661 +481 0.328788915600001 1.5098906304 3.4589348764 +482 1.7793682596 0.513103308 3.2547240411 +485 -1.5442500648 1.4771566584 3.5068089638 +484 1.4766213816 -2.7646903428 3.8054953898 +483 2.9607455592 3.4130822436 3.6540886711 +478 -0.654942792 -3.5627488812 3.9418373578 +480 -3.9346796472 0.0988683168 3.6711506309 +487 1.1766310836 5.37276156384 3.7083644197 +490 -3.767981232 1.0986372888 3.7266935479 +492 2.6240845452 4.83379671528 3.8374518514 +489 0.149761229999999 -3.6527826684 3.3553469256 +491 -0.8811510504 -1.3429252332 3.7133830066 +494 2.9508394488 -4.6414893636 3.7531329054 +493 5.4832559016 0.43583973 4.0264132256 +495 0.397739698800001 2.6754799128 3.538898992 +488 1.1229719436 1.1072210352 3.9135534073 +502 4.4100981036 -3.2865825276 3.7581621067 +498 -1.1655754452 -0.41746146 3.4638780279 +503 1.7542235064 -4.462672266 3.745981999 +496 4.0030056492 -1.601610534 3.8326508132 +499 -1.38397155 2.438564754 3.7435174556 +501 3.3551269236 1.468191474 3.8705637109 +504 -2.3566699224 -4.9696493388 3.6458985362 +497 -2.4160893576 -2.3024151072 4.0581440475 +500 -2.455438608 3.9264193944 3.7735962906 +512 2.0505046416 -1.8224117004 3.5962227474 +506 3.1016753268 2.428931592 3.7604097989 +511 -1.2882709476 0.5359475028 3.7384145332 +507 1.8279803412 4.1700258504 3.2478289715 +509 -4.4480417628 3.236532948 3.5993410312 +513 2.5050539064 -0.2320069116 3.7880822248 +510 0.650872311600001 -4.7699317368 3.6999851197 +505 1.096935336 -3.6805853748 3.6754151397 +508 -2.9945781708 0.4647911124 3.7309189874 +520 3.3988905372 0.1991599392 3.6654716975 +515 -0.6933759828 -2.5666539264 4.019924814 +518 -3.0576942432 -3.0137367264 3.7716406153 +516 -3.9960659964 2.1807918408 3.9561189741 +517 0.308708171999999 4.8528377856 3.7277301755 +521 -0.5493319356 2.960230452 3.9183050966 +522 -2.5238299596 -3.8591481648 3.7826453456 +519 2.6128008216 0.8021197368 3.7995368147 +514 -0.3098444988 -4.4913993432 3.8076840673 +524 1.2180269652 2.9370874176 4.0474420043 +530 3.0444424188 -3.4950807444 4.2355633591 +525 2.087690946 -3.5426975244 3.9489351209 +527 1.7593752348 -0.8661892368 3.5841242751 +531 -0.0271456548 4.6760972556 4.6679632693 +523 -5.45548978812 0.703788019199999 4.0988935599 +526 1.16536848 4.3936266852 3.962479024 +528 -0.4839219792 -5.4787985976 4.8133746748 +529 -3.9491790912 -2.7348016152 4.1286254894 +532 -1.303395408 -0.765800111999999 4.4124070379 +538 -3.296680014 -3.7473123876 4.4075830442 +540 -3.0249547644 -1.3799334192 4.4025574544 +537 -4.83008381316 2.6308276212 4.296726232 +535 4.93826949 -2.4215055396 3.7526461713 +533 -1.298344272 -4.3408807872 3.805464954 +539 1.868460402 5.16807053904 4.4000952825 +536 -5.0053321878 -2.2797054744 4.4071174676 +534 3.7479203592 -2.5616458116 3.9477968319 +548 3.0411163644 -1.8703548948 3.7878688921 +545 3.3192273456 -1.6916387016 4.7699448435 +546 -2.227957026 1.9860918888 4.0290087874 +543 3.1539837168 -0.89086794 4.1944821839 +544 -2.9088404172 -4.668425772 4.4227360457 +541 4.6846856616 -2.8840372212 4.6311747571 +547 1.8802902756 3.7012300548 4.1289217595 +542 0.4581105144 -5.4817486944 4.4345798623 +549 1.2734970456 -1.4090100624 4.2689910497 +554 2.1768413244 2.8057540764 3.7981097204 +557 3.3492087264 -4.3630036392 4.6270242198 +551 -3.502554696 3.0877185804 3.8878714325 +552 -2.1523458756 5.06188849008 4.0511824953 +553 2.2811134236 -5.0047626876 4.4005336783 +556 -0.5064795948 5.47677662748 4.3091261421 +550 -0.1484670732 2.157857112 4.3594495829 +555 4.4944861272 3.1714292532 4.4664778765 +558 -0.686183478 0.162891714 4.4436089006 +563 0.187826279999999 1.2189309108 4.4291660037 +566 -0.8029224132 1.213550868 4.2905107692 +564 3.9462496956 0.771328474800001 4.2759440242 +561 -4.6117195644 0.253796544 4.3904103896 +560 -0.5652188004 4.3744842744 3.6423526725 +559 -1.4194987068 5.31402083976 4.6827119781 +562 5.2196309664 -1.735239972 4.4930597255 +565 -1.9929757728 -5.1265753656 4.5639615522 +567 4.5112940196 -0.0288111636000004 4.4761510235 +574 -2.4156718716 -3.1901751108 4.5177075465 +575 -1.5929318148 -2.6219192568 4.52724155 +572 -2.6596444728 0.304812624 4.6712468916 +570 -3.1810414056 4.4871121152 4.172721148 +573 0.410368270799999 -4.0209705048 4.3172045468 +569 0.8923452696 -0.5378802156 3.9579104362 +568 -5.4209033412 -0.9315344496 4.4450489033 +571 -0.3122673828 -0.7497138384 4.2826388276 +576 2.3878359732 -1.483585332 4.4736981454 +577 0.268329312 3.9198180096 4.0847640699 +580 0.776715385199999 -2.2748348208 4.3278668945 +585 -2.1081908556 0.9452630376 4.1377219992 +581 -1.9370274552 -4.1286434148 4.5448959353 +582 2.7809063532 4.0052351472 4.4395064567 +578 -1.6773443112 0.1475016096 4.5731928252 +579 5.328936798 1.3636182888 4.3647868095 +583 -4.4790157344 1.2446549304 4.4144820818 +584 -2.3073429432 3.0940836564 4.3072193693 +588 3.86699529 2.3965112748 4.4022591166 +594 1.2688273608 -4.43498967 4.6196172937 +592 3.8473790292 3.9308267052 4.5283537277 +587 2.875165236 -2.5469665908 4.5038816271 +593 1.18805235 -3.3581997504 4.6175640707 +590 3.0538079388 0.9677082132 4.6818834411 +589 0.8240069916 2.0263384944 4.1687375953 +586 -2.9907859092 1.3922906976 4.2816516791 +591 -1.3644024384 2.9456534256 4.6048564608 +597 3.4127977836 4.3137483732 5.3430699202 +596 -0.1303669284 -1.89753732 4.5135294378 +595 -1.186029252 -3.5178583812 4.7943400207 +601 -4.2553098432 -3.4847605332 4.7807737201 +600 -2.9769313428 2.3927222172 4.5512659517 +598 4.8785693016 2.2483781304 4.4785045652 +602 -4.5432741756 -1.3321815684 4.7074771372 +599 -1.4148591036 1.9375496544 4.6082018475 +603 -5.50007849076 -0.00258654719999996 4.8046405705 +606 0.168243540000001 -3.0582416352 4.2009128549 +605 2.6333820648 4.82905102896 4.9867400575 +607 4.6958787876 0.840732345599999 4.9337202057 +609 0.31250373 0.1485785748 4.3959488155 +610 -0.8266609392 -4.5517081896 4.6616376883 +611 -0.10474629 3.7541395836 5.0464155659 +612 -5.43383953212 -0.853707721200001 5.441729088 +608 2.3527118124 1.7675652588 3.7949586665 +604 0.4783206672 2.1292206744 5.1373654553 +616 -0.413756178 0.836166201599999 5.130126884 +620 -4.0795519452 3.6900474084 4.4665265527 +618 2.3993095812 -4.07111982 4.7385628863 +617 -1.7158481208 4.2877384524 4.5085245498 +619 1.0444845504 3.7051161624 4.6775222185 +614 3.9866045664 1.5452484684 4.9122944038 +621 2.894739984 1.952453856 4.6145827821 +615 -5.16190489716 1.8995425776 4.8920110604 +613 -1.1151386076 -1.7466979596 4.597478188 +623 0.633880395599999 -5.4634875504 5.4181736388 +622 -0.491709864 -1.2006668136 5.1568134014 +628 4.5130879008 -1.0280291772 4.5085014331 +626 0.4621773324 -1.1334994908 4.7844656682 +624 1.7572544304 2.1244250904 4.5142706726 +625 5.4995504316 0.0736310676 4.9583119229 +627 -0.8605349268 3.7834236408 4.3926863352 +629 -4.0242567948 -2.1545177256 4.9391947902 +630 3.1423595376 3.0640338732 4.5733946228 +632 -2.565612282 -4.8647308764 5.340442478 +638 1.0690206996 1.3653557868 4.8779676977 +637 -4.0430011584 -0.469649582400001 4.7812694287 +639 -2.077307646 -1.812900606 4.8612312658 +636 5.4153588012 -0.961292215199999 5.276308686 +633 -3.0984412068 3.6071203896 4.6400226066 +634 1.9539491832 1.1451234048 4.4683471393 +631 0.7103790312 3.9897187668 5.5758724957 +635 0.1353804888 -4.712615394 4.9840969045 +641 0.501711808800001 -2.8270570884 5.1143134926 +643 1.5566272932 -5.2756104036 5.0781231781 +647 3.4954744584 -0.0557463612000006 4.6264061945 +642 -0.255276199200001 -3.7938711204 5.0319238099 +640 -0.4868220708 -2.8237839756 4.9633386039 +646 4.2225507276 3.5255142204 5.36113473 +645 -2.6104104312 4.84163298768 4.9121683113 +648 4.0842051768 -3.6836520996 4.6275796065 +644 -5.1843618396 -1.8367362672 5.2855800885 +653 -0.0690039336000003 -0.295775665200001 5.2064698617 +654 -2.6830611312 -3.883869816 5.1861385737 +651 0.8734252032 -1.9104554868 5.2601524687 +656 -3.626206332 0.514751109600001 4.5258262698 +655 1.734322662 -2.227652046 4.6115826889 +657 3.5049120132 2.369011884 5.3331877247 +652 -3.8827828032 2.7571102776 4.7651342263 +649 1.8786950124 -0.626920719600001 4.5474122642 +650 -3.6264883572 -1.2754689312 5.201856544 +666 -2.2926306528 -0.6338802432 4.4722464402 +662 -1.0656812304 -0.2476510824 5.2721150184 +658 2.3770225848 0.2321387904 4.6642266657 +660 -2.9504271036 2.0053279224 5.4726372691 +665 -2.116448154 2.4801786492 5.0726731952 +663 3.7560336744 -0.871484367599999 5.141531536 +661 5.2132484604 1.7527839432 5.2798329241 +659 -0.4795464012 2.8028394564 5.0480976011 +664 1.2223722828 2.7886640112 5.0357724041 +669 0.5433136776 5.473875597 4.4754546023 +675 2.1660637464 2.9976665664 4.7793866778 +673 -1.346193444 -5.3328616848 5.2981677749 +674 5.4369216264 0.8338447956 5.6044034015 +671 -2.2606973472 1.4977639692 4.95669726 +667 3.2558082432 1.4347190748 5.5866657843 +668 -3.736172166 1.7703811416 4.8300642409 +672 -0.9296452476 4.5355583952 5.0740616325 +670 1.0134745572 -0.313834305599999 4.9388584061 +680 -3.3818106192 -2.9203561008 4.962696442 +678 -0.1174865988 5.49895356624 5.2294950466 +681 1.7101614324 -1.3663590648 5.1992671698 +684 0.974527381200001 4.6790703048 4.9016112985 +679 -2.0599908708 -0.2954740908 5.3838204494 +676 -3.3927340656 4.3291639524 5.2658198329 +683 -2.2222760976 3.676585428 5.1155126749 +677 0.299017636799999 -1.2042519 5.7684412469 +682 2.1294587568 -3.114421524 4.8505691165 +691 0.3365281188 3.0186093372 4.5122721429 +686 2.3796985836 -3.984064992 5.7345250862 +687 -2.982796596 -2.0403790392 5.2190179053 +689 4.7902812708 2.7032077872 5.3636043729 +692 -1.2336301884 -2.335869882 5.4152144315 +693 2.4752882772 -2.0648817612 5.282585225 +690 -2.6409963144 -1.1029800516 5.2831568309 +688 -0.604537456799999 1.8159021564 5.1804082733 +685 4.2757471596 -1.9761875628 4.7184127964 +699 4.4009100804 -3.2994479184 5.495863675 +694 -1.4690752572 -4.3459137828 5.4005150406 +701 3.2611001028 3.316810302 5.5367371936 +695 5.0199207804 -2.2493023044 5.326958563 +697 2.776224996 -0.590110800000001 5.0694647417 +700 -1.2473080188 3.623135628 5.3306676572 +696 1.5371701584 0.5171782212 5.1254355052 +702 -3.6525787344 -4.1121512208 5.2737054703 +698 -0.0781983539999995 -2.0922083592 5.5078173556 +705 -3.2298180024 -0.2170835844 5.3049810324 +707 0.395420270400001 3.0416458368 5.5373138587 +706 -1.2548277564 2.4617248992 5.5794934507 +709 2.4427444056 -4.9269136008 5.3840470625 +704 -1.0393007196 5.40108413376 5.6034481458 +711 -1.8983945628 -3.117468456 5.3702429051 +710 -4.2688796412 0.5192168016 5.2914272806 +703 3.7382906964 -2.7985250808 4.9396067182 +708 1.5181574592 -3.442561584 5.5689556889 +717 1.8511230612 4.206729132 4.9907302597 +712 -0.4925598612 3.3126556104 5.9081090592 +718 -0.6269267604 -0.6808334976 6.059265673 +720 -1.027097574 4.5062537016 6.0687443911 +716 0.70186809 -3.9419470824 5.2793458397 +714 3.7815908928 -2.037314502 5.5863124215 +715 3.7816358604 0.6402106176 5.2839078989 +713 -1.8049266048 4.7671269324 5.4981064692 +719 -4.97937099096 -2.3358124776 6.1274910527 +726 -3.1603210008 -4.50145806 6.057201135 +723 3.9103995528 -3.8676773184 6.1565077161 +728 -4.4544637212 1.4860060392 5.4643349824 +729 1.5566654004 4.3886547072 5.9287513361 +724 1.3763942112 -5.3253566748 6.0728540797 +727 -1.4773366176 -1.1572693812 5.31904944 +722 -1.4086660992 0.9830825472 5.0516024673 +721 -5.41686658716 0.9527667924 5.0872940445 +725 -0.8177289624 -1.6617007236 6.0252370567 +733 4.2898011996 1.9492881048 5.7886850715 +732 -0.1165438092 4.5469962048 5.6555419067 +736 -3.9889373688 -3.2070626412 5.7035149647 +734 0.549287830800001 0.599581764 5.2559244345 +735 1.4971461084 -4.4404238808 5.6238728709 +737 -3.1446978168 1.0600268544 5.2113144735 +731 2.2913285328 1.2452391744 5.4041378897 +738 4.6246514208 -0.000741661199999299 5.4691524909 +730 -1.720718628 1.5647761188 5.8022211068 +740 -3.9437736804 2.322419856 5.6631590748 +742 -4.7583464532 -2.7586689612 5.2490983492 +747 0.8251192416 5.43798427728 5.5559093823 +743 1.0974267468 0.0779238252000001 5.9087470609 +744 -0.1162795608 -3.1249759404 5.841598925 +745 2.8386207804 0.4180609344 5.5315831367 +741 -3.2769363804 3.0998231532 5.4830847682 +739 -4.4500961772 -1.354590516 5.7634277502 +746 0.170881902000001 1.3906870944 5.7361077695 +756 -4.7395053132 2.7909317208 5.2793350734 +749 -2.1664935672 -2.2375708752 5.7618053094 +755 1.7832284424 5.20326823284 5.3952245713 +748 1.9134690552 -0.329542395600001 5.5008595296 +753 3.049216038 -1.3430249088 5.6672623712 +750 4.793331864 -2.6975198688 6.1911066084 +752 3.70822647 -0.1752039864 5.8568586037 +751 -3.7000411452 -2.2660304448 5.8782574697 +754 3.271868478 -4.421252928 5.6220909878 +764 2.5127093868 2.3436021768 5.4515144674 +757 -1.3790292768 0.460732128 5.903634606 +763 2.474074476 4.91266569936 6.0560460099 +762 -4.5762724764 -0.372796810800001 5.6215068424 +760 0.834464115599999 -2.8979952756 6.0539255758 +761 1.5925825404 1.954934886 5.4923224334 +758 0.402007026 -4.6458381276 5.9446476308 +765 1.6249581744 -2.4507420108 5.6376366632 +759 -4.1662302996 3.5905061208 5.4576670498 +769 2.533791636 3.9858496452 5.6870938555 +767 -4.5267487296 -3.1249311996 6.542480002 +772 1.1784295488 1.1046141864 5.8501108988 +771 -2.2769895096 0.6712344684 5.5189399479 +766 4.5371240712 -1.3894462068 5.4892540224 +768 3.1062733584 -3.515064186 5.2332857669 +773 2.4585635832 -2.9827771428 5.7851755987 +770 -0.596943662399999 -4.7573922924 5.6627877103 +774 -2.6302798152 1.3528983072 6.1596383689 +782 -2.8143713028 -3.0826599264 5.7699314262 +779 -3.6143014836 1.4429336292 6.0062386478 +777 5.271305622 1.5695286756 6.2611549121 +776 3.5651374332 -2.9547759408 5.9228315947 +778 1.695620826 3.4462398708 5.6206762098 +781 4.4936105064 0.9774347196 5.903150758 +780 -5.31783404328 -1.4053858044 6.267262653 +775 -0.7867341204 1.2610996464 5.9916850561 +783 -2.0249950188 -5.1139903272 6.1429506752 +786 -3.7241290644 -0.709957204799999 6.0207508855 +784 -2.1055088088 -3.8641172628 6.0020642777 +790 2.276799876 -5.00692785 6.3667314571 +788 1.9787499528 0.5336427912 6.033065434 +792 -0.2145599748 2.3524762356 5.9277445367 +791 3.1226417508 2.1816591504 6.2379741165 +787 -3.10247799 -1.4905954956 6.0806767933 +785 -3.2764416216 0.4831999188 6.0169475885 +789 -1.6740802068 -0.4087529916 6.2990797169 +796 2.1480381048 -1.2949745364 6.0972377373 +801 -5.49598948104 0.2160600192 5.7797917822 +795 4.68332787 -0.6914113668 6.1896584496 +799 -2.7149614716 -0.53364348 6.1015012324 +793 -4.6355820972 0.4932625908 6.2212035753 +800 2.4845850084 3.0849359724 6.1218047351 +798 -2.0768080632 -1.3031268048 6.1056210766 +794 -1.8852732888 -2.967169506 6.3849564098 +797 5.2874684004 0.5743879596 6.5578022542 +805 -2.3202608424 0.3372264792 6.459955832 +803 -5.374744869 1.1671285596 6.0631207803 +808 -0.8857314348 -2.6710338456 6.2906761191 +804 -5.0782521594 2.1127118388 5.93096743 +802 -2.3568157956 3.034415226 5.8691860017 +807 0.9705323364 -3.8922601104 6.2734039948 +810 0.1218689568 -1.4032223052 6.7320525505 +806 5.2976756676 -1.4783504268 6.1322753354 +809 1.1884188936 2.6909685144 6.0345296384 +818 1.0855917768 -1.8582617928 6.2359270284 +817 1.126947594 3.6321756804 6.4214815088 +819 -1.0354846404 -3.5191007856 5.7824771262 +811 -0.0931347780000005 -5.4997787424 6.1034837599 +814 1.2364576344 -0.9111184224 5.9528556 +813 -3.8766100884 -3.901811214 6.4132838781 +812 -0.396270958800001 0.2875035528 5.9648312255 +815 -2.1228299784 4.0007958348 6.0558276366 +816 3.1213680864 -4.5289257072 6.6045815859 +822 0.669233952000001 4.7310378324 6.2454409005 +827 1.6384548432 1.3348396356 6.7075048192 +823 2.1181148472 3.8881804524 6.5912531111 +825 2.6217053736 1.292804778 6.3467670076 +820 -2.6550343164 -4.81710828 6.8601930314 +821 3.9787974384 2.8585066176 6.0646286234 +826 -4.2004969404 -2.2009111572 6.7414857513 +824 -2.8780355028 -3.7182850764 6.6194926572 +828 3.5808224052 0.765698058 6.254817765 +832 -0.9797285868 0.1413291312 6.762627494 +830 4.3622063964 0.197767090799999 6.5145053354 +836 0.661449126000001 -5.460379674 6.7579894538 +834 1.8903543828 -4.1138442888 6.5965066191 +833 0.2882215596 -0.3585625464 6.3010944286 +835 2.9532977112 -2.2029021972 6.1677368399 +829 -3.6893351208 4.0799493876 6.1875384929 +831 -1.9771210248 5.13270127032 6.4126075914 +837 2.7413831232 -0.4775634696 6.062458828 +844 4.3814897124 -3.3246751224 6.8515119929 +841 -1.0737935592 -5.394918624 6.2674215931 +846 4.028909322 2.1847394292 6.8018148823 +840 3.8735072652 -1.2766026252 6.2285032042 +842 -5.48203329396 0.4498277964 6.7515817941 +845 3.99212451 -2.2168353096 6.5471901699 +839 -1.2444047292 -4.4154552096 6.3721852623 +838 -0.1111636524 5.49881013624 6.2292334371 +843 -5.12697644988 -1.9915049736 7.0543228434 +849 0.781322035200001 1.8486937464 6.3865393411 +850 0.0911992692000005 -2.3636907672 6.4556774693 +853 -3.539656716 -2.970454476 6.5694170521 +852 -1.1581615788 -1.1112342912 6.7889771592 +855 -5.138551734 -0.4381233924 6.4458132507 +848 -1.4365891116 3.2074438164 6.2200033452 +851 -2.751028074 4.7626934112 5.8987729225 +847 5.4972958032 -0.1731720984 5.9273321561 +854 -2.1552013836 2.2231327704 6.4164316429 +860 0.434683700400001 0.665865108 6.371501021 +857 2.9541974136 -3.5579073612 6.4355423245 +858 -1.1805544548 2.0198521224 6.5098846831 +863 -1.1402993484 -3.5071060248 6.7765360842 +859 2.0948119152 2.1437684712 6.3374588918 +856 -4.498987476 -1.2497143272 6.8191351899 +861 -4.6162761024 2.990142774 6.2513373299 +864 -1.5947285148 -2.0327139516 6.5902303374 +862 -1.478060574 1.0717358772 6.6886963535 +873 4.5050077296 1.3065514704 6.8473361131 +865 -0.1188619644 1.9064813784 6.8170073127 +868 3.830084856 3.9480599664 6.1771916787 +872 -4.0141709424 2.3044737192 6.660194194 +871 2.7564733404 0.343975914 6.6323545727 +869 1.2830150376 0.408697285200001 6.8333575497 +870 1.5963159972 -5.2633794948 7.0529035952 +866 -0.309015286799999 -4.0109666592 6.2622128026 +867 1.4889751152 5.29466951076 6.3465270924 +874 5.0678233272 -2.1383079192 6.9728162608 +882 0.160049305199999 3.88523748 6.404078053 +881 -2.7835796412 -2.3171085912 6.5442541816 +877 0.350578629599999 2.9124645456 6.5328201602 +878 -4.209906918 -0.236418717599999 6.7562053387 +880 0.7518172116 1.2052052976 7.1511949573 +876 1.8515593704 -0.3422486784 6.4982254064 +875 1.9958440896 -2.184697656 6.5272909971 +879 -0.3426246924 -0.575349087599999 7.0459339055 +884 -0.6706912872 -1.965987768 6.9662452497 +889 1.7644490832 2.9639368188 6.804254449 +887 -0.419060509199999 -4.8514085364 6.7918443864 +885 -4.1680312068 3.5886867876 6.9150753384 +890 -3.4319787132 -4.2984328284 7.2161435316 +883 2.97082941 -1.3346067912 6.663916364 +891 2.1959952288 5.04271031412 7.0072570376 +886 3.3890492016 1.435343976 6.9719917414 +888 -1.4259889044 4.5289972296 6.988073072 +898 4.5017838408 -1.3151219292 7.0049035455 +897 1.0068698244 -0.6639052836 6.9256987935 +899 -1.5814192356 2.6803758276 7.1442091476 +895 -3.2246807076 -0.0873546407999992 6.8362588738 +894 -3.22418289 1.7314626 6.8804870171 +893 0.502498782 -4.4875127604 6.9260781808 +896 -3.1107945048 2.539396062 6.3022440729 +892 -4.7288418132 -2.8089236436 7.4694425724 +900 -2.9494780536 4.642342722 6.8711958025 +909 4.4299087872 3.2600044308 6.8613989159 +901 -2.2754695236 1.5086893668 7.1045734993 +902 -2.6100557436 2.7344812656 7.1454716846 +903 -4.98389092368 2.3266500192 6.9028942759 +908 4.5580522008 0.5964766764 7.5494337603 +906 -1.9783601724 -4.0891725636 6.9677833705 +904 -3.5317579908 -1.0321496304 6.9473428199 +905 0.2712094584 -3.3531985368 6.7417320649 +907 1.3727540976 4.4747442252 6.9077518705 +912 -0.3939014508 0.946237596 6.8554349127 +913 -2.8595633304 -2.9869239252 7.3022384428 +910 3.4748765976 -2.932383156 7.016405057 +918 -0.8036552052 3.7902110148 6.7296497188 +916 -4.5039981588 1.4548037424 6.4620308542 +911 1.0000161 -2.602256064 6.9946273555 +915 5.462806758 -0.641449021200001 6.8136745275 +914 -4.6323915168 0.6929067468 7.2188692004 +917 2.6658563256 2.5783932492 7.0340526223 +926 -2.9490791256 3.5001965124 6.5258726479 +924 -2.6076403512 -1.4128996716 6.9457134599 +925 1.694115072 -3.1376973804 6.5047539444 +919 3.808582986 3.9680906244 7.1964244254 +922 -0.619351444799999 2.8080018756 6.7619052219 +923 -0.0517430363999996 -5.500721796 7.4570537386 +927 0.403670454 0.0894008507999997 7.1874780765 +920 4.8819638568 2.533475532 6.3441449873 +921 -5.40092759052 -1.0409551236 7.1989898986 +935 -2.206468158 -2.2310977188 7.3558642237 +928 3.5555773332 -0.5101026216 6.7860098733 +930 -4.1488843824 -3.6110844396 7.3302245949 +934 1.8572739036 -1.1781679848 7.0467515367 +933 2.4852918288 -4.9065450432 7.339547817 +929 -1.8168516816 -1.2350184528 7.5310899009 +931 -2.1925953804 5.04415269168 7.386470161 +932 2.6131594404 -0.520164232799999 7.1203574903 +936 -3.5779269216 2.8993175676 7.3352452464 +940 -3.7345660272 0.8700181548 6.8166747912 +937 -1.8796260072 -3.1761893304 7.3627584997 +943 -2.3200308228 -0.462290790000001 7.060242126 +939 -5.32063418448 1.3946429256 7.0354312078 +942 3.2984514528 3.2635316568 6.6746986941 +944 -0.479102634 -2.9108053692 7.2312725825 +945 4.2823147296 -2.530670574 7.4511185096 +938 5.3419025928 -1.31061234 7.5467259072 +941 3.1561341384 4.5045686196 6.6617354303 +948 5.4983479632 0.14403951 7.4350017553 +952 -3.7719988308 -1.1209239204 7.913581451 +947 -3.3813519768 -1.967985426 7.2658577976 +946 -1.7911812624 0.3494778108 7.3081664054 +953 -0.815084447999999 0.5384378244 7.6650227783 +951 -0.869835012 2.0531448096 7.4597703988 +950 -1.767972774 -5.2084628592 7.1041749664 +949 -2.5773381948 -4.3201929492 7.7342709441 +954 -1.2022504116 -0.4462651296 7.5399891453 +963 -0.2773636416 -3.9806886312 7.2928978359 +960 0.828687271200001 -5.0757641172 7.6654353015 +956 -0.328313394 4.680451398 6.7617502064 +962 -3.3255256788 3.8660058768 7.3765584442 +955 3.6251703756 -1.648037268 7.3516112624 +958 -4.5824001396 -0.6277353168 7.5976033304 +957 -1.0333060932 5.40210952836 6.6032354512 +961 1.1289409248 -3.570888774 7.2068027883 +959 2.5795430916 -3.9122138892 7.292285186 +970 5.09294193 2.0769630732 7.2075867194 +969 3.646946784 1.1161870596 7.8839024323 +967 -0.8470190928 -1.3589850252 7.7405738145 +971 0.183879281999999 -2.1880018788 7.4357263152 +966 -3.7457955132 -2.7822029964 7.7176434958 +972 0.0750380471999996 2.7398438556 7.477986005 +964 -5.49879174504 -0.118945873199999 7.5732709313 +965 2.1774265704 -2.9998735152 7.3690486384 +968 -0.0465725364000003 3.7272919812 7.3796943298 +977 1.623058146 -4.380738462 7.522049901 +978 0.976139530799999 -1.6243945788 7.2019370624 +980 0.61098054 5.46655618944 6.919970319 +979 2.4585203424 1.6321254144 7.2807904759 +975 -4.6520679588 0.230803222800001 8.1051907894 +976 0.9788999088 2.451593316 7.1594347976 +974 1.390377732 5.32175080788 7.5289804005 +981 2.1123911784 0.694835772 7.3120644787 +973 -4.2723634992 1.6904045676 7.4053630056 +985 0.483177020399999 4.5747320688 7.3532409758 +984 1.723259838 -0.2466335028 7.4851126973 +990 2.7760500792 -2.2293080868 7.1510576242 +987 0.357991176000001 -3.1591867896 7.7183865038 +989 -4.33341294 -1.9177969752 7.6912700226 +988 -1.2607845444 5.35366682676 7.5754829828 +986 0.1372506636 -1.1584182996 7.7014770082 +983 0.974292354 3.7053188256 7.4068569142 +982 1.9547192472 4.3655630964 7.7130865454 +993 0.2081398764 1.7884270836 7.7542843953 +991 -0.1824661092 -0.1812137988 7.9508596671 +998 -1.2643919508 -2.4321948132 7.6219973203 +997 1.8654854436 3.3696503328 7.7119121817 +996 -2.7446770428 0.6504259608 7.3093453695 +995 -0.7015217568 4.531066482 7.6773313097 +994 0.438001009200001 3.535134402 8.2333105437 +999 3.6484705032 0.4026437856 7.1835353198 +992 5.175677856 -0.508564699199999 8.1197914081 +1002 4.6301377044 -0.367117031999999 7.2943331886 +1003 2.7335645328 3.72034353 7.3612510255 +1000 1.8205190016 -2.066414136 7.5046450068 +1008 2.6203839924 -1.3827183468 7.6593985351 +1006 -3.48316323 1.1725518444 7.7354617099 +1004 3.2667013536 -3.4456250328 7.8488941974 +1007 -1.4778782832 1.2868686396 7.6649760148 +1005 3.3674022312 -0.722383430400001 7.744186167 +1001 3.7434985176 3.0373991808 7.5557781335 +1015 1.8708517332 2.3751281148 7.6048765721 +1009 4.2457778256 -1.1501649408 7.9573596789 +1014 -2.0410529796 3.5442635316 6.9410965865 +1016 3.7514905908 -4.0223407476 7.1914480295 +1011 -1.9230268476 -3.723697134 8.1987170113 +1010 1.3362262716 -2.8766641584 7.8955096662 +1017 1.103136948 0.5382836724 7.8079660134 +1013 4.0725667896 -0.0982369223999999 8.0798734211 +1035 1.0870037616 4.6004128752 8.1507735273 +1021 2.9005419804 4.6734376056 7.6128812495 +1018 -1.1447831484 -4.4719940256 7.3654679648 +1026 -2.3628725532 -2.807991024 8.1568815906 +1024 -1.3079771028 3.7407488112 7.5916092138 +1020 -0.6129482796 1.3847272836 8.1577498665 +1022 -3.5229724644 -2.0058178752 8.3069487032 +1019 3.3951522456 -2.4483850692 7.9046660029 +1025 -1.1240567412 0.9044058924 8.8763608355 +1023 1.557028002 1.4305573632 7.6994807446 +1029 -3.1152530856 2.1149937552 7.7974828271 +1027 -3.0449766456 -0.4547941968 7.7486915427 +1028 -5.43586415052 0.8375941608 7.857733339 +1032 -4.6222498548 2.9810439396 7.5664230282 +1034 3.1986563616 -4.4743742448 7.8910517174 +1030 5.3821635216 1.1356571724 7.3796337496 +1033 2.5535350128 -2.8355737572 8.2808545524 +1031 -3.7921780416 0.231978156 7.5949796795 +1038 -2.5422203472 1.3051130448 8.0464551917 +1012 -4.5170149788 1.2113341836 8.2475759594 +1036 -0.4313991192 -2.7426854556 8.2158553799 +1039 -2.0724168348 -0.3506171736 8.0225234304 +1037 4.2721883604 -3.463680036 7.8357243496 +1043 -0.2981280756 5.4924436032 7.3434637556 +1044 -1.8541515744 5.1781772748 8.3607031992 +1041 -1.8597291672 0.593187697199999 8.2751361281 +1042 0.289350312 -5.4925241112 8.3967469891 +1040 -5.2493536488 -1.6424652648 7.9830807509 +1048 5.2125435792 1.7553440664 8.1463434258 +1051 -1.7492412276 1.6209710868 8.5672126039 +1053 3.7875776724 -3.9886857756 8.536806071 +1050 -3.5669183964 -1.1943586524 8.8895150686 +1046 1.7938222464 -2.222561934 8.4971542097 +1052 0.135007803600001 0.795150406799999 7.8427703086 +1045 2.8585074456 0.2058507468 7.7625327916 +1049 3.5815825236 4.1740275156 8.1482406661 +1047 -0.2405788044 0.4674435912 8.7095383965 +1059 4.7092687596 2.8415438916 7.7253018877 +1054 1.4958396708 -1.2192870384 7.9782082546 +1057 -3.7156432116 -0.296154708 8.4759518527 +1056 3.9098868636 2.5403897844 8.4073449064 +1061 2.3663196816 -4.5443394468 8.4402877508 +1062 2.379377832 -0.5648208684 8.18123759 +1055 -2.0036931516 -1.8817648248 8.2705202281 +1058 1.7381974788 -5.2191104232 8.0538962643 +1060 -0.326889288 -4.699019844 7.9862719901 +1068 5.0551081944 -2.168667798 7.9721880143 +1063 2.526794208 2.0029791144 8.2612861744 +1071 -1.038230004 -3.54160095 7.7704208656 +1065 -2.4046975764 4.1116642512 7.6785715019 +1066 3.3545540856 -1.5395655828 8.3196198323 +1067 0.892965291599999 -2.0038376004 8.1231228076 +1069 0.8380387428 -0.4710319788 7.8922233283 +1070 0.597428796 -4.120878822 7.8509069964 +1064 5.4568401456 0.690207606 8.2715838474 +1080 4.6681942584 -2.909263362 8.5665611017 +1076 0.1002724044 4.4977089564 8.2737057416 +1073 4.544637222 1.0676956596 8.4304549817 +1075 -4.077586866 3.6915346896 8.0113362434 +1078 -1.1084745312 2.8540381488 8.0080097729 +1074 -3.734139264 -4.0387338336 8.1329396644 +1077 -1.4906661252 -1.04395032 8.456817546 +1079 -5.45016319872 -0.737316381599999 8.3570217942 +1072 1.3836015108 1.0616174748 8.6124032941 +1088 1.1237819856 -3.615938466 8.5344893821 +1085 -0.0503496431999997 -1.83874338 8.4099682256 +1084 4.2929033436 1.8710067612 7.7708438017 +1086 3.5802546252 -3.0246467208 8.6997896188 +1083 -2.08807176 3.1815235728 7.871737868 +1087 0.624201564 1.7163796548 8.6601768392 +1089 -4.2616513188 2.2968871656 8.1999988737 +1082 -2.1179784816 2.1831064932 7.8256485467 +1081 0.8205505056 2.6167789176 8.1328625798 +1098 -2.0485148364 -5.104394904 8.0582452915 +1090 -3.1377916884 3.8314158492 8.3579658868 +1094 0.4967384148 5.47764545028 7.9493897246 +1097 -0.1709385888 2.7712038 8.4463238197 +1093 2.5126360836 3.813037224 8.3319887827 +1092 3.3323363448 2.1350601972 7.6838936594 +1095 -0.217655215200001 -3.755841912 8.2997805701 +1096 -1.0101343968 -5.4066391392 7.7252512244 +1091 -1.092988992 -0.0264623279999991 8.440897403 +1107 2.0267173404 -3.6689570184 8.0965536965 +1103 -0.5064245628 -0.902766532799999 8.5623487442 +1101 -3.7268231088 0.6980487156 8.5812350943 +1100 1.4999608284 -0.445578360000001 8.6412136711 +1105 1.984138008 0.3516412992 8.2424792556 +1102 2.4126625764 -1.4511050088 8.6423533458 +1106 0.711838905600001 0.1694597592 8.6505194588 +1104 -1.7075742156 4.189547004 8.3907748546 +1099 2.785964028 2.9241110784 7.9646100643 +1115 3.512408466 -0.6410138472 8.7295939178 +1110 -3.5718387588 -2.927061252 8.6925431704 +1113 2.8147885104 4.7257032024 8.6068789391 +1116 -4.91616692808 -2.466048384 8.4416578826 +1111 4.2640410792 3.474186444 8.3589023503 +1122 -5.1329588436 1.9756618416 7.8271968727 +1108 -3.4645769796 2.8868257584 8.3286888482 +1112 -1.3024634448 -5.344037838 8.679207237 +1114 -2.815447236 -1.4121148728 7.9238048542 +1123 -3.0317822988 -4.5894529944 8.5831567564 +1118 -0.4111144272 -5.484676182 9.109938597 +1124 -0.5510308044 3.679569948 8.2416801531 +1125 -4.3973045844 -3.3038059644 8.2723607911 +1121 0.574224364799999 -1.0899766128 8.631608876 +1119 5.31979035 -1.3976802576 8.5526456202 +1120 -1.2044851212 -4.4014433244 8.360588152 +1132 1.9468282272 5.1441714672 8.3403573877 +1127 -4.5043207488 -1.3175082912 8.5649669639 +1128 -1.3845849564 -2.9302007676 8.4816661416 +1129 1.5546550164 2.0408102856 8.4920846247 +1126 -1.4268409596 -3.7367537112 9.0727458634 +1131 1.9944032136 2.9321704056 8.6016925306 +1134 2.8243976364 -3.6972638508 8.7097183577 +1133 3.7149229656 0.602922085199999 8.7394222756 +1130 1.3801671672 3.7163318628 8.5138387383 +1136 4.7688640368 0.1485174084 8.7537006152 +1138 -1.8196249464 2.6234769948 8.6721247755 +1142 -2.7270383928 -2.2151513076 8.8750659872 +1137 1.0662491436 -4.6657236696 8.5457114875 +1135 -4.6190581728 0.6013530708 9.0330872844 +1141 -0.582986866800001 5.46905443704 8.3014912865 +1140 2.8187644092 2.5667322828 9.0338426893 +1109 0.176355294 2.354310354 9.286155617 +1117 5.4777552324 -0.495553081200001 9.0725446858 +1139 0.496849939200001 -2.8468706232 8.6575468395 +1143 -2.0751052464 -4.4694899592 8.8471051435 +1148 4.8775086408 2.5423879632 8.6642604754 +1145 -5.36352401976 1.2195536496 8.7790012373 +1147 1.8681147864 -5.1727075332 9.0439097068 +1144 0.6624564048 -1.9674439164 9.1028767567 +1146 2.3160544752 -0.621123762 9.1916782872 +1149 -4.5966536304 -3.0202961088 9.2101454491 +1150 -1.8734201472 -0.2997984372 9.0041506537 +1152 2.4869377584 -2.4014094396 9.1951251307 +1154 1.3883827116 0.2324197044 9.3838660918 +1155 -1.034686644 -1.9937125296 8.4898662647 +1157 -2.864705118 1.090870674 8.9683810557 +1161 1.9183228908 -3.1917775548 8.9684002664 +1153 0.9098170224 -5.4244686252 9.1776562494 +1159 -5.49564211668 0.2201155344 8.642006927 +1156 -2.8350605412 0.374649864 8.2657758145 +1158 4.5566647224 -0.8239334364 8.8500331369 +1160 2.7504234672 1.0300608912 8.3182377996 +1164 -2.7585198228 -0.641773149600001 8.68855073 +1173 -4.6691823036 -0.386994144000001 8.8911268981 +1167 -0.9204668028 2.16267885 8.7055907263 +1168 2.2048131816 0.7805630496 9.1181371639 +1170 1.4678441076 -1.3914765084 8.9639386379 +1163 2.2234548876 1.7780202468 9.1871852061 +1166 -5.05066917408 2.1784812372 8.8027008241 +1165 1.9567997292 4.3818768864 8.9872906186 +1176 1.0748499324 5.39431153356 8.7607391962 +1151 1.7255231772 -4.1694227952 9.1099888914 +1180 2.8476720324 0.1054492524 8.7567849571 +1162 5.3216274912 1.3897167864 9.0702350215 +1177 4.2126383868 -2.0228500212 8.489437947 +1172 0.856105300799999 3.0438506256 9.0363627537 +1174 -0.929856253200001 -0.4346221344 9.3378788008 +1169 3.4460063184 -2.1286845108 9.1222276046 +1183 -4.93783061976 -0.167809818 9.9082665186 +1171 -0.5552036724 -3.2477001816 9.0916076057 +1179 4.2092197248 3.009918888 9.2428698706 +1175 -4.3611362868 1.5571147308 9.1737050514 +1181 1.1467108644 2.1418906812 9.3992246171 +1186 -1.0207543632 3.1605350712 8.9553203465 +1185 -4.5290801844 3.1216505172 8.6976544659 +1188 4.40322414 1.784779314 9.1116620544 +1182 2.6527646556 3.7455435696 9.3195463122 +1187 0.0907994196000006 -4.647434838 8.8929589144 +1196 -1.1938274184 5.36940119064 9.0866402153 +1190 3.4022221356 1.7132338596 8.6477458516 +1194 -3.9173586396 3.8607412272 8.9834144809 +1178 -4.3333453344 -1.0858733328 9.5226078876 +1189 0.535869115200001 0.931911876 9.2730373997 +1195 -2.252360928 -3.1733364432 9.0808295009 +1193 3.3272727516 3.355113042 8.687729323 +1206 -2.7615280032 2.2905308328 8.7161826451 +1197 1.9788842916 2.6702958636 9.5665850115 +1205 -3.5645298756 1.6927152504 8.5849294852 +1191 -0.00795945960000033 4.3146024024 9.2507636331 +1203 3.5040653304 4.2394939884 9.1430248319 +1199 -0.9750623256 -4.6366833936 9.3050061435 +1201 -2.7610552176 4.7575971 8.3524620631 +1200 0.3311998596 -3.708224562 9.1376080996 +1192 -5.20527797304 -1.7774429256 9.1091712416 +1184 -0.8153373072 4.5420085512 8.6726768545 +1207 -1.445095266 3.9832530132 9.3330562548 +1209 -0.4245053316 -2.266949814 9.2334739349 +1210 0.966305842800001 -0.677966427599999 9.4541040814 +1222 3.0735927828 -4.5614579064 9.1466383903 +1208 -2.8859278644 -3.6103819296 8.4427131474 +1213 -2.3037600516 3.4963663788 8.7958209755 +1212 -3.981111198 -3.7954455576 9.0705833747 +1221 4.2573319776 -3.4829277336 9.2748164649 +1241 1.190749068 -3.4759768284 9.5927190314 +1214 0.9724416252 4.473440628 9.1357889824 +1216 -1.7682475152 -2.2938200352 9.150704372 +1217 0.1102403796 5.2741263186 8.9952609852 +1218 4.0319667204 -0.0926041656000001 9.3841726446 +1198 -0.2783110932 1.4844647736 9.0947708643 +1223 5.0527107792 -2.1735342516 9.123225724 +1231 -0.0738356075999995 -1.3383767004 9.3512672668 +1224 -1.7733865536 5.206418655 9.8844627811 +1225 1.5972085848 3.5903433528 9.4810931526 +1215 -5.4372519852 -0.8313405012 9.3519979213 +1204 0.8620796976 -4.4805864204 9.5068181647 +1228 -3.2493246504 1.8278737128 9.5242467491 +1211 5.2698710808 1.5748903356 10.0512806166 +1240 5.4814512504 0.4542319176 9.3848459119 +1227 0.444811486799999 -2.8129335828 9.6553172167 +1219 1.4986854564 -2.4042726228 9.4348578492 +1226 -1.0691676192 -1.42341966 9.3091321691 +1220 4.9318571016 2.4349173972 9.656967697 +1232 -5.46662959572 0.6073793328 9.563477804 +1238 -5.2695052554 1.5767771532 9.7080626875 +1245 -3.6834049284 0.9276601692 9.5532159236 +1234 0.0557022755999999 -0.360702461999999 9.1869581311 +1235 4.2638305308 -1.6288774572 9.4067568421 +1242 3.6474918 1.2519470412 9.5001570366 +1230 3.6259385172 2.2510419744 9.5324689969 +1250 -3.0406813884 -3.8157991788 9.4089218077 +1202 -2.74793901 -4.7646822336 9.5254265843 +1248 2.7007303404 1.2208065672 9.8662864984 +1278 2.766376974 -0.682890007200001 10.1293474423 +1229 1.439888238 1.2074515332 9.5998134217 +1255 -1.5725434728 -3.0742984836 9.8074454449 +1243 2.409668958 -1.5097291956 9.6404259172 +1247 -2.1674463036 4.650097962 9.1499815047 +1257 3.3598471596 -1.2198803328 9.5299482691 +1246 -3.905860032 2.4645598776 9.120482441 +1273 -3.3593649744 -1.8891450864 9.577685011 +1258 -3.09382458 0.1466835276 9.2037571582 +1259 -3.2735095668 -0.698308506 9.7065517909 +1237 -2.0132003772 0.6564406128 9.2608861189 +1252 4.5613185864 0.8515947996 9.4337711256 +1253 -4.1772208332 -2.1262679244 9.0535199052 +1249 3.1916264592 0.3757830588 9.6554203072 +1264 4.006927236 3.7676337372 9.8665147173 +1272 -2.1907197108 -1.3549282536 9.0996304026 +1261 3.0557376468 -3.1469939628 9.5417273174 +1256 -0.6013325616 0.486552056400001 9.6418358592 +1269 -3.6866711616 -3.0573780024 9.6772827937 +1268 -1.8401861832 -5.18322948 9.5066364985 +1346 -1.412152332 -4.5567541572 10.2007747717 +1263 -3.1720788684 3.2369156016 9.2185282118 +1262 -3.177415644 4.489543062 9.2206498859 +1275 0.782553629999999 5.44406985108 9.7157370444 +1267 5.3351917788 -1.337381556 9.5929319642 +1265 1.1462738808 -1.5870834252 9.8907853768 +1271 -2.2587011136 1.746686352 9.4179820134 +1270 2.5010904864 -3.9619837884 9.7055439623 +1254 -2.655117762 2.5904333796 9.7795024851 +1260 3.1902702972 3.0919582872 9.8518986048 +1280 2.7675877968 4.7534698944 9.6047220113 +1266 -1.8120108828 3.081197232 9.5608927481 +1236 -0.5307260304 5.01031911252 9.7428722713 +1284 -4.7089231152 2.4043398192 9.7147917304 +1274 0.6570580212 3.7687070268 9.7703307445 +1279 -2.1183952404 -4.0173386532 9.7378894553 +1287 3.6696817548 -4.0970387148 9.8012500949 +1244 1.7373589932 5.21855354472 9.4887133897 +1301 4.560258648 3.0754235568 10.3288091644 +1289 -1.7009663328 -0.8451016848 9.8246262184 +1288 -2.7634908888 0.7703401164 9.9120457007 +1282 -2.6776245816 4.80476788884 10.0268191242 +1290 2.2483189452 0.1365523872 9.8847473425 +1352 3.0818511324 -2.2813367208 10.0405479981 +1276 -0.1469374584 -4.5636953484 9.8604423691 +1296 -4.3677042456 3.343750284 9.7106994545 +1281 -1.2657246396 1.66959138 9.5039839246 +1295 4.2849664056 1.7391643716 10.1032818952 +1297 1.78296453 -0.825730763999999 10.0125309111 +1294 -1.2162290808 -2.1549387696 9.9735253409 +1314 4.7331525168 -2.802112422 9.831531363 +1369 -4.6036952208 0.8866830516 9.9909528899 +1309 -1.4906037912 0.1367871132 9.9363884693 +1283 0.2316045588 -1.938415152 10.0905175925 +1343 1.4555079756 -5.304329826 10.0068256742 +1305 -0.6427947396 -0.280089845999999 10.2824052334 +1315 2.7478962 2.2091982432 10.008699928 +1312 -0.739683840000001 2.5058171376 9.6565022723 +1328 -2.7691724256 -2.6720219688 9.7739609747 +1300 -0.0879856812000002 3.3184558812 9.2788370812 +1321 2.0928755544 -3.0310301628 9.9396701665 +1292 1.1072277936 2.9151545316 10.031807638 +1342 -0.967967328 -5.4141663888 9.9372345678 +1311 0.3533479716 0.216850956 9.9470011922 +1320 -2.44044426 -0.175477383600001 9.8883968826 +1286 -4.0162485192 -0.0152103132000008 9.5528847475 +1330 -0.82269306 -3.8224904028 9.864770431 +1318 -0.4903874064 1.3846254948 10.0672998387 +1310 -2.5412871576 3.8727723972 9.6911898246 +1277 0.125803490400001 -3.6378751968 10.1215896489 +1316 -1.8105222 1.1101355124 10.1283580773 +1285 5.49157296 -0.303565674 10.0535959725 +1325 -3.7111119972 4.0593269652 9.9485150834 +1332 3.8579508576 -3.174649296 10.1379291289 +1306 0.2131307112 -5.4960193296 9.8910654122 +1319 5.1199292676 -2.0093526444 10.301961416 +1326 -0.5290954332 -2.8796389368 10.0208392118 +1308 4.5460410516 -0.7938649032 9.8778836418 +1322 1.938597708 4.3677785196 10.0088627958 +1341 -1.7788490376 2.259447324 10.1296270964 +1299 3.0978223452 4.0234199292 10.2022524053 +1239 -0.6143920128 -1.3071131772 10.191779325 +1348 2.2826817096 3.4128700404 10.1867556138 +1317 -1.2638211192 4.4129594388 10.2172421112 +1349 4.0596249072 -2.1734246016 10.2202216483 +1298 -3.6072605556 2.7749177316 10.0224874477 +1329 -2.1796698096 -1.8877269756 9.9665672886 +1331 -4.96307004528 -2.37116613 9.8761374242 +1397 1.656513 -4.3291537092 10.094640205 +1334 4.6118672928 0.1634973432 10.157235591 +1336 2.4066664932 -4.9458767988 9.8548063118 +1353 -5.30257001004 -1.4613089616 10.1161369504 +1333 -0.7790912388 3.5722433988 9.9555229093 +1357 1.8115986408 1.9151199636 10.2005105494 +1233 0.4625896716 1.6639029024 9.9502731957 +1382 -4.0587856512 1.7534475072 10.1062758318 +1313 0.115108558799999 2.8621768524 10.1453013505 +1410 -2.7564534276 -3.5109377568 10.3178055687 +1339 0.9881586156 4.6016258508 10.2136942449 +1356 -4.0251416376 -2.2829036604 10.2112881055 +1411 -3.3040605552 -4.3970055564 10.2705399958 +1307 0.2178680088 -0.7594098804 10.1119970864 +1390 1.9154707608 -2.0838391524 10.2925884854 +1361 3.6483885936 -0.2418785232 10.295248583 +1360 -4.044436944 -3.727377246 10.327630284 +1335 1.1988820128 -2.7805859592 10.3112225978 +1393 -3.7223134224 -1.337813112 10.330133844 +1449 -2.8443986868 -4.7078281932 11.1591323348 +1291 0.925600497600001 0.9002451276 10.3999257994 +1386 -2.1004765116 5.08343162208 10.821197714 +1363 0.253505389200001 -2.7903301092 10.6365187635 +1323 -1.7169040176 -3.6807992628 10.5892075803 +1347 1.38347322 3.7296042456 10.5420093394 +1344 -0.7751204352 -1.004655738 11.131217616 +1378 0.873699591599999 5.4305476842 10.9554300917 +1345 -1.2261376008 1.68423825 10.7325606602 +1302 -1.5142035684 -1.4402136276 10.60615121 +1437 -4.7860948848 -0.0498869771999999 11.1093694856 +1380 1.4136709284 0.5816801976 11.2123403318 +1376 3.8196449484 -1.2192055872 10.4174749893 +1327 1.0222029096 -0.9688713276 10.6666999357 +1402 2.0228961708 -3.6457251048 10.7254192181 +1338 3.7613533848 2.4970187532 10.4921837958 +1324 5.3877049392 -1.1071385052 10.639201922 +1337 5.4623880372 0.6457357476 10.3659275569 +1351 3.8180097564 0.7422824208 10.3433342919 +1391 -0.9948865692 2.6496094716 10.6122329853 +1374 -2.2856867064 -2.6696613792 10.6492716117 +1408 -1.9251965484 2.2864895244 11.1184596404 +1396 -4.99656809952 2.2990990524 10.6666703307 +1367 -5.3301081558 1.3565448504 10.6815007927 +1368 0.9308166312 -1.9546553916 10.8067484621 +1372 -4.0955728848 3.4757391696 10.6637773456 +1392 -0.4995658716 0.0551124251999999 11.2126929723 +1415 -2.28901098 -5.0014538388 10.3814196798 +1373 1.9277404596 0.916097472 10.4225918493 +1371 0.0751926780000005 3.7604991024 10.5826315131 +1355 -2.3099185836 4.1200480728 10.6551873789 +1387 -1.616904228 3.4211665488 10.4801453023 +1340 0.049486138799999 5.49984168432 10.3935906952 +1691 -3.6262116828 2.0312487972 13.3362013051 +1490 4.429749204 2.2016476728 11.5303444667 +1385 4.6116094944 -2.9971761 10.8047207862 +1354 2.9803958304 -3.5234598792 10.4653713967 +1359 -3.2539353336 4.4342509116 10.7548923937 +1370 0.1293251124 -1.3646225244 10.9029171085 +1436 3.274703178 1.8093827352 11.5180093776 +1358 -3.0619351668 3.492293898 10.4554529839 +1395 3.3344208612 1.59434865 10.5433387837 +1422 -0.5833739568 -4.5182943072 10.7588092313 +1375 -1.0138467468 0.71660199 10.5967726219 +1364 3.7079679936 3.4767483216 10.7752883477 +1389 -5.46549536616 -0.617931434399999 10.6281787157 +1365 -1.0252804008 5.40361608612 10.5178300338 +1362 -0.0200389019999996 0.764780564400001 10.6952809871 +1381 -5.48704813632 0.3792326352 10.5397389831 +1546 -2.0800734108 5.09148357828 12.2265861705 +1377 2.8590520236 0.542451157199999 10.5833124715 +1383 -1.5124125768 -0.450137744400001 10.7456699991 +1406 4.5785075892 -0.558813393599999 10.8489934827 +1384 -3.8031251808 0.50152308 10.4495210688 +1428 -2.093546346 1.2613686348 11.0751663083 +1379 2.6437021608 4.8231565158 10.5943658749 +1394 -4.0409465076 2.5010484792 10.8804916527 +1388 1.971609582 -1.0375824156 10.9713963627 +1438 1.732288206 5.22034024104 10.4885341596 +1403 2.7654981276 -1.5443760036 10.6369035944 +1399 -0.3482973216 -5.489254392 10.7182619009 +1643 -2.1818112312 -0.583197912 12.2139011689 +1401 5.324761266 1.3769312736 11.0337835682 +1398 -0.3947284524 5.48603814576 11.2893705671 +1400 0.6428550336 -4.6505936064 10.4673816351 +1404 -1.377268098 -5.325084174 10.8451036802 +1405 -2.122382388 0.3396452232 10.6841155776 +1412 -2.9724980964 0.8150244432 10.9089153171 +1303 -3.0883705416 -2.0875702848 10.5194139416 +1450 1.5905071704 -2.8949635992 11.2241286398 +1413 0.664237139999999 -3.191291184 11.4552261781 +1566 3.91840971 3.8596793616 11.7760230906 +1407 2.4835153416 -2.725394766 10.807835133 +1409 -2.3332617708 -1.7557044012 11.0843590204 +1419 1.7854559256 2.7513781992 10.7480858105 +1418 -0.840038172 3.7998497508 10.9823242285 +1421 -4.1425299456 -0.438752652 10.4501559643 +1417 2.475950916 2.0022014652 10.9482304099 +1416 3.36131925 4.3534932492 11.1084208639 +1420 0.9326133024 2.1691839204 10.6738029161 +1414 5.4779704344 -0.1678501368 11.0442198763 +1426 3.1875578508 -0.7305145188 11.0357770387 +1430 4.753919064 0.55567293 11.0656145573 +1304 -0.3967166664 4.6385812344 10.6613269568 +1423 -2.949932292 2.528548746 10.7342253013 +1424 0.574774218 1.3945844352 11.1945780169 +1429 2.893558338 2.8966579788 10.7866259746 +1431 -2.4078412584 -0.5436572232 11.180639552 +1425 0.419964852000001 -0.1473101088 10.8765003128 +1427 -3.1670307612 -0.255832332 10.5969284868 +1433 2.0044963152 -1.986853146 11.2837217874 +1435 -0.5216346552 -2.1563151432 10.7110744455 +1439 -4.3427172048 1.2141479436 10.8987117601 +1434 0.7279422672 3.1037720088 10.9643185915 +1432 4.4901380076 3.1771180188 11.3209846771 +1440 -0.247337028 3.0157762668 11.1660594305 +1443 -2.3612545536 3.2372637228 11.1217665499 +1441 -1.297061508 -2.786673642 10.7435523984 +1445 -3.5054363088 -2.9767380828 10.7097345325 +1451 3.8913812736 0.0690428700000005 11.21391644 +1655 0.0618574584000005 -0.768278111999999 12.6259176491 +1447 -0.150107148 2.0764588068 10.7041008126 +1442 -0.617658260400001 -3.5183037216 10.7948033716 +1448 5.009100816 2.271873774 10.7187449553 +1446 1.5940223508 1.5599623968 11.1109551604 +1444 -3.4615597728 1.6867879524 10.9054036898 +1471 4.1807721288 1.3740544548 11.0280823613 +1457 2.313198648 3.9767996724 11.0118141131 +1456 0.8591237868 -1.2452306328 11.613666462 +1503 -3.9798798468 0.447209661600001 11.4319423602 +1452 3.4759544748 -2.635599492 10.888111803 +1455 0.0330191952000005 -0.6823715112 11.6274174482 +1453 -4.791446148 -1.9974690084 10.7869744735 +1454 -1.4123557836 3.096313692 11.4033652272 +1458 4.5197512056 -1.6259309256 11.0039065308 +1463 0.1583844156 -2.2060936944 11.4421862854 +1467 -4.63009851 -2.9691982848 10.6140883415 +1464 -0.7107590064 3.5598643596 11.9443450337 +1460 2.105271366 -0.0527737776000006 10.8613018219 +1462 2.0624254464 -5.0989687044 10.7807204436 +1461 -3.1616099172 -1.1993664036 11.1463664077 +1465 2.9465486928 0.1941660396 11.5161378177 +1459 1.3476407136 -0.394612098 11.4174221679 +1466 -1.2488648628 -2.02004898 11.3837592803 +1474 -4.6654483404 -1.0417976772 11.0524940863 +1472 -1.1747939868 0.6920514264 11.5833059734 +1470 -5.18064287856 1.8470490948 11.5399656422 +1473 3.8330924664 -3.9443063808 10.775862384 +1468 -1.2545066592 4.6879548396 11.1783046723 +1469 -3.85783761 -1.9164266196 11.1341607033 +1475 -0.8320030092 2.292292584 11.5316229842 +1476 3.5419402692 -1.7040799224 11.2463239082 +1482 1.4958636504 4.5299404608 11.1721028309 +1477 -3.8725483536 -0.546501214799999 11.407096753 +1480 0.4088135868 5.1965087868 11.8091773426 +1484 -2.5284520224 -3.7646001432 11.2576487073 +1485 0.2503856016 -4.9716353568 11.3291770719 +1483 -1.50676908 1.6081142796 11.806130117 +1478 2.3112074052 4.99098948768 11.5221765092 +1479 2.8424474244 -3.4042718292 11.4482659403 +1481 1.3885130316 2.408034726 11.5992896881 +1492 1.0147091388 -3.72817848 10.5703544436 +1486 -5.44836353724 0.7500028692 11.467607575 +1494 0.260995284 0.5515508868 11.6308679621 +1487 0.4999203792 4.5125342664 11.0857294808 +1493 -1.8653954556 -4.503216882 11.1375636322 +1488 -0.3449765748 4.5573875076 11.6565700869 +1508 2.2793801436 -0.508285326 11.7615366356 +1491 -2.7292879284 4.775184504 11.534923734 +1489 2.4207267972 1.04195115 11.3304314249 +1499 2.987673486 3.5369811852 11.604402825 +1500 -3.5976919812 1.3528197924 11.8380113571 +1495 -1.6878471972 -1.1357653764 11.5426585409 +1498 1.8644827272 -5.1745415148 11.757790608 +1502 -0.487024548 1.374424134 11.3356888203 +1496 -1.6823907312 -3.2969285916 11.5117305849 +1501 -3.7909919868 3.9851290596 11.4685305039 +1497 2.316714342 2.7799278852 11.5947237074 +1366 3.0864351324 -4.5524309352 10.4735111907 +1506 1.5385264116 3.3957637068 11.4717904701 +1504 -5.49876828276 0.1224878616 12.2444662544 +1510 0.9390906228 4.3674949932 11.9866872176 +1505 0.231339117599999 3.7403749608 11.6614882276 +1509 -3.0571923924 0.1033088604 11.6059030359 +1507 0.711136335600001 -0.170984192400001 12.1552009918 +1515 -3.4242756 3.055329978 11.4394395924 +1511 -4.6116539952 -0.3433908744 12.0492759448 +1512 -2.4663051588 2.82636201 12.0273094812 +1629 -0.6209662488 1.1190386148 12.2979271804 +1518 5.4743475336 0.5319409056 11.7585503219 +1513 3.5982032184 2.7547716588 11.4817410702 +1514 -3.6495330432 -4.11491976 11.1654542268 +1516 -1.8978654744 4.0079828388 11.5589114813 +1519 2.5051909788 -4.3403968764 11.2587570751 +1521 0.3964121772 2.3288152992 11.5026126696 +1520 -1.177648812 5.37355463844 11.9011377545 +1517 2.8258063332 0.1504929084 12.5077206662 +1526 -5.45987376408 -0.6630545472 11.6270472524 +1523 1.119361926 -5.3850495804 10.9501437485 +1528 1.4949656112 -4.3716907344 11.1661212631 +1530 -4.3088668836 -3.418183536 11.4477919224 +1524 -4.3123957908 -1.4513166192 11.8936224803 +1522 2.7079485924 -4.787424426 12.1296584147 +1525 4.23700284 -3.5068247568 11.5792506898 +1527 -4.7610910764 2.7545727768 11.5257509518 +1529 -0.586281822 -2.1969236868 12.1135418929 +1531 4.5963720684 0.964131996 11.9643519284 +1533 -1.0496138376 -4.07084208 11.5216113296 +1534 1.1066893512 -2.2028969532 11.759346808 +1536 -4.85231345556 -2.5907575548 11.5889825632 +1537 5.214323814 1.7502082812 11.9547254643 +1539 -2.773114236 1.9955596416 11.5616088223 +1532 -3.028315224 -2.3552148516 11.4810067918 +1535 3.2390011308 -0.6236717568 12.0284608336 +1538 2.7041965728 -1.4115097344 11.7068076856 +1545 1.4059673652 5.31691130184 11.7942504458 +1540 -1.199672022 4.4065708248 12.1529734744 +1544 5.3111891388 -1.4296137312 11.5825438353 +1542 -0.7205503572 -3.0947277228 11.6946675214 +1547 -0.7649459592 -5.4466015092 11.6261175655 +1543 -2.0782361736 -2.4206746104 11.7859322065 +1548 0.205891524 -4.0017174876 11.0904488805 +1541 4.697082582 -0.1623480408 11.7590257844 +1688 -2.2051650084 -2.371779666 12.7764769797 +1554 -1.233582054 -0.283338586799999 11.8014312052 +1549 -2.8546547088 3.8124142692 11.7736718863 +1550 -1.0280414208 -3.8449091988 12.4954314726 +1556 1.9303001628 -3.6842708784 11.7472746671 +1553 4.0904377572 -0.9585384612 11.624842458 +1551 3.630995484 0.8956327176 11.7123957797 +1557 3.0589899132 4.5709965792 12.0362300691 +1552 -3.3248693664 -3.2969054352 11.6398800899 +1555 0.774487543199999 -4.3020823356 11.8558806313 +1559 0.2630334504 1.5567431208 12.1303520149 +1563 1.75923027 -1.36918089 12.0309203488 +1562 -3.9365589504 2.293408362 11.8530517821 +1561 -2.0681512884 0.253677714 11.6786418668 +1565 -3.9099119064 -2.5353913908 11.917001648 +1572 -5.37216551412 -1.1795276556 12.4795560347 +1558 4.70489592 2.8489426608 12.2408380919 +1560 -5.249846916 -1.640295594 11.6005609609 +1564 -0.3701955948 0.0284412696 12.2033744028 +1568 1.193661762 1.2104608332 11.9579880066 +1574 0.0149829912000001 -3.6775489572 12.0393690237 +1571 0.918485541599999 3.3295073508 12.2603247508 +1567 2.1658097196 1.8347841408 11.8838899838 +1570 2.8880793312 -2.393266446 11.6598406117 +1575 3.435173766 -4.2953411664 11.6234336692 +1573 0.374768769600001 -2.6998404852 12.2841436349 +1569 -0.3667286772 -4.6014779532 12.0234423862 +1579 -2.6476678452 1.0436541612 11.8784813859 +1583 5.4624979188 -0.6451438212 12.1838191254 +1585 -3.5986079976 0.4968642336 12.3548606117 +1580 -0.3289825272 5.49031564212 12.4166220171 +1577 2.0031695748 4.1411535432 11.9496332028 +1578 -0.6748608564 -1.2010924152 12.1064762241 +1581 -1.5322010064 2.5210750116 12.2122806656 +1582 0.1216704924 4.5781687884 12.5407291531 +1584 3.8822053104 0.1063133388 12.2720722132 +1576 -4.6293412704 0.4745375532 12.6242881744 +1586 0.8994784704 5.42614542816 12.6494053757 +1587 -3.1484192472 -0.784699484399999 12.056049389 +1590 3.5407248804 -1.5542471712 12.2355577689 +1589 -3.4137897012 -1.730517204 12.2418849836 +1593 -4.5709920996 1.1254613988 11.8676989287 +1592 2.0915177148 5.0868039054 12.4929805661 +1591 0.00836209680000088 2.9184921696 12.2107307462 +1588 0.91137039 -5.4242019828 11.9273695081 +1602 3.531164934 3.170711928 12.3886500475 +1600 -2.6380636968 0.2604672696 12.5000844052 +1601 -3.1164832272 -4.531837164 12.1051432551 +1596 -3.3679642332 3.247179192 12.419211041 +1597 2.0087864664 0.4242912672 12.0003400578 +1595 -1.7211863136 -5.2239753168 11.8151654204 +1594 3.95537457 1.6806609756 12.2391335383 +1598 2.9231624892 -2.2799238108 12.6536402981 +1599 3.3733609896 -3.0619327236 12.223111458 +1610 -3.13262181 -2.6556110592 12.5335037103 +1609 2.9356186872 2.376437376 12.2685877946 +1608 0.217838508 0.703183726800001 12.6490021835 +1603 4.96526946 -2.3661996612 11.5071163589 +1611 -1.8198365832 0.8809679208 12.4162848394 +1605 3.9934961028 -2.4569412204 11.7240750049 +1607 -1.9026713904 -4.1073371724 12.0546965428 +1604 0.803640207599999 2.3480684268 12.4156100531 +1606 -2.45230479 -1.532140122 12.0517108801 +1620 2.8717595112 1.2382576044 12.2656437556 +1614 0.778996725600001 -3.7718646192 12.7036296984 +1617 -0.489121927199999 -3.0211467336 12.6713238823 +1613 5.0915770548 0.1787302284 12.6121288739 +1616 -5.0693058252 -2.1336482568 12.4513513853 +1618 -4.442938158 -1.1855082132 12.8486028166 +1615 -3.8813026668 -3.8969615004 12.2145077738 +1612 -2.2789733232 1.80619032 12.4100375768 +1619 -4.9860881964 2.3214073932 12.3985134105 +1628 -4.2294879468 1.7011909344 12.610192028 +1621 2.723096358 3.7745496096 12.5388849786 +1626 2.0429404848 -2.3980193724 12.1943150682 +1627 -0.509631486 2.0997371772 12.458056273 +1625 -0.0178571567999999 -5.5002506124 12.2883021609 +1623 0.258231834 -1.6929812496 12.2943469625 +1624 -2.459393976 -3.2812955628 12.140497512 +1631 1.6318519128 -0.3526087884 12.5068770756 +1622 1.3018580352 -3.0685496832 12.2220734199 +1637 -4.3059726624 3.4222904292 12.1145527192 +1635 -1.3613490684 1.6957790268 12.7915318507 +1630 1.4412352416 -5.307921804 12.7672765393 +1633 -1.6120331952 3.5045476344 12.3740026839 +1634 -4.5976293876 -3.0194605944 12.4570464201 +1638 0.310590568799999 3.6930931068 12.9660834949 +1636 4.6446064524 -2.9469130812 12.3024927767 +1632 1.9036528632 3.2213181456 12.3909664512 +1647 1.7635938396 2.2762109832 12.6858472149 +1639 3.6481372548 4.1162045388 12.7039477305 +1641 1.2241336632 -2.0869327128 12.7454738859 +1644 -0.6446139432 3.9689364912 12.8598762518 +1642 1.0020929844 -1.1183183184 12.6347423974 +1645 2.7261666852 -3.8130015936 12.3533246454 +1640 -0.1652233548 -4.1324361816 12.9111651938 +1646 -0.482040206400001 -1.6845608604 12.9663485046 +1654 3.8785446072 -3.899984244 12.4278203052 +1652 -5.4797427384 0.4738605528 13.2167386294 +1650 -3.8230896588 -0.4160272008 12.6954520224 +1648 -1.5116573064 -1.7516726112 12.3105133943 +1651 4.5224307864 -1.7110410852 12.1286063274 +1649 1.516222566 4.3296622872 12.8024487239 +1653 -1.37212524 -0.8551312872 12.7338509195 +1701 -3.1612157976 2.2709817408 12.4840063482 +1656 -1.0356243276 -5.1378492324 12.5378615229 +1664 -1.2249638916 0.133503726 12.7111344636 +1663 1.9390454772 1.2024843492 12.6244424397 +1662 5.0931875136 2.0759226288 12.8923494121 +1661 2.1310671996 -1.6950921504 12.8999781711 +1665 -2.0809886376 2.8581653844 12.9769345179 +1660 0.680786617199999 -0.186673812 13.1543192769 +1657 0.741450834 4.698023652 13.3162762008 +1658 5.38290582 1.1291856708 12.7198504608 +1659 -2.343186426 -4.9758973356 12.557712934 +1673 -5.38993230552 1.0970275548 12.4400164337 +1667 1.6295781864 -4.4134457688 12.3620611057 +1671 1.8896365356 -3.57985512 12.848864562 +1669 -3.1253255256 -3.6175403856 12.8063937498 +1668 -0.0735472524 1.5202192068 13.1464445298 +1666 -1.7568060516 -4.2732403176 13.029645092 +1674 -4.1194860924 2.6832723252 12.7611282225 +1670 2.59634622 2.9115259644 13.0422413902 +1672 4.5319400724 -0.7906448148 12.5192883441 +1680 4.4309989824 0.8928561024 12.9478030398 +1677 3.4949228052 1.414351938 13.0853341709 +1683 -2.16674067 -1.3987553664 13.0032545657 +1679 -0.3111597012 0.0585491736000003 13.2006344177 +1681 -0.8410361736 2.9939300196 12.7583375343 +1675 -0.9076249044 0.9233786328 13.2357335632 +1676 -3.125960856 1.299539274 12.7185574694 +1682 -3.5068751964 4.2372431748 12.401171893 +1678 4.086229584 2.4200721396 12.898949526 +1692 0.5557360968 -4.7920619208 12.6994765075 +1684 -2.532330114 3.7108867728 12.7146110423 +1689 -1.3446859008 5.2702182606 12.8812116019 +1690 -5.21637076056 1.7436264288 13.1825092416 +1720 0.182668703999999 2.6224382136 13.1498252286 +1686 1.2016806312 0.530697498 12.6913653792 +1685 0.3281846112 -2.2348801248 13.1681061859 +1687 -2.8141910412 -0.6370053132 12.9866291975 +1716 2.5907582808 1.838240568 13.0375982815 +1695 3.6462512712 -0.5978744772 12.9412612493 +1696 -2.7769759872 4.7475648348 12.8558441128 +1698 -1.441208592 -2.8939411872 12.3942057094 +1699 0.915626592 1.4695356084 12.8828005503 +1697 3.980625156 -2.3145001488 12.7134262657 +1694 -0.6801027324 -0.8351772384 13.4553121556 +1693 -4.1303191536 3.6320879496 13.0763657624 +1700 2.3436699408 -4.9757259264 13.0415806469 +1707 -1.6157701224 0.871359164399999 13.9407681101 +1710 2.1414650124 -2.6618788008 13.1548738359 +1708 1.8913701288 3.562442898 13.330800606 +1704 1.9977527256 2.3551298292 13.6547353354 +1703 0.701083411200001 0.739274199600001 13.5313858983 +1709 5.4722761296 -0.5515530588 13.1793572453 +1705 -4.13408043 -2.1352604592 12.8052332803 +1706 -2.2882493616 1.1523750384 13.2562853263 +1293 -2.6372727876 1.66501758 10.3396779349 +1702 4.31137011 3.4150165404 12.9651107986 +1721 -3.9417746736 0.9355470024 13.1852319127 +1717 -1.2836508252 -2.2544353728 13.146467352 +1718 -5.0219882244 -0.379071648 12.9661408511 +1715 5.2981920648 -1.4766262656 12.7143646233 +1714 2.5100765412 -0.793657176 12.6915131159 +1712 -3.010971498 -1.9040022204 13.1814180478 +1711 -2.0493864684 -0.0468980195999995 13.2473883449 +1713 1.2409261716 -4.4101502784 13.3193635745 +1719 -3.0043911876 3.0232353828 13.3234127883 +1727 -4.1520889236 -3.6069530844 13.1323986034 +1725 0.2312519268 -3.22277313 13.3347609986 +1738 -0.4800398268 -2.588974122 13.6386022348 +1728 4.3642717116 -3.347357916 13.1745921919 +1736 2.6758399332 0.8530800612 13.2031136272 +1724 4.4257771392 -0.0903086508000008 13.307895915 +1722 -4.4473862052 -0.6967818576 13.7208302339 +1726 -2.0570721636 -3.3201828156 13.0563144881 +1723 -2.8707820752 -2.9078078232 13.4646775346 +1773 1.568468256 2.0117030928 14.4899655671 +1739 -1.8405530472 4.4029068264 12.9202603272 +1735 0.4029551868 -1.2702181524 13.4206688217 +1731 -4.83339721644 2.6249338164 13.4586446308 +1734 5.3040447264 1.455525066 13.661712865 +1737 3.2066335836 -4.4687453196 12.9355326012 +1729 -1.1099114628 -3.371594628 13.3724742284 +1730 3.5777370084 0.421557276 13.1707399459 +1733 1.1909095056 -2.9673910944 13.2181361962 +1732 -1.6676475372 -0.8585274936 13.6891285427 +1746 -0.7079702412 2.2603099968 13.4245801878 +1741 3.4343199792 -2.9826789948 13.2179135449 +1350 -2.5875651288 -1.0550861808 10.3404960776 +1742 -3.065422674 -4.566683028 13.1151701364 +1740 2.8848554676 4.6827408792 13.0144362781 +1745 3.1339708824 -1.4328122604 13.1409915895 +1743 0.1422541416 5.49838983528 13.2983931471 +1744 4.5890855412 0.688216407600001 13.9136923164 +1750 -1.6861150044 -5.2355627328 13.2908572486 +1749 1.6823591304 -0.9080351532 13.3368683011 +1754 3.8194378932 3.9579742896 13.6762800781 +1748 1.9394865024 0.182592972 13.2933454853 +1753 0.923722759199999 2.09880759 13.6597115515 +1751 1.1320939896 2.9362175772 13.1545541081 +1752 -2.6284948032 2.0909967564 13.310886206 +1747 1.6524286788 1.4217668976 13.5570448215 +1760 2.8609748904 -0.2238208608 13.4342731531 +1755 -5.23488277668 -1.6871555604 13.3304951878 +1758 -3.2461815072 4.0131620208 13.3461594971 +1759 -4.84286738448 -2.6070408312 13.3342761927 +1757 3.509095968 3.039954042 13.4300185333 +1756 -3.263355228 0.2071935132 13.2785492969 +1764 -0.2151879216 0.733703140799999 13.9316432322 +1763 -4.577399304 0.2878643352 13.6052184619 +1761 -0.8461435392 1.4989929492 14.057659435 +1762 0.709292004 -5.4542064036 13.432715493 +1765 -3.597872244 -1.1190106044 13.3789628601 +1767 1.9182288696 -3.3689306964 13.8258516309 +1771 -0.3892059156 -5.486263284 13.2164803467 +1770 2.1388293492 4.4778856344 13.6478164826 +1769 -0.7779289608 5.44478809692 13.6860197294 +1768 0.121922311200001 -0.4610561112 13.9366160228 +1766 0.9905168244 3.8049373704 13.6906881403 +1772 -1.412858046 3.5597864088 13.352175137 +1783 4.9676957316 -2.360559678 13.0451008333 +1781 -2.4638246208 -4.917276642 13.8328755303 +1778 -0.398208388800001 3.3306572892 13.5891141417 +1775 -2.056225248 -2.4112446852 13.7644078019 +1777 4.411646754 -1.5380616288 13.1727099525 +1779 -4.4174608164 1.5962325696 13.7654563521 +1782 -0.3537449904 -1.6434240336 13.9572090066 +1776 2.7426501768 -3.6906544524 13.358695243 +1774 -1.6808996964 2.1462050484 13.6251027113 +1780 1.056754338 -1.1192739924 14.1620399907 +1790 -0.2421544356 4.6025507844 13.520200097 +1786 -2.4848505072 -1.5253256004 13.9428029408 +1788 -3.8497149456 -2.727687546 13.5585112951 +1784 0.318132816 -4.5655278768 13.671920669 +1787 4.1663164704 -2.4832127388 13.6812272286 +1791 -2.1877421556 2.9723887836 13.9644453304 +1789 1.5986737692 5.26273103568 13.3451004162 +1785 1.5189274248 -1.8592798296 13.6734524224 +1795 -2.0232963132 5.11438754652 13.598745541 +1802 -0.8925032352 -4.6269749832 13.3868250801 +1796 4.7646431076 2.7478588812 13.5560568205 +1797 -2.5747089036 -0.5293845108 13.9512860226 +1792 4.7689225032 -0.8725198932 13.8277537165 +1794 0.85727064 5.43229645608 13.9942765746 +1798 -2.3005295328 3.9196958412 13.6648226858 +1800 -1.1670983592 0.00675538920000029 13.7148162928 +1799 2.90516253 -2.2574699976 13.6579903757 +1793 -3.1607543292 1.2420672348 13.735806275 +1808 -2.3221916172 1.5907015416 14.1542558535 +1804 3.2420563848 2.1274197372 13.7390762697 +1805 2.8462232604 3.781380072 13.5309756195 +1801 -2.5573617912 0.4702958808 13.9359812854 +1809 -0.9927032772 0.445561447199999 14.5967686116 +1806 -4.3098917796 -1.7399357004 13.7067696662 +1810 5.47840554 0.487727094 13.4808338945 +1803 -5.44003637148 -0.8105133024 13.7654020029 +1807 -1.630039818 -4.3648217184 14.0171684316 +1814 -1.346576964 -1.7501564496 14.0075780825 +1818 1.5317326032 3.0945121908 14.1403937571 +1815 -1.2230444532 4.5229290324 13.6975690336 +1811 -0.0186439487999994 -5.4999865704 14.1450355328 +1812 -3.9121683924 2.9055891852 13.7279107052 +1813 3.7902663072 -1.0776356664 13.8065292472 +1816 1.6683379716 -5.23969596 13.7386024657 +1823 -3.798131034 0.5939822388 14.1518112834 +1817 -0.2043622752 2.5836707412 14.2255294074 +1827 -0.0620703971999994 5.49985277628 14.3818135359 +1820 -5.38137568464 1.1361390084 13.9594883343 +1824 0.8473717704 -3.729753396 13.9375179492 +1819 0.336010569599999 4.5838421004 14.3356121651 +1825 3.6519502572 1.0278533556 13.9937923794 +1821 2.535923094 2.1822597816 14.6766322903 +1822 -1.1659196076 2.888703474 14.0531027233 +1826 -3.1921647264 -2.218265796 14.1132905966 +1832 5.05467045 2.1681782232 14.3172560142 +1834 -3.0504186492 2.4516777936 14.1426632175 +1830 -2.0686395348 3.2299737468 14.9232775376 +1828 2.815689114 0.4960651536 14.1265976039 +1836 -4.2974794308 -3.4331433624 14.1071839097 +1833 4.3410700752 1.694701164 13.5383560592 +1831 -0.3651343716 -3.841105974 13.8464661907 +1835 -5.10992201436 2.0351548428 14.3374372405 +1829 -1.1331356412 5.38206942288 14.6185805309 +1840 2.2211712144 -0.3942262404 14.1832671136 +1844 -3.9288702528 3.8491804764 14.0582035284 +1838 3.765385074 -4.008999798 13.62554873 +1837 -2.857744836 4.69938786 13.9609399062 +1841 -1.8558353112 -3.3518945724 14.0381681726 +1848 2.1223038132 -4.3472925372 13.78711732 +1842 0.2873448072 3.450491862 14.3069616706 +1843 0.151567941600001 1.652239002 14.1117460712 +1839 -3.557895336 -0.3699810444 14.0400963943 +1845 2.722444128 2.9281151844 14.0372949305 +1850 4.3646584884 3.3468397656 14.2496920877 +1849 2.40009843 -1.409693736 13.819714626 +1846 -0.9185447148 -3.1643092008 14.3318378159 +1852 0.1681652148 -2.9671972008 14.2994617445 +1854 1.2742613484 -0.164663554800001 13.9586808401 +1851 -3.6344187396 -4.128109956 13.8107661164 +1853 -5.49882346956 0.1112623428 14.1484313813 +1847 2.551082496 1.451283792 13.9945525428 +1858 -3.9735110544 2.1966910464 14.4305273358 +1859 0.9437329164 -5.4186936624 14.4040901762 +1860 -2.6391251028 -3.857286408 13.6763221668 +1856 -3.0123303528 3.4805466804 14.212676423 +1855 3.6707332536 -0.106864376400001 14.0145808399 +1861 5.207084832 -1.7712556512 13.8165469964 +1857 3.029266386 4.5908217864 14.0885856736 +1862 -3.3230915172 -3.2827145424 14.2734767943 +1863 -2.088637032 5.088017127 14.5962206401 +1871 3.244573056 -3.3191298876 14.1400884009 +1868 1.0035238956 1.1956813884 14.368101743 +1867 4.3860844284 1.4539095204 14.5238490352 +1869 -0.8993587632 -0.9467679288 14.424393248 +1872 1.1664921324 -2.8211624244 14.2069666942 +1865 -1.8556482216 -0.0342990815999995 14.4388108303 +1866 -1.1948094804 -3.9850708572 14.8333614765 +1864 -1.5074962356 1.3758763332 14.7972899664 +1870 -1.8569442996 -1.1525629176 14.6259653075 +1876 2.2539396084 -5.0170418064 14.5178709673 +1881 0.5306502192 0.3013702824 14.4380273735 +1873 1.8166231248 0.6485385768 14.1694124975 +1875 -4.6577335056 2.9251470912 14.3960323648 +1874 0.7531499292 2.5901223948 14.5136122183 +1880 2.1011621532 -2.4659312928 14.2146589753 +1878 1.3965654228 -4.4860841328 14.4606346164 +1877 -0.7584479388 -2.232275184 14.6567831918 +1879 -1.8010355184 2.3129407824 14.6088237769 +1889 3.8207087256 -2.6469651624 14.6051213787 +1886 2.180091354 -1.3292305668 14.7916896707 +1890 4.3299729924 -3.3914276016 14.1729605467 +1888 5.4940238904 -0.260724978000001 14.1434717719 +1887 -3.453659202 -1.296872232 14.3999839472 +1885 -0.8464246464 2.1249533508 14.8397072509 +1883 -3.0904098384 0.1814533188 14.7309263413 +1882 -3.3792296316 4.3394558172 14.7344684757 +1884 0.183882073199999 -1.1602459116 14.6482523607 +1899 3.440689716 1.7559383868 14.6458564575 +1894 0.550725872399999 -2.0363551572 14.1225121852 +1897 -5.25678040944 -1.6179588072 14.3277890268 +1898 -4.4787582324 -1.0761840624 14.6453679037 +1891 1.3297397256 4.5783144096 14.226383631 +1896 -0.322971412799999 1.1489608824 14.8346563713 +1892 -0.3036101868 -0.245250866399999 14.8153272358 +1895 4.084133796 2.3878539312 14.211555122 +1893 3.0265405524 -0.9306651756 14.434977795 +1901 2.1241381584 1.27866804 14.8821907483 +1904 -4.5956804844 1.0289237688 14.5692995147 +1900 -2.5091865408 -2.7853274472 14.5735663361 +1908 1.384318302 -1.920720306 14.6624171938 +1902 2.2520088792 3.7603012392 14.33498218 +1907 4.5582610968 -0.139318873200001 14.4741886441 +1903 4.7280440148 2.8100675388 15.0109798825 +1906 4.3528830984 -1.7146000044 14.3332868055 +1905 0.7443579708 -2.8763636544 15.111691706 +1915 -4.450792356 -0.0838816187999996 14.5248393457 +1913 2.1876386904 5.04642342888 14.4688211708 +1916 5.3781634272 -1.1515734324 14.5824569656 +1914 -1.0039703184 -5.407955172 14.0011227448 +1909 3.2427007788 3.6790120272 14.4440685264 +1911 -3.444417396 2.305203786 15.2729866931 +1912 -2.3861037684 4.1342102112 14.6377042542 +1910 -3.7532108484 3.1165163148 14.7768025965 +1917 -1.23699666 -0.347656490399999 15.1591780671 +1920 -2.3624016624 0.8587687104 14.8365139812 +1919 -0.5457340044 -4.6311061308 14.432209464 +1925 1.0699087572 1.8860381088 15.347623251 +1922 -2.7482425944 -0.7914460632 14.900367372 +1924 0.4256032068 -4.6051829388 14.6671416248 +1926 -3.8261267808 -3.9513149688 14.8207697477 +1921 3.7076605416 -4.0626111036 14.6223785703 +1918 -0.531863232 4.0325166036 14.2889602837 +1923 1.5185357136 -0.583385496 14.8687918508 +1931 -5.08260674832 -2.1016281528 15.1854701033 +1932 -0.760985016 3.2642188452 14.886570729 +1928 4.0077860844 3.7666559448 15.0841253187 +1933 -4.85983544928 -2.5754789112 14.333553824 +1930 3.0590552256 -4.5709184316 14.0559312718 +1934 5.438714352 0.819270149999999 14.4243796948 +1929 -2.5742770128 1.8493031568 15.0865917717 +1927 1.607768754 -3.5417137308 14.7605181136 +1935 -1.50188415 3.7916369664 14.3205697251 +1938 1.1212767732 3.7604211768 14.7632669301 +1936 2.5308915108 -3.873966288 14.5674428844 +1944 -2.3227200456 -0.00309963000000035 15.3443489256 +1939 5.4997322568 0.0599703252000001 15.0905773115 +1942 -5.45576044068 0.6980093616 14.9569520843 +1937 3.0457079424 0.9111717768 15.0067110306 +1943 0.153125014800001 3.0047036892 15.1976463825 +1940 1.320945432 5.3390956206 14.8753005178 +1941 2.710194852 4.3455940392 15.0039213406 +1949 -2.7132990504 -1.7904365988 14.8795654482 +1953 0.57536343 1.0198642632 15.254503405 +1948 -0.1186342728 -3.7792954788 14.8134873765 +1945 -0.4216067448 4.7686938792 14.9615012661 +1946 -0.3499481076 -2.9158395576 15.2615158778 +1952 -3.711990234 -0.549526219200001 15.0120096095 +1950 2.7850504008 -2.8021606524 14.8621352456 +1947 3.2440844856 -0.0838292772000004 14.9200880468 +1951 5.2144211376 1.7496778848 15.2111111085 +1957 -3.0837623376 -4.5541772964 14.5284281661 +1955 3.1403259936 -1.9151463384 14.5675563227 +1961 0.7901455908 -3.8674671708 15.2349836505 +1956 -1.4187071136 2.6535264084 15.4676676758 +1962 -1.1330521332 -1.4991744456 15.2243622352 +1958 -5.03512179912 2.2132027632 15.3184656492 +1959 2.300789952 0.2468137908 14.9466019252 +1960 0.126868651200001 2.017344936 15.042363399 +1954 0.195750890399999 4.001696388 15.1361235066 +1965 3.9767203116 0.5909268996 14.8322792944 +1964 -0.660605268 -3.7815240744 15.6537515525 +1970 0.938595461999999 -1.2784934172 15.293439467 +1971 -4.1075926848 -2.0056817496 14.6641064923 +1969 -4.4597549184 -3.21902388 15.0702553328 +1967 0.611365066799999 -0.3355395048 15.2083212542 +1966 5.1409187892 -1.9549228116 15.1285043297 +1963 -4.5522694908 3.0868313364 15.3771451183 +1968 3.3531758256 2.7468145392 14.7917772984 +1973 3.0438583752 2.024629938 15.5234474979 +1972 -2.2730281836 -3.990152916 14.6851151706 +1975 1.3153726764 0.3782969712 15.0527218971 +1980 1.1401788108 2.9560349124 15.3598137685 +1979 4.8609158316 -2.5736328372 14.3947019161 +1976 1.5539444568 -5.2760131488 15.1833431716 +1977 -1.78013751 -2.1440742576 14.8178639906 +1986 -1.669278036 -3.1209322524 14.9998922458 +1974 -0.767706204 -5.4461659236 14.9719557247 +1978 -1.5291611928 0.5995258392 15.4270245802 +1989 0.0529691327999995 1.54926402 15.9229315182 +1981 4.1951898492 -1.6929915528 15.3204734355 +1983 -3.4558355172 -1.7602023564 15.5484759121 +1997 -1.0059580764 -0.8623643928 15.9847594372 +1982 4.145972916 2.047219248 15.2921145518 +1984 2.5397127516 -0.615586062 15.3926139075 +1985 2.9943068532 -4.6135676976 15.0554091259 +1987 -0.4772765868 2.4326852604 15.7224014896 +1988 -3.9188931636 3.859075734 15.4257615534 +1992 1.7261809968 4.46326185 15.1371756342 +1996 3.263793678 -1.303902546 15.349239808 +1995 0.220574916 -5.495668254 15.1159128334 +1994 -2.9947575684 -3.5154547476 15.1888567417 +1990 -3.3913090644 -2.611012254 15.0110747022 +1991 2.0725300056 3.0156415308 14.9778221864 +1993 -2.9682770484 3.5581444356 15.2112744506 +1998 -3.4101788184 1.411983516 14.6891468756 +2002 0.148598848800001 -2.0759616588 15.0476777507 +2004 4.50619083 -3.1534956552 15.1280662377 +2000 -1.8800660112 1.5016102008 15.7166015942 +2001 -2.7066672384 4.7880842172 15.3228784558 +2005 -5.44713333672 -0.681594584400001 14.7569284717 +2006 1.8422008872 -2.6562459936 15.1615494245 +2007 3.5279909184 -3.3278840004 15.2763759572 +2003 -1.8133731528 -5.1925764192 14.5472882189 +1999 3.2901789744 0.4344228348 15.8510244297 +2011 -4.1769213048 2.3605885776 15.9529479998 +2012 -0.2123190396 -1.294441542 15.5564934173 +2016 -5.3688896634 -1.1939343204 15.612102076 +2014 2.0414241936 2.033275668 15.5328787798 +2015 2.5561671432 -2.0069211684 15.4235010644 +2013 -4.206562272 1.6587627228 15.2412900828 +2008 -0.5451409908 0.4392319836 15.5030805506 +2009 -0.2680513032 -4.6680543924 15.3921130529 +2010 -2.0205274212 -0.925223814000001 15.585915136 +2019 1.7572170468 3.653823948 15.7233666529 +2017 2.3720410332 4.96241120136 15.7146196681 +2022 2.9778407076 3.4600926732 15.3836007939 +2021 -0.8881641756 1.4701354152 15.5943224879 +2020 3.9669632472 -0.888494982000001 14.7723070664 +2025 -2.4214821648 -2.7899566236 15.5696663217 +2023 0.876911553599999 4.5098546196 15.6628929286 +2018 3.8324436036 2.9263708272 15.6508183666 +2024 0.5082117624 2.451869982 15.9513724496 +2027 3.978603366 1.1367587952 15.6700538232 +2030 5.3070353892 -1.4442333216 15.9719397468 +2029 2.3421568164 -3.46849854 15.4618512605 +2026 4.8612953556 0.8147386608 15.2407970309 +2034 -5.4993551292 -0.0947209752000004 15.5648497153 +2032 0.237391882800001 -3.4768174356 15.9709549512 +2033 -3.3108127044 4.3918848012 16.0142371729 +2028 -3.8829284676 0.6265555596 15.1475424062 +2031 1.4751775512 2.5223646348 16.1962488741 +2040 3.8664400668 -2.525031858 15.7670240304 +2036 -3.0532671576 1.0230190416 15.5405042094 +2038 2.3671905216 2.8897302804 15.9329470044 +2037 0.538447016400001 -1.5392309772 16.171975778 +2035 -1.1812995636 -2.4466714836 15.5593254533 +2039 1.1485175604 -2.170593438 15.6933680025 +2043 0.393412602 5.27845363476 15.2440358706 +2041 4.7902609752 -0.8665938792 15.3394674486 +2042 -1.3830095784 4.4994321096 15.0165308944 +2048 -2.4776079768 -4.9104494856 15.2394039715 +2044 4.0564458852 2.0344157424 16.287986117 +2050 2.9163259104 -2.793501408 15.9250146283 +2051 1.48265442 -0.430984238400001 15.856349774 +2047 -2.5057557528 -1.8357410304 15.8566530997 +2052 1.4096502084 -3.3074946408 15.7850332727 +2046 1.5508600524 1.0898438532 15.7145842475 +2045 2.001765624 -4.3844339412 15.2500375791 +2049 -2.2924364688 0.6684101352 16.0846481549 +2058 0.8316738252 0.324819097200001 15.926222658 +2056 -1.5857661396 -5.2665048576 15.5182086591 +2059 -2.589131622 2.7079332036 15.5989225252 +2055 -4.394872146 -1.4180974812 15.5812369136 +2061 0.7693156164 -4.8038206008 15.5849268405 +2054 -0.105000732 -0.363477248400001 15.905349459 +2053 0.6984339288 -0.5888010108 16.4563611197 +2060 -3.2717983116 0.0251650140000006 15.701796329 +2057 2.5382898312 1.212258816 15.8139845354 +2064 2.229451884 0.233296362 15.9438353731 +2065 -1.8417897876 -4.209388686 15.5620297135 +2063 1.4456123076 5.30664899568 15.8669367421 +2062 4.0777510152 -0.176357892 15.4654605874 +2070 -0.5750404476 -5.4698565672 15.9528864214 +2066 3.118329192 2.3266992696 16.4737431266 +2069 -5.33352037116 1.34330709 15.7110263558 +2067 2.8549234536 0.00549161040000001 16.6900188984 +2068 0.565480820399999 3.5342184288 15.9389576564 +2076 -3.9243713988 1.105012866 16.0246451997 +2071 -1.5494945808 -1.6938873804 16.112297151 +2073 -1.086240966 4.495788384 15.971389038 +2074 -4.7356516836 0.5432593572 15.6628959945 +2075 5.4736889592 0.53933349 15.981623812 +2072 -0.4385938908 3.5750716932 15.7806441997 +2078 -0.0319297391999998 0.605239764 16.3450298773 +2079 3.4278395172 4.3011817128 15.6988322857 +2077 -4.2206970996 -2.4025780584 15.5955364541 +2084 3.3260542884 -0.5526457104 16.007018392 +2088 -3.4671486504 3.0643713744 15.9234114509 +2086 1.833073242 -1.3839709332 15.7279086086 +2087 4.084610484 3.683567226 16.253232265 +2082 4.4942027892 0.4251202668 16.1471531077 +2080 -1.4073270228 3.6504946056 15.5443973103 +2081 0.2312468472 -2.4769849428 15.9598806817 +2085 -5.07715234524 2.1149045508 16.3126532448 +2083 -2.0870623668 4.2798379368 15.9208433551 +2097 -4.55912835 -0.4330737696 15.5301420905 +2096 -1.8292133196 5.18713533708 15.5888437649 +2090 -0.630357851999999 -2.958165966 16.220428964 +2094 1.436355024 -1.7673222072 16.5619508118 +2091 -0.8561776368 5.43295238592 15.5780799573 +2095 -4.56198102 -3.0722500416 16.2550703883 +2092 1.9857364944 0.944471064 16.6032286107 +2089 -2.8334088768 1.8520255188 16.0546540553 +2093 -1.9317683964 -2.5676874276 16.4127351359 +2103 1.61736174 4.4357155872 16.3308285262 +2105 1.3947919896 -5.3203055964 16.1695789293 +2102 4.8606015972 -2.57408973 15.8620074011 +2101 1.9893873744 -2.482917114 16.1352738736 +2100 -2.0821622064 3.3210942012 16.204672997 +2099 -1.064603358 -4.60326921 16.0552162031 +2106 5.4807619032 -0.459898458 15.9445760871 +2098 -1.5110482284 -3.3534740856 15.9594657498 +2104 -2.9816917608 -0.937365017999999 15.8616133477 +2115 -4.3328854584 3.387872604 16.3050887643 +2111 -2.2668975456 -1.137633942 16.5315975338 +2108 -1.1723921544 0.8513313072 16.3265980957 +2107 -3.2906131128 -4.407053304 15.531653387 +2112 -0.5894774028 -1.95920757 16.2012937583 +2109 2.291131944 -0.7480456128 16.3520457911 +2114 0.391068823199999 -5.4861255336 16.2104502283 +2120 -1.077243084 3.0335351652 16.3272396903 +2110 2.4691870668 -4.9146646368 15.9572612933 +2113 -2.5159066512 -3.6592394688 16.0548648925 +2121 0.969521026800001 1.641548142 16.3125629728 +2118 -0.591755214 -3.8672545776 16.6476334757 +2116 -1.9291163856 2.3349537036 16.266928282 +2117 -0.795940176 -0.0464956619999999 16.5549268101 +2122 4.9081536492 1.3582947432 16.0788180438 +2124 -3.9123593196 -0.798039817199999 16.1998176065 +2123 0.8711827344 -3.78459057 16.6805232977 +2119 3.115053156 -4.0289876892 15.857639932 +2128 3.1600130928 3.3197844396 16.3644692023 +2132 -3.1977264468 0.6148029144 16.5059610112 +2125 1.4801858448 -4.3263137016 16.1012093345 +2127 -4.011862866 -3.7623869016 15.7849591548 +2126 1.021062 0.7705505952 16.8010766526 +2129 -1.0117672644 1.9795803168 16.4458412883 +2131 3.3338763948 1.3527853692 16.4032138393 +2133 -1.682437578 -0.1351759404 16.1009043844 +2130 2.5487274264 4.0836391932 16.1577741789 +1251 1.2544103472 -0.0415785071999997 10.3361543571 +2136 0.1459127376 -4.426700778 16.2697892069 +2135 -2.6202246108 -0.206614774799999 16.4406500407 +2142 -1.9376729136 1.3710641052 16.7063006874 +2134 -1.64171805 4.442805642 16.8011929398 +2140 2.377869048 4.9594526916 16.7145532315 +2139 0.777577017600001 2.6574435588 16.8998566584 +2137 -0.0869578859999995 4.519007256 15.9436799298 +2141 -3.8609465328 -1.9912284756 16.4329852597 +2138 1.6637851968 0.00718364400000038 16.7367781669 +2145 -1.3470213708 5.33257579152 16.4526984759 +2151 -2.8030437624 2.7066949044 16.5798605906 +2148 -3.6497235456 1.8502238952 16.6322566325 +2150 0.990381536400001 -2.7897315444 16.5307287681 +2143 2.2956588804 -3.8271996348 16.394123824 +2147 -2.260931724 -3.1366654872 17.1663154317 +2144 4.6406707848 -1.8970269948 16.5642410112 +2149 -0.0223980600000004 5.50003851816 16.1260667465 +2146 4.5385092948 -0.570277844400001 16.2607618798 +2152 2.3405088972 -2.0062947072 16.9411651101 +2157 -4.7460568872 2.779387872 16.9825731307 +2153 0.0898368467999999 -3.1227088188 16.8943881902 +2156 2.888286192 -1.5428839368 16.244665539 +2158 -4.7405238792 1.2156100992 16.5917460929 +2154 -0.0706422108 3.143601282 16.6042901499 +2160 3.7170240768 0.505577292 16.7711767279 +2155 2.2830956232 3.3955706472 16.8389336356 +2159 3.4029322356 4.3208972568 16.6982851011 +2163 -4.402586154 -0.6270591684 17.1376292283 +2162 4.941051324 2.4158242956 15.9049226293 +2169 4.3055093004 -3.4223956128 16.0700137493 +2165 4.632436482 2.9649606708 16.6815215101 +2161 -3.45977301 -2.9453641884 15.9509135256 +2164 2.2077231768 1.9152201024 16.5118150977 +2166 3.8718145332 -1.3659416952 16.2083537262 +2167 -1.4153059836 -0.756047482800001 16.8908960681 +2168 -5.01257709168 -0.3077032344 16.4124744445 +2178 -4.7923342596 -1.2801665724 16.4883864168 +2176 -0.0636243395999996 2.1497189268 16.714030711 +2171 -2.7397602072 0.2771066016 17.3282628603 +2177 -2.6456522256 -4.7590069152 16.2134281069 +2170 -2.8739724528 1.3837633104 17.0571587742 +2173 0.7511336136 5.00541070656 16.5222403884 +2172 -1.8307396716 0.402507649199999 16.930854011 +2175 1.314565788 3.4440496608 16.5951442199 +2174 1.5159705648 5.28696807492 17.1016307108 +2181 -1.2933821784 -3.210985578 16.9250129786 +2180 5.4202423164 -0.9334182336 16.8241075446 +2185 -5.04169131924 -2.1980945916 16.1799192862 +2182 1.6281106824 -0.932264357999999 17.0775541051 +2186 4.6941815148 -2.8662006576 16.8045342283 +2187 2.077901886 -5.092390266 16.8633595276 +2184 1.743554598 2.6152009932 17.1550402853 +2179 -2.9111115252 3.700228038 16.6157420831 +2183 2.8295505408 0.899180844 17.1379379046 +2193 -0.5026962876 4.90034217228 16.7693083083 +2192 3.5467237344 -1.450757466 17.1501953046 +2195 -5.46960211632 0.5787906936 16.3410431192 +2190 0.2261102064 4.2176066808 16.844274545 +2191 -3.4670694144 -4.2696435624 16.506272214 +2189 1.548909024 1.615806876 17.2019361708 +2194 3.0638653236 -3.3085187796 16.7693365865 +2196 -0.7227638412 3.8973303096 16.6852837848 +2188 -1.5904532484 3.4785398628 17.0610741207 +2205 2.9626800768 -4.6338820956 16.780391171 +2199 -3.1666842528 -3.3653990724 16.8096965095 +2204 3.74484054 -4.028240064 16.6343656431 +2201 2.6275265784 4.2026073456 17.3185499341 +2197 -0.2487601584 -1.0917899136 16.5962031737 +2202 3.4195420152 -2.2964123616 16.631859321 +2203 -4.1017130016 0.173487310800001 16.3420752363 +2198 -0.494169852 1.273012746 16.9283792407 +2200 -3.4730890548 -0.308006522399999 16.9527458669 +2213 -1.2751227684 1.7108539824 17.3737764837 +2207 3.6994137888 -0.4812509772 16.9319086496 +2214 -1.7773952316 -4.111288218 16.5550946503 +2210 3.9224719692 -3.2868455928 17.2814782555 +2206 2.764909932 -0.832224656400001 17.2286297686 +2208 2.9542496544 -2.5977359112 17.4641355286 +2209 -3.2272405176 -1.2919744656 16.7637739496 +2211 -0.884942500799999 2.6179964604 17.2162084871 +2212 -0.1111658244 -0.328189096799999 17.2269942861 +2218 -2.6539939428 -0.718893146400001 17.3530339156 +2215 5.1579704364 0.0306515196000001 16.7825704772 +2221 0.0317124851999999 2.836945608 17.5505661574 +2217 2.1253818372 -3.0240872076 16.9650717583 +2223 0.1730730804 -2.1261812628 16.8944527663 +2222 0.720921908399999 3.5442619968 17.3935737409 +2219 0.892734067200001 -4.7718372324 16.8382098755 +2220 -2.5990814964 4.84723734828 16.5655876047 +2216 -3.9045879876 1.0025550432 17.0975059066 +2231 1.0520922684 -2.232988818 17.3590974536 +2227 -5.42618482656 0.8981950284 17.2876356863 +2230 5.117793264 2.0145317676 16.8036303799 +2224 -3.7507290588 2.813602992 16.8805511077 +2229 4.3756433808 1.2436883868 16.9174012758 +2226 -2.9036736876 -2.4012410556 16.5790171643 +2232 3.7138942164 2.8702220112 17.0652046785 +2228 -2.2272259284 2.1852145068 17.2095993615 +2225 0.551530368 1.546736316 17.2218532895 +2235 0.707612122800001 -1.31778306 17.1407673304 +2233 -0.5234006772 -3.5139145752 17.5806029936 +2241 -1.1896622616 -1.7713627092 17.0420327551 +2240 -2.21453058 -1.9345871604 17.1333022731 +2237 -0.944838354 4.405513338 17.5173953483 +2238 0.8607804528 -0.1125125448 17.3205319966 +2234 1.5132550872 4.1439734424 17.2816069179 +2236 3.9778699632 3.7982772876 17.3277967877 +2239 4.4765504952 -1.0818672756 17.1197037883 +2242 -0.2894026476 -5.1193741668 16.8448222375 +2249 3.2558366772 0.1169065572 17.5993125104 +2244 -1.2545351016 -5.3551443144 16.6863704557 +2250 -4.2010015344 -2.661670008 17.0923729421 +2243 -3.0148001712 4.3914236304 17.3525802957 +2245 -1.817131962 -0.2719017912 17.6690372795 +2247 -4.1170454724 -3.646972908 16.9418414898 +2248 -3.8190492672 3.957956766 16.9460863663 +2246 -5.43226279872 -0.8606961264 17.1322024923 +2254 5.2152946956 -1.7466845892 17.3686917397 +2253 2.2294981644 -4.2128526684 17.3143749254 +2251 -1.1246871792 -4.5075249168 17.2008087318 +2255 -0.942191076 0.500837752800001 17.3789278591 +2257 -3.400761246 -2.108248986 17.3957154224 +2258 -5.17387596216 1.8657612984 17.2762447859 +2259 -1.6578092748 5.24422097136 17.3990479472 +2256 -4.2569392836 -1.6078182768 17.2673163674 +2252 -0.3377536848 -1.5142068696 17.498203177 +2266 2.657243064 2.2635919512 17.3588173655 +2261 -1.7399744112 -1.2681247356 17.7082672308 +2268 3.736357332 0.992728536 17.6442570947 +2260 0.1846184472 5.49692462088 17.1836223039 +2265 -4.6043620584 0.3309995628 17.3409905055 +2262 -0.63185412 -2.5607010168 17.2984540942 +2264 3.6540497112 1.8799314408 17.1903182171 +2263 1.088738754 0.9209600988 17.7873600015 +2267 -2.128579716 1.048721238 17.6334600427 +2273 -0.3403486584 1.9174652592 17.6773490119 +2274 0.180240840000001 0.6236567292 17.3220519018 +2272 -2.1028228488 -4.9528249104 17.0305733819 +2275 -0.861832096800001 -5.4320636784 17.6027919101 +2277 -2.0932394196 4.1249854932 17.634911534 +2270 1.4639130276 -3.5865151488 17.4611570951 +2271 1.9759376892 0.5450173236 17.5199007497 +2276 1.9283398068 3.3787886208 17.7737245709 +2269 -2.498436444 3.2139989628 17.3859739483 +2278 2.3217516252 1.4370805932 17.8108213254 +2284 -3.56167812 -1.0072208124 17.6621291837 +2279 1.1141385312 -0.861752061599999 17.9324434549 +2282 -5.032879296 -2.218252692 17.4260545892 +2283 -0.8826071184 -0.710084329199999 17.7359262771 +2280 -2.7287478012 -4.1865683028 17.175561253 +2285 2.1666742692 -1.4421624504 17.7483209668 +2281 0.6474156312 -3.071943834 17.7229265387 +2286 -2.5196029164 1.8410195196 18.1017988388 +2295 1.9479520476 -2.4361332924 17.7542503058 +2291 2.0679015756 -0.4084321512 17.8070410211 +2292 2.9599032732 3.2930254248 17.5678907368 +2290 -1.5814446468 -2.543305962 17.6114380333 +2293 0.2461887564 0.000369817200000178 18.1012467226 +2288 -0.3924155616 0.9926299908 18.0541020001 +2287 -4.207197372 2.067795306 17.4334072591 +2294 0.485183086800001 -1.7403897708 18.0193502499 +2289 -3.1903056576 2.2359216336 17.4739565518 +2296 4.1209930668 -2.248496688 17.3429404086 +2299 -4.4000594484 -3.2999491464 17.8359637173 +2298 -3.4378719816 -3.0533963916 17.7202254312 +2300 3.2293792824 -3.9817339944 17.4900057943 +2297 4.4747238468 2.3719185816 17.4809041881 diff --git a/contrib/voro++/examples/walls/pack_torus b/contrib/voro++/examples/walls/pack_torus new file mode 100644 index 0000000000000000000000000000000000000000..56674a1587df605c09e5ef5e449b55a89866a775 --- /dev/null +++ b/contrib/voro++/examples/walls/pack_torus @@ -0,0 +1,2393 @@ +781 -2.98183 -10.5796 2.24335 +1701 -3.51002 -11.1007 1.42227 +94 -3.96031 -10.4655 2.04987 +2300 -2.22896 -11.34 1.57513 +1432 -1.8873 -10.7017 2.31215 +1531 -1.66817 -10.5435 1.33447 +1231 -0.889531 -10.7236 2.39495 +2149 -0.226391 -10.902 1.4864 +990 -1.24004 -11.3748 1.72034 +1646 1.09538 -10.9135 2.19743 +1199 1.54164 -11.5193 1.34014 +886 0.12941 -10.7553 2.41071 +108 2.08174 -10.9724 2.02286 +136 3.519 -11.0337 1.43927 +1371 -7.90924 -8.26861 1.73918 +633 -6.8519 -9.1683 1.73708 +1061 -5.93676 -9.71229 1.79833 +1827 -6.06384 -8.8245 2.25296 +1752 -7.07273 -8.35766 2.28068 +408 -6.37913 -8.11831 1.60049 +1662 -6.21866 -7.96463 2.74195 +643 -5.31418 -8.46363 2.82031 +2302 -5.3296 -8.89543 1.57291 +615 -4.91424 -10.1853 1.91134 +43 -5.16195 -9.38735 2.46092 +217 -3.83667 -9.66755 2.64485 +903 -2.84735 -9.73499 2.76783 +591 -3.22378 -9.41092 1.89618 +201 -4.64817 -8.23416 1.99909 +250 -3.33874 -8.78378 2.92974 +1208 -3.67422 -8.14058 2.21274 +455 -4.44002 -7.86742 2.91154 +1924 -4.25336 -9.14902 1.89488 +2072 -4.39891 -8.86794 2.85592 +54 -2.7452 -8.52324 2.15534 +564 -2.77558 -7.87972 2.92153 +2286 -2.92975 -7.89256 1.36408 +1787 -0.335562 -9.96527 2.00466 +657 -0.846715 -9.83527 2.85864 +1839 -1.32228 -9.81949 1.93289 +1882 -0.321583 -8.98996 2.99757 +1770 -1.8479 -9.82784 2.82723 +811 -1.33054 -8.96966 2.98928 +1641 -0.801643 -8.98198 2.11966 +2101 -2.32134 -9.84416 1.92345 +703 -2.3313 -8.90648 2.98824 +1084 -1.80215 -8.07363 2.79827 +1944 -1.8058 -8.92994 2.05467 +162 -1.25343 -8.09496 1.94636 +464 -0.807162 -8.12452 2.88239 +981 -0.351271 -8.29799 1.51569 +2248 0.664308 -9.98861 1.89073 +573 0.232936 -8.99645 2.15035 +1300 0.163775 -9.85674 2.86424 +1856 0.286314 -8.1949 2.88373 +854 0.790578 -9.05331 2.99115 +185 2.32173 -10.154 2.60869 +710 1.15026 -10.0673 2.76996 +807 2.2443 -9.24316 2.05191 +1510 1.22337 -9.13248 2.06471 +109 1.76695 -9.273 2.95422 +822 0.835583 -8.20977 2.00662 +86 1.84129 -8.32203 2.07376 +563 2.26936 -8.39161 2.97813 +1241 1.28725 -8.17292 2.90546 +395 1.66129 -10.0606 1.81674 +736 3.40283 -10.2226 2.38885 +1190 2.77009 -9.28619 2.90151 +663 3.24097 -9.22698 1.92123 +954 3.75878 -9.3588 2.77061 +456 5.12281 -8.74073 2.77731 +1184 4.57937 -9.34254 2.19094 +441 3.27106 -8.41962 2.99639 +2201 3.42447 -8.14977 2.00532 +578 4.18169 -8.47151 2.57998 +2319 2.74477 -10.2854 1.62836 +824 4.21122 -10.3933 1.81674 +782 5.16862 -10.0858 1.87124 +397 2.65287 -8.50968 1.46746 +2033 4.27189 -8.46532 1.57392 +669 5.72536 -9.33188 2.22973 +1018 6.66406 -8.97928 2.00681 +2020 5.30839 -7.96268 2.12165 +116 6.99223 -8.12901 2.42569 +817 6.06711 -8.45693 2.62134 +2041 5.21633 -8.79404 1.5569 +151 6.04956 -9.90849 1.42925 +1587 6.24722 -8.07373 1.71153 +422 7.87826 -8.08795 1.89031 +1147 -9.69987 -5.94751 1.33788 +670 -8.61947 -7.56523 1.70468 +1211 -9.30392 -6.83264 1.59071 +942 -8.01034 -7.20542 2.42756 +920 -9.36444 -5.72525 2.25295 +178 -8.52302 -5.51175 2.76967 +813 -8.72751 -6.49191 2.33755 +1589 -7.85912 -6.28236 2.80452 +667 -7.9494 -6.85424 1.48923 +1703 -7.86772 -5.66269 2.02116 +1269 -8.70816 -6.04217 1.44087 +2215 -6.55949 -5.27416 2.93713 +1865 -7.20342 -6.60983 2.12403 +1691 -7.23581 -7.53078 1.68174 +225 -7.08384 -7.4517 2.70295 +1980 -6.97064 -5.64722 1.57078 +1169 -6.87839 -6.21976 2.98767 +689 -7.56133 -5.34491 2.98756 +348 -6.23669 -6.99237 2.97383 +2032 -6.35036 -7.18842 1.99583 +1407 -5.35603 -7.47096 2.97796 +434 -5.52366 -7.75045 2.01115 +131 -5.48714 -6.74268 2.30519 +123 -6.2776 -6.19144 2.04142 +801 -5.40772 -5.68103 1.8402 +1845 -5.86272 -6.06822 2.94763 +714 -5.64789 -6.52092 1.33743 +1620 -4.68098 -6.377 1.83538 +1365 -4.2296 -7.27263 2.08002 +576 -4.60374 -6.80979 2.8845 +1989 -3.7173 -6.38951 2.52928 +419 -3.31104 -7.05302 1.75214 +2106 -3.60317 -7.32261 2.86625 +1760 -2.73631 -6.92571 2.56037 +1394 -4.90329 -5.87903 2.68995 +1773 -4.12123 -5.55065 2.15763 +1121 -2.90988 -6.1111 2.00163 +1857 -4.93859 -7.22851 1.38235 +1540 -3.76531 -6.2025 1.48703 +1014 -3.53908 -5.23748 1.35379 +1366 -2.22766 -7.59677 2.01289 +2102 -1.90769 -6.59671 2.1081 +1951 -0.224595 -7.62234 2.24224 +1461 -0.823258 -6.62995 1.89465 +1502 -1.26858 -7.27236 2.51873 +532 -1.49902 -7.21682 1.43903 +1481 -2.14226 -5.95998 1.37426 +804 0.733158 -7.36499 2.53733 +1260 0.179999 -6.7454 1.98159 +1258 0.756527 -7.36669 1.45288 +800 1.73157 -7.32389 2.60533 +690 2.47221 -6.7432 2.25911 +2222 1.5472 -6.51485 1.92581 +868 1.74576 -7.44132 1.60196 +2324 3.46963 -7.05337 2.1292 +1386 3.7684 -7.55047 2.94341 +2053 2.79902 -7.62272 2.61209 +180 4.3157 -7.6062 2.09651 +1529 4.74604 -7.75793 2.99524 +1048 3.22067 -6.08468 2.10581 +1920 4.14624 -5.73902 2.28652 +538 5.03497 -6.99006 2.4128 +143 4.15191 -6.645 2.76071 +1604 4.97133 -6.05311 2.75899 +2112 2.74331 -7.52537 1.60852 +262 4.96534 -5.77001 1.62077 +1755 4.32224 -6.59406 1.77549 +471 3.54473 -5.34285 1.51491 +1738 7.73208 -5.41765 2.9637 +308 6.44651 -5.28761 2.01888 +460 5.84554 -5.5729 2.85196 +355 6.68901 -6.09278 2.99908 +196 7.34938 -5.77248 2.10903 +6 7.62438 -6.40427 2.83464 +533 7.61545 -7.35421 2.51709 +997 5.9441 -7.17226 2.03923 +2345 5.72772 -7.56482 2.94452 +1246 6.67127 -7.23677 2.83862 +2384 6.72545 -6.55255 2.1121 +1762 5.84481 -6.08482 1.98739 +722 5.81272 -6.56949 2.92713 +2289 7.00881 -7.42302 1.71273 +1826 5.26473 -6.71254 1.46375 +1640 9.7302 -6.14014 1.60701 +1224 8.52186 -6.04143 2.57922 +1170 9.3191 -5.50998 2.29084 +1323 8.20597 -5.2585 2.03971 +2366 8.75158 -5.87981 1.47727 +1909 8.0022 -6.63604 1.93624 +152 8.99926 -6.70299 1.99294 +215 8.68393 -7.56654 1.5994 +919 -10.5057 -4.27044 1.8768 +134 -11.2126 -2.89086 1.52905 +190 -10.5515 -3.26623 2.18553 +1647 -10.108 -5.18583 1.85086 +2356 -7.99923 -3.49414 2.97911 +758 -8.75192 -4.03916 2.09647 +637 -9.47976 -4.46269 1.55699 +729 -8.63585 -5.01661 1.90843 +2254 -9.36718 -4.77221 2.56447 +774 -8.46045 -4.52427 2.92148 +2164 -9.76515 -2.90876 2.69858 +2309 -9.83859 -3.89178 2.52123 +44 -9.21475 -3.1733 1.90629 +1934 -8.99782 -3.51268 2.91544 +1563 -8.23109 -3.11806 2.07952 +1706 -9.96257 -3.58743 1.38748 +1777 -7.46137 -4.33741 2.97244 +909 -7.75671 -4.12258 2.04117 +696 -7.13555 -4.89077 2.20267 +996 -7.75725 -4.88798 1.38823 +910 -6.14571 -3.3834 2.2496 +810 -6.78078 -4.03926 1.81674 +2322 -7.01865 -3.44604 2.74313 +2361 -6.48091 -4.29837 2.73476 +1062 -7.2557 -3.15923 1.79442 +922 -6.18522 -4.99301 1.85779 +507 -5.60677 -5.14443 2.66091 +51 -5.60225 -4.22746 2.2511 +1550 -4.84144 -4.86985 2.07542 +877 -4.95761 -4.05697 1.50486 +2316 5.07587 -5.1293 2.39364 +1874 4.39797 -4.8595 1.70965 +204 6.75448 -5.09644 2.95349 +731 5.92511 -4.60684 2.59182 +1961 5.26016 -4.20017 1.94981 +147 6.45292 -4.3499 1.65851 +32 5.62279 -5.02334 1.51256 +816 6.88174 -4.10561 2.83164 +799 7.3382 -4.77737 2.20368 +2267 7.36873 -3.92304 1.68424 +2105 6.61403 -3.3218 1.41643 +1429 5.55179 -3.31555 1.58089 +2095 6.14266 -3.65832 2.31356 +1869 6.9162 -3.10623 2.63291 +2221 6.27675 -2.61493 2.03842 +1127 7.6786 -3.02 1.98991 +2218 7.81598 -3.4223 2.94027 +1679 8.70498 -4.90355 2.83514 +22 7.82807 -4.42055 3.00285 +583 8.26593 -4.26146 2.11113 +1446 8.68767 -3.91106 2.95669 +2380 9.06902 -4.74377 1.68848 +1028 9.42763 -3.821 1.84925 +2025 9.58374 -4.52509 2.54366 +1051 10.3119 -3.63847 2.28974 +664 10.1825 -4.97639 1.88605 +1091 8.61839 -3.32766 2.14313 +189 8.6298 -2.80631 3.00843 +166 9.50987 -2.82893 1.95229 +1357 9.49909 -3.35777 2.80483 +1727 10.3358 -2.65475 2.493 +1763 10.1388 -3.33461 1.34767 +1271 10.9797 -3.04551 1.80533 +199 10.8564 -4.00573 1.54164 +638 -11.0925 -0.144316 2.13476 +1428 -10.8499 -2.20648 2.1662 +1986 -10.5595 -1.53686 1.38019 +1615 -11.481 -1.93567 1.39066 +2372 -10.7148 -1.24526 2.40347 +728 -11.3986 -0.995435 1.71168 +1456 -10.2284 -0.664934 1.74566 +1846 -10.0658 -1.94863 2.72577 +1367 -7.89644 -2.18348 1.95337 +2050 -8.11308 -1.70883 2.89276 +904 -9.69422 -1.50662 1.90046 +814 -9.97582 -2.52239 1.75706 +2059 -8.54951 -1.34663 1.96572 +1943 -9.86086 -0.977458 2.84795 +333 -9.01488 -2.21697 2.13414 +593 -8.59769 -0.793871 2.85427 +1183 -8.6117 -2.57272 2.97852 +2022 -9.13478 -1.66695 2.96117 +1800 -9.30077 -0.0567947 2.95288 +120 -9.26235 -0.63281 2.12417 +2086 -10.2722 -0.0776003 2.70273 +897 -8.59572 -0.355781 1.42454 +557 -7.61437 -0.78287 2.62585 +1292 -6.90476 -2.18788 1.47537 +1010 -7.60616 -2.58191 2.82847 +934 -5.99052 -2.5681 1.68459 +1039 -6.70561 -2.56552 2.38359 +2038 -7.58912 -1.24697 1.70022 +1988 -7.18579 -1.69677 2.51554 +270 -6.62006 -1.11806 1.92024 +0 -7.66833 -0.238212 1.78075 +1071 -6.67744 -0.117933 1.85991 +1497 7.59102 -1.01775 1.84538 +707 6.60192 -0.891464 1.87436 +2055 6.86511 -1.76757 2.31114 +133 7.54742 -0.372238 2.62472 +1798 6.97986 -2.34591 1.37362 +1656 6.19793 -1.74113 1.53356 +416 7.68308 -2.43475 2.84454 +2269 7.694 -1.42207 2.75937 +2168 7.75117 -2.00324 1.90958 +302 7.67313 -0.0791513 1.51488 +1115 8.67372 -2.31336 2.12475 +1319 9.47995 -2.25661 2.90551 +1651 8.50537 -1.33165 2.10689 +202 8.58748 -1.807 2.98976 +2378 8.47372 -0.805341 2.95435 +706 10.2125 -1.01666 1.65455 +1618 10.2469 -1.66009 2.66308 +1235 9.4403 -1.67969 2.07033 +1133 9.39789 -1.2239 2.96294 +987 10.3668 -2.00867 1.73027 +1883 10.1918 -0.659745 2.74245 +2145 9.26312 -0.194878 2.98711 +1586 9.39575 -0.678911 2.12433 +1711 10.1144 -0.0391355 1.85374 +1953 8.46406 -0.328556 2.07589 +517 11.03 -1.34299 2.12954 +2 11.3501 -2.14207 1.57403 +1643 10.9943 -0.342166 2.23515 +2024 11.6223 -1.21023 1.3369 +372 -10.7466 0.765001 2.39921 +478 -11.3802 0.606645 1.53694 +1733 -11.0464 1.59584 1.92827 +52 -11.2659 2.50043 1.56251 +466 -8.78794 0.830154 2.92282 +695 -9.80036 0.811548 2.85341 +2210 -8.11924 0.0948155 2.77179 +1402 -9.28656 1.70035 2.9534 +191 -7.85506 1.22293 2.78888 +1804 -8.68711 2.50207 2.993 +666 -9.75224 2.58162 2.78886 +1959 -9.76466 0.217987 1.88471 +639 -8.28732 0.553234 1.89645 +1789 -10.3196 2.30485 1.86399 +64 -10.2313 1.05209 1.59031 +253 -10.2562 1.67989 2.6428 +1838 -9.1713 1.01459 2.00087 +1277 -9.3733 2.00613 1.9899 +597 -8.41602 1.69873 2.1114 +1927 -7.72799 2.21641 2.84149 +505 -7.29075 0.512239 2.35871 +2196 -7.59094 1.26613 1.72416 +2156 -7.62671 2.28175 1.82279 +331 -6.86214 1.84597 2.31398 +1171 -6.58137 1.00239 1.84737 +1252 7.55896 0.933993 2.64777 +982 6.85334 0.103642 2.08117 +1535 7.14919 1.90153 2.52825 +1947 6.74058 1.09825 2.07032 +948 7.14061 1.82455 1.50603 +1872 7.54374 0.904423 1.50496 +802 6.37555 2.24144 1.99001 +1315 10.1466 0.368723 2.77327 +998 8.32648 0.183477 2.92453 +2352 8.34663 0.722158 2.06788 +431 8.57743 1.14631 2.97175 +1178 10.0739 1.08432 2.06378 +1783 9.30346 0.472987 2.24702 +2280 9.57705 1.17469 2.93138 +2183 10.2969 2.07343 1.51708 +1549 9.02768 1.50975 2.15105 +1457 10.0468 2.03013 2.72216 +592 9.07889 2.09718 2.97333 +559 9.44984 2.3991 1.94074 +353 8.07274 2.00581 2.91251 +1579 8.01578 1.66118 1.97222 +2167 8.48681 2.53643 2.17325 +2274 10.959 0.661754 2.26315 +511 11.5471 0.248222 1.57158 +719 11.4651 1.2433 1.59838 +214 11.326 2.2421 1.5324 +955 10.8507 1.67977 2.25297 +1046 -10.6994 3.21551 2.04913 +926 -9.0263 3.45169 2.89096 +1639 -7.92722 3.231 2.94493 +567 -8.29052 4.20222 2.98027 +1532 -9.93601 3.70468 2.52042 +1915 -9.47574 3.00721 1.92446 +1504 -8.47318 3.75442 2.09429 +19 -8.51902 2.72898 2.02046 +651 -10.2562 4.48063 1.95223 +2242 -9.22571 4.48386 2.66458 +412 -9.45785 5.07449 1.58812 +2336 -9.36553 4.04448 1.74448 +2013 -8.55693 4.85934 1.96332 +932 -6.82443 4.1657 1.78038 +929 -5.51339 4.42094 2.29293 +1672 -7.16875 3.90996 2.88227 +1576 -7.68655 4.4346 2.20787 +809 -5.569 3.55527 1.78312 +724 -7.54303 3.40275 1.9768 +5 -6.95927 2.89943 2.61658 +876 -6.2602 2.60483 1.96034 +671 -6.30063 3.65014 2.4596 +38 -6.37476 4.60446 2.77383 +2110 -7.29131 4.9494 2.98922 +911 -5.77684 4.80993 1.41237 +1881 -4.04414 4.85375 1.343 +1164 -4.87811 4.27676 1.48004 +960 -4.65391 5.0871 2.0987 +53 4.63322 4.46472 1.40101 +775 4.57234 5.16322 2.11656 +745 3.74551 5.16832 1.43168 +916 6.74406 3.02515 2.50411 +211 7.66949 2.92109 2.88775 +1490 6.69706 4.75073 2.88655 +176 7.21357 3.84401 2.85643 +1536 7.51942 2.64315 1.93921 +205 5.76547 5.06607 2.67857 +607 6.27131 3.91202 2.52049 +1070 5.95767 3.18126 1.88916 +236 6.75334 2.9073 1.33913 +2348 5.2004 3.63388 1.38671 +978 6.31091 4.70576 1.90712 +946 5.42256 4.27901 2.12708 +972 7.38971 4.60518 2.15905 +1287 7.23263 3.63802 1.86111 +1822 5.46008 5.18054 1.65199 +923 9.61603 2.93267 2.77292 +574 8.65112 3.09033 2.98796 +595 9.33081 4.89871 2.55425 +831 9.79288 3.88952 2.53599 +631 8.86754 4.06053 2.87893 +853 9.89622 3.34354 1.64027 +233 9.74268 4.39062 1.66478 +1886 7.96271 4.4992 2.97348 +991 8.45447 4.58316 2.10193 +1612 9.00048 3.39577 2.08361 +445 8.08402 3.68299 2.38397 +1011 8.16016 3.25856 1.481 +1919 8.86097 4.05038 1.33725 +1765 7.88074 4.25273 1.35248 +1463 10.499 2.8362 2.29148 +851 10.7389 3.91786 1.70549 +2107 10.5798 4.85891 1.34484 +751 -9.5553 6.05395 1.78564 +858 -8.59021 5.81886 1.67278 +61 -9.13068 5.48086 2.49858 +177 -8.25784 5.20173 2.89968 +674 -8.23397 6.19195 2.69708 +896 -8.80455 6.716 2.06402 +409 -8.10985 7.43862 2.19965 +362 -7.28959 5.94878 2.92724 +1670 -6.29499 5.79099 2.94037 +828 -5.40524 5.41772 2.67277 +300 -5.49735 6.4089 2.86457 +410 -6.74971 5.31805 2.16318 +150 -7.72803 5.54719 2.12215 +1321 -7.38453 6.95877 2.71368 +1200 -6.39904 6.84543 2.90851 +1997 -5.72475 7.6643 2.79131 +2146 -5.94197 5.7979 1.81929 +1843 -7.72137 6.58061 1.84133 +1406 -6.63141 7.44527 2.11494 +2292 -7.37092 7.56377 1.41919 +1726 -6.7726 6.3202 2.11618 +2142 -5.8874 6.78454 2.02296 +76 -4.51166 6.14871 2.65809 +1629 -4.23627 7.09524 2.85125 +2049 -3.29222 7.45081 2.77853 +261 -3.48615 6.50586 2.51344 +1404 -3.84317 5.68126 2.07072 +2111 -2.76064 6.11919 1.93825 +1917 -3.16504 7.20328 1.79744 +1215 -5.00359 6.26918 1.78705 +295 -5.02896 7.27679 2.17151 +1485 -4.15825 6.88185 1.87759 +290 -1.71618 6.46774 1.90884 +344 -1.32445 7.21933 1.36251 +1399 -0.805614 6.83762 2.12583 +2065 -1.51637 7.35713 2.60326 +18 -0.0333251 7.59647 2.63636 +575 -2.1182 7.60282 1.8368 +2363 -2.4275 6.89552 2.47846 +387 0.188199 6.80033 2.03781 +1037 1.85165 6.98315 2.38242 +347 0.914116 7.30961 2.49913 +2260 1.11971 6.5608 1.76456 +2180 2.45454 7.1632 1.54976 +1167 2.07073 6.24764 1.73972 +975 0.436796 7.78475 1.75846 +915 1.45056 7.48939 1.60367 +1896 2.80895 6.57358 2.32764 +702 3.5365 7.08137 2.78748 +1627 4.33989 7.65723 2.94184 +711 4.34843 6.4995 2.74117 +570 3.86629 6.87932 1.86143 +165 2.96825 5.81931 1.68299 +605 2.6135 7.48322 2.78705 +1996 3.21742 7.63213 2.00195 +884 4.75916 7.25557 2.12443 +1393 5.08519 5.80391 2.71146 +1547 3.82331 5.84216 2.20084 +2158 4.76698 6.2582 1.85395 +1830 6.89967 7.5844 1.71545 +1342 7.52444 6.89484 2.13598 +1298 5.30137 6.75404 2.94994 +375 6.31285 6.7564 2.98868 +717 5.3395 7.75311 2.96342 +1426 6.06464 7.51816 2.30598 +1450 7.2315 6.36377 2.93088 +2225 6.96768 7.47135 2.7331 +2340 6.43034 5.75301 2.97618 +1373 7.46599 5.38528 2.96618 +2209 5.91351 5.93016 2.13454 +2124 7.23158 6.20675 1.45786 +654 6.9002 5.51309 2.11286 +389 5.58743 6.82941 1.76138 +1495 6.55273 6.69052 2.01988 +486 9.72627 6.24607 1.37019 +223 8.87816 5.44943 1.81459 +173 8.45403 5.36803 2.81342 +821 9.91912 5.41303 1.89925 +1449 9.20522 7.10645 1.43023 +268 8.19957 6.34368 2.66332 +1995 8.47514 7.20771 2.10673 +280 9.0682 6.39055 2.14043 +2257 7.89234 5.46474 1.98242 +1828 8.20726 6.36514 1.63041 +1192 -8.23652 8.10558 1.45973 +2091 -5.41877 8.6661 2.61176 +207 -6.65941 9.1447 1.76941 +242 -6.34288 8.37767 2.33309 +1237 -7.33842 8.2297 2.18119 +135 -7.53757 8.81682 1.39612 +1273 -5.69909 8.88216 1.67377 +755 -5.70035 7.88354 1.74352 +2157 -5.24297 9.58503 2.22519 +1299 -5.98509 9.85411 1.56208 +326 -4.48386 9.05455 2.68429 +224 -4.75842 7.95513 2.85324 +551 -2.89041 8.6746 2.91405 +1552 -3.81495 8.30203 2.83984 +1073 -3.54915 9.40915 2.72599 +940 -3.07607 10.2395 2.42586 +1289 -3.55325 9.89165 1.52021 +1134 -4.27288 9.91474 2.21888 +293 -2.8354 9.16011 2.01824 +1345 -2.93521 8.15339 2.01167 +346 -4.72339 8.47373 1.90578 +655 -3.92617 7.84963 1.95755 +254 -3.85861 8.99868 1.85984 +678 -4.65728 9.43647 1.42645 +1326 -5.09053 10.3295 1.57268 +1788 -0.397313 8.65014 1.36029 +510 -0.666419 7.81523 1.89573 +1626 -1.44084 8.24442 1.41785 +1377 -0.881048 8.088 2.87266 +1290 -0.739348 9.71435 1.96359 +1361 -0.522993 9.01588 2.99647 +440 -2.01595 8.52764 2.20793 +673 -1.52003 8.88871 2.99811 +10 -1.00465 8.76817 2.14957 +1375 -2.01978 10.392 2.51559 +2247 -2.33544 9.50476 2.87062 +437 -0.160942 9.93791 2.83686 +1616 -1.17639 9.83897 2.85426 +1824 -2.4738 10.0721 1.64529 +500 -1.45343 10.3553 1.67336 +956 -1.71854 9.47361 2.07472 +971 -2.36597 7.82374 2.84955 +1033 0.0109258 8.56758 2.26974 +2311 0.724042 8.20931 2.89224 +1228 0.602385 8.70788 1.39509 +1159 2.11742 9.00222 2.18711 +571 1.80941 9.78858 2.8252 +66 2.58332 10.3546 2.46468 +512 0.843996 10.0775 2.78498 +676 0.468055 9.17419 2.99195 +950 1.2638 8.35873 2.0646 +1078 2.4813 8.45975 2.96271 +1266 2.23634 8.02502 2.01106 +1533 1.6793 7.86513 2.83119 +545 1.5242 8.84595 2.98671 +418 1.17426 9.34741 2.19014 +2244 1.94945 9.97963 1.78542 +12 0.236424 9.50139 1.88034 +1145 0.943642 10.2181 1.74146 +1592 4.23869 10.3911 1.97013 +1712 3.05391 8.61889 2.06103 +506 3.41577 8.06499 2.92918 +105 3.95148 8.99436 1.79627 +1148 2.86719 9.58122 1.8557 +1257 3.5144 9.96625 2.51243 +1196 2.74567 9.41872 2.84453 +1013 3.66795 9.03142 2.85837 +2074 4.43212 9.55197 2.47764 +1278 4.13477 8.03754 2.0227 +75 5.12463 8.3275 2.05243 +1683 4.59303 8.62224 2.84672 +492 4.65452 9.62933 1.37319 +1965 6.18067 8.25951 1.53587 +1718 6.92167 8.48963 2.18871 +1114 6.01956 8.45529 2.6524 +1702 7.72586 7.87462 2.20078 +2075 5.36686 9.19642 2.49447 +1875 5.53348 9.92058 1.77206 +1177 6.26044 9.23347 2.03166 +1993 5.50757 8.99438 1.37754 +203 7.0711 9.18879 1.44008 +1714 7.85651 8.55167 1.46141 +1191 -3.18396 10.8977 1.66572 +2305 -4.15943 10.6931 1.56696 +1834 -0.632544 10.7115 2.41243 +887 -0.0972628 10.4032 1.58997 +2066 -2.20361 11.1196 1.85362 +1149 -0.183679 11.4065 1.74443 +944 -1.18231 11.3179 1.81046 +2019 2.36881 11.1161 1.83785 +550 1.55726 10.6664 2.40328 +70 0.382909 10.8514 2.35366 +1398 1.06464 11.3449 1.7936 +856 3.31435 10.7646 1.86928 +1436 -5.41215 -10.6592 -0.473607 +2295 -4.39521 -10.7442 -1.28996 +2381 -3.50838 -11.2215 -1.07479 +2067 -4.44403 -11.1163 -0.343233 +2226 -5.03119 -10.8539 0.431563 +1230 -3.95339 -11.2715 0.538824 +1217 -4.4753 -10.8196 1.26884 +1723 -3.71402 -10.4365 -0.451126 +341 -2.839 -11.5435 0.809418 +1945 -3.1233 -11.3407 -0.138751 +1259 -2.70706 -10.5079 1.28249 +1835 -3.29218 -10.5244 0.465047 +1948 -2.28472 -10.806 0.424719 +77 -2.20699 -11.7704 0.00998425 +2061 -2.51625 -11.389 -0.941421 +1546 -1.01536 -10.6118 -1.31467 +1097 -1.80511 -10.8754 -0.456353 +2243 -1.44669 -11.7631 -0.77931 +1479 -0.543263 -11.7752 1.10687 +1119 -1.62898 -11.5112 0.791218 +2325 -0.343167 -11.0175 0.481493 +1699 -1.28949 -10.649 0.405936 +1427 -0.804638 -11.0008 -0.408088 +733 -0.910257 -11.9497 0.189654 +1197 -0.443759 -11.8898 -0.69506 +423 1.07821 -10.6343 1.23432 +1447 0.542206 -11.5206 1.28966 +1206 2.04807 -10.5625 -1.32715 +1570 2.36835 -11.5079 -1.1931 +2077 0.128 -11.8968 0.287526 +704 1.26622 -10.9736 -0.406283 +1654 0.653683 -10.9769 0.384176 +841 0.84916 -11.9036 -0.468908 +1522 0.182955 -11.1397 -0.483069 +778 1.1286 -11.8646 0.491866 +658 1.97735 -11.3011 0.466066 +608 1.85228 -11.8224 -0.396882 +986 0.36058 -11.65 -1.32913 +222 1.37757 -11.6203 -1.29417 +407 2.57678 -11.408 1.26129 +1698 2.01633 -10.4184 0.944943 +1027 2.05066 -10.4235 -0.0616407 +1508 4.23966 -10.9432 -1.23081 +1314 2.80388 -10.8043 -0.630392 +1731 2.77776 -11.6701 -0.0243659 +1911 3.60401 -11.3952 -0.525192 +935 2.97017 -10.6797 0.672558 +1819 3.66349 -11.3822 0.4744 +1075 4.43509 -10.9486 0.97165 +2228 3.6138 -10.4982 -0.0710904 +665 4.46868 -11.1279 -0.0996899 +1372 5.22376 -10.6106 -1.00016 +41 5.39753 -10.5249 0.982452 +439 5.37769 -10.7106 -0.00614841 +1492 -8.99586 -7.83296 -0.647058 +1355 -8.51562 -8.45523 -0.0181487 +874 -8.8057 -7.98627 0.816026 +63 -8.08845 -8.69552 0.853527 +485 -8.04943 -8.70375 -0.867372 +1871 -5.55773 -10.3626 1.13021 +1346 -6.10015 -10.3268 0.171849 +1914 -7.3251 -9.34038 0.873227 +328 -5.22277 -9.85867 0.305851 +1999 -5.3027 -8.88017 0.566005 +1847 -6.21451 -8.89685 0.994835 +429 -6.48128 -9.86767 0.974033 +1600 -7.07752 -8.34961 0.836456 +1438 -6.36189 -8.04208 -0.612237 +1973 -6.22163 -8.08679 0.376774 +1977 -7.26967 -9.34695 -0.856049 +2237 -6.852 -8.7264 -0.0639254 +914 -7.76957 -9.12471 0.00212665 +727 -6.9789 -9.74695 0.0272362 +864 -5.56614 -8.6054 -0.380675 +2014 -5.52575 -9.55011 -0.709684 +1156 -6.07007 -9.32455 0.0983602 +2031 -6.32978 -8.99358 -0.920921 +1185 -6.41957 -10.007 -0.764678 +882 -7.20365 -8.22255 -1.11959 +23 -7.59607 -8.06049 0.00793055 +2217 -5.34468 -8.10241 -1.21677 +692 -5.45858 -8.01539 1.04185 +1422 -2.78464 -10.0821 -0.279474 +11 -2.70559 -9.7068 0.667994 +973 -3.07667 -10.1423 -1.23412 +2368 -3.6844 -9.97956 1.21127 +943 -4.2516 -10.2029 0.408409 +1557 -2.63014 -8.35594 -1.24434 +329 -4.6733 -9.60747 1.11127 +1799 -3.48294 -9.35984 -0.584494 +619 -3.62285 -8.63635 -1.29239 +933 -4.51084 -9.19417 0.0419852 +1668 -4.04323 -9.79915 -1.30476 +26 -4.63889 -10.0204 -0.525857 +74 -4.54956 -8.9966 -0.945919 +1107 -3.58442 -9.28962 0.412322 +107 -4.48701 -8.60088 1.07703 +1105 -3.49877 -8.70535 1.22256 +1220 -3.85187 -8.31631 0.349006 +158 -2.85622 -8.38551 0.500189 +1000 -3.22124 -8.32767 -0.429962 +339 -4.62889 -8.25565 -0.279874 +873 -4.34686 -7.9357 -1.18506 +1774 -0.15458 -8.05945 -0.882976 +2229 -0.725163 -8.82989 -1.20232 +872 -0.366275 -9.16243 -0.329134 +315 -0.231162 -10.1263 0.0145953 +1122 -0.314427 -9.78829 -1.11378 +2176 -1.08834 -10.0403 -0.496345 +406 -2.10396 -10.3933 -1.29134 +1364 -0.779416 -10.1439 1.10982 +2184 -0.30921 -9.2777 1.27894 +2276 -1.0012 -8.36286 -0.316869 +1795 -2.48229 -9.34722 -1.08291 +880 -1.78644 -9.58633 1.0554 +1506 -1.87919 -9.89308 0.104006 +1894 -1.59242 -9.15517 -0.515304 +1267 -1.0072 -9.4895 0.382049 +2128 -0.463117 -8.63972 0.524614 +738 -2.5166 -8.93259 1.27206 +292 -1.95963 -8.10248 1.18748 +721 -1.72048 -8.66815 0.354883 +902 -1.19464 -8.78687 1.21508 +1786 -0.997913 -7.86861 0.86661 +2379 -2.51555 -9.10717 -0.112689 +1151 -2.21833 -8.02556 -0.390016 +481 1.28664 -9.03043 -1.31614 +1814 0.268856 -8.92057 -1.27394 +2177 2.33607 -8.86058 -1.28917 +1036 1.45057 -9.93631 -0.807076 +1340 1.85583 -8.03414 -1.00085 +834 0.31213 -8.45638 -0.0846069 +660 0.870854 -8.19834 -0.921671 +974 0.489898 -10.2087 -0.687239 +137 0.262884 -7.93171 0.791201 +1984 0.788728 -9.25679 -0.470877 +2162 1.09197 -10.0829 0.127066 +953 0.582594 -8.78537 1.2274 +2388 0.269021 -9.33242 0.434886 +1792 0.225281 -10.2223 0.899996 +1099 1.06951 -9.65352 1.03848 +301 2.46103 -8.65978 0.49739 +2056 1.17275 -8.88816 0.395811 +1816 1.93862 -9.54923 0.439878 +577 1.76465 -8.90952 1.22312 +1682 1.28481 -8.06713 0.968037 +1265 2.44317 -9.78988 -0.765269 +474 1.80799 -9.05962 -0.429333 +1923 1.68359 -8.12549 -0.00178841 +1093 3.57893 -10.0266 1.12656 +531 4.64016 -10.1129 0.461984 +1092 2.70494 -9.44463 1.07906 +1970 3.56827 -8.92295 1.02429 +1655 4.40847 -9.44279 1.2092 +1276 3.22024 -7.98168 0.826637 +675 4.25794 -8.06875 0.650575 +2208 4.44356 -10.1909 -0.537059 +1681 3.43632 -9.68708 -0.657748 +139 3.81996 -9.56626 0.271206 +450 2.85444 -9.82911 0.147132 +726 3.71397 -8.57544 -0.0314818 +1721 2.83716 -8.92169 -0.42037 +890 5.03433 -9.60095 -1.11392 +1395 4.61145 -8.95416 0.318934 +1907 4.30132 -9.11157 -0.637908 +1928 5.18152 -8.65085 -0.454243 +1530 2.94213 -7.95009 -0.144115 +167 4.41173 -7.92515 -0.370891 +2294 3.50452 -8.77071 -1.16635 +1754 2.84358 -8.00422 -1.16862 +2272 4.69874 -8.29258 -1.25641 +1746 7.28559 -8.13012 -1.00419 +1057 6.73121 -8.76139 -0.454318 +1396 7.65587 -9.15597 -0.511398 +2344 6.80552 -9.67205 -0.982958 +312 7.57206 -7.98729 0.301876 +2351 7.64864 -9.11951 0.5124 +2213 6.95015 -9.68758 0.00756165 +2100 6.10686 -10.2458 -0.52654 +1772 6.18426 -10.1579 0.467914 +2224 5.3378 -9.46117 0.821902 +1779 6.12862 -8.91014 1.15763 +2339 6.89895 -9.54336 1.02109 +2051 7.26292 -8.60648 1.2924 +1408 5.43399 -8.45148 0.602805 +1548 6.68325 -8.40086 0.499575 +313 5.32265 -9.71367 -0.162181 +284 5.92219 -9.21385 -0.832054 +3 6.08029 -9.16513 0.191407 +838 5.64013 -7.91964 -1.0866 +1897 5.99094 -8.13204 -0.172465 +913 8.20695 -8.41929 0.990372 +2115 8.3188 -8.58091 0.00138728 +1717 8.92316 -7.81239 0.628115 +458 8.22228 -8.4829 -0.992774 +630 8.93373 -7.88407 -0.374645 +272 -10.4494 -5.84403 -0.391781 +1023 -9.94449 -6.69664 -0.254476 +129 -10.0701 -5.95764 -1.30798 +28 -9.35886 -5.85079 -0.609869 +1645 -9.39432 -5.89668 0.38941 +1720 -9.46906 -7.05383 -1.05869 +818 -8.61742 -6.54286 -1.18898 +626 -10.3734 -5.90972 0.60173 +596 -8.94259 -6.6865 -0.251458 +645 -9.81561 -6.73861 0.736537 +36 -9.38898 -7.46368 0.19293 +2214 -8.80035 -6.83509 0.729462 +769 -7.85138 -7.70447 0.914672 +97 -8.40766 -6.02933 0.285839 +961 -7.95119 -6.75889 -0.482478 +2108 -8.39751 -7.46367 0.066083 +604 -8.01704 -7.70188 -0.829142 +1089 -8.26851 -5.7526 -0.666385 +229 -7.83897 -5.20241 0.425902 +648 -6.99574 -7.38643 0.454708 +686 -6.93688 -5.73127 0.558208 +1358 -7.79963 -6.79026 0.508573 +1182 -7.6789 -5.21296 -1.26995 +71 -7.28797 -5.49468 -0.355072 +232 -6.34696 -5.8304 -0.246611 +2328 -6.4941 -6.5172 -0.95413 +1195 -7.01687 -6.61958 1.1324 +187 -7.77379 -5.96401 1.07379 +2206 -6.65422 -5.5206 -1.1637 +1176 -7.10467 -7.30167 -0.741903 +83 -6.2719 -7.13572 -0.198242 +820 -7.42082 -6.16626 -1.08434 +1931 -6.04748 -7.35396 -1.26573 +1614 -7.05093 -6.51975 -0.106583 +985 -6.17421 -7.31785 1.02035 +1311 -6.22971 -6.45253 0.526712 +1829 -5.36734 -6.96305 0.481681 +1832 -5.71958 -5.24259 0.262062 +1569 -6.08986 -5.64925 1.10104 +2096 -5.40046 -7.62101 -0.269109 +334 -5.54455 -6.46923 -0.385226 +1470 -5.5152 -5.5218 -0.708568 +1545 -3.93085 -7.79331 1.27873 +1004 -4.66712 -7.67769 0.531978 +393 -3.24436 -6.48302 0.685556 +1542 -4.1404 -6.89641 0.871984 +1328 -3.36323 -7.46163 0.524928 +266 -5.11232 -5.99578 0.537709 +2143 -4.53736 -5.54568 1.25043 +226 -4.08143 -5.9836 0.476435 +342 -2.7521 -5.4447 0.774482 +255 -4.65697 -6.89598 -0.215682 +380 -5.07887 -7.14714 -1.09 +1341 -3.70618 -6.58919 -0.271677 +1567 -4.08571 -6.97565 -1.12783 +688 -3.35112 -7.65598 -1.16082 +1979 -3.89123 -7.56986 -0.318113 +1625 -2.84182 -6.36479 -0.895096 +2178 -2.92864 -7.22044 -0.351538 +2141 -4.75385 -6.21009 -0.996605 +1695 -3.25943 -5.73379 -0.0374426 +1270 -3.76338 -6.02699 -1.10091 +945 -4.29601 -5.55216 -0.398377 +310 -3.07827 -5.32093 -0.930234 +1769 -0.314549 -6.08982 -0.642677 +2236 -2.44523 -6.91293 1.26323 +171 -2.35803 -7.51751 0.468895 +1499 -1.72721 -6.75074 0.582601 +931 -0.311841 -7.28638 1.30242 +2023 -0.208107 -6.28048 1.18795 +1369 -0.72808 -6.86522 0.491229 +1336 -1.85571 -5.74525 0.434353 +1137 -0.907985 -5.93559 0.16684 +1622 -1.18651 -6.09966 1.11617 +154 -1.79896 -6.81722 -0.557043 +237 -2.49038 -6.4171 0.0437528 +303 -2.43046 -7.26682 -1.21903 +848 -1.43631 -7.70776 -0.945727 +285 -0.360423 -7.68037 0.0425829 +1140 -1.44923 -7.54 0.0372815 +509 -0.807228 -6.98679 -0.550596 +192 -2.22536 -5.61393 -0.497131 +1686 -1.30155 -5.96971 -0.751203 +968 2.23099 -6.44857 -0.81413 +2144 2.5962 -5.50838 -0.713685 +2326 1.36071 -6.17403 -1.28963 +240 0.189945 -6.9281 -0.383638 +112 0.464752 -7.35031 -1.2708 +1060 1.64253 -5.79254 -0.328346 +1333 2.38384 -5.54833 0.342715 +1223 0.0889167 -6.01228 0.266374 +1713 0.68546 -6.02113 -0.552005 +2373 1.05479 -6.25096 0.346501 +2283 0.784205 -6.26894 1.32286 +1165 0.34573 -6.92881 0.609212 +1437 1.70734 -5.94622 1.04027 +1935 1.28728 -6.82332 -0.479618 +31 0.834805 -7.58715 0.0282795 +1294 2.2169 -7.71959 0.762687 +859 1.42455 -7.10876 0.708995 +2122 2.3119 -6.72718 1.1864 +1803 2.18372 -7.32501 -0.334838 +98 2.0714 -6.49487 0.242058 +819 4.70657 -5.86433 -0.697546 +1619 3.70877 -5.81878 -0.744631 +894 4.23276 -5.34287 0.0619875 +246 2.88504 -7.06913 0.391231 +21 3.87642 -7.33559 1.23329 +260 4.90591 -7.62476 1.26973 +1138 2.67022 -5.78414 1.30524 +1771 3.33891 -6.49758 1.09049 +1544 3.36957 -5.60149 0.545457 +376 4.58006 -6.82194 0.740742 +1850 4.17515 -5.94766 1.02665 +1742 4.9595 -5.93791 0.405487 +2313 3.84057 -7.29685 0.163528 +1476 3.11067 -7.11222 -0.669223 +1214 5.09136 -7.56762 0.277936 +2062 4.87005 -7.28172 -1.07078 +1946 3.98239 -6.30834 0.111292 +2353 3.01238 -6.24171 -0.161218 +1520 4.05306 -6.77865 -0.771644 +1939 4.87991 -6.72248 -0.212991 +1280 3.83791 -7.77024 -1.20677 +1029 7.16652 -5.57564 -0.490063 +1678 5.6728 -5.37846 -0.959498 +1630 7.3522 -6.6643 -0.669942 +1778 7.78738 -5.64145 1.21635 +1810 5.60383 -6.60118 -1.17158 +780 6.7823 -5.70306 1.17232 +1066 6.49679 -7.03115 -1.03745 +2282 7.28268 -6.56676 1.24511 +1025 6.4331 -6.03373 -1.00043 +377 6.84235 -7.60071 -0.266768 +912 5.68581 -6.13549 -0.289422 +435 6.55437 -6.67227 0.0387942 +263 7.58881 -6.98473 0.251849 +2263 7.34901 -6.02456 0.396386 +1575 6.42911 -5.67943 0.204762 +378 5.85822 -7.60002 0.919662 +1764 6.82358 -7.41507 0.729715 +2170 5.57404 -6.72364 0.513216 +1243 6.28662 -6.68185 1.21651 +599 5.78782 -5.84432 0.965882 +941 5.7644 -7.17455 -0.358792 +2036 10.3833 -5.57369 1.10424 +812 7.81499 -7.43081 1.12319 +1507 8.57198 -7.03611 0.0769697 +1573 8.21768 -6.50531 0.894846 +791 8.11602 -6.1949 -0.226275 +1512 10.0263 -6.411 0.683303 +1658 9.28366 -6.97718 1.04914 +572 9.05398 -6.14514 0.471551 +1785 9.55588 -7.22855 0.0956954 +1325 8.24195 -5.39221 0.358347 +2303 9.419 -5.34264 0.961086 +756 9.60886 -5.58164 -0.231871 +159 7.98174 -7.57249 -0.548901 +1941 8.33784 -6.78197 -1.06774 +1650 10.0683 -6.47327 -0.327955 +2109 9.07017 -6.3759 -0.519442 +977 9.77164 -6.35567 -1.28982 +601 9.34761 -7.21405 -0.999493 +1135 8.6425 -5.41259 -0.578852 +1356 10.3947 -5.69196 -0.869309 +612 10.542 -5.70756 0.125937 +1059 -11.1037 -3.82368 1.20788 +2189 -10.8849 -5.03997 0.0236843 +1443 -10.8335 -4.76137 0.983872 +2098 -11.4918 -3.34868 -0.368517 +2203 -10.5198 -3.58141 -0.410052 +1255 -11.2581 -4.09398 0.253903 +752 -11.5036 -3.13043 0.605489 +1005 -10.4803 -3.35679 0.563677 +2125 -10.8797 -2.62307 -0.00155648 +2261 -10.6088 -5.1443 -1.08654 +742 -11.0847 -4.35763 -0.691511 +447 -10.6131 -2.74697 -0.963211 +792 -11.1504 -3.54476 -1.28777 +2231 -7.98654 -3.58381 1.22903 +2068 -7.91805 -4.7083 -0.441144 +111 -8.81678 -5.1821 -0.0487409 +160 -9.00737 -3.71343 1.08789 +579 -8.25432 -3.13712 -0.524631 +2002 -8.47968 -3.13505 0.455697 +1163 -8.32465 -4.38314 0.728641 +1710 -8.79426 -4.76412 -0.955049 +1496 -8.60257 -4.02482 -0.188021 +1146 -8.02516 -4.2244 -1.3087 +2273 -8.89273 -5.18848 0.951021 +1076 -9.81386 -5.10499 -0.122934 +2347 -10.2686 -4.297 0.294034 +1068 -9.28254 -4.42979 0.420397 +29 -9.88964 -5.08032 0.878351 +850 -9.47012 -3.50684 0.0819742 +1242 -9.52608 -2.86942 0.8471 +1009 -9.12879 -2.61172 -0.213229 +1849 -9.75899 -4.21133 -0.569436 +1400 -9.70454 -3.19025 -0.837118 +472 -8.9001 -2.71089 -1.18995 +860 -8.88151 -3.71068 -1.10173 +869 -7.36281 -3.56978 -0.935905 +1047 -5.80505 -3.7952 -0.538409 +1249 -6.73291 -3.72278 -0.172748 +899 -5.37338 -3.25482 -1.26039 +2392 -6.32932 -2.95646 -0.673089 +403 -6.31898 -4.86106 -0.488496 +2150 -5.82785 -4.48675 -1.26865 +1440 -7.00158 -4.49117 -1.11804 +980 -7.31903 -2.69724 -0.449843 +2343 -5.46202 -2.67617 -0.246343 +1309 -7.12197 -3.97621 0.877311 +269 -7.08132 -4.6319 0.116647 +2297 -5.93567 -4.1728 1.311 +386 -6.14994 -4.34303 0.350468 +992 -6.69442 -4.86704 1.00686 +1933 -5.40257 -3.21985 1.20009 +1494 -7.71468 -2.63277 1.07857 +1021 -7.69357 -3.68633 0.109146 +1203 -7.02118 -3.00442 0.46138 +1802 -6.43779 -3.32488 1.20576 +1227 -5.91641 -3.34743 0.351963 +1637 -5.34499 -4.9646 1.15067 +618 -5.26261 -4.61482 -0.359204 +249 -4.88896 -3.47917 -0.0903434 +705 -4.56085 -4.07429 -0.823664 +735 -4.73267 -5.07482 0.365656 +1922 -3.54271 -4.87728 0.399779 +278 -5.17355 -4.19231 0.542601 +489 -4.2166 -4.56172 1.06484 +1991 -4.26231 -4.22726 0.124992 +2152 -4.75304 -5.01777 -1.11612 +1056 -3.8191 -4.7162 -0.625652 +862 3.34069 -5.00479 -0.263599 +1368 4.05443 -4.9421 -1.09969 +2246 3.86443 -4.72325 0.756865 +1734 4.11886 -4.37309 -0.174891 +1352 4.85991 -5.04136 0.838814 +1327 4.69399 -4.09515 1.12675 +1034 5.04594 -4.26329 0.206824 +544 5.12068 -3.33214 0.638003 +2299 4.75308 -4.04766 -1.08975 +1370 4.89361 -4.89166 -0.558975 +779 5.16167 -3.44912 -0.373913 +590 5.68548 -4.11349 0.989119 +1745 5.56107 -5.18227 0.136848 +1388 6.30505 -4.87773 0.79306 +685 6.01484 -4.0855 0.0341453 +2386 6.80204 -4.0124 0.716619 +49 7.01184 -3.09035 0.106179 +2070 6.19386 -3.23098 -0.466034 +562 7.22693 -4.79985 1.20676 +2185 5.49616 -3.40827 -1.31878 +737 6.11939 -3.23618 0.551507 +1216 5.70021 -4.37678 -0.904101 +1125 7.49099 -3.11622 0.984479 +1960 6.41122 -3.81562 -1.32971 +1293 6.95932 -4.02673 -0.288821 +1465 7.77531 -4.05508 0.491437 +2163 7.10058 -3.21812 -0.913545 +1281 6.43754 -4.87807 -0.409663 +1910 7.24142 -4.85147 0.207239 +930 6.80753 -5.14267 -1.3188 +448 7.29706 -4.26895 -1.22446 +1179 9.10022 -3.18309 1.11217 +1174 8.25486 -3.6846 1.29236 +72 8.25315 -3.9862 -1.30346 +1245 8.23427 -4.69386 1.13353 +2133 9.58805 -4.01214 -0.0308226 +2364 9.97658 -4.30893 1.17102 +1992 10.0302 -4.85998 0.332442 +1887 9.03401 -4.15281 0.872728 +46 10.1734 -4.73458 -0.649968 +1553 8.34769 -3.24018 0.392714 +146 7.82064 -2.65554 -0.289889 +561 9.42936 -5.18833 -1.15428 +2040 7.87143 -3.64325 -0.437293 +368 8.09029 -2.99974 -1.19126 +1753 8.98784 -4.38047 -0.750937 +875 8.83537 -3.41117 -0.557682 +1117 8.14211 -4.59918 -0.263485 +2093 9.04762 -4.83642 0.142085 +79 7.82872 -5.10633 -1.07752 +286 9.82011 -3.1492 0.418081 +1636 9.88072 -4.03335 -1.30328 +1008 10.2115 -3.08712 -1.25596 +4 9.61693 -2.79217 -0.50378 +793 11.0266 -4.65891 -0.133811 +2190 10.8745 -4.7377 0.859869 +1735 10.541 -3.85345 0.48566 +798 11.3779 -3.72369 -0.0507723 +1633 11.3309 -3.4039 0.901491 +549 10.7258 -2.94678 0.037928 +2043 11.6444 -2.6852 -0.298834 +1478 10.4243 -3.73168 -0.50382 +100 11.2721 -3.35486 -0.973877 +2136 10.9123 -4.31405 -1.17748 +309 -11.7198 -0.272845 1.10149 +1538 -10.897 -1.65391 0.407513 +430 -11.8935 -1.43906 -0.203189 +1880 -11.7537 -2.17486 0.460231 +1213 -11.8177 -1.21954 0.771995 +1201 -10.5415 -2.43197 0.929516 +206 -11.9557 -0.487545 0.10242 +918 -11.0394 -0.863 -0.195157 +784 -10.794 -0.735571 0.789751 +267 -10.8958 -1.7912 -0.583657 +1002 -11.6647 -1.38167 -1.17569 +640 -11.7081 -2.37702 -0.518123 +825 -10.8007 -0.85759 -1.17034 +1077 -11.8154 -0.406381 -0.930149 +330 -8.08896 -1.70216 0.962466 +1898 -8.68997 -2.46367 1.2208 +1483 -7.98508 -2.32091 -1.09406 +113 -9.82668 -0.373427 -1.07039 +610 -8.8418 -0.211834 -1.21374 +2018 -8.96454 -1.22026 1.06112 +797 -8.76408 -1.80229 -0.738264 +1837 -9.7439 -2.18567 -0.920212 +1482 -8.20599 -2.26688 -0.0345694 +1113 -8.24243 -1.22607 0.0929066 +1766 -8.21594 -0.947776 -0.891357 +2341 -9.69778 -1.89049 0.978075 +1901 -9.99295 -2.16141 0.0536082 +796 -9.11885 -1.69265 0.192834 +238 -9.94833 -1.14146 0.371084 +231 -10.0206 -1.26596 -0.617245 +878 -9.0969 -0.879582 -0.404595 +1860 -7.85134 -0.728918 0.86756 +1590 -10.2089 -0.300074 -0.146312 +1514 -9.59829 -0.446869 1.00083 +1360 -8.77146 -0.451025 0.438689 +484 -6.20258 -0.665114 1.13245 +836 -6.01264 -0.1509 0.287469 +2354 -7.56123 -0.0505411 -1.04433 +1599 -6.06723 -1.66093 1.27369 +2355 -6.18025 -1.30838 -1.32606 +795 -5.77931 -1.76336 -0.497203 +2219 -6.6923 -2.01247 -0.826138 +361 -6.79611 -1.17096 -0.0476428 +2076 -6.78186 -0.150023 -0.403656 +1487 -7.5586 -1.62743 -0.513572 +762 -5.9972 -0.771879 -0.502138 +883 -5.88992 -1.26778 0.364525 +1715 -6.94997 -1.30385 0.93334 +560 -7.04187 -0.916885 -1.00045 +1316 -7.31714 -2.04282 0.368513 +723 -5.61107 -2.3718 0.701958 +1413 -6.39603 -2.30709 0.0844374 +1952 -7.71447 -0.401548 -0.114383 +47 -6.96504 -0.372888 0.554547 +1351 5.68762 -2.47949 1.04916 +2092 6.06726 -0.924926 0.890432 +2116 6.98658 -1.33745 1.06104 +1381 7.48328 -2.18352 0.526226 +546 5.56329 -2.58617 0.0324992 +37 6.56782 -2.28635 -0.520291 +1756 6.18805 -0.211249 -1.04181 +106 6.49256 -2.30516 0.477312 +488 5.96544 -0.696224 -0.182043 +1708 5.79148 -1.63039 0.232439 +2197 7.42725 -1.79963 -0.672427 +1175 7.61842 -0.899464 -0.27786 +1864 6.7915 -1.33547 0.0802482 +1564 7.57851 -0.622399 0.683084 +668 6.86496 -0.325137 0.0493247 +20 5.72503 -2.48096 -1.02234 +1861 5.90833 -1.53282 -0.761594 +58 6.75773 -1.0171 -0.880272 +777 6.76583 -0.250742 1.12596 +1749 8.04865 -0.37218 -1.01049 +835 9.03767 -0.756071 1.19187 +554 8.28012 -2.52788 1.15891 +1892 8.08091 -0.0289922 -0.0434227 +1565 9.6976 -2.37996 1.08496 +504 8.91839 -1.75885 1.21851 +1421 7.97614 -1.47415 1.03576 +2284 8.33567 -1.83045 0.145114 +1631 8.48563 -0.860355 0.34035 +832 9.28502 -1.6353 -0.0981382 +1747 9.04083 -2.52143 0.334998 +208 10.0632 -2.20431 0.170728 +1893 9.45848 -0.689745 0.197264 +1339 9.77166 -1.40716 0.837457 +634 10.0431 -0.236986 0.875727 +1026 10.2879 -0.223988 -0.108455 +487 10.2638 -1.24419 -0.0187693 +1390 8.71656 -2.36346 -0.627205 +827 9.08251 -1.71267 -1.29329 +2306 9.96525 -1.89702 -0.784112 +646 8.92297 -0.249372 -0.534769 +13 8.51525 -1.20371 -0.620834 +1102 9.61109 -0.950639 -0.758859 +1964 10.9451 -0.477945 1.24399 +1069 10.6748 -2.58018 0.968912 +2216 11.0304 -1.97827 0.0636138 +759 10.7712 -1.56244 0.936716 +1680 11.8575 -1.538 0.419911 +1957 11.6421 -2.4799 0.679379 +2121 11.1192 -0.846033 0.330339 +1130 11.9543 -0.773065 -0.21425 +2194 11.8646 -0.366139 0.846919 +2037 10.828 -2.41623 -0.817447 +17 11.77 -1.72531 -0.558876 +749 10.5582 -0.493414 -1.23866 +2315 11.2069 -0.174755 -0.499322 +2331 10.8561 -1.36512 -0.815969 +2147 11.6961 -0.929167 -1.17664 +652 -11.6549 0.550002 -1.3294 +16 -10.9177 0.0757261 -0.830842 +764 -11.9542 0.414553 -0.373248 +476 -11.8427 0.615604 0.600252 +1469 -11.1001 0.0429144 0.224498 +1045 -11.8954 1.46594 0.0736289 +1423 -11.7423 1.4583 -0.915828 +1218 -10.5394 0.131264 1.21889 +483 -10.7484 0.908174 0.610767 +1378 -11.6384 2.41802 0.630774 +2021 -11.5008 1.48078 1.01971 +1566 -10.4531 1.82067 0.989723 +1904 -10.9208 1.82702 0.104064 +2000 -11.0973 0.930296 -0.33502 +501 -11.7186 2.39233 -0.377076 +385 -10.6443 1.08575 -1.219 +1209 -10.9312 2.04898 -0.894514 +1363 -8.69283 2.11191 1.23146 +2042 -9.0357 0.911403 0.263843 +1110 -9.88889 0.401111 0.501111 +69 -9.12316 0.468338 1.15872 +2230 -8.3259 0.403557 -0.261368 +1889 -8.12438 0.245642 0.778822 +114 -9.43365 1.42581 1.10963 +491 -9.07677 1.92497 0.284688 +2202 -9.94303 1.39023 0.238293 +1744 -9.65503 2.41699 1.09858 +2005 -9.94756 2.40454 0.142395 +2165 -8.28179 1.49553 -0.21194 +773 -8.37984 1.16084 1.09264 +1468 -8.25141 2.48718 -0.0113219 +2385 -10.1278 0.686935 -0.453842 +1583 -9.28934 0.139639 -0.390951 +1596 -9.55447 0.574324 -1.26555 +1776 -8.48233 0.743499 -1.19447 +1671 -9.14546 1.2709 -0.663512 +57 -9.97748 1.826 -0.672717 +104 -8.1394 1.68809 -1.18715 +182 -5.83943 2.33961 -1.19293 +1031 -6.13563 1.33781 -1.2073 +928 -6.76295 0.560905 -1.11039 +1966 -6.01945 0.550596 -0.425201 +2337 -6.04569 1.79326 1.28172 +1519 -7.21634 0.420324 1.1629 +1968 -6.21268 0.377299 1.12285 +2027 -6.73896 0.572954 0.291763 +374 -7.73778 1.9189 0.895168 +694 -7.63112 1.01714 0.37728 +1103 -7.40538 1.95032 -0.0509096 +1324 -6.47746 2.00823 0.326155 +1888 -6.88243 1.34502 0.955835 +1653 -6.85422 2.4019 1.16832 +1118 -5.95037 1.17261 0.478621 +172 -5.59736 2.39221 0.612088 +1141 -7.5784 0.933809 -0.660061 +1685 -6.65435 2.29504 -0.618667 +1704 -7.10053 1.60074 -1.25043 +547 -5.78656 1.73327 -0.349626 +2245 -6.69987 1.31788 -0.37725 +452 7.45299 0.374092 0.634363 +282 7.34902 0.26028 -0.664 +363 6.11719 1.58277 1.27951 +1551 6.28142 0.596969 1.32687 +2371 6.99777 1.15398 -0.943538 +1728 6.07073 0.763542 -0.835366 +164 6.04586 0.0779847 0.491946 +1793 7.51557 1.17864 -0.0844397 +1486 6.66735 0.649884 -0.0432066 +426 6.88916 1.18728 0.773077 +2266 5.91972 1.15978 0.380438 +1415 5.75434 2.50799 1.17691 +1106 7.58496 2.51647 0.932957 +1359 5.83383 1.72989 -0.648162 +1673 5.63588 2.1124 0.262744 +650 6.80003 1.90201 -0.299192 +275 7.79238 2.13874 -0.0158769 +1301 6.64387 2.16421 0.658487 +2241 6.36551 2.54874 -0.927428 +2166 10.2154 0.696127 -0.593318 +392 9.22085 0.774997 -0.664721 +1761 9.8441 1.24372 1.10311 +34 8.74039 1.18644 1.24265 +163 8.41543 0.840743 0.331661 +2342 8.46861 0.024982 0.910897 +1978 9.26601 0.31573 0.247061 +287 9.34313 0.38449 1.24817 +220 9.44385 2.1422 0.924785 +993 8.21818 0.76642 -0.671757 +2307 9.37989 2.51511 -0.994663 +1790 9.3156 2.50902 0.00353034 +1665 10.2231 2.45192 -0.431412 +1750 8.82384 1.70941 -0.658881 +1310 9.68817 0.0151361 -1.12152 +82 9.80864 1.59922 -0.809399 +27 10.2132 0.630791 0.407042 +1338 10.3589 2.33147 0.552535 +2174 9.50889 1.28901 0.148636 +335 8.49396 2.15792 1.2463 +1831 7.82944 1.54774 0.791017 +55 8.67643 1.8116 0.324527 +1123 7.85365 1.6739 -0.899544 +1418 10.6492 0.606624 1.30675 +613 11.8653 0.806515 0.795673 +2346 11.5416 2.08828 -1.11932 +2278 11.1694 2.25428 -0.0424973 +2323 10.8163 1.49879 0.882168 +1284 11.7601 1.80825 0.734561 +1081 10.468 1.53546 -0.0544669 +1628 11.0983 0.175246 0.503788 +1424 11.1781 0.851289 -0.227646 +641 11.9891 0.205541 0.001086 +744 11.8722 1.58197 -0.318935 +2365 10.7936 1.42265 -0.997554 +757 11.818 0.524503 -0.933878 +383 -10.8563 4.63592 -0.445119 +1439 -11.2863 2.94724 -1.1542 +1841 -10.7302 3.86112 1.26408 +2153 -11.3657 3.39935 0.535729 +1100 -10.7831 2.80593 -0.236928 +2046 -10.616 2.78701 0.787415 +989 -10.4116 3.75389 0.312694 +999 -10.7953 4.64504 0.56816 +1434 -11.2122 3.70095 -0.441871 +699 -10.2982 4.65934 -1.28437 +1132 -8.9057 2.91477 0.625651 +1420 -9.0028 3.91377 0.784004 +833 -9.56346 3.32746 -0.00495006 +1405 -9.8516 3.40729 1.06612 +1863 -8.57833 3.42608 -0.213082 +1813 -8.02695 2.91905 1.14006 +247 -8.65229 4.86001 0.927238 +837 -9.10135 4.29293 -0.197083 +467 -9.95258 4.78106 -0.00330461 +81 -9.8699 4.40877 0.95578 +1610 -8.19529 4.27966 0.226028 +1442 -8.08293 3.98211 1.1891 +1509 -10.1271 3.01796 -1.09556 +1120 -9.29925 2.60536 -0.6527 +1716 -9.21774 3.57388 -0.97463 +1391 -10.086 3.92109 -0.620171 +700 -8.16281 3.6697 -1.09281 +622 -8.45264 2.71439 -1.20099 +218 -9.31905 4.73245 -1.06907 +56 -8.2986 4.63559 -0.788149 +1593 -5.67913 4.14211 -0.620275 +141 -6.28408 3.22076 -0.721388 +1166 -5.3768 3.23898 -1.16447 +494 -5.48771 4.40203 0.504701 +161 -7.57225 2.68446 -0.72186 +513 -7.1944 3.62041 -0.846904 +2006 -5.42928 2.67553 -0.336543 +815 -7.7265 4.94379 1.32502 +1334 -7.67492 3.38334 0.226883 +230 -7.10764 3.40171 1.0554 +103 -6.14002 3.10019 1.09074 +1950 -6.75855 2.98051 0.159692 +319 -5.83567 3.48704 0.145143 +1784 -7.28293 4.3165 0.682637 +1623 -6.66312 4.01302 -0.0549675 +216 -7.43365 4.53746 -1.28136 +1873 -6.33755 4.06753 0.915266 +2113 -6.73539 5.01272 1.21152 +449 -7.40158 4.65421 -0.27525 +451 -6.29562 5.03762 0.305039 +823 -5.40811 5.05469 -0.249083 +1611 -6.50387 4.83181 -0.688458 +2335 -3.20275 5.11054 -0.306236 +1466 -4.93684 3.55138 -0.3017 +520 -5.18505 3.32732 0.889451 +1730 -3.7798 5.03374 -1.16822 +962 -4.26903 4.35283 -0.432134 +1297 -4.54849 4.03696 0.520154 +493 -3.80116 4.68929 0.386345 +2069 -4.85108 4.10355 -1.23317 +1541 -4.72719 5.05421 0.484545 +414 -4.81528 5.11224 -1.06952 +465 4.25573 4.25696 -0.27503 +144 4.66609 3.86639 0.569751 +2212 3.99577 4.62129 0.625468 +1556 4.90802 3.49341 -0.328144 +1844 3.33603 4.99693 -0.0726821 +776 4.99247 4.82712 0.539795 +2279 4.42676 4.55336 -1.23478 +421 5.04716 3.77077 -1.27886 +442 3.57184 5.05922 -1.04355 +525 5.76015 4.41168 1.0778 +1417 6.05766 3.47367 0.897152 +1775 7.40468 3.50974 0.87458 +1527 6.73743 4.2072 1.14857 +2048 7.26496 5.05376 1.27242 +186 6.17003 2.94726 0.0540355 +684 5.24477 3.01718 0.482727 +558 5.43478 2.67798 -0.571979 +427 7.52599 2.69549 -0.803767 +967 7.16824 2.91021 0.109798 +2281 5.84456 3.58788 -0.673724 +2357 6.25088 4.47888 -0.445835 +1985 5.56374 4.07256 0.156879 +25 6.82812 3.40627 -0.696357 +2359 7.39143 4.48796 0.43216 +1136 6.67232 3.83521 0.193767 +691 7.23242 4.30762 -0.538973 +1603 5.5985 5.18859 -0.169023 +847 6.45568 4.88083 0.456883 +1431 5.43615 4.65861 -1.01126 +1385 6.63279 5.06176 -1.20139 +617 7.61546 4.86992 -1.27499 +970 9.97334 4.13348 -1.20954 +1503 9.07924 3.04495 1.15074 +1969 9.86207 5.09688 0.213259 +1674 9.79508 3.24564 0.481822 +2382 9.67478 3.37704 -0.537459 +1561 10.2019 4.1987 -0.226481 +337 10.2837 4.05358 0.819291 +1188 8.24312 5.16584 1.08949 +390 9.23727 4.98176 0.995924 +1534 8.48993 2.64585 -0.543904 +871 8.41931 2.77768 0.446667 +1560 7.81441 3.6692 -0.0238086 +153 8.80436 3.54233 -0.0721475 +730 8.19025 4.58235 -0.452249 +1460 8.39713 4.31192 0.488169 +1275 9.1404 4.2895 -0.666027 +2030 9.3996 4.20946 0.378703 +1212 8.88878 5.19088 -0.0452337 +1222 9.80285 5.02914 -0.788282 +1020 7.80971 3.62781 -1.02755 +251 8.81336 3.43453 -1.06887 +898 10.7276 2.9834 1.21766 +2333 11.5585 2.8186 0.686277 +555 11.2498 3.77065 0.821885 +649 11.5194 3.0923 -0.48529 +2127 10.7207 3.17291 0.111199 +1198 11.2058 4.05039 -0.18553 +611 10.8102 5.00265 -0.658263 +1042 10.833 4.79761 0.370516 +623 10.9769 4.16561 -1.19068 +1202 10.6099 3.28077 -0.879319 +659 -10.4296 5.62091 0.310372 +1304 -9.44477 5.39564 0.620508 +1162 -10.3915 5.27441 1.28032 +1425 -9.66176 6.35154 -1.11457 +1580 -9.96785 6.31128 0.892152 +580 -9.82297 6.30492 -0.105142 +1250 -9.25583 5.47652 -0.397535 +89 -9.33017 7.02181 1.24658 +1652 -10.2533 5.48699 -0.673676 +1574 -8.32267 7.08341 1.20328 +2220 -8.06871 5.78814 0.808793 +2265 -8.34604 5.2523 0.00121411 +95 -8.94368 6.26321 0.717755 +244 -9.47107 7.20581 0.252929 +1891 -8.33806 6.90384 0.154499 +243 -8.51714 6.16408 -0.505304 +1262 -7.97831 7.37061 -0.698075 +1649 -9.04578 7.02166 -0.634167 +568 -7.21296 5.89656 1.31852 +364 -5.30806 5.62608 1.065 +766 -6.57223 6.85971 1.2917 +1562 -5.63961 6.57032 1.07415 +1908 -7.63613 6.20151 -0.00855684 +1462 -7.23117 5.39238 0.428179 +1374 -6.32548 5.87109 0.859863 +360 -6.67976 5.91762 -0.228013 +1477 -5.69995 5.95863 0.0846891 +425 -7.74758 7.67293 0.496294 +644 -6.32974 6.70819 0.296365 +2140 -6.72401 7.57801 0.613287 +553 -7.44984 6.76365 0.797815 +1194 -7.19581 7.09738 -0.135868 +1055 -5.23845 6.85393 0.204467 +1692 -5.6698 7.53567 0.805724 +2081 -5.90082 7.50742 -0.167975 +1929 -7.69912 5.50215 -0.722476 +1331 -6.8626 5.57232 -1.26528 +582 -5.94564 5.64697 -0.856622 +1518 -6.62766 7.24617 -0.946627 +585 -7.22477 6.43779 -0.897621 +603 -5.90225 6.62394 -0.636227 +354 -5.71842 7.60839 -1.16126 +1524 -2.64198 5.4345 0.467631 +2008 -3.18132 5.44309 1.31795 +1913 -2.86663 5.63449 -1.16456 +1261 -2.63054 6.42905 0.370533 +1975 -4.32488 5.80918 1.19854 +1126 -4.79983 7.69054 1.28436 +2304 -3.83871 7.38805 1.07 +522 -3.49127 6.39322 1.31215 +624 -4.60268 6.06972 0.261595 +1937 -3.61469 5.67231 0.444134 +1657 -4.19587 5.35295 -0.316688 +145 -4.61887 6.7488 0.996477 +2090 -3.31577 7.07182 -0.415043 +265 -3.75322 6.66213 0.385796 +771 -4.24695 7.5041 0.164985 +2199 -2.93538 7.35624 0.590591 +958 -5.03049 6.06067 -0.651483 +1049 -3.44836 6.07308 -0.476667 +786 -4.1817 5.95124 -1.17476 +1684 -4.93575 7.40608 -0.573259 +2120 -4.25523 6.67669 -0.479109 +698 -2.12869 5.88003 1.20391 +149 -1.42283 5.87294 0.486676 +2034 -0.925783 6.24053 1.33085 +1902 -0.476591 6.00497 0.176004 +1998 -2.405 6.83777 1.25954 +1697 -2.08335 5.67384 -0.337215 +1498 -0.579457 6.78715 -0.455957 +1955 -1.88599 7.3431 0.544763 +2317 -0.931054 6.82767 0.520425 +125 -1.87031 6.02935 -1.27579 +1709 -1.14841 5.95175 -0.570135 +647 -1.75705 6.6039 -0.118154 +1725 -0.231532 7.72213 -0.412761 +1818 -0.243912 7.16746 1.21249 +2104 -1.18358 7.52658 -0.158763 +1634 -1.55152 6.97737 -1.03056 +1836 -2.55329 6.48898 -0.712092 +1817 -2.35975 7.3956 -0.33469 +1868 0.0606903 6.21568 1.08443 +399 0.784725 7.12028 0.949425 +35 1.04448 6.06163 0.901688 +345 1.73311 6.78984 0.952664 +1669 2.07514 5.79893 0.847654 +296 1.98972 7.7513 0.80386 +1109 2.45433 5.6525 -0.856499 +1124 1.79681 5.75378 -0.108916 +1488 0.0591758 6.86227 0.309649 +128 0.0877094 6.14888 -0.840074 +169 1.30717 6.63466 0.0609852 +2001 1.2237 7.04129 -0.860789 +396 0.516411 6.00864 0.0548249 +45 1.09736 6.0528 -0.759432 +2182 0.18529 7.11266 -1.0952 +2327 2.08979 6.58372 -0.590354 +2233 2.40907 7.03918 0.240616 +1617 0.653087 7.62599 0.0448827 +322 2.50358 7.69704 -0.591778 +2367 1.63881 7.56382 -0.11458 +1523 2.97826 5.37367 0.787806 +2332 4.35737 7.4865 1.20837 +1958 2.8553 6.4599 0.92253 +188 3.78 6.13861 1.19026 +1303 3.97292 7.4667 0.196544 +1286 2.75917 6.0152 0.0238997 +2193 3.38827 7.29652 1.05308 +734 3.13971 6.93175 -0.491628 +2129 4.63761 5.54301 1.16364 +1885 4.6413 6.56998 0.912154 +2094 4.60167 5.20044 -0.337178 +358 4.01555 5.59926 0.372524 +966 3.42627 5.99793 -0.727351 +276 4.42649 6.13849 -0.641473 +1739 5.02241 5.88889 0.281512 +1253 4.74892 6.86671 -0.0369241 +2017 4.66538 7.7129 -0.562839 +239 3.63541 6.52878 0.277809 +1794 4.82762 5.46961 -1.28985 +420 4.03808 7.02009 -0.941464 +681 5.02303 6.86221 -1.09715 +2087 7.7763 7.36705 1.28598 +88 5.36965 7.70487 1.30937 +462 5.50412 6.04559 1.1465 +867 6.34132 5.48959 1.27824 +1096 6.38412 6.54989 1.04353 +1601 6.3541 7.53403 0.862329 +2358 6.06675 5.91821 0.330116 +93 6.50699 6.10031 -0.56302 +1572 7.01635 5.73785 0.581731 +959 7.02038 5.27075 -0.302278 +2264 7.4099 6.28608 -0.173373 +1870 5.5637 6.3984 -0.394946 +1812 5.5691 7.42575 -0.211542 +865 5.53691 6.95207 0.673105 +373 7.12378 7.3194 -0.315373 +1362 6.33481 6.84673 0.0821272 +984 7.20589 6.91827 0.59871 +170 5.79897 5.59781 -1.06327 +1052 7.39787 5.83967 -1.0698 +1152 5.38117 7.7923 -1.25706 +2207 5.99874 6.62158 -1.2708 +1768 6.28465 7.51127 -0.907017 +1160 6.99877 6.76018 -1.13568 +1382 9.88689 6.68343 -0.602674 +257 9.14471 7.71458 0.467273 +1451 10.3777 5.71524 0.828517 +1823 10.2073 5.88229 -1.12037 +398 9.25554 7.35755 -1.01296 +2204 9.71389 6.87133 0.585673 +351 7.90161 6.18919 0.692268 +479 8.84993 5.96213 0.941349 +2079 8.51098 6.98516 0.722043 +446 7.90716 5.32625 0.159458 +320 8.46237 6.09622 -0.155746 +1791 9.43388 6.02246 0.128583 +1064 7.86371 7.61479 0.292828 +628 8.07693 6.966 -0.477314 +842 9.02739 6.9221 -0.139425 +1806 8.34049 5.45809 -0.916164 +2251 9.24707 5.87661 -0.842945 +294 10.4083 5.9472 -0.143883 +279 -8.14621 8.62496 0.571364 +1090 -8.67998 7.99514 -0.328816 +1024 -8.78638 7.84782 0.665235 +197 -8.21366 8.3606 -1.15915 +2296 -6.50114 8.27879 1.29349 +1247 -7.71972 8.31396 -0.278504 +983 -6.58397 9.11579 -0.0105534 +1098 -6.77025 7.99749 -0.29645 +2200 -7.14822 8.47976 0.531698 +539 -6.10352 8.32679 0.374161 +556 -5.97705 9.23487 0.775952 +1379 -6.44305 10.0693 0.289309 +142 -6.96793 9.43449 0.855446 +1700 -7.57143 9.2777 0.069714 +1916 -5.59479 10.3925 0.710741 +588 -5.72321 9.49596 -0.38774 +1940 -7.31163 7.93068 -1.20165 +682 -7.56359 9.08027 -0.916128 +1676 -6.6179 8.75256 -0.941993 +1515 -5.75613 8.41561 -0.560297 +405 -6.63934 9.86651 -0.669756 +1539 -5.82677 10.1611 -1.21102 +2320 -3.16544 9.86011 -0.473286 +1154 -2.83689 9.61615 0.831976 +1317 -3.13733 8.71908 1.15628 +541 -4.08191 8.36998 1.11162 +117 -4.9096 8.91156 -0.367278 +1173 -5.13097 8.07624 0.143828 +181 -5.03617 8.6321 0.968409 +1558 -4.13905 8.50879 0.124664 +2052 -3.20396 8.98868 0.143988 +1493 -3.29334 8.01292 -0.0739396 +1767 -4.83628 10.0447 -0.352361 +2195 -5.06702 9.48285 0.443624 +2085 -4.43673 10.2133 0.720058 +209 -3.91231 9.34232 0.764818 +1240 -4.04753 9.44457 -0.220421 +2007 -4.94301 8.24006 -1.13493 +2258 -4.06419 7.97913 -0.726068 +1189 -3.20708 8.85216 -0.84845 +1925 -4.18466 8.91623 -1.06389 +1705 -3.06593 7.81008 -1.05887 +1112 -5.0691 9.50153 -1.15964 +763 -4.15095 9.91884 -1.11244 +1484 -0.731345 8.44029 -0.897683 +2252 -2.39786 8.39497 -0.325163 +609 -2.37724 8.09034 0.992975 +1302 -0.820161 7.83263 0.737425 +2080 -2.39167 8.52886 -1.32882 +2350 -1.62347 8.29193 0.329444 +1815 -1.64407 8.024 -0.892622 +367 -2.11417 9.01253 1.27676 +2290 -1.79417 9.89628 0.850816 +1722 -0.797733 9.95738 0.987873 +502 -1.1951 9.04416 0.84983 +527 -0.679022 8.60071 0.113937 +366 -2.1453 9.14748 0.282747 +1858 -1.41495 9.04184 -0.400542 +524 -2.14051 9.99313 -0.253251 +433 -0.219527 10.2125 0.210207 +384 -1.16394 9.91072 0.0303939 +1063 -0.601423 10.2737 -0.743071 +2308 -0.194844 9.41502 -0.392845 +1383 -0.11352 9.26155 0.605851 +1954 -1.47346 9.84492 -0.995166 +130 -2.44047 9.49278 -1.06668 +1080 -0.602164 9.43892 -1.30824 +587 0.158487 8.01226 0.825167 +2137 1.12817 8.24475 0.676206 +855 2.27108 9.50104 0.879716 +1225 1.32582 9.44997 1.20169 +829 1.87161 8.61695 1.29154 +1729 1.63582 9.66456 -1.14352 +1458 0.655667 7.97485 -0.907514 +1343 0.779868 9.39739 -0.618135 +297 0.860499 9.16162 0.359058 +1661 0.276159 8.55728 -0.18578 +2330 1.26467 8.47423 -0.296044 +124 1.68032 9.37852 -0.178131 +1905 2.2018 8.65371 -0.63257 +938 2.26596 8.62692 0.371778 +866 0.16806 8.81429 -1.14926 +1157 2.41369 10.034 -0.0192234 +1480 1.18124 8.78683 -1.30152 +2126 1.64382 7.93168 -1.04619 +2383 0.545273 9.97123 0.856977 +540 0.726089 10.2553 -0.108792 +1403 1.52978 10.1247 0.476149 +589 0.256061 10.0239 -1.19342 +740 2.82799 8.11099 1.20957 +73 3.7607 8.20858 0.837576 +195 2.91392 8.30032 -1.28265 +1158 4.03307 10.3473 0.297758 +87 3.6952 9.89089 1.26415 +2073 3.22249 9.0233 1.10404 +1675 4.13454 9.13801 0.670389 +175 3.27501 9.69701 0.362967 +921 4.69105 8.46016 1.15166 +1251 3.01793 7.83218 0.264827 +299 3.04473 9.58051 -0.650199 +1337 3.20248 8.7082 -0.182497 +9 3.5314 7.85155 -0.616648 +2391 2.72004 10.349 1.16925 +477 4.15622 8.41678 -0.0595995 +683 5.0012 8.89397 0.206268 +616 4.89175 7.80322 0.423577 +2154 3.96026 9.371 -0.28597 +1602 4.57666 10.117 -0.50532 +1528 4.91562 9.89248 0.409406 +1805 3.72446 8.86277 -1.11704 +281 4.71915 8.66744 -0.876938 +2044 4.91464 9.56722 -1.2712 +2298 6.36705 9.86227 1.19788 +370 7.19653 8.07394 0.880801 +343 5.58978 8.39188 -0.46936 +881 5.74239 8.32849 0.619172 +1582 7.33946 8.38647 -0.0744992 +499 6.60593 8.84375 0.624188 +787 6.76669 9.75269 -0.869305 +794 6.28813 9.08646 -0.295254 +1743 6.19757 10.1509 -0.147026 +461 5.41462 9.57734 -0.40255 +2291 5.79415 9.42251 0.507822 +2172 7.50576 9.33812 -0.339923 +1219 6.94697 9.75262 0.379997 +1180 7.64855 9.06796 0.613153 +761 5.79944 9.0818 -1.17843 +687 6.77502 8.4528 -0.897563 +1983 5.90349 10.2015 -1.10457 +1142 6.41771 7.99655 -0.0427021 +1642 7.6264 7.91821 -0.937509 +1500 8.61588 7.91258 1.29853 +1313 8.61555 7.80162 -0.375363 +2277 8.41604 8.45465 0.3701 +463 8.19489 8.6754 -0.624667 +60 -5.73125 10.4976 -0.275314 +927 -3.6421 10.7968 -1.05652 +252 -4.60314 10.9381 -0.784892 +715 -3.1202 11.4229 0.809206 +1032 -3.38744 10.4389 0.690534 +1938 -2.90895 11.4637 -0.908871 +2227 -4.08589 11.154 0.682662 +1876 -2.87223 10.7488 -0.12087 +2192 -3.65439 11.4011 -0.195414 +305 -3.93558 10.4401 -0.149811 +1155 -4.91392 10.8976 0.165807 +480 -1.41855 10.8212 0.749254 +1161 -2.41609 10.6967 0.82133 +1972 -2.03545 11.6325 0.99129 +863 -1.01351 11.7896 0.931081 +227 -0.374976 10.9863 0.824507 +1041 -2.5483 11.689 0.0114974 +2173 -1.56476 11.8686 0.0949302 +1971 -1.88282 10.9558 -0.169321 +1104 -0.458168 11.9245 0.050264 +115 -0.882887 10.9935 -0.103686 +2057 -1.42446 10.8519 -1.08015 +1895 -1.90256 11.7002 -0.846893 +1525 -2.46694 10.5352 -1.05497 +1796 -0.85895 11.6687 -0.8982 +1912 2.24658 11.6457 -0.902233 +1741 1.65561 10.4644 -0.518178 +1058 2.1125 10.9416 0.259292 +712 0.174485 11.8456 0.889993 +969 0.63385 10.9604 0.968111 +1848 1.66002 10.7866 1.21439 +581 1.18728 11.795 0.86237 +528 2.16732 11.6301 0.983639 +2058 0.138024 11.1152 -0.116542 +1312 0.629933 11.984 -0.0183475 +508 1.14465 11.1362 0.105951 +2268 1.82946 11.8595 -0.0155052 +1263 0.244052 11.7878 -0.919609 +1128 1.2446 11.8121 -0.829303 +1348 0.797518 10.9166 -0.866883 +1694 4.95671 10.5972 1.3019 +995 4.81844 10.9618 0.374056 +1987 2.81388 11.6622 0.0946263 +1288 4.05295 11.0163 1.21175 +905 3.13561 11.3846 1.01481 +697 2.66707 10.7782 -0.632824 +516 3.08815 10.7131 0.276336 +1489 3.62058 10.429 -0.624662 +1648 3.46052 11.4179 -0.631591 +750 3.86699 11.3455 0.278408 +627 4.418 11.1039 -0.535335 +1150 4.95221 10.6084 -1.2928 +1808 5.73436 10.4506 0.684675 +1 5.39229 10.6877 -0.396908 +102 -2.85061 -10.931 -1.82366 +1344 -3.71626 -10.4228 -2.05336 +259 -0.963175 -10.8427 -2.29328 +2275 -1.69922 -11.2686 -1.63446 +2084 -2.01005 -10.5644 -2.31273 +1690 -0.636404 -11.4966 -1.59511 +2232 -0.021617 -10.7208 -1.39082 +1517 1.05415 -10.6627 -1.38278 +1921 0.544052 -11.077 -2.14232 +118 1.62269 -10.9785 -2.14475 +325 3.77708 -10.534 -2.05308 +2088 3.27638 -11.159 -1.44289 +747 2.61482 -10.8191 -2.11178 +2015 -8.00314 -8.17414 -1.71896 +614 -5.29519 -10.2592 -1.38735 +40 -6.8755 -9.12089 -1.74993 +720 -5.30643 -9.02575 -1.59903 +2054 -6.0384 -8.82309 -2.42154 +861 -6.05555 -9.69131 -1.70158 +1234 -7.15946 -8.30518 -2.2543 +228 -5.31382 -8.24915 -2.88341 +198 -6.36694 -7.92939 -2.73468 +870 -6.29061 -8.26352 -1.60782 +33 -4.63197 -9.97173 -2.10575 +352 -3.90172 -9.55457 -2.68264 +852 -2.9006 -10.0481 -2.5503 +121 -2.8004 -8.10878 -2.95487 +174 -4.32101 -8.54421 -2.92662 +785 -3.04184 -9.07813 -2.90398 +1274 -3.11986 -9.32521 -1.88894 +1903 -5.07651 -9.18534 -2.57807 +1688 -4.33029 -9.00556 -1.92463 +518 -4.69226 -8.09141 -2.1093 +168 -3.56454 -8.42642 -2.27139 +789 -0.440184 -9.50239 -2.95445 +1392 -0.283516 -8.96119 -2.12296 +1976 -2.15954 -9.6201 -1.9884 +1568 -0.828506 -8.57872 -2.93314 +2099 -0.930075 -8.21006 -1.96115 +2135 -1.79108 -8.28016 -2.93501 +2285 -2.39244 -8.65974 -2.18259 +444 -2.0078 -9.25642 -2.92611 +1116 -1.35888 -9.6616 -1.38258 +892 -0.625648 -9.9244 -2.05456 +625 -1.32804 -9.98925 -2.76463 +1663 -1.27029 -9.12345 -2.22067 +2288 -1.69922 -8.71812 -1.40845 +1030 -1.85267 -7.83072 -1.84382 +2064 0.0249154 -10.3924 -2.65523 +1414 1.04008 -10.3204 -2.6427 +906 0.480128 -9.80822 -1.76929 +1248 2.43726 -9.57356 -1.98431 +1473 2.03288 -10.2075 -2.64765 +1707 1.49174 -9.88918 -1.84606 +338 0.765198 -8.87308 -2.16441 +1543 0.0603959 -8.04824 -1.8859 +600 1.79473 -8.80926 -2.15125 +1644 1.08966 -7.95038 -1.87847 +739 2.12194 -7.87103 -1.95726 +2179 1.18571 -8.29894 -2.88873 +1332 0.182306 -8.45063 -2.93721 +1759 0.572964 -9.45868 -2.9599 +1879 2.18711 -8.25332 -2.91323 +988 2.5942 -9.22953 -2.91745 +379 1.5726 -9.35446 -2.9601 +537 4.80397 -8.85583 -2.79628 +2262 3.18169 -8.11579 -2.97558 +1168 4.18395 -8.09336 -2.99587 +656 4.66587 -7.84107 -2.1507 +2123 4.57754 -9.09328 -1.8521 +1419 3.84788 -8.44406 -2.12027 +126 4.87292 -10.2497 -1.86401 +515 3.61159 -9.02907 -2.91109 +713 3.07333 -10.0637 -2.58603 +976 4.08739 -9.83777 -1.4022 +2186 4.21299 -9.76121 -2.51595 +1433 2.7946 -8.58309 -2.18001 +495 3.43103 -9.3489 -1.97962 +891 3.05687 -10.181 -1.45742 +1475 5.39861 -9.51029 -2.28647 +1607 5.87099 -10.0126 -1.47564 +1949 5.28009 -7.98164 -2.93615 +1859 7.26846 -8.99479 -1.55583 +1139 5.49816 -8.7636 -1.63082 +42 6.42395 -8.48281 -1.36564 +716 6.39338 -9.2997 -1.94158 +277 6.85884 -8.47062 -2.31613 +1445 5.91224 -8.68054 -2.57338 +127 7.74165 -8.18457 -1.9238 +2114 -8.75897 -7.53587 -1.57226 +424 -8.53796 -6.82752 -2.24305 +843 -9.36653 -6.43976 -1.84345 +526 -9.66447 -5.49414 -2.1064 +1044 -8.8888 -5.62013 -1.46462 +1083 -8.82142 -5.89692 -2.48198 +1453 -7.94776 -5.58816 -2.86276 +213 -8.05521 -6.0393 -1.84563 +2334 -6.24583 -5.23496 -2.87357 +473 -6.94221 -5.96008 -2.96477 +1890 -7.72299 -7.49195 -2.39656 +140 -7.7158 -6.55168 -2.73446 +193 -7.79697 -7.0116 -1.5219 +1043 -6.92882 -7.47692 -1.7286 +2211 -5.60716 -7.68855 -2.10157 +200 -6.8191 -6.97744 -2.85825 +1221 -7.2287 -5.53689 -2.10211 +1877 -7.05564 -6.51791 -1.981 +2259 -5.32171 -5.57696 -2.70237 +80 -6.12067 -6.83639 -2.15579 +157 -5.65 -6.3031 -1.44464 +454 -6.27374 -5.84722 -2.08469 +1974 -5.51197 -5.33356 -1.6939 +2271 -5.69196 -7.22636 -2.98569 +2035 -5.98737 -6.27016 -2.98136 +957 -4.82546 -7.06794 -2.05301 +566 -3.89039 -7.50207 -1.98913 +438 -2.83396 -7.74134 -2.01556 +530 -3.08761 -7.02875 -2.6756 +2138 -4.82029 -6.06908 -1.98168 +1732 -4.05783 -6.75354 -2.63257 +1719 -3.87937 -5.84181 -2.24002 +2375 -5.00367 -6.50681 -2.88869 +635 -4.7071 -7.4571 -2.98232 +1852 -3.74416 -7.72815 -2.96458 +845 -3.21012 -6.82488 -1.70386 +1272 -2.997 -5.85471 -1.76857 +1144 -0.636252 -7.3969 -1.45673 +594 -0.684467 -6.39519 -1.52015 +1376 -2.15166 -7.38114 -2.68496 +415 -1.21473 -7.14504 -2.4176 +552 -2.36311 -6.54482 -2.18242 +1131 -0.0715678 -6.93642 -2.1425 +1780 -0.426322 -7.69463 -2.693 +1677 -1.56851 -6.86015 -1.52954 +767 -2.0622 -6.00085 -1.40034 +122 0.308569 -6.37321 -1.41076 +1900 1.54832 -7.16542 -1.39346 +2083 2.5518 -5.95163 -1.61995 +2301 0.561348 -7.55143 -2.63067 +979 0.920896 -6.79365 -2.08271 +1238 1.93598 -6.61101 -2.13375 +1035 1.55159 -7.39476 -2.62794 +1409 2.57454 -7.08589 -1.52768 +893 2.55968 -7.34227 -2.73573 +1441 3.5081 -5.52574 -1.7246 +221 3.20641 -7.66491 -2.03845 +536 2.96051 -6.50932 -2.35366 +2314 4.42218 -5.44414 -2.22734 +952 3.38356 -6.48005 -1.45101 +2240 4.03426 -7.09132 -1.92147 +1012 5.01687 -6.88738 -1.98735 +1296 3.92993 -6.28293 -2.51717 +490 4.94232 -6.17289 -2.70946 +2387 4.35105 -6.19951 -1.57399 +1153 3.58351 -7.18861 -2.83823 +2010 4.5922 -7.14639 -2.87637 +708 5.35279 -5.2024 -2.55541 +790 5.33656 -5.86606 -1.79456 +1452 7.40116 -5.97044 -1.38908 +1821 7.56225 -7.27689 -1.46513 +1006 6.27922 -7.76541 -2.83294 +2148 6.61955 -7.61852 -1.83429 +1226 5.64736 -7.67789 -2.05742 +148 7.23569 -7.55568 -2.61948 +1256 6.61619 -6.82778 -2.93194 +606 6.98844 -6.65416 -1.99737 +323 5.95829 -5.99768 -2.8374 +1687 6.95506 -5.88674 -2.93442 +1581 5.99258 -6.69073 -2.09647 +1855 5.60223 -7.02628 -2.96051 +908 7.60129 -6.64312 -2.79202 +1559 6.44917 -5.8075 -1.98015 +1054 7.32125 -5.34492 -2.16874 +1605 8.6018 -7.69126 -1.47364 +857 8.84573 -5.96566 -1.41307 +1782 8.11763 -6.3598 -1.97806 +542 8.14604 -7.3127 -2.28001 +2249 9.00757 -6.85645 -1.89361 +2039 8.84809 -5.92293 -2.50305 +50 8.29487 -5.23008 -1.96735 +2250 7.94658 -5.70751 -2.87856 +1638 9.67685 -5.65987 -2.00899 +1264 -10.6342 -4.32061 -1.6541 +194 -10.5857 -3.39642 -2.09982 +1737 -8.03922 -3.20442 -2.96114 +1918 -9.05552 -4.94077 -2.67665 +1397 -8.95934 -4.36793 -1.8622 +1094 -8.92783 -3.96507 -2.87242 +321 -8.99077 -2.88363 -2.95457 +1833 -8.15254 -4.61255 -2.95571 +1143 -8.15109 -3.9036 -2.2468 +584 -8.27778 -5.07971 -2.0589 +1740 -8.10342 -3.22408 -1.51345 +994 -9.70369 -4.81902 -1.36875 +62 -9.76248 -3.82493 -1.61658 +67 -9.82217 -2.82339 -1.76075 +1074 -9.89619 -4.53928 -2.31295 +1318 -9.76143 -3.4534 -2.66337 +85 -8.97041 -3.3524 -2.0559 +2171 -6.43164 -4.2117 -2.66456 +1516 -7.19738 -4.93042 -2.93069 +1491 -7.22698 -3.5733 -1.93818 +369 -5.74027 -3.72186 -2.07884 +183 -6.43273 -3.69478 -1.33969 +8 -7.03108 -2.74841 -1.40659 +101 -6.30851 -2.89862 -2.0813 +2009 -7.41531 -4.55941 -2.02777 +248 -7.37378 -3.94368 -2.87063 +90 -7.1077 -2.90485 -2.68238 +1205 -6.4756 -4.87961 -1.91848 +2338 -5.5632 -4.64653 -2.42691 +1866 -4.96781 -4.25143 -1.72006 +469 -4.64413 -5.10015 -2.13958 +1454 -3.85395 -5.13835 -1.53188 +772 4.98259 -4.95921 -1.55454 +1085 6.11545 -2.83735 -1.88015 +1598 5.3669 -4.14506 -1.989 +1797 7.36058 -3.47626 -1.84967 +672 7.08667 -3.80353 -2.80521 +2097 5.96036 -4.92926 -1.80671 +1017 6.19586 -3.7195 -2.35613 +2004 6.88108 -2.85309 -2.52623 +1053 6.34752 -5.07663 -2.7825 +2376 6.80969 -4.48099 -2.12047 +621 7.29817 -4.76792 -2.98582 +1613 9.03911 -4.01236 -2.78959 +1001 9.21677 -4.97953 -2.5817 +523 8.29726 -4.76388 -2.90927 +1353 7.80849 -4.3611 -2.12095 +1239 8.07862 -3.77493 -2.93963 +1082 8.54674 -3.38319 -2.06527 +1801 8.34917 -2.78964 -2.94409 +636 9.06283 -4.3908 -1.76882 +602 10.3294 -5.01628 -1.60797 +1186 9.11795 -2.92273 -1.38292 +2362 9.55112 -3.49443 -2.08184 +1513 9.97135 -4.38105 -2.29658 +91 9.34605 -2.86273 -2.84074 +1606 10.2542 -2.85782 -2.41684 +314 11.0176 -2.75661 -1.74658 +1471 10.6174 -3.7126 -1.92408 +642 -11.3679 -2.30749 -1.45875 +283 -10.4677 -1.75459 -1.49044 +1095 -11.3293 -0.257248 -1.82551 +1521 -11.0867 -1.21553 -2.0628 +1809 -10.7213 -2.40858 -2.21496 +311 -10.5761 -0.329932 -2.53558 +350 -8.56934 -0.246661 -2.9531 +2253 -9.45695 -0.102058 -1.99552 +1444 -8.15495 -1.16146 -2.87868 +2293 -9.22582 -1.64299 -2.95287 +680 -8.75582 -2.37621 -2.12209 +806 -9.73566 -0.764019 -2.88106 +1022 -8.93321 -0.918489 -2.29896 +1696 -8.19042 -2.17319 -2.93158 +1851 -8.36154 -1.51903 -1.71521 +2390 -9.59256 -1.85181 -1.96433 +1825 -9.22527 -1.13371 -1.36392 +963 -10.0614 -0.917859 -1.87942 +2078 -9.86593 -2.44917 -2.73254 +1878 -10.3111 -1.55969 -2.60482 +1990 -5.85545 -2.37363 -1.34279 +2155 -7.75466 -2.46219 -2.05811 +1577 -7.37055 -1.68181 -1.55763 +7 -6.52471 -1.92319 -2.03612 +830 -7.33533 -1.68588 -2.57764 +805 -7.72238 -0.746859 -1.74673 +1632 -6.77719 -0.947351 -2.05825 +2029 -7.61889 -0.334409 -2.65174 +2011 -6.30736 -0.311643 -1.33821 +939 7.07729 -2.34804 -1.4342 +1594 6.97785 -1.85618 -2.40166 +2370 6.22364 -1.86786 -1.64955 +1781 6.65372 -1.02054 -1.95985 +846 7.5628 -1.14468 -1.46142 +1994 7.08847 -0.264027 -1.46855 +677 7.4304 -0.988195 -2.59182 +1597 7.78099 -2.58741 -2.11918 +529 7.87694 -1.86968 -2.83978 +709 7.9441 -0.365472 -1.99267 +1236 8.12435 -2.00401 -1.36964 +2063 9.78889 -2.27813 -1.74819 +725 8.8924 -0.736248 -1.42788 +849 10.1676 -1.35016 -1.60197 +241 9.81215 -1.98375 -2.73524 +1040 8.86315 -1.72953 -2.95438 +138 8.74268 -2.31235 -2.11417 +620 8.43708 -0.785076 -2.92454 +569 8.34252 -1.30213 -2.07168 +1007 8.87447 -0.141749 -2.27774 +2310 9.81739 -0.393655 -2.02511 +2169 9.34131 -1.28846 -2.16349 +2159 9.45502 -0.586652 -2.95905 +2071 10.2649 -1.07963 -2.62179 +1232 11.4088 -1.86928 -1.48279 +2003 11.428 -0.0673064 -1.65865 +2130 10.6873 -1.94531 -2.25273 +1884 10.7255 -0.167962 -2.41428 +497 11.0931 -1.04209 -1.9708 +2139 -10.4613 1.85231 -2.50841 +428 -11.2073 1.87606 -1.84016 +2238 -11.093 0.912114 -2.09576 +1554 -10.409 0.241673 -1.71689 +324 -9.47055 1.22005 -2.92947 +543 -9.45614 0.217254 -2.9476 +413 -10.312 0.654565 -2.66947 +235 -7.85788 2.42978 -2.85561 +748 -9.94088 1.22322 -1.92119 +1608 -8.28734 0.167282 -2.08391 +754 -9.48444 2.01877 -2.32697 +1942 -8.57996 0.762359 -2.94368 +1306 -8.63141 1.77655 -2.96508 +783 -9.00891 0.879659 -2.04599 +1842 -8.15992 1.4085 -2.15044 +1050 -10.1606 2.14882 -1.60123 +2318 -9.10429 1.95736 -1.39634 +156 -8.54857 2.3479 -2.13419 +521 -6.87814 0.0628851 -2.07846 +2119 -7.62501 0.677695 -2.64128 +48 -7.26819 1.65527 -2.54457 +1268 -6.4533 2.02251 -1.93089 +356 -6.68825 1.04666 -1.98847 +1016 -7.58422 0.751704 -1.64572 +1129 -7.60363 2.25425 -1.81797 +1350 7.64739 2.01663 -2.79312 +317 7.57721 0.680453 -1.62997 +2374 6.51982 0.524901 -1.7174 +1748 7.58507 1.00938 -2.68124 +1751 6.88154 1.6017 -2.28962 +1088 7.16859 0.152737 -2.38061 +2198 6.2454 1.46855 -1.52354 +746 6.28271 2.37451 -1.94492 +2223 7.0768 2.04232 -1.41397 +1555 8.06852 0.142029 -2.85402 +1956 8.41817 0.79587 -2.17475 +2181 10.2237 1.91256 -2.59536 +743 8.57567 2.36296 -2.64665 +1862 9.36602 1.36957 -2.54128 +1664 7.86434 1.61554 -1.90048 +1467 8.45199 1.42045 -2.95721 +1584 8.99637 1.34397 -1.56994 +586 10.2784 2.31928 -1.42263 +1210 9.41725 2.1725 -1.93883 +1282 9.92509 0.308588 -2.81784 +1330 8.72774 0.266442 -1.37307 +2089 10.0527 1.39001 -1.75596 +99 9.4978 0.567874 -1.95061 +1689 8.96671 0.563702 -2.98983 +803 8.53577 2.24083 -1.45858 +1474 11.3609 0.988687 -1.70793 +2239 10.491 0.48524 -1.53449 +1526 10.6307 0.921505 -2.42481 +1411 11.013 1.90053 -1.96663 +404 -10.8509 3.83126 -1.37958 +210 -10.7879 2.83014 -2.01427 +24 -10.2356 3.65974 -2.14944 +359 -10.0083 2.81077 -2.64085 +84 -9.56801 4.41148 -2.00707 +839 -8.78758 4.4096 -2.64427 +1295 -7.95234 4.24168 -2.1066 +2134 -8.4039 3.48397 -2.85994 +661 -8.58664 4.93087 -1.73047 +1019 -9.3875 3.59695 -2.67796 +1571 -9.03381 2.69918 -2.95007 +598 -9.35249 2.90331 -1.76804 +401 -8.8053 3.77099 -1.86487 +245 -8.00435 3.17414 -1.98912 +1591 -7.15541 3.68986 -1.86028 +718 -5.93803 4.63084 -2.5366 +888 -6.02776 3.01261 -1.91678 +653 -6.37325 4.03184 -1.33812 +1659 -5.57014 3.92308 -1.93238 +889 -6.88208 2.82813 -1.43322 +2377 -7.39956 3.52741 -2.83196 +1853 -6.94228 2.69462 -2.5003 +1389 -6.41699 3.72851 -2.53452 +901 -7.49018 4.57325 -2.93024 +1736 -6.83091 4.63447 -2.07373 +534 -5.75596 4.81784 -1.39244 +765 -4.98385 4.73823 -2.02722 +2389 4.91652 4.83324 -2.06254 +826 5.67714 3.02005 -1.48149 +2026 6.94539 3.06282 -1.62836 +1936 7.76767 2.61933 -1.98446 +1207 5.54448 4.05405 -2.09873 +1233 6.21789 3.32991 -2.26552 +212 6.25616 4.14812 -1.39305 +1472 7.1987 4.03245 -1.71558 +30 5.89743 4.96568 -1.8759 +1660 6.96818 2.72757 -2.58006 +949 7.28984 4.6599 -2.97568 +2205 6.47907 4.29737 -2.35764 +1757 7.13553 3.68832 -2.80225 +1930 6.41541 5.14064 -2.89163 +1305 9.81925 4.67257 -2.33883 +2191 9.75129 3.58391 -2.65616 +432 8.81628 3.31457 -2.94511 +1181 9.53894 2.61213 -2.8287 +1193 9.82526 3.21278 -1.57068 +732 10.393 2.87611 -2.34965 +1537 8.89905 3.03854 -1.98341 +2287 7.90605 4.57179 -2.19048 +1963 8.05305 3.59179 -2.02743 +1435 8.44137 4.31535 -1.38565 +234 9.23967 3.98072 -1.88729 +110 9.08375 5.07519 -1.48416 +1254 7.8635 3.01226 -2.92474 +2060 8.07099 3.99364 -2.98997 +548 9.02006 4.29496 -2.81309 +394 11.1157 2.87035 -1.6381 +895 10.4961 3.85421 -2.02631 +2360 10.4054 4.9892 -1.58788 +1108 -9.85659 5.49942 -1.60064 +788 -9.06353 5.69773 -2.17679 +565 -8.27839 5.27175 -2.67038 +907 -8.30424 5.84989 -1.45108 +632 -8.91493 6.58981 -1.73542 +503 -7.90509 6.80548 -1.53171 +316 -8.66669 7.51031 -1.4248 +1079 -8.23349 6.2301 -2.37483 +1384 -7.88283 7.70149 -2.01706 +535 -6.7117 5.2099 -2.88774 +2255 -5.29841 5.79049 -1.62689 +336 -6.37303 6.4368 -1.50172 +402 -7.0259 7.19356 -1.87469 +2329 -5.21479 6.7529 -1.35242 +1448 -6.5605 6.19722 -2.98741 +2369 -7.18539 6.21249 -2.04052 +2047 -6.2246 5.4526 -2.02605 +1981 -7.49465 5.8375 -2.95054 +964 -7.58818 5.30094 -1.94671 +760 -5.40208 5.47112 -2.67942 +2161 -7.6268 6.97897 -2.66101 +332 -6.66779 7.18561 -2.87266 +1067 -5.63803 7.07702 -2.975 +1072 -5.80449 6.31586 -2.32139 +1758 -6.02819 7.26745 -2.0681 +1511 -3.1639 7.58716 -2.88175 +468 -3.50547 5.8301 -1.91582 +1666 -3.33578 6.64752 -2.51453 +119 -3.31623 6.6649 -1.34459 +1588 -4.33137 7.23798 -1.35281 +1416 -4.49001 5.57774 -2.2764 +96 -4.91754 6.35062 -2.78413 +840 -4.96729 7.18327 -2.22048 +155 -4.23131 6.51314 -2.03426 +318 -3.52428 7.4581 -1.94298 +741 -4.21228 7.07057 -2.87781 +1380 -0.853834 7.27251 -2.44582 +1229 -2.58887 6.27121 -1.93232 +132 -0.0420629 6.84944 -2.04314 +2235 -0.715952 6.40351 -1.38121 +1635 -0.722505 7.43928 -1.36183 +271 -1.53134 6.65549 -1.99541 +951 -2.43648 7.14837 -1.46679 +2103 -2.33962 7.0797 -2.5112 +2160 -1.63146 7.63943 -1.82623 +1724 0.2894 7.59681 -2.6286 +340 1.28938 7.61125 -2.6813 +925 0.774203 6.47714 -1.60461 +936 1.54237 6.80004 -2.1579 +1335 1.82331 6.14955 -1.4541 +1840 2.14693 7.12489 -1.42428 +808 2.53619 6.41344 -2.11833 +1609 0.926586 7.45921 -1.72185 +65 2.30745 7.24062 -2.63436 +388 3.32205 7.00706 -2.71369 +1464 2.95594 7.52764 -1.91629 +1624 4.00126 7.70414 -2.97622 +1291 5.19676 7.35589 -2.96961 +1038 3.97179 7.17692 -1.93229 +2312 3.23871 6.68514 -1.45608 +417 3.08857 5.71169 -1.62907 +1003 4.03596 5.31997 -1.89256 +1086 4.3369 6.28876 -1.62606 +1501 4.98508 6.88828 -2.10473 +307 4.6131 5.86787 -2.49943 +1693 3.65298 6.13632 -2.34155 +770 4.29183 6.75648 -2.82408 +1621 5.4604 6.02491 -1.90689 +917 7.15646 5.23043 -2.09525 +1283 7.42783 6.22554 -1.9919 +701 6.47929 5.8855 -1.75909 +1349 5.82673 7.42813 -2.08192 +2187 6.95115 7.68319 -1.63763 +1926 6.63351 6.83549 -2.06442 +256 5.47086 5.38747 -2.6856 +2321 6.38326 6.1349 -2.72979 +1820 7.24632 5.69229 -2.98108 +2012 6.16205 7.08201 -2.96482 +2045 5.42809 6.37841 -2.90228 +68 7.11747 7.65345 -2.62369 +1578 7.20918 6.68701 -2.869 +1899 8.80486 7.14361 -1.87951 +15 9.5397 6.54745 -1.53803 +1279 9.73423 5.65745 -1.97179 +14 8.21484 5.54273 -1.92793 +1308 8.9771 6.22466 -2.29865 +1204 7.89149 7.09919 -1.45114 +475 8.52743 6.32548 -1.375 +453 8.12054 5.21122 -2.92848 +327 8.08316 6.21479 -2.75006 +1322 9.06518 5.27231 -2.60521 +1065 7.98091 7.17622 -2.44409 +1285 -6.4383 8.08629 -1.66482 +2028 -7.19943 8.75459 -1.8007 +289 -5.75123 8.82837 -1.47162 +349 -6.48385 9.50762 -1.59216 +1906 -6.32694 8.83594 -2.31667 +184 -7.04121 8.01667 -2.45909 +1505 -5.38518 8.82753 -2.67311 +498 -6.05222 7.98563 -2.7806 +39 -5.40705 8.05674 -2.00896 +298 -5.58906 9.64971 -2.0388 +519 -3.21245 9.99317 -1.46918 +1412 -2.87462 9.16151 -1.93401 +264 -3.39961 8.77399 -2.70215 +482 -3.39258 9.89823 -2.61417 +1982 -2.65673 7.93439 -2.0872 +381 -4.76327 8.8947 -1.89301 +1187 -3.53407 8.43548 -1.70558 +937 -3.85965 9.36623 -1.90775 +496 -5.04239 7.92107 -2.93817 +1585 -4.04547 8.05755 -2.99065 +470 -4.38609 8.98358 -2.82516 +2117 -4.38054 7.97949 -2.02135 +753 -4.6422 9.82053 -2.33627 +2016 -1.36391 8.83016 -2.99126 +1015 -1.46082 8.92172 -1.39678 +693 -2.52185 8.36522 -2.98007 +457 -0.865002 8.28684 -1.89498 +382 -0.627484 8.16174 -2.86275 +1244 -1.63179 7.88225 -2.80178 +436 -2.58762 9.36891 -2.88841 +357 -0.73767 10.1609 -2.75465 +1867 -2.00262 8.76608 -2.22282 +443 -2.47923 10.3031 -2.52002 +924 -1.66554 9.78074 -2.85345 +1410 -1.04019 9.3514 -2.20299 +306 -0.101237 8.89953 -2.1112 +2188 -0.442033 9.21975 -2.99016 +1087 -1.92431 9.7562 -1.88307 +2151 -0.830316 10.3079 -1.7664 +662 1.97646 7.93492 -1.989 +2132 0.0693891 7.97441 -1.71768 +1459 0.305093 8.54601 -2.95493 +1430 2.05845 8.21923 -2.94162 +219 0.903657 9.43201 -2.02975 +1172 0.897796 8.37401 -2.17018 +1329 2.5001 9.21427 -1.40511 +92 1.75354 8.90172 -2.11297 +1101 1.09288 10.3477 -1.63957 +1595 0.0259705 9.89732 -2.15818 +1854 2.16394 9.80341 -2.13632 +288 1.25627 8.84871 -2.99023 +1667 0.514327 9.5298 -2.94987 +1932 2.28912 9.19098 -2.93711 +2349 1.46387 9.82716 -2.84687 +291 3.00695 10.1294 -1.47338 +2234 2.70307 8.59286 -2.21653 +885 3.02546 7.94243 -2.93934 +365 4.672 7.84008 -2.2306 +1307 4.16302 8.00207 -1.37855 +2256 3.64311 8.24518 -2.20036 +1811 4.29188 8.95905 -1.93555 +965 3.98352 9.90916 -1.39841 +768 3.35316 9.3049 -1.93185 +179 4.66984 10.1017 -2.10704 +2270 3.31412 8.9134 -2.95006 +514 4.28505 8.66062 -2.90877 +59 3.01006 9.8398 -2.70422 +273 3.99595 9.59628 -2.65043 +371 4.99817 9.27544 -2.56972 +78 6.15221 8.28167 -1.66478 +629 5.21867 8.59291 -1.84036 +2082 7.50418 8.89283 -1.43062 +1347 6.93653 8.55304 -2.22466 +1354 7.79059 8.07672 -2.01522 +900 5.60873 9.77888 -1.95839 +411 6.56606 9.354 -1.76037 +1387 5.93824 8.96369 -2.43114 +844 6.21384 8.05932 -2.75408 +304 5.26405 8.35288 -2.8542 +1967 8.53715 7.96255 -1.35927 +391 -3.041 10.8932 -1.87543 +2175 -3.95478 10.4503 -1.96425 +1455 -4.91412 10.4104 -1.57506 +947 -2.08024 11.2125 -1.754 +1320 -0.940934 11.3072 -1.86454 +2131 -0.101327 10.9496 -1.34406 +2118 -1.52197 10.6773 -2.40396 +258 -0.150015 10.8672 -2.34011 +879 0.722928 10.4544 -2.60643 +679 1.6696 10.6954 -2.38067 +400 2.07553 10.5181 -1.43541 +1111 1.63056 11.3887 -1.64819 +274 0.68325 11.2571 -1.94062 +459 2.65771 10.6724 -2.24831 +1962 2.96286 11.2266 -1.47653 +1807 3.64899 10.4199 -2.19785 +1401 3.94709 10.9569 -1.40844 diff --git a/contrib/voro++/examples/walls/tetrahedron.cc b/contrib/voro++/examples/walls/tetrahedron.cc new file mode 100644 index 0000000000000000000000000000000000000000..eadfb8afecdd872525891ffefb67313f2ef7b6a1 --- /dev/null +++ b/contrib/voro++/examples/walls/tetrahedron.cc @@ -0,0 +1,59 @@ +// Tetrahedron example code +// +// Author : Chris H. Rycroft (LBL / UC Berkeley) +// Email : chr@alum.mit.edu +// Date : August 30th 2011 + +#include "voro++.hh" +using namespace voro; + +// Set up constants for the container geometry +const double x_min=-2,x_max=2; +const double y_min=-2,y_max=2; +const double z_min=-2,z_max=2; + +// Set up the number of blocks that the container is divided +// into +const int n_x=7,n_y=7,n_z=7; + +// Set the number of particles that are going to be randomly +// introduced +const int particles=64; + +// This function returns a random double between 0 and 1 +double rnd() {return double(rand())/RAND_MAX;} + +int main() { + int i=0; + double x,y,z; + + // Create a container with the geometry given above, and make it + // non-periodic in each of the three coordinates. Allocate space for 8 + // particles within each computational block. + container con(x_min,x_max,y_min,y_max,z_min,z_max,n_x,n_y,n_z, + false,false,false,8); + + // Add four plane walls to the container to make a tetrahedron + wall_plane p1(1,1,1,1);con.add_wall(p1); + wall_plane p2(-1,-1,1,1);con.add_wall(p2); + wall_plane p3(1,-1,-1,1);con.add_wall(p3); + wall_plane p4(-1,1,-1,1);con.add_wall(p4); + + // Randomly insert particles into the container, checking that they lie + // inside the tetrahedron + while(i<particles) { + x=x_min+rnd()*(x_max-x_min); + y=y_min+rnd()*(y_max-y_min); + z=z_min+rnd()*(z_max-z_min); + if (con.point_inside(x,y,z)) { + con.put(i,x,y,z);i++; + } + } + + // Output the particle positions and the Voronoi cells in Gnuplot and + // POV-Ray formats + con.draw_particles("tetrahedron_p.gnu"); + con.draw_cells_gnuplot("tetrahedron_v.gnu"); + con.draw_particles_pov("tetrahedron_p.pov"); + con.draw_cells_pov("tetrahedron_v.pov"); +} diff --git a/contrib/voro++/examples/walls/tetrahedron.pov b/contrib/voro++/examples/walls/tetrahedron.pov new file mode 100644 index 0000000000000000000000000000000000000000..b327925fe0c4886fae77a622c189ca6665f59c11 --- /dev/null +++ b/contrib/voro++/examples/walls/tetrahedron.pov @@ -0,0 +1,38 @@ +#version 3.6; + +#include "colors.inc" +#include "metals.inc" +#include "textures.inc" + +global_settings { + max_trace_level 64 +} + +camera { + location <20,30,-50> + right 0.26*x*image_width/image_height + up 0.26*y + look_at <0,-2,0> +} + +background{rgb 1} + +light_source{<-8,30,-20> color rgb <0.77,0.75,0.75>} +light_source{<20,5,-15> color rgb <0.38,0.40,0.40>} + +#declare r=0.025; +#declare s=0.07; + +union{ +#include "tetrahedron_p.pov" + scale 5 + rotate <0,-65,0> + texture{T_Silver_3C} +} + +union{ +#include "tetrahedron_v.pov" + scale 5 + rotate <0,-65,0> + pigment{rgb <0.3,0.3,0.9>} finish{phong 0.9 ambient 0.42 reflection 0.1} +} diff --git a/contrib/voro++/examples/walls/torus.cc b/contrib/voro++/examples/walls/torus.cc new file mode 100644 index 0000000000000000000000000000000000000000..7948a84a40fd4ad5702e391400c1fd16f61023dd --- /dev/null +++ b/contrib/voro++/examples/walls/torus.cc @@ -0,0 +1,111 @@ +// Custom wall class example code +// +// Author : Chris H. Rycroft (LBL / UC Berkeley) +// Email : chr@alum.mit.edu +// Date : August 30th 2011 + +#include "voro++.hh" +using namespace voro; + +// Major and minor torus radii +const double arad=9,brad=3.5; + +// The outer radius of the torus, that determines how big the container should +// be +const double crad=arad+brad; + +// Set up constants for the container geometry +const double x_min=-crad-0.5,x_max=crad+0.5; +const double y_min=-crad-0.5,y_max=crad+0.5; +const double z_min=-brad-0.5,z_max=brad+0.5; + +// Set the computational grid size +const int n_x=10,n_y=10,n_z=3; + +// This class creates a custom toroidal wall object that is centered on the +// origin and is aligned with the xy plane. It is derived from the pure virtual +// "wall" class. The "wall" class contains virtual functions for cutting the +// Voronoi cell in response to a wall, and for telling whether a given point is +// inside the wall or not. In this derived class, specific implementations of +// these functions are given. +class wall_torus : public wall { + public: + + // The wall constructor initializes constants for the major and + // minor axes of the torus. It also initializes the wall ID + // number that is used when the plane cuts are made. This is + // only tracked with the voronoicell_neighbor class and is + // ignored otherwise. It can be omitted, and then an arbitrary + // value of -99 is used. + wall_torus(double imjr,double imnr,int iw_id=-99) + : w_id(iw_id), mjr(imjr), mnr(imnr) {}; + + // This returns true if a given vector is inside the torus, and + // false if it is outside. For the current example, this + // routine is not needed, but in general it would be, for use + // with the point_inside() routine in the container class. + bool point_inside(double x,double y,double z) { + double temp=sqrt(x*x+y*y)-mjr; + return temp*temp+z*z<mnr*mnr; + } + + // This template takes a reference to a voronoicell or + // voronoicell_neighbor object for a particle at a vector + // (x,y,z), and makes a plane cut to to the object to account + // for the toroidal wall + template<class vc_class> + inline bool cut_cell_base(vc_class &c,double x,double y,double z) { + double orad=sqrt(x*x+y*y); + double odis=orad-mjr; + double ot=odis*odis+z*z; + + // Unless the particle is within 1% of the major + // radius, then a plane cut is made + if(ot>0.01*mnr) { + ot=2*mnr/sqrt(ot)-2; + z*=ot; + odis*=ot/orad; + x*=odis; + y*=odis; + return c.nplane(x,y,z,w_id); + } + return true; + } + + // These virtual functions are called during the cell + // computation in the container class. They call instances of + // the template given above. + bool cut_cell(voronoicell &c,double x, + double y,double z) {return cut_cell_base(c,x,y,z);} + bool cut_cell(voronoicell_neighbor &c,double x, + double y,double z) {return cut_cell_base(c,x,y,z);} + private: + // The ID number associated with the wall + const int w_id; + // The major radius of the torus + const double mjr; + // The minor radius of the torus + const double mnr; +}; + +int main() { + + // Create a container with the geometry given above, and make it + // non-periodic in each of the three coordinates. Allocate space for + // eight particles within each computational block. + container con(x_min,x_max,y_min,y_max,z_min,z_max,n_x,n_y,n_z, + false,false,false,8); + + // Add the custom toroidal wall to the container + wall_torus tor(arad,brad); + con.add_wall(tor); + + // Import the particles from a file + con.import("pack_torus"); + + // Output the particle positions in POV-Ray format + con.draw_particles_pov("torus_p.pov"); + + // Output the Voronoi cells in POV-Ray format + con.draw_cells_pov("torus_v.pov"); +} diff --git a/contrib/voro++/examples/walls/torus.pov b/contrib/voro++/examples/walls/torus.pov new file mode 100644 index 0000000000000000000000000000000000000000..95cb5137f1123981e7bb73c4ade6f623ea255058 --- /dev/null +++ b/contrib/voro++/examples/walls/torus.pov @@ -0,0 +1,46 @@ +#version 3.6; + +// Increase the trace level for more accurate reflections +global_settings { + max_trace_level 64 +} + +// Right-handed coordinate system in which the z-axis points upwards +camera { + location <0,-40,34> + sky z + right -0.4*x*image_width/image_height + up 0.4*z + look_at <0,0,-1.31> +} + +// White background +background{rgb 1} + +// Two lights with slightly different colors +light_source{<-16,-20,43> color rgb <0.72,0.69,0.69>} +light_source{<30,-15,12> color rgb <0.34,0.37,0.37>} + +// Radius of the Voronoi cell network, and the particle radius +#declare r=0.06; +#declare s=0.5; + +// Particles +union{ + #include "torus_p.pov" + pigment{rgb 0.97} + finish{reflection 0.1 ambient 0.30 specular 0.3} +} + +// Voronoi cells, using a radial pigment map +union{ + #include "torus_v.pov" + pigment{radial pigment_map { + [0 rgb <0.5,0.7,1>] + [0.25 rgb <0.38,0.82,0.92>] + [0.5 rgb <0.5,0.7,1>] + [0.75 rgb <0.65,0.4,1>] + [1 rgb <0.5,0.7,1>]} + rotate <270,0,0>} + finish{specular 0.3 ambient 0.3 reflection 0.1} +} diff --git a/contrib/voro++/man/voro++.1 b/contrib/voro++/man/voro++.1 new file mode 100644 index 0000000000000000000000000000000000000000..f91c288c5a9330a5ba1b9925260cf807fc81e9de --- /dev/null +++ b/contrib/voro++/man/voro++.1 @@ -0,0 +1,346 @@ +.TH VORO++ 1 "August 28 2011" +.UC 4 +.SH NAME +voro++ \- a 3D Voronoi cell library +.SH SYNOPSIS +.B voro++ +[options] <x_min> <x_max> <y_min> <y_max> <z_min> <z_max> <filename> +.br +.SH DESCRIPTION +.PP +Voro++ is a software library for carrying out three-dimensional computations of +the Voronoi tessellation. A distinguishing feature of the Voro++ library is +that it carries out cell-based calculations, computing the Voronoi cell for +each particle individually, rather than computing the Voronoi tessellation as a +global network of vertices and edges. It is particularly well-suited for +applications that rely on cell-based statistics, where features of Voronoi +cells ( +.I eg. +volume, centroid, number of faces) can be used to analyze a system of +particles. + +.PP +Voro++ is written in C++ and can be built as a static library that can be +linked to. This man page describes a command-line utility that is provided with +the library, which can be used to access most of the library's functionality. +The utility imports text files of particle positions, computes the Voronoi +cells for them, and then saves text files containing various types of +information about the Voronoi cells. + +.SH FILE INPUT AND OUTPUT +.PP +The input file should have entries on separate lines with the following +format: +.PP +.RS +<Numerical ID label> <x coordinate> <y coordinate> <z coordinate> +.RE +.PP +When the command imports the particles, any that lie outside the container +geometry are ignored. The program then computes Voronoi cells for all the +particles, and generates an output file using the same filename but with a +".vol" suffix, that has the following entries: +.PP +.RS +<Numerical ID label> <x coordinate> <y coordinate> <z coordinate> <Voronoi cell volume> +.RE +.PP +To compute different statistics about the Voronoi cells, the \-c option can be +used to specify a custom output string. By default, the command assumes +non-periodic boundary conditions, although this can be modified with the \-p +option described below. If periodicity is enabled, then particles will be +re-mapped into the primary domain when the file is imported. + +.PP +Under normal operation, the output file should have exactly the same number +of lines in as the input file. However, if particles lie outside the container +geometry, they will be omitted by the program, and will not appear in the +output file. In certain cases, a Voronoi cell for a valid particle may be +completely deleted ( +.I eg. +by a wall cut) and it will also not appear in +the output file. By default, the particles in the output file may be ordered +differently to those in the input file, although the original ordering can be +preserved with the \-o option described below. + +.SH INTERNAL COMPUTATIONAL GRID +.PP +To carry out the computation, the code divides the computational box into a +grid of equally-sized rectangular blocks. Particles are internally sorted into +this grid for computational efficiency, with maximum performance usually being +achieved when there is an average of 3 to 8 particles per block. Performance is +also improved if the blocks are close to cubes, with similar side lengths in +three directions. In general the code is not very sensitive to the block size, +and reasonable performance is achieved over a large range of values. +.PP +By default, the code estimates the grid size to use by counting the number +of particles in the input file and choosing the number of blocks to aim for a +3 to 8 particles per block. However, is also possible to manually configure the +grid size using the \-l and \-n options. + +.SH OPTIONS +The utility accepts the following basic options: + +.B +.IP \-c <string> +This option allows the format of the output file to be customized to hold a +variety of statistics about the computed Voronoi cells. The specified string +can contain regular characters, plus control sequences beginning with +percentage signs that are expanded to contain different Voronoi cell +statistics. See below for a full custom output reference. +.B +.IP \-g +If this option is specified, then an additional output file is generated with +the ".gnu" extension, which contains a description of all the cells in a format +that can be viewed using gnuplot using the +.I splot +command. Caution: For large input files, the gnuplot output file will be +extremely large, so this option is best used on smaller systems. +.B +.IP \-h or \-\-help +This option prints out a summary of the command syntax and the available +options. +.B +.IP \-hc +This option prints out all the available control sequences for the customized +output. +.B +.IP -l <len> +Manually specify a typical length scale between particles, with which to +configure the internal grid size. For example, if the particles represent +densely-packed hard spheres of diameter d, then d would be an appropriate value +to use. The length scale can be used to estimate the optimal grid size. Using +this option will result in a small performance boost, since the internal grid +can be set up immediately, and it is not necessary to temporarily store the +input file contents while estimating the grid size. +.B +.IP -m <mem> +Manually specify the initial number of particles that can be stored in each +block. By default a value of 8 is used. For any block where this limit is +reached, the code will dynamically allocate more memory as neccessary, so +usually it is not necessary to alter this. +.B +.IP -n <nx> <ny> <nz> +Manually specify the internal computational grid to have nx, ny, and nz blocks +in the x, y, and z directions respectively, giving nx*ny*nz blocks in total. +Manually specifying the size will result in a small performance boost, since +the internal grid can be set up immediately, and it is not necessary to +temporarily store the input file contents while estimating the size. +.B +.IP \-o +Ensure that particles in the output file are in the same order as those in the +input file. This may result in a very small increase in memory usage and +execution time, and is turned off by default. +.B +.B +.IP \-p +Make the container periodic in all three coordinate directions. +.B +.IP \-px +Make container periodic in the x direction. +.B +.IP \-py +Make container periodic in the y direction. +.B +.IP \-pz +Make container periodic in the z direction. +.B +.IP \-r +Carry out a Voronoi tessellation for a polydisperse particle arrangement using +the radical Voronoi tessellation. For this case, an extra column is required in +the input file, that contains the particle radii. The radii are also included +in the output file. +.B +.IP \-v +Verbose output. After the computation is completed, some statistics are printed +about the container geometry, the internal computational grid, the number of +particles imported, the number Voronoi cells computed, and the volume of the +computed Voronoi cells. +.B +.IP \-\-version +Print version information. +.B +.IP \-y +Save the particles in POV-Ray format to "filename_p.pov" and the Voronoi cells +in POV-Ray format to "filename_v.pov". Caution: For large input files, the +POV-Ray Voronoi cell file will be extremely large, so this option is best used +on smaller systems. +.B +.IP \-yp +Save the particles in POV-Ray format to "filename_p.pov". +.B +.IP \-yv +Save the Voronoi cells in POV-Ray format to "filename_v.pov". + +.SH OPTIONS FOR WALLS +In addition, a number of options can be used to specify wall objects. Walls +are implemented by applying extra plane cuts during the cell construction +process. At present, four wall types are supported: + +.B +.IP \-wb <x1> <x2> <x3> <x4> <x5> <x6> +Add six plane wall objects to make a box containing the space x1<x<x2, x3<y<x4, +and x5<z<z6. This can be useful for embedding a smaller box within a larger +container, in cases when the influence of particles outside the smaller box +still need to be considered. This option is shorthand to avoid using the \-wp +option six times. +.B +.IP \-wc <x1> <x2> <x3> <x4> <x5> <x6> <x7> +Add a cylindrical wall object, where (x1,x2,x3) is a point on the cylinder +axis, (x4,x5,x6) is a vector along the cylinder axis, and x7 is the cylinder +radius. +.B +.IP \-wo <x1> <x2> <x3> <x4> <x5> <x6> <x7> +Add a conical wall object, with apex at (x1,x2,x3), axis along (x4,x5,x6), and +half angle x7 (specified in radians). +.B +.IP \-ws <x1> <x2> <x3> <x4> +Add a spherical wall object, centered on (x1,x2,x3), with radius x4. +.B +.IP \-wp <x1> <x2> <x3> <x4> +Add a plane wall object, with normal (x1,x2,x3), and displacement x4. + +Each wall is accounted for using a single approximating plane; several of the +examples on the library website discuss this in more detail. If neighbor +information is requested via the custom output string, then the walls are +numbered sequentially, starting at -7 and decreasing. + +.SH CUSTOM OUTPUT COMMANDS +.PP +The output files created by Voro++ can be fully customized to contain a variety +of different statistics about the computed Voronoi cells. This is done by +specifying a format string that contains text plus additional control sequences +that begin with percentage signs. The output file contains a line for each +particle, where the control sequences are expanded to different statistics. +Several examples on the library website describe the customized output in +more detail. + +.PP +Particle-related entries: + +.B +.IP %i +The particle ID number. +.B +.IP %x +The x coordinate of the particle. +.B +.IP %y +The y coordinate of the particle. +.B +.IP %z +The z coordinate of the particle. +.B +.IP %q +The position vector of the particle, short for "%x %y %z". +.B +.IP %r +The radius of the particle (only printed if the polydisperse information is +available). + +.PP +Vertex-related entries: + +.B +.IP %w +The number of vertices in the Voronoi cell. +.B +.IP %p +A list of the vertices of the Voronoi cell in the format (x,y,z), relative to +the particle center. +.B +.IP %P +A list of the vertices of the Voronoi cell in the format (x,y,z), relative to +the global coordinate system. +.B +.IP %o +A list of the orders of each vertex. +.B +.IP %m +The maximum radius squared of a vertex position, relative to the particle +center. + +.PP +Edge-related entries: + +.B +.IP %g +The number of edges of the Voronoi cell. +.B +.IP %E +The total edge distance. +.B +.IP %e +A list of perimeters of each face. + +.PP +Face-related entries: + +.B +.IP %s +The number of faces of the Voronoi cell. +.B +.IP %F +The total surface area of the Voronoi cell. +.B +.IP %A +A frequency table of the orders of the faces. +.B +.IP %a +A list of the orders of the faces, showing how many edges make up each face. +.B +.IP %f +A list of areas of each face. +.B +.IP %t +A list of bracketed sequences of vertices that make up each face. +.B +.IP %l +A list of normal vectors for each face. +.B +.IP %n +A list of the neighboring particle or wall IDs corresponding to each face. The +list can contain negative numbers. For the non-periodic case these correspond +to when the particles have faces created by the edges of the computational +region. The numbers -1 to -6 correspond to the minimum x, maximum x, minimum y, +maximum y, minimum z, and maximum z walls respectively. For periodic boundary +conditions, negative numbers correspond to the cases when a face of the Voronoi +cell is created by the periodic image of the current particle. + +In general, the neighbor information will be symmetric, so that if particle A +reports particle B as a neighbor, then particle B will report particle A as a +neighbor. However, due to the fact that Voro++ computes each Voronoi cell +individually, it does not provide an explicit guarantee that the neighbor +information will always be symmetric. Suppose there is a very small Voronoi +face connecting A to B - it may be the case that due to roundoff error, the +Voronoi cell computed for particle A has a face connecting it to B, but the +cell computed for particle B does not have a face connecting it to A. If the +user requires perfectly symmetric neighbor information, this can be achieved by +scanning the output for any one-sided connections, and either deleting them or +adding in the reverse connections. The face areas output from "%f" can also be +used to remove connections between particles that only have a very small face +between them. + +.PP +Volume-related entries: +.B +.IP %v +The volume of the Voronoi cell. +.B +.IP %c +The centroid of the Voronoi cell, relative to the particle center. +.B +.IP %C +The centroid of the Voronoi cell, in the global coordinate system. + + +.SH AUTHOR +Voro++ is written and maintained by Chris H. Rycroft, a visiting assistant +professor in the Department of Mathematics, University of California, Berkeley +and Department of Mathematics, Lawrence Berkeley National Laboratory. +Feedback about the code is welcome; please email chr@alum.mit.edu. +.SH BUGS +Contact Chris H. Rycroft (chr@alum.mit.edu) to report problems with the code. +.SH SEE ALSO +See the library website http://math.lbl.gov/voro++/ for complete documentation +and examples. diff --git a/contrib/voro++/scripts/README b/contrib/voro++/scripts/README new file mode 100644 index 0000000000000000000000000000000000000000..ad4ab777e61290ca0ffd5e858095c6a6bfb39564 --- /dev/null +++ b/contrib/voro++/scripts/README @@ -0,0 +1,12 @@ +Voro++ helper scripts +===================== +This directory contains auxiliary helper perl scripts for use with the library. + +random.pl - generates a random file of particles for testing the command-line +utility. Type "perl -h random.pl" for more information. + +network.pl - creates a neighbor network plot from a .vol file created by the +command line utility using the -n option. + +sum.pl - sums the volumes in a .vol file created by the command line utility, +for checking purposes. diff --git a/contrib/voro++/scripts/network.pl b/contrib/voro++/scripts/network.pl new file mode 100644 index 0000000000000000000000000000000000000000..2e7bf7aaafb3c476a46dd7d2c7707585d7213d6f --- /dev/null +++ b/contrib/voro++/scripts/network.pl @@ -0,0 +1,27 @@ +#!/usr/bin/perl +# This script takes a .vol file that has neighbor information created with +# the custom output string "%i %q %v %n", and creates a map of the network, by +# drawing a line between all particles which are neighbors + +open A,"@ARGV[0].vol" or die "Can't open input file"; +open B,">@ARGV[0].net" or die "Can't open output file"; + +$maxn=0; + +while(<A>) { + @A=split; + $n=@A[0]; + $x[$n]=@A[1]; + $y[$n]=@A[2]; + $z[$n]=@A[3]; + $c[$n]=$#A-5; + $l[$n][$_-5]=@A[$_] foreach 5..$#A; + $maxn=$n if $n>$maxn; +} + +foreach $n (1..$maxn) { + foreach (0..$c[$n]) { + $j=$l[$n][$_]; + print B "$x[$j] $y[$j] $z[$j]\n$x[$n] $y[$n] $z[$n]\n\n\n" if $j>=$n; + } +} diff --git a/contrib/voro++/scripts/random.pl b/contrib/voro++/scripts/random.pl new file mode 100644 index 0000000000000000000000000000000000000000..0cb65450849da26c3790212372f755157078ebbb --- /dev/null +++ b/contrib/voro++/scripts/random.pl @@ -0,0 +1,24 @@ +#!/usr/bin/perl +# This script can be used to generate random lists of particles in the unit +# box 0<x<1, 0<y<1, 0<z<1, that can be used as test input to voro++. The -r +# switch adds extra radial information for use with the Voronoi radical +# tessellation. +use Getopt::Std; +getopts("hr:"); + +if ($opt_h) { + print "Usage: random.pl [switches] <number of particles> <filename>\n"; + print "Switches:\n"; + print "-h Print this information\n"; + print "-r <max radius> Add extra radial column\n"; + exit 0; +}; + +@ARGV==2 or die "Exactly two command line arguments required\n"; +open A,">@ARGV[1]" or die "Can't open output file"; + +foreach (1..@ARGV[0]) { + printf A "$_ %f %f %f", rand(), rand(), rand(); + printf A " %f",$opt_r*rand() if $opt_r; + printf A "\n"; +} diff --git a/contrib/voro++/scripts/sum.pl b/contrib/voro++/scripts/sum.pl new file mode 100644 index 0000000000000000000000000000000000000000..64dc0674267134adb3b0fe9e565f6c60804812a0 --- /dev/null +++ b/contrib/voro++/scripts/sum.pl @@ -0,0 +1,14 @@ +#!/usr/bin/perl +# This script will take a .vol file created by voro++, and it will sum up the +# volumes of all the Voronoi cells. In many cases, this will equal the volume +# of the container, and it can be a useful check. +# +# It assumes that the volume is stored in the final column, so it works with +# both regular and polydisperse calculations. + +open A,"@ARGV[0]" or die "Can't open input file"; +while(<A>) { + @A=split; + $c+=pop @A; +} +print "$c\n"; diff --git a/contrib/voro++/src/Doxyfile b/contrib/voro++/src/Doxyfile new file mode 100644 index 0000000000000000000000000000000000000000..e0e8569a37ab9ee59983256a7b6074e6451b386d --- /dev/null +++ b/contrib/voro++/src/Doxyfile @@ -0,0 +1,1758 @@ +# Doxyfile 1.7.5.1 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" "). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or sequence of words) that should +# identify the project. Note that if you do not use Doxywizard you need +# to put quotes around the project name if it contains spaces. + +PROJECT_NAME = Voro++ + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer +# a quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = + +# With the PROJECT_LOGO tag one can specify an logo or icon that is +# included in the documentation. The maximum height of the logo should not +# exceed 55 pixels and the maximum width should not exceed 200 pixels. +# Doxygen will copy the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = .. + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, +# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English +# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, +# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, +# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = NO + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = YES + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful if your file system +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 8 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = YES + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given extension. +# Doxygen has a built-in mapping, but you can override or extend it using this +# tag. The format is ext=language, where ext is a file extension, and language +# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C, +# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make +# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C +# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions +# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also makes the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = YES + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate getter +# and setter methods for a property. Setting this option to YES (the default) +# will make doxygen replace the get and set methods by a property in the +# documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and +# unions are shown inside the group in which they are included (e.g. using +# @ingroup) instead of on a separate page (for HTML and Man pages) or +# section (for LaTeX and RTF). + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and +# unions with only public data fields will be shown inline in the documentation +# of the scope in which they are defined (i.e. file, namespace, or group +# documentation), provided this scope is documented. If set to NO (the default), +# structs, classes, and unions are shown on a separate page (for HTML and Man +# pages) or section (for LaTeX and RTF). + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = NO + +# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to +# determine which symbols to keep in memory and which to flush to disk. +# When the cache is full, less often used symbols will be written to disk. +# For small to medium size projects (<1000 input files) the default value is +# probably good enough. For larger projects a too small cache size can cause +# doxygen to be busy swapping symbols to and from disk most of the time +# causing a significant performance penalty. +# If the system has enough physical memory increasing the cache will improve the +# performance by keeping more symbols in memory. Note that the value works on +# a logarithmic scale so increasing the size by one will roughly double the +# memory usage. The cache size is given by this formula: +# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols + +SYMBOL_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespaces are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen +# will list include files with double quotes in the documentation +# rather than with sharp brackets. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen +# will sort the (brief and detailed) documentation of class members so that +# constructors and destructors are listed first. If set to NO (the default) +# the constructors will appear in the respective orders defined by +# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. +# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO +# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to +# do proper type resolution of all parameters of a function it will reject a +# match between the prototype and the implementation of a member function even +# if there is only one candidate or it is obvious which candidate to choose +# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen +# will still accept a match between prototype and implementation in such cases. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or macro consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and macros in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. The default is NO. + +SHOW_DIRECTORIES = NO + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. +# This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command <command> <input-file>, where <command> is the value of +# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. The create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. +# You can optionally specify a file name after the option, if omitted +# DoxygenLayout.xml will be used as the name of the layout file. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files +# containing the references data. This must be a list of .bib files. The +# .bib extension is automatically appended if omitted. Using this command +# requires the bibtex tool to be installed. See also +# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style +# of the bibliography can be controlled using LATEX_BIB_STYLE. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# The WARN_NO_PARAMDOC option can be enabled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = . + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh +# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py +# *.f90 *.f *.for *.vhd *.vhdl + +FILE_PATTERNS = + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# Note that relative paths are relative to directory from which doxygen is run. + +EXCLUDE = cmd_line.cc + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command <filter> <input-file>, where <filter> +# is the value of the INPUT_FILTER tag, and <input-file> is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. +# If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. +# Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. +# The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty or if +# non of the patterns match the file name, INPUT_FILTER is applied. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) +# and it is also possible to disable source filtering for a specific pattern +# using *.ext= (so without naming a filter). This option only has effect when +# FILTER_SOURCE_FILES is enabled. + +FILTER_SOURCE_PATTERNS = + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = NO + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. +# Otherwise they will link to the documentation. + +REFERENCES_LINK_SOURCE = NO + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = NO + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. Note that when using a custom header you are responsible +# for the proper inclusion of any scripts and style sheets that doxygen +# needs, which is dependent on the configuration options used. +# It is adviced to generate a default header using "doxygen -w html +# header.html footer.html stylesheet.css YourConfigFile" and then modify +# that header. Note that the header is subject to change so you typically +# have to redo this when upgrading to a newer version of doxygen or when +# changing the value of configuration settings such as GENERATE_TREEVIEW! + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# stylesheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that +# the files will be copied as-is; there are no commands or markers available. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. +# Doxygen will adjust the colors in the stylesheet and background images +# according to this color. Hue is specified as an angle on a colorwheel, +# see http://en.wikipedia.org/wiki/Hue for more information. +# For instance the value 0 represents red, 60 is yellow, 120 is green, +# 180 is cyan, 240 is blue, 300 purple, and 360 is red again. +# The allowed range is 0 to 359. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of +# the colors in the HTML output. For a value of 0 the output will use +# grayscales only. A value of 255 will produce the most vivid colors. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to +# the luminance component of the colors in the HTML output. Values below +# 100 gradually make the output lighter, whereas values above 100 make +# the output darker. The value divided by 100 is the actual gamma applied, +# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, +# and 100 does not change the gamma. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting +# this to NO can help when comparing the output of multiple runs. + +HTML_TIMESTAMP = YES + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. For this to work a browser that supports +# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox +# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). + +HTML_DYNAMIC_SECTIONS = YES + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated +# that can be used as input for Qt's qhelpgenerator to generate a +# Qt Compressed Help (.qch) of the generated HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#namespace + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#virtual-folders + +QHP_VIRTUAL_FOLDER = doc + +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to +# add. For more information please see +# http://doc.trolltech.com/qthelpproject.html#custom-filters + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see +# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters"> +# Qt Help Project / Custom Filters</a>. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's +# filter section matches. +# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes"> +# Qt Help Project / Filter Attributes</a>. + +QHP_SECT_FILTER_ATTRS = + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files +# will be generated, which together with the HTML files, form an Eclipse help +# plugin. To install this plugin and make it available under the help contents +# menu in Eclipse, the contents of the directory containing the HTML and XML +# files needs to be copied into the plugins directory of eclipse. The name of +# the directory within the plugins directory should be the same as +# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before +# the help appears. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have +# this name. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values +# (range [0,1..20]) that doxygen will group on one line in the generated HTML +# documentation. Note that a value of 0 will completely suppress the enum +# values from appearing in the overview section. + +ENUM_VALUES_PER_LINE = 4 + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to YES, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). +# Windows users are probably better off using the HTML help feature. + +GENERATE_TREEVIEW = NO + +# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, +# and Class Hierarchy pages using a tree view instead of an ordered list. + +USE_INLINE_TREES = NO + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open +# links to external symbols imported via tag files in a separate window. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are +# not supported properly for IE 6.0, but are supported on all modern browsers. +# Note that when changing this option you need to delete any form_*.png files +# in the HTML output before the changes have effect. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax +# (see http://www.mathjax.org) which uses client side Javascript for the +# rendering instead of using prerendered bitmaps. Use this if you do not +# have LaTeX installed or if you want to formulas look prettier in the HTML +# output. When enabled you also need to install MathJax separately and +# configure the path to it using the MATHJAX_RELPATH option. + +USE_MATHJAX = NO + +# When MathJax is enabled you need to specify the location relative to the +# HTML output directory using the MATHJAX_RELPATH option. The destination +# directory should contain the MathJax.js script. For instance, if the mathjax +# directory is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the +# mathjax.org site, so you can quickly see the result without installing +# MathJax, but it is strongly recommended to install a local copy of MathJax +# before deployment. + +MATHJAX_RELPATH = http://www.mathjax.org/mathjax + +# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension +# names that should be enabled during MathJax rendering. + +MATHJAX_EXTENSIONS = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box +# for the HTML output. The underlying search engine uses javascript +# and DHTML and should work on any modern browser. Note that when using +# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets +# (GENERATE_DOCSET) there is already a search function so this one should +# typically be disabled. For large projects the javascript based search engine +# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. + +SEARCHENGINE = NO + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a PHP enabled web server instead of at the web client +# using Javascript. Doxygen will generate the search PHP script and index +# file to put on the web server. The advantage of the server +# based approach is that it scales better to large projects and allows +# full text search. The disadvantages are that it is more difficult to setup +# and does not have live searching capabilities. + +SERVER_BASED_SEARCH = NO + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. +# Note that when enabling USE_PDFLATEX this option is only used for +# generating bitmaps for formulas in the HTML output, but not in the +# Makefile that is written to the output directory. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = YES + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = letter + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = fullpage, \ + palatino + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for +# the generated latex document. The footer should contain everything after +# the last chapter. If it is left blank doxygen will generate a +# standard footer. Notice: only use this tag if you know what you are doing! + +LATEX_FOOTER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = YES + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = YES + +# If LATEX_SOURCE_CODE is set to YES then doxygen will include +# source code with syntax highlighting in the LaTeX output. +# Note that which sources are shown also depends on other settings +# such as SOURCE_BROWSER. + +LATEX_SOURCE_CODE = NO + +# The LATEX_BIB_STYLE tag can be used to specify the style to use for the +# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See +# http://en.wikipedia.org/wiki/BibTeX for more info. + +LATEX_BIB_STYLE = plain + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. +# This is useful +# if you want to understand what is going on. +# On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# pointed to by INCLUDE_PATH will be searched when a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition that +# overrules the definition found in the source code. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all references to function-like macros +# that are alone on a line, have an all uppercase name, and do not end with a +# semicolon, because these will confuse the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option also works with HAVE_DOT disabled, but it is recommended to +# install and use dot, since it yields more powerful graphs. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is +# allowed to run in parallel. When set to 0 (the default) doxygen will +# base this on the number of processors available in the system. You can set it +# explicitly to a value larger than 0 to get control over the balance +# between CPU load and processing speed. + +DOT_NUM_THREADS = 0 + +# By default doxygen will use the Helvetica font for all dot files that +# doxygen generates. When you want a differently looking font you can specify +# the font name using DOT_FONTNAME. You need to make sure dot is able to find +# the font, which can be done by putting it in a standard location or by setting +# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the +# directory containing the font. + +DOT_FONTNAME = FreeSans + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the Helvetica font. +# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to +# set the path where dot can find it. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will generate a graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are svg, png, jpg, or gif. +# If left blank png will be used. If you choose svg you need to set +# HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible in IE 9+ (other browsers do not have this requirement). + +DOT_IMAGE_FORMAT = png + +# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to +# enable generation of interactive SVG images that allow zooming and panning. +# Note that this requires a modern browser other than Internet Explorer. +# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you +# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible. Older versions of IE do not have SVG support. + +INTERACTIVE_SVG = NO + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the +# \mscfile command). + +MSCFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = YES + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES diff --git a/contrib/voro++/src/Makefile b/contrib/voro++/src/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..f205a54b79db39c18834e5f0a18c16bdd6c32e19 --- /dev/null +++ b/contrib/voro++/src/Makefile @@ -0,0 +1,39 @@ +# Voro++ makefile +# +# Author : Chris H. Rycroft (LBL / UC Berkeley) +# Email : chr@alum.mit.edu +# Date : August 30th 2011 + +# Load the common configuration file +include ../config.mk + +# List of the common source files +objs=cell.o common.o container.o unitcell.o v_compute.o c_loops.o \ + v_base.o wall.o pre_container.o container_prd.o +src=$(patsubst %.o,%.cc,$(objs)) + +# Makefile rules +all: libvoro++.a voro++ + +depend: + $(CXX) -MM $(src) >Makefile.dep + +include Makefile.dep + +libvoro++.a: $(objs) + rm -f libvoro++.a + ar rs libvoro++.a $^ + +voro++: libvoro++.a cmd_line.cc + $(CXX) $(CFLAGS) -L. -o voro++ cmd_line.cc -lvoro++ + +%.o: %.cc + $(CXX) $(CFLAGS) -c $< + +help: Doxyfile $(SOURCE) + doxygen Doxyfile + +clean: + rm -f $(objs) voro++ libvoro++.a + +.PHONY: all help execs depend diff --git a/contrib/voro++/src/Makefile.dep b/contrib/voro++/src/Makefile.dep new file mode 100644 index 0000000000000000000000000000000000000000..fdf7390804f39b04ca1c61f5374a9dacab484f10 --- /dev/null +++ b/contrib/voro++/src/Makefile.dep @@ -0,0 +1,18 @@ +cell.o: cell.cc config.hh common.hh cell.hh +common.o: common.cc common.hh config.hh +container.o: container.cc container.hh config.hh common.hh v_base.hh \ + worklist.hh cell.hh c_loops.hh v_compute.hh rad_option.hh +unitcell.o: unitcell.cc unitcell.hh config.hh cell.hh common.hh +v_compute.o: v_compute.cc worklist.hh v_compute.hh config.hh cell.hh \ + common.hh container.hh v_base.hh c_loops.hh rad_option.hh \ + container_prd.hh unitcell.hh +c_loops.o: c_loops.cc c_loops.hh config.hh +v_base.o: v_base.cc v_base.hh worklist.hh config.hh v_base_wl.cc +wall.o: wall.cc wall.hh cell.hh config.hh common.hh container.hh \ + v_base.hh worklist.hh c_loops.hh v_compute.hh rad_option.hh +pre_container.o: pre_container.cc config.hh pre_container.hh c_loops.hh \ + container.hh common.hh v_base.hh worklist.hh cell.hh v_compute.hh \ + rad_option.hh +container_prd.o: container_prd.cc container_prd.hh config.hh common.hh \ + v_base.hh worklist.hh cell.hh c_loops.hh v_compute.hh unitcell.hh \ + rad_option.hh diff --git a/contrib/voro++/src/README b/contrib/voro++/src/README new file mode 100644 index 0000000000000000000000000000000000000000..09326db58b337dfe84849ff473801237820c4546 --- /dev/null +++ b/contrib/voro++/src/README @@ -0,0 +1,21 @@ +Voro++ library source files +=========================== +This directory contains the source code for the library. For full details of +each file, see the files section of the online reference manual at +http://math.lbl.gov/voro++/doc/refman/ + +Several other files are present: + +Makefile - the GNU Makefile controlling the compilation. + +Makefile.dep - a file containing all the dependencies of the source files, +automatically generated by the GNU compiler. + +cmd_line.cc - source file for creating the command-line utility that makes use +of the library. + +Doxyfile - configuration file for Doxygen, used to automatically generate +documentation based on the source code comments. + +worklist_gen.pl - perl script for automatically generating the worklist.hh and +v_base_wl.cc files. diff --git a/contrib/voro++/src/c_loops.cc b/contrib/voro++/src/c_loops.cc new file mode 100644 index 0000000000000000000000000000000000000000..391215211de5e15c798a1296ee3bda3b88aedfca --- /dev/null +++ b/contrib/voro++/src/c_loops.cc @@ -0,0 +1,150 @@ +// Voro++, a 3D cell-based Voronoi library +// +// Author : Chris H. Rycroft (LBL / UC Berkeley) +// Email : chr@alum.mit.edu +// Date : August 30th 2011 + +/** \file c_loops.cc + * \brief Function implementations for the loop classes. */ + +#include "c_loops.hh" + +namespace voro { + +/** Initializes a c_loop_subset object to scan over all particles within a + * given sphere. + * \param[in] (vx,vy,vz) the position vector of the center of the sphere. + * \param[in] r the radius of the sphere. + * \param[in] bounds_test whether to do detailed bounds checking. If this is + * false then the class will loop over all particles in + * blocks that overlap the given sphere. If it is true, + * the particle will only loop over the particles which + * actually lie within the sphere. + * \return True if there is any valid point to loop over, false otherwise. */ +void c_loop_subset::setup_sphere(double vx,double vy,double vz,double r,bool bounds_test) { + if(bounds_test) {mode=sphere;v0=vx;v1=vy;v2=vz;v3=r*r;} else mode=no_check; + ai=step_int((vx-ax-r)*xsp); + bi=step_int((vx-ax+r)*xsp); + aj=step_int((vy-ay-r)*ysp); + bj=step_int((vy-ay+r)*ysp); + ak=step_int((vz-az-r)*zsp); + bk=step_int((vz-az+r)*zsp); + setup_common(); +} + +/** Initializes the class to loop over all particles in a rectangular subgrid + * of blocks. + * \param[in] (ai_,bi_) the subgrid range in the x-direction, inclusive of both + * ends. + * \param[in] (aj_,bj_) the subgrid range in the y-direction, inclusive of both + * ends. + * \param[in] (ak_,bk_) the subgrid range in the z-direction, inclusive of both + * ends. + * \return True if there is any valid point to loop over, false otherwise. */ +void c_loop_subset::setup_intbox(int ai_,int bi_,int aj_,int bj_,int ak_,int bk_) { + ai=ai_;bi=bi_;aj=aj_;bj=bj_;ak=ak_;bk=bk_; + mode=no_check; + setup_common(); +} + +/** Sets up all of the common constants used for the loop. + * \return True if there is any valid point to loop over, false otherwise. */ +void c_loop_subset::setup_common() { + if(!xperiodic) { + if(ai<0) {ai=0;if(bi<0) bi=0;} + if(bi>=nx) {bi=nx-1;if(ai>=nx) ai=nx-1;} + } + if(!yperiodic) { + if(aj<0) {aj=0;if(bj<0) bj=0;} + if(bj>=ny) {bj=ny-1;if(aj>=ny) aj=ny-1;} + } + if(!zperiodic) { + if(ak<0) {ak=0;if(bk<0) bk=0;} + if(bk>=nz) {bk=nz-1;if(ak>=nz) ak=nz-1;} + } + ci=ai;cj=aj;ck=ak; + di=i=step_mod(ci,nx);apx=px=step_div(ci,nx)*sx; + dj=j=step_mod(cj,ny);apy=py=step_div(cj,ny)*sy; + dk=k=step_mod(ck,nz);apz=pz=step_div(ck,nz)*sz; + inc1=di-step_mod(bi,nx); + inc2=nx*(ny+dj-step_mod(bj,ny))+inc1; + inc1+=nx; + ijk=di+nx*(dj+ny*dk); + q=0; +} + +/** Starts the loop by finding the first particle within the container to + * consider. + * \return True if there is any particle to consider, false otherwise. */ +bool c_loop_subset::start() { + while(co[ijk]==0) {if(!next_block()) return false;} + while(mode!=no_check&&out_of_bounds()) { + q++; + while(q>=co[ijk]) {q=0;if(!next_block()) return false;} + } + return true; +} + +/** Initializes the class to loop over all particles in a rectangular box. + * \param[in] (xmin,xmax) the minimum and maximum x coordinates of the box. + * \param[in] (ymin,ymax) the minimum and maximum y coordinates of the box. + * \param[in] (zmin,zmax) the minimum and maximum z coordinates of the box. + * \param[in] bounds_test whether to do detailed bounds checking. If this is + * false then the class will loop over all particles in + * blocks that overlap the given box. If it is true, the + * particle will only loop over the particles which + * actually lie within the box. + * \return True if there is any valid point to loop over, false otherwise. */ +void c_loop_subset::setup_box(double xmin,double xmax,double ymin,double ymax,double zmin,double zmax,bool bounds_test) { + if(bounds_test) {mode=box;v0=xmin;v1=xmax;v2=ymin;v3=ymax;v4=zmin;v5=zmax;} else mode=no_check; + ai=step_int((xmin-ax)*xsp); + bi=step_int((xmax-ax)*xsp); + aj=step_int((ymin-ay)*ysp); + bj=step_int((ymax-ay)*ysp); + ak=step_int((zmin-az)*zsp); + bk=step_int((zmax-az)*zsp); + setup_common(); +} + +/** Computes whether the current point is out of bounds, relative to the + * current loop setup. + * \return True if the point is out of bounds, false otherwise. */ +bool c_loop_subset::out_of_bounds() { + double *pp=p[ijk]+ps*q; + if(mode==sphere) { + double fx(*pp+px-v0),fy(pp[1]+py-v1),fz(pp[2]+pz-v2); + return fx*fx+fy*fy+fz*fz>v3; + } else { + double f(*pp+px);if(f<v0||f>v1) return true; + f=pp[1]+py;if(f<v2||f>v3) return true; + f=pp[2]+pz;return f<v4||f>v5; + } +} + +/** Returns the next block to be tested in a loop, and updates the periodicity + * vector if necessary. */ +bool c_loop_subset::next_block() { + if(i<bi) { + i++; + if(ci<nx-1) {ci++;ijk++;} else {ci=0;ijk+=1-nx;px+=sx;} + return true; + } else if(j<bj) { + i=ai;ci=di;px=apx;j++; + if(cj<ny-1) {cj++;ijk+=inc1;} else {cj=0;ijk+=inc1-nxy;py+=sy;} + return true; + } else if(k<bk) { + i=ai;ci=di;j=aj;cj=dj;px=apx;py=apy;k++; + if(ck<nz-1) {ck++;ijk+=inc2;} else {ck=0;ijk+=inc2-nxyz;pz+=sz;} + return true; + } else return false; +} + +/** Extends the memory available for storing the ordering. */ +void particle_order::add_ordering_memory() { + int *no=new int[size<<2],*nop=no,*opp=o; + while(opp<op) *(nop++)=*(opp++); + delete [] o; + size<<=1;o=no;op=nop; +} + +} diff --git a/contrib/voro++/src/c_loops.hh b/contrib/voro++/src/c_loops.hh new file mode 100644 index 0000000000000000000000000000000000000000..0a3fc09301f7859bac89b6209694fc04d04dcada --- /dev/null +++ b/contrib/voro++/src/c_loops.hh @@ -0,0 +1,462 @@ +// Voro++, a 3D cell-based Voronoi library +// +// Author : Chris H. Rycroft (LBL / UC Berkeley) +// Email : chr@alum.mit.edu +// Date : August 30th 2011 + +/** \file c_loops.hh + * \brief Header file for the loop classes. */ + +#ifndef VOROPP_C_LOOPS_HH +#define VOROPP_C_LOOPS_HH + +#include <cstdio> +#include <cstdlib> +#include <cmath> +#include <vector> +using namespace std; + +#include "config.hh" + +namespace voro { + +/** A type associated with a c_loop_subset class, determining what type of + * geometrical region to loop over. */ +enum c_loop_subset_mode { + sphere, + box, + no_check +}; + +/** \brief A class for storing ordering information when particles are added to + * a container. + * + * When particles are added to a container class, they are sorted into an + * internal computational grid of blocks. The particle_order class provides a + * mechanism for remembering which block particles were sorted into. The import + * and put routines in the container class have variants that also take a + * particle_order class. Each time they are called, they will store the block + * that the particle was sorted into, plus the position of the particle within + * the block. The particle_order class can used by the c_loop_order class to + * specifically loop over the particles that have their information stored + * within it. */ +class particle_order { + public: + /** A pointer to the array holding the ordering. */ + int *o; + /** A pointer to the next position in the ordering array in + * which to store an entry. */ + int *op; + /** The current memory allocation for the class, set to the + * number of entries which can be stored. */ + int size; + /** The particle_order constructor allocates memory to store the + * ordering information. + * \param[in] init_size the initial amount of memory to + * allocate. */ + particle_order(int init_size=init_ordering_size) + : o(new int[init_size<<1]),op(o),size(init_size) {} + /** The particle_order destructor frees the dynamically allocated + * memory used to store the ordering information. */ + ~particle_order() { + delete [] o; + } + /** Adds a record to the order, corresponding to the memory + * address of where a particle was placed into the container. + * \param[in] ijk the block into which the particle was placed. + * \param[in] q the position within the block where the + * particle was placed. */ + inline void add(int ijk,int q) { + if(op==o+size) add_ordering_memory(); + *(op++)=ijk;*(op++)=q; + } + private: + void add_ordering_memory(); +}; + +/** \brief Base class for looping over particles in a container. + * + * This class forms the base of all classes that can loop over a subset of + * particles in a contaner in some order. When initialized, it stores constants + * about the corresponding container geometry. It also contains a number of + * routines for interrogating which particle currently being considered by the + * loop, which are common between all of the derived classes. */ +class c_loop_base { + public: + /** The number of blocks in the x direction. */ + const int nx; + /** The number of blocks in the y direction. */ + const int ny; + /** The number of blocks in the z direction. */ + const int nz; + /** A constant, set to the value of nx multiplied by ny, which + * is used in the routines that step through blocks in + * sequence. */ + const int nxy; + /** A constant, set to the value of nx*ny*nz, which is used in + * the routines that step through blocks in sequence. */ + const int nxyz; + /** The number of floating point numbers per particle in the + * associated container data structure. */ + const int ps; + /** A pointer to the particle position information in the + * associated container data structure. */ + double **p; + /** A pointer to the particle ID information in the associated + * container data structure. */ + int **id; + /** A pointer to the particle counts in the associated + * container data structure. */ + int *co; + /** The current x-index of the block under consideration by the + * loop. */ + int i; + /** The current y-index of the block under consideration by the + * loop. */ + int j; + /** The current z-index of the block under consideration by the + * loop. */ + int k; + /** The current index of the block under consideration by the + * loop. */ + int ijk; + /** The index of the particle under consideration within the current + * block. */ + int q; + /** The constructor copies several necessary constants from the + * base container class. + * \param[in] con the container class to use. */ + template<class c_class> + c_loop_base(c_class &con) : nx(con.nx), ny(con.ny), nz(con.nz), + nxy(con.nxy), nxyz(con.nxyz), ps(con.ps), + p(con.p), id(con.id), co(con.co) {} + /** Returns the position vector of the particle currently being + * considered by the loop. + * \param[out] (x,y,z) the position vector of the particle. */ + inline void pos(double &x,double &y,double &z) { + double *pp=p[ijk]+ps*q; + x=*(pp++);y=*(pp++);z=*pp; + } + /** Returns the ID, position vector, and radius of the particle + * currently being considered by the loop. + * \param[out] pid the particle ID. + * \param[out] (x,y,z) the position vector of the particle. + * \param[out] r the radius of the particle. If no radius + * information is available the default radius + * value is returned. */ + inline void pos(int &pid,double &x,double &y,double &z,double &r) { + pid=id[ijk][q]; + double *pp=p[ijk]+ps*q; + x=*(pp++);y=*(pp++);z=*pp; + r=ps==3?default_radius:*(++pp); + } + /** Returns the x position of the particle currently being + * considered by the loop. */ + inline double x() {return p[ijk][ps*q];} + /** Returns the y position of the particle currently being + * considered by the loop. */ + inline double y() {return p[ijk][ps*q+1];} + /** Returns the z position of the particle currently being + * considered by the loop. */ + inline double z() {return p[ijk][ps*q+2];} + /** Returns the ID of the particle currently being considered + * by the loop. */ + inline int pid() {return id[ijk][q];} +}; + +/** \brief Class for looping over all of the particles in a container. + * + * This is one of the simplest loop classes, that scans the computational + * blocks in order, and scans all the particles within each block in order. */ +class c_loop_all : public c_loop_base { + public: + /** The constructor copies several necessary constants from the + * base container class. + * \param[in] con the container class to use. */ + template<class c_class> + c_loop_all(c_class &con) : c_loop_base(con) {} + /** Sets the class to consider the first particle. + * \return True if there is any particle to consider, false + * otherwise. */ + inline bool start() { + i=j=k=ijk=q=0; + while(co[ijk]==0) if(!next_block()) return false; + return true; + } + /** Finds the next particle to test. + * \return True if there is another particle, false if no more + * particles are available. */ + inline bool inc() { + q++; + if(q>=co[ijk]) { + q=0; + do { + if(!next_block()) return false; + } while(co[ijk]==0); + } + return true; + } + private: + /** Updates the internal variables to find the next + * computational block with any particles. + * \return True if another block is found, false if there are + * no more blocks. */ + inline bool next_block() { + ijk++; + i++; + if(i==nx) { + i=0;j++; + if(j==ny) { + j=0;k++; + if(ijk==nxyz) return false; + } + } + return true; + } +}; + +/** \brief Class for looping over a subset of particles in a container. + * + * This class can loop over a subset of particles in a certain geometrical + * region within the container. The class can be set up to loop over a + * rectangular box or sphere. It can also rectangular group of internal + * computational blocks. */ +class c_loop_subset : public c_loop_base { + public: + /** The current mode of operation, determining whether tests + * should be applied to particles to ensure they are within a + * certain geometrical object. */ + c_loop_subset_mode mode; + /** The constructor copies several necessary constants from the + * base container class. + * \param[in] con the container class to use. */ + template<class c_class> + c_loop_subset(c_class &con) : c_loop_base(con), ax(con.ax), ay(con.ay), az(con.az), + sx(con.bx-ax), sy(con.by-ay), sz(con.bz-az), xsp(con.xsp), ysp(con.ysp), zsp(con.zsp), + xperiodic(con.xperiodic), yperiodic(con.yperiodic), zperiodic(con.zperiodic) {} + void setup_sphere(double vx,double vy,double vz,double r,bool bounds_test=true); + void setup_box(double xmin,double xmax,double ymin,double ymax,double zmin,double zmax,bool bounds_test=true); + void setup_intbox(int ai_,int bi_,int aj_,int bj_,int ak_,int bk_); + bool start(); + /** Finds the next particle to test. + * \return True if there is another particle, false if no more + * particles are available. */ + inline bool inc() { + do { + q++; + while(q>=co[ijk]) {q=0;if(!next_block()) return false;} + } while(mode!=no_check&&out_of_bounds()); + return true; + } + private: + const double ax,ay,az,sx,sy,sz,xsp,ysp,zsp; + const bool xperiodic,yperiodic,zperiodic; + double px,py,pz,apx,apy,apz; + double v0,v1,v2,v3,v4,v5; + int ai,bi,aj,bj,ak,bk,s; + int ci,cj,ck,di,dj,dk,inc1,inc2; + inline int step_mod(int a,int b) {return a>=0?a%b:b-1-(b-1-a)%b;} + inline int step_div(int a,int b) {return a>=0?a/b:-1+(a+1)/b;} + inline int step_int(double a) {return a<0?int(a)-1:int(a);} + void setup_common(); + bool next_block(); + bool out_of_bounds(); +}; + +/** \brief Class for looping over all of the particles specified in a + * pre-assembled particle_order class. + * + * The particle_order class can be used to create a specific order of particles + * within the container. This class can then loop over these particles in this + * order. The class is particularly useful in cases where the ordering of the + * output must match the ordering of particles as they were inserted into the + * container. */ +class c_loop_order : public c_loop_base { + public: + /** A reference to the ordering class to use. */ + particle_order &vo; + /** A pointer to the current position in the ordering class. */ + int *cp; + /** A pointer to the end position in the ordering class. */ + int *op; + /** The constructor copies several necessary constants from the + * base class, and sets up a reference to the ordering class to + * use. + * \param[in] con the container class to use. + * \param[in] vo_ the ordering class to use. */ + template<class c_class> + c_loop_order(c_class &con,particle_order &vo_) + : c_loop_base(con), vo(vo_), nx(con.nx), nxy(con.nxy) {} + /** Sets the class to consider the first particle. + * \return True if there is any particle to consider, false + * otherwise. */ + inline bool start() { + cp=vo.o;op=vo.op; + if(cp!=op) { + ijk=*(cp++);decode(); + q=*(cp++); + return true; + } else return false; + } + /** Finds the next particle to test. + * \return True if there is another particle, false if no more + * particles are available. */ + inline bool inc() { + if(cp==op) return false; + ijk=*(cp++);decode(); + q=*(cp++); + return true; + } + private: + /** The number of computational blocks in the x direction. */ + const int nx; + /** The number of computational blocks in a z-slice. */ + const int nxy; + /** Takes the current block index and computes indices in the + * x, y, and z directions. */ + inline void decode() { + k=ijk/nxy; + int ijkt=ijk-nxy*k; + j=ijkt/nx; + i=ijkt-j*nx; + } +}; + +/** \brief A class for looping over all particles in a container_periodic or + * container_periodic_poly class. + * + * Since the container_periodic and container_periodic_poly classes have a + * fundamentally different memory organization, the regular loop classes cannot + * be used with them. */ +class c_loop_all_periodic : public c_loop_base { + public: + /** The constructor copies several necessary constants from the + * base periodic container class. + * \param[in] con the periodic container class to use. */ + template<class c_class> + c_loop_all_periodic(c_class &con) : c_loop_base(con), ey(con.ey), ez(con.ez), wy(con.wy), wz(con.wz), + ijk0(nx*(ey+con.oy*ez)), inc2(2*nx*con.ey+1) {} + /** Sets the class to consider the first particle. + * \return True if there is any particle to consider, false + * otherwise. */ + inline bool start() { + i=0; + j=ey; + k=ez; + ijk=ijk0; + q=0; + while(co[ijk]==0) if(!next_block()) return false; + return true; + } + /** Finds the next particle to test. + * \return True if there is another particle, false if no more + * particles are available. */ + inline bool inc() { + q++; + if(q>=co[ijk]) { + q=0; + do { + if(!next_block()) return false; + } while(co[ijk]==0); + } + return true; + } + private: + /** The lower y index (inclusive) of the primary domain within + * the block structure. */ + int ey; + /** The lower y index (inclusive) of the primary domain within + * the block structure. */ + int ez; + /** The upper y index (exclusive) of the primary domain within + * the block structure. */ + int wy; + /** The upper z index (exclusive) of the primary domain within + * the block structure. */ + int wz; + /** The index of the (0,0,0) block within the block structure. + */ + int ijk0; + /** A value to increase ijk by when the z index is increased. + */ + int inc2; + /** Updates the internal variables to find the next + * computational block with any particles. + * \return True if another block is found, false if there are + * no more blocks. */ + inline bool next_block() { + i++; + if(i==nx) { + i=0;j++; + if(j==wy) { + j=ey;k++; + if(k==wz) return false; + ijk+=inc2; + } else ijk++; + } else ijk++; + return true; + } +}; + +/** \brief Class for looping over all of the particles specified in a + * pre-assembled particle_order class, for use with container_periodic classes. + * + * The particle_order class can be used to create a specific order of particles + * within the container. This class can then loop over these particles in this + * order. The class is particularly useful in cases where the ordering of the + * output must match the ordering of particles as they were inserted into the + * container. */ +class c_loop_order_periodic : public c_loop_base { + public: + /** A reference to the ordering class to use. */ + particle_order &vo; + /** A pointer to the current position in the ordering class. */ + int *cp; + /** A pointer to the end position in the ordering class. */ + int *op; + /** The constructor copies several necessary constants from the + * base class, and sets up a reference to the ordering class to + * use. + * \param[in] con the container class to use. + * \param[in] vo_ the ordering class to use. */ + template<class c_class> + c_loop_order_periodic(c_class &con,particle_order &vo_) + : c_loop_base(con), vo(vo_), nx(con.nx), oxy(con.nx*con.oy) {} + /** Sets the class to consider the first particle. + * \return True if there is any particle to consider, false + * otherwise. */ + inline bool start() { + cp=vo.o;op=vo.op; + if(cp!=op) { + ijk=*(cp++);decode(); + q=*(cp++); + return true; + } else return false; + } + /** Finds the next particle to test. + * \return True if there is another particle, false if no more + * particles are available. */ + inline bool inc() { + if(cp==op) return false; + ijk=*(cp++);decode(); + q=*(cp++); + return true; + } + private: + /** The number of computational blocks in the x direction. */ + const int nx; + /** The number of computational blocks in a z-slice. */ + const int oxy; + /** Takes the current block index and computes indices in the + * x, y, and z directions. */ + inline void decode() { + k=ijk/oxy; + int ijkt=ijk-oxy*k; + j=ijkt/nx; + i=ijkt-j*nx; + } +}; + +} + +#endif diff --git a/contrib/voro++/src/cell.cc b/contrib/voro++/src/cell.cc new file mode 100644 index 0000000000000000000000000000000000000000..1e0c8f3435c1d4547db873882156bf1e60d96b2a --- /dev/null +++ b/contrib/voro++/src/cell.cc @@ -0,0 +1,2252 @@ +// Voro++, a 3D cell-based Voronoi library +// +// Author : Chris H. Rycroft (LBL / UC Berkeley) +// Email : chr@alum.mit.edu +// Date : August 30th 2011 + +/** \file cell.cc + * \brief Function implementations for the voronoicell and related classes. */ + +#include <cstring> +using namespace std; + +#include "config.hh" +#include "common.hh" +#include "cell.hh" + +namespace voro { + +/** Constructs a Voronoi cell and sets up the initial memory. */ +voronoicell_base::voronoicell_base() : + current_vertices(init_vertices), current_vertex_order(init_vertex_order), + current_delete_size(init_delete_size), current_delete2_size(init_delete2_size), + ed(new int*[current_vertices]), nu(new int[current_vertices]), + pts(new double[3*current_vertices]), mem(new int[current_vertex_order]), + mec(new int[current_vertex_order]), mep(new int*[current_vertex_order]), + ds(new int[current_delete_size]), stacke(ds+current_delete_size), + ds2(new int[current_delete2_size]), stacke2(ds2+current_delete_size), + current_marginal(init_marginal), marg(new int[current_marginal]) { + int i; + for(i=0;i<3;i++) { + mem[i]=init_n_vertices;mec[i]=0; + mep[i]=new int[init_n_vertices*((i<<1)+1)]; + } + mem[3]=init_3_vertices;mec[3]=0; + mep[3]=new int[init_3_vertices*7]; + for(i=4;i<current_vertex_order;i++) { + mem[i]=init_n_vertices;mec[i]=0; + mep[i]=new int[init_n_vertices*((i<<1)+1)]; + } +} + +/** The voronoicell destructor deallocates all the dynamic memory. */ +voronoicell_base::~voronoicell_base() { + for(int i=current_vertex_order-1;i>=0;i--) if(mem[i]>0) delete [] mep[i]; + delete [] marg; + delete [] ds2;delete [] ds; + delete [] mep;delete [] mec; + delete [] mem;delete [] pts; + delete [] nu;delete [] ed; +} + +/** Ensures that enough memory is allocated prior to carrying out a copy. + * \param[in] vc a reference to the specialized version of the calling class. + * \param[in] vb a pointered to the class to be copied. */ +template<class vc_class> +void voronoicell_base::check_memory_for_copy(vc_class &vc,voronoicell_base* vb) { + while(current_vertex_order<vb->current_vertex_order) add_memory_vorder(vc); + for(int i=0;i<current_vertex_order;i++) while(mem[i]<vb->mec[i]) add_memory(vc,i,ds2); + while(current_vertices<vb->p) add_memory_vertices(vc); +} + +/** Copies the vertex and edge information from another class. The routine + * assumes that enough memory is available for the copy. + * \param[in] vb a pointer to the class to copy. */ +void voronoicell_base::copy(voronoicell_base* vb) { + int i,j; + p=vb->p;up=0; + for(i=0;i<current_vertex_order;i++) { + mec[i]=vb->mec[i]; + for(j=0;j<mec[i]*(2*i+1);j++) mep[i][j]=vb->mep[i][j]; + for(j=0;j<mec[i]*(2*i+1);j+=2*i+1) ed[mep[i][j+2*i]]=mep[i]+j; + } + for(i=0;i<p;i++) nu[i]=vb->nu[i]; + for(i=0;i<3*p;i++) pts[i]=vb->pts[i]; +} + +/** Copies the information from another voronoicell class into this + * class, extending memory allocation if necessary. + * \param[in] c the class to copy. */ +void voronoicell_neighbor::operator=(voronoicell &c) { + voronoicell_base *vb=((voronoicell_base*) &c); + check_memory_for_copy(*this,vb);copy(vb); + int i,j; + for(i=0;i<c.current_vertex_order;i++) { + for(j=0;j<c.mec[i]*i;j++) mne[i][j]=0; + for(j=0;j<c.mec[i];j++) ne[c.mep[i][(2*i+1)*j+2*i]]=mne[i]+(j*i); + } +} + +/** Copies the information from another voronoicell_neighbor class into this + * class, extending memory allocation if necessary. + * \param[in] c the class to copy. */ +void voronoicell_neighbor::operator=(voronoicell_neighbor &c) { + voronoicell_base *vb=((voronoicell_base*) &c); + check_memory_for_copy(*this,vb);copy(vb); + int i,j; + for(i=0;i<c.current_vertex_order;i++) { + for(j=0;j<c.mec[i]*i;j++) mne[i][j]=c.mne[i][j]; + for(j=0;j<c.mec[i];j++) ne[c.mep[i][(2*i+1)*j+2*i]]=mne[i]+(j*i); + } +} + +/** Translates the vertices of the Voronoi cell by a given vector. + * \param[in] (x,y,z) the coordinates of the vector. */ +void voronoicell_base::translate(double x,double y,double z) { + x*=2;y*=2;z*=2; + double *ptsp=pts; + while(ptsp<pts+3*p) { + *(ptsp++)=x;*(ptsp++)=y;*(ptsp++)=z; + } +} + +/** Increases the memory storage for a particular vertex order, by increasing + * the size of the of the corresponding mep array. If the arrays already exist, + * their size is doubled; if they don't exist, then new ones of size + * init_n_vertices are allocated. The routine also ensures that the pointers in + * the ed array are updated, by making use of the back pointers. For the cases + * where the back pointer has been temporarily overwritten in the marginal + * vertex code, the auxiliary delete stack is scanned to find out how to update + * the ed value. If the template has been instantiated with the neighbor + * tracking turned on, then the routine also reallocates the corresponding mne + * array. + * \param[in] i the order of the vertex memory to be increased. */ +template<class vc_class> +void voronoicell_base::add_memory(vc_class &vc,int i,int *stackp2) { + int s=(i<<1)+1; + if(mem[i]==0) { + vc.n_allocate(i,init_n_vertices); + mep[i]=new int[init_n_vertices*s]; + mem[i]=init_n_vertices; +#if VOROPP_VERBOSE >=2 + fprintf(stderr,"Order %d vertex memory created\n",i); +#endif + } else { + int j=0,k,*l; + mem[i]<<=1; + if(mem[i]>max_n_vertices) voro_fatal_error("Point memory allocation exceeded absolute maximum",VOROPP_MEMORY_ERROR); +#if VOROPP_VERBOSE >=2 + fprintf(stderr,"Order %d vertex memory scaled up to %d\n",i,mem[i]); +#endif + l=new int[s*mem[i]]; + int m=0; + vc.n_allocate_aux1(i); + while(j<s*mec[i]) { + k=mep[i][j+(i<<1)]; + if(k>=0) { + ed[k]=l+j; + vc.n_set_to_aux1_offset(k,m); + } else { + int *dsp; + for(dsp=ds2;dsp<stackp2;dsp++) { + if(ed[*dsp]==mep[i]+j) { + ed[*dsp]=l+j; + vc.n_set_to_aux1_offset(*dsp,m); + break; + } + } + if(dsp==stackp2) voro_fatal_error("Couldn't relocate dangling pointer",VOROPP_INTERNAL_ERROR); +#if VOROPP_VERBOSE >=3 + fputs("Relocated dangling pointer",stderr); +#endif + } + for(k=0;k<s;k++,j++) l[j]=mep[i][j]; + for(k=0;k<i;k++,m++) vc.n_copy_to_aux1(i,m); + } + delete [] mep[i]; + mep[i]=l; + vc.n_switch_to_aux1(i); + } +} + +/** Doubles the maximum number of vertices allowed, by reallocating the ed, nu, + * and pts arrays. If the allocation exceeds the absolute maximum set in + * max_vertices, then the routine exits with a fatal error. If the template has + * been instantiated with the neighbor tracking turned on, then the routine + * also reallocates the ne array. */ +template<class vc_class> +void voronoicell_base::add_memory_vertices(vc_class &vc) { + int i=(current_vertices<<1),j,**pp,*pnu; + if(i>max_vertices) voro_fatal_error("Vertex memory allocation exceeded absolute maximum",VOROPP_MEMORY_ERROR); +#if VOROPP_VERBOSE >=2 + fprintf(stderr,"Vertex memory scaled up to %d\n",i); +#endif + double *ppts; + pp=new int*[i]; + for(j=0;j<current_vertices;j++) pp[j]=ed[j]; + delete [] ed;ed=pp; + vc.n_add_memory_vertices(i); + pnu=new int[i]; + for(j=0;j<current_vertices;j++) pnu[j]=nu[j]; + delete [] nu;nu=pnu; + ppts=new double[3*i]; + for(j=0;j<3*current_vertices;j++) ppts[j]=pts[j]; + delete [] pts;pts=ppts; + current_vertices=i; +} + +/** Doubles the maximum allowed vertex order, by reallocating mem, mep, and mec + * arrays. If the allocation exceeds the absolute maximum set in + * max_vertex_order, then the routine causes a fatal error. If the template has + * been instantiated with the neighbor tracking turned on, then the routine + * also reallocates the mne array. */ +template<class vc_class> +void voronoicell_base::add_memory_vorder(vc_class &vc) { + int i=(current_vertex_order<<1),j,*p1,**p2; + if(i>max_vertex_order) voro_fatal_error("Vertex order memory allocation exceeded absolute maximum",VOROPP_MEMORY_ERROR); +#if VOROPP_VERBOSE >=2 + fprintf(stderr,"Vertex order memory scaled up to %d\n",i); +#endif + p1=new int[i]; + for(j=0;j<current_vertex_order;j++) p1[j]=mem[j];while(j<i) p1[j++]=0; + delete [] mem;mem=p1; + p2=new int*[i]; + for(j=0;j<current_vertex_order;j++) p2[j]=mep[j]; + delete [] mep;mep=p2; + p1=new int[i]; + for(j=0;j<current_vertex_order;j++) p1[j]=mec[j];while(j<i) p1[j++]=0; + delete [] mec;mec=p1; + vc.n_add_memory_vorder(i); + current_vertex_order=i; +} + +/** Doubles the size allocation of the main delete stack. If the allocation + * exceeds the absolute maximum set in max_delete_size, then routine causes a + * fatal error. */ +void voronoicell_base::add_memory_ds(int *&stackp) { + current_delete_size<<=1; + if(current_delete_size>max_delete_size) voro_fatal_error("Delete stack 1 memory allocation exceeded absolute maximum",VOROPP_MEMORY_ERROR); +#if VOROPP_VERBOSE >=2 + fprintf(stderr,"Delete stack 1 memory scaled up to %d\n",current_delete_size); +#endif + int *dsn=new int[current_delete_size],*dsnp=dsn,*dsp=ds; + while(dsp<stackp) *(dsnp++)=*(dsp++); + delete [] ds;ds=dsn;stackp=dsnp; + stacke=ds+current_delete_size; +} + +/** Doubles the size allocation of the auxiliary delete stack. If the + * allocation exceeds the absolute maximum set in max_delete2_size, then the + * routine causes a fatal error. */ +void voronoicell_base::add_memory_ds2(int *&stackp2) { + current_delete2_size<<=1; + if(current_delete2_size>max_delete2_size) voro_fatal_error("Delete stack 2 memory allocation exceeded absolute maximum",VOROPP_MEMORY_ERROR); +#if VOROPP_VERBOSE >=2 + fprintf(stderr,"Delete stack 2 memory scaled up to %d\n",current_delete2_size); +#endif + int *dsn=new int[current_delete2_size],*dsnp=dsn,*dsp=ds2; + while(dsp<stackp2) *(dsnp++)=*(dsp++); + delete [] ds2;ds2=dsn;stackp2=dsnp; + stacke2=ds2+current_delete2_size; +} + +/** Initializes a Voronoi cell as a rectangular box with the given dimensions. + * \param[in] (xmin,xmax) the minimum and maximum x coordinates. + * \param[in] (ymin,ymax) the minimum and maximum y coordinates. + * \param[in] (zmin,zmax) the minimum and maximum z coordinates. */ +void voronoicell_base::init_base(double xmin,double xmax,double ymin,double ymax,double zmin,double zmax) { + for(int i=0;i<current_vertex_order;i++) mec[i]=0;up=0; + mec[3]=p=8;xmin*=2;xmax*=2;ymin*=2;ymax*=2;zmin*=2;zmax*=2; + *pts=xmin;pts[1]=ymin;pts[2]=zmin; + pts[3]=xmax;pts[4]=ymin;pts[5]=zmin; + pts[6]=xmin;pts[7]=ymax;pts[8]=zmin; + pts[9]=xmax;pts[10]=ymax;pts[11]=zmin; + pts[12]=xmin;pts[13]=ymin;pts[14]=zmax; + pts[15]=xmax;pts[16]=ymin;pts[17]=zmax; + pts[18]=xmin;pts[19]=ymax;pts[20]=zmax; + pts[21]=xmax;pts[22]=ymax;pts[23]=zmax; + int *q=mep[3]; + *q=1;q[1]=4;q[2]=2;q[3]=2;q[4]=1;q[5]=0;q[6]=0; + q[7]=3;q[8]=5;q[9]=0;q[10]=2;q[11]=1;q[12]=0;q[13]=1; + q[14]=0;q[15]=6;q[16]=3;q[17]=2;q[18]=1;q[19]=0;q[20]=2; + q[21]=2;q[22]=7;q[23]=1;q[24]=2;q[25]=1;q[26]=0;q[27]=3; + q[28]=6;q[29]=0;q[30]=5;q[31]=2;q[32]=1;q[33]=0;q[34]=4; + q[35]=4;q[36]=1;q[37]=7;q[38]=2;q[39]=1;q[40]=0;q[41]=5; + q[42]=7;q[43]=2;q[44]=4;q[45]=2;q[46]=1;q[47]=0;q[48]=6; + q[49]=5;q[50]=3;q[51]=6;q[52]=2;q[53]=1;q[54]=0;q[55]=7; + *ed=q;ed[1]=q+7;ed[2]=q+14;ed[3]=q+21; + ed[4]=q+28;ed[5]=q+35;ed[6]=q+42;ed[7]=q+49; + *nu=nu[1]=nu[2]=nu[3]=nu[4]=nu[5]=nu[6]=nu[7]=3; +} + +/** Initializes a Voronoi cell as a regular octahedron. + * \param[in] l The distance from the octahedron center to a vertex. Six + * vertices are initialized at (-l,0,0), (l,0,0), (0,-l,0), + * (0,l,0), (0,0,-l), and (0,0,l). */ +void voronoicell_base::init_octahedron_base(double l) { + for(int i=0;i<current_vertex_order;i++) mec[i]=0;up=0; + mec[4]=p=6;l*=2; + *pts=-l;pts[1]=0;pts[2]=0; + pts[3]=l;pts[4]=0;pts[5]=0; + pts[6]=0;pts[7]=-l;pts[8]=0; + pts[9]=0;pts[10]=l;pts[11]=0; + pts[12]=0;pts[13]=0;pts[14]=-l; + pts[15]=0;pts[16]=0;pts[17]=l; + int *q=mep[4]; + *q=2;q[1]=5;q[2]=3;q[3]=4;q[4]=0;q[5]=0;q[6]=0;q[7]=0;q[8]=0; + q[9]=2;q[10]=4;q[11]=3;q[12]=5;q[13]=2;q[14]=2;q[15]=2;q[16]=2;q[17]=1; + q[18]=0;q[19]=4;q[20]=1;q[21]=5;q[22]=0;q[23]=3;q[24]=0;q[25]=1;q[26]=2; + q[27]=0;q[28]=5;q[29]=1;q[30]=4;q[31]=2;q[32]=3;q[33]=2;q[34]=1;q[35]=3; + q[36]=0;q[37]=3;q[38]=1;q[39]=2;q[40]=3;q[41]=3;q[42]=1;q[43]=1;q[44]=4; + q[45]=0;q[46]=2;q[47]=1;q[48]=3;q[49]=1;q[50]=3;q[51]=3;q[52]=1;q[53]=5; + *ed=q;ed[1]=q+9;ed[2]=q+18;ed[3]=q+27;ed[4]=q+36;ed[5]=q+45; + *nu=nu[1]=nu[2]=nu[3]=nu[4]=nu[5]=4; +} + +/** Initializes a Voronoi cell as a tetrahedron. It assumes that the normal to + * the face for the first three vertices points inside. + * \param (x0,y0,z0) a position vector for the first vertex. + * \param (x1,y1,z1) a position vector for the second vertex. + * \param (x2,y2,z2) a position vector for the third vertex. + * \param (x3,y3,z3) a position vector for the fourth vertex. */ +void voronoicell_base::init_tetrahedron_base(double x0,double y0,double z0,double x1,double y1,double z1,double x2,double y2,double z2,double x3,double y3,double z3) { + for(int i=0;i<current_vertex_order;i++) mec[i]=0;up=0; + mec[3]=p=4; + *pts=x0*2;pts[1]=y0*2;pts[2]=z0*2; + pts[3]=x1*2;pts[4]=y1*2;pts[5]=z1*2; + pts[6]=x2*2;pts[7]=y2*2;pts[8]=z2*2; + pts[9]=x3*2;pts[10]=y3*2;pts[11]=z3*2; + int *q=mep[3]; + *q=1;q[1]=3;q[2]=2;q[3]=0;q[4]=0;q[5]=0;q[6]=0; + q[7]=0;q[8]=2;q[9]=3;q[10]=0;q[11]=2;q[12]=1;q[13]=1; + q[14]=0;q[15]=3;q[16]=1;q[17]=2;q[18]=2;q[19]=1;q[20]=2; + q[21]=0;q[22]=1;q[23]=2;q[24]=1;q[25]=2;q[26]=1;q[27]=3; + *ed=q;ed[1]=q+7;ed[2]=q+14;ed[3]=q+21; + *nu=nu[1]=nu[2]=nu[3]=3; +} + +/** Checks that the relational table of the Voronoi cell is accurate, and + * prints out any errors. This algorithm is O(p), so running it every time the + * plane routine is called will result in a significant slowdown. */ +void voronoicell_base::check_relations() { + int i,j; + for(i=0;i<p;i++) for(j=0;j<nu[i];j++) if(ed[ed[i][j]][ed[i][nu[i]+j]]!=i) + printf("Relational error at point %d, edge %d.\n",i,j); +} + +/** This routine checks for any two vertices that are connected by more than + * one edge. The plane algorithm is designed so that this should not happen, so + * any occurrences are most likely errors. Note that the routine is O(p), so + * running it every time the plane routine is called will result in a + * significant slowdown. */ +void voronoicell_base::check_duplicates() { + int i,j,k; + for(i=0;i<p;i++) for(j=1;j<nu[i];j++) for(k=0;k<j;k++) if(ed[i][j]==ed[i][k]) + printf("Duplicate edges: (%d,%d) and (%d,%d) [%d]\n",i,j,i,k,ed[i][j]); +} + +/** Constructs the relational table if the edges have been specified. */ +void voronoicell_base::construct_relations() { + int i,j,k,l; + for(i=0;i<p;i++) for(j=0;j<nu[i];j++) { + k=ed[i][j]; + l=0; + while(ed[k][l]!=i) { + l++; + if(l==nu[k]) voro_fatal_error("Relation table construction failed",VOROPP_INTERNAL_ERROR); + } + ed[i][nu[i]+j]=l; + } +} + +/** Starting from a point within the current cutting plane, this routine attempts + * to find an edge to a point outside the cutting plane. This prevents the plane + * routine from . + * \param[in] vc a reference to the specialized version of the calling class. + * \param[in,out] up */ +template<class vc_class> +inline bool voronoicell_base::search_for_outside_edge(vc_class &vc,int &up) { + int i,lp,lw,*j(ds2),*stackp2(ds2); + double l; + *(stackp2++)=up; + while(j<stackp2) { + up=*(j++); + for(i=0;i<nu[up];i++) { + lp=ed[up][i]; + lw=m_test(lp,l); + if(lw==-1) return true; + else if(lw==0) add_to_stack(vc,lp,stackp2); + } + } + return false; +} + +/** Adds a point to the auxiliary delete stack if it is not already there. + * \param[in] vc a reference to the specialized version of the calling class. + * \param[in] lp the index of the point to add. + * \param[in,out] stackp2 a pointer to the end of the stack entries. */ +template<class vc_class> +inline void voronoicell_base::add_to_stack(vc_class &vc,int lp,int *&stackp2) { + for(int *k(ds2);k<stackp2;k++) if(*k==lp) return; + if(stackp2==stacke2) add_memory_ds2(stackp2); + *(stackp2++)=lp; +} + +/** Cuts the Voronoi cell by a particle whose center is at a separation of + * (x,y,z) from the cell center. The value of rsq should be initially set to + * \f$x^2+y^2+z^2\f$. + * \param[in] vc a reference to the specialized version of the calling class. + * \param[in] (x,y,z) the normal vector to the plane. + * \param[in] rsq the distance along this vector of the plane. + * \param[in] p_id the plane ID (for neighbor tracking only). + * \return False if the plane cut deleted the cell entirely, true otherwise. */ +template<class vc_class> +bool voronoicell_base::nplane(vc_class &vc,double x,double y,double z,double rsq,int p_id) { + int count=0,i,j,k,lp=up,cp,qp,rp,*stackp(ds),*stackp2(ds2),*dsp; + int us=0,ls=0,qs,iqs,cs,uw,qw,lw; + int *edp,*edd; + double u,l,r,q;bool complicated_setup=false,new_double_edge=false,double_edge=false; + + // Initialize the safe testing routine + n_marg=0;px=x;py=y;pz=z;prsq=rsq; + + // Test approximately sqrt(n)/4 points for their proximity to the plane + // and keep the one which is closest + uw=m_test(up,u); + + // Starting from an initial guess, we now move from vertex to vertex, + // to try and find an edge which intersects the cutting plane, + // or a vertex which is on the plane + try { + if(uw==1) { + + // The test point is inside the cutting plane. + us=0; + do { + lp=ed[up][us]; + lw=m_test(lp,l); + if(l<u) break; + us++; + } while (us<nu[up]); + + if(us==nu[up]) { + return false; + } + + ls=ed[up][nu[up]+us]; + while(lw==1) { + if(++count>=p) throw true; + u=l;up=lp; + for(us=0;us<ls;us++) { + lp=ed[up][us]; + lw=m_test(lp,l); + if(l<u) break; + } + if(us==ls) { + us++; + while(us<nu[up]) { + lp=ed[up][us]; + lw=m_test(lp,l); + if(l<u) break; + us++; + } + if(us==nu[up]) { + return false; + } + } + ls=ed[up][nu[up]+us]; + } + + // If the last point in the iteration is within the + // plane, we need to do the complicated setup + // routine. Otherwise, we use the regular iteration. + if(lw==0) { + up=lp; + complicated_setup=true; + } else complicated_setup=false; + } else if(uw==-1) { + us=0; + do { + qp=ed[up][us]; + qw=m_test(qp,q); + if(u<q) break; + us++; + } while (us<nu[up]); + if(us==nu[up]) return true; + + while(qw==-1) { + qs=ed[up][nu[up]+us]; + if(++count>=p) throw true; + u=q;up=qp; + for(us=0;us<qs;us++) { + qp=ed[up][us]; + qw=m_test(qp,q); + if(u<q) break; + } + if(us==qs) { + us++; + while(us<nu[up]) { + qp=ed[up][us]; + qw=m_test(qp,q); + if(u<q) break; + us++; + } + if(us==nu[up]) return true; + } + } + if(qw==1) { + lp=up;ls=us;l=u; + up=qp;us=ed[lp][nu[lp]+ls];u=q; + complicated_setup=false; + } else { + up=qp; + complicated_setup=true; + } + } else { + + // Our original test point was on the plane, so we + // automatically head for the complicated setup + // routine + complicated_setup=true; + } + } + catch(bool except) { + // This routine is a fall-back, in case floating point errors + // cause the usual search routine to fail. In the fall-back + // routine, we just test every edge to find one straddling + // the plane. +#if VOROPP_VERBOSE >=1 + fputs("Bailed out of convex calculation\n",stderr); +#endif + qw=1;lw=0; + for(qp=0;qp<p;qp++) { + qw=m_test(qp,q); + if(qw==1) { + + // The point is inside the cutting space. Now + // see if we can find a neighbor which isn't. + for(us=0;us<nu[qp];us++) { + lp=ed[qp][us]; + if(lp<qp) { + lw=m_test(lp,l); + if(lw!=1) break; + } + } + if(us<nu[qp]) { + up=qp; + if(lw==0) { + complicated_setup=true; + } else { + complicated_setup=false; + u=q; + ls=ed[up][nu[up]+us]; + } + break; + } + } else if(qw==-1) { + + // The point is outside the cutting space. See + // if we can find a neighbor which isn't. + for(ls=0;ls<nu[qp];ls++) { + up=ed[qp][ls]; + if(up<qp) { + uw=m_test(up,u); + if(uw!=-1) break; + } + } + if(ls<nu[qp]) { + if(uw==0) { + up=qp; + complicated_setup=true; + } else { + complicated_setup=false; + lp=qp;l=q; + us=ed[lp][nu[lp]+ls]; + } + break; + } + } else { + + // The point is in the plane, so we just + // proceed with the complicated setup routine + up=qp; + complicated_setup=true; + break; + } + } + if(qp==p) return qw==-1?true:false; + } + + // We're about to add the first point of the new facet. In either + // routine, we have to add a point, so first check there's space for + // it. + if(p==current_vertices) add_memory_vertices(vc); + + if(complicated_setup) { + + // We want to be strict about reaching the conclusion that the + // cell is entirely within the cutting plane. It's not enough + // to find a vertex that has edges which are all inside or on + // the plane. If the vertex has neighbors that are also on the + // plane, we should check those too. + if(!search_for_outside_edge(vc,up)) return false; + + // The search algorithm found a point which is on the cutting + // plane. We leave that point in place, and create a new one at + // the same location. + pts[3*p]=pts[3*up]; + pts[3*p+1]=pts[3*up+1]; + pts[3*p+2]=pts[3*up+2]; + + // Search for a collection of edges of the test vertex which + // are outside of the cutting space. Begin by testing the + // zeroth edge. + i=0; + lp=*ed[up]; + lw=m_test(lp,l); + if(lw!=-1) { + + // The first edge is either inside the cutting space, + // or lies within the cutting plane. Test the edges + // sequentially until we find one that is outside. + rp=lw; + do { + i++; + + // If we reached the last edge with no luck + // then all of the vertices are inside + // or on the plane, so the cell is completely + // deleted + if(i==nu[up]) return false; + lp=ed[up][i]; + lw=m_test(lp,l); + } while (lw!=-1); + j=i+1; + + // We found an edge outside the cutting space. Keep + // moving through these edges until we find one that's + // inside or on the plane. + while(j<nu[up]) { + lp=ed[up][j]; + lw=m_test(lp,l); + if(lw!=-1) break; + j++; + } + + // Compute the number of edges for the new vertex. In + // general it will be the number of outside edges + // found, plus two. But we need to recognize the + // special case when all but one edge is outside, and + // the remaining one is on the plane. For that case we + // have to reduce the edge count by one to prevent + // doubling up. + if(j==nu[up]&&i==1&&rp==0) { + nu[p]=nu[up]; + double_edge=true; + } else nu[p]=j-i+2; + k=1; + + // Add memory for the new vertex if needed, and + // initialize + while (nu[p]>=current_vertex_order) add_memory_vorder(vc); + if(mec[nu[p]]==mem[nu[p]]) add_memory(vc,nu[p],stackp2); + vc.n_set_pointer(p,nu[p]); + ed[p]=mep[nu[p]]+((nu[p]<<1)+1)*mec[nu[p]]++; + ed[p][nu[p]<<1]=p; + + // Copy the edges of the original vertex into the new + // one. Delete the edges of the original vertex, and + // update the relational table. + us=cycle_down(i,up); + while(i<j) { + qp=ed[up][i]; + qs=ed[up][nu[up]+i]; + vc.n_copy(p,k,up,i); + ed[p][k]=qp; + ed[p][nu[p]+k]=qs; + ed[qp][qs]=p; + ed[qp][nu[qp]+qs]=k; + ed[up][i]=-1; + i++;k++; + } + qs=i==nu[up]?0:i; + } else { + + // In this case, the zeroth edge is outside the cutting + // plane. Begin by searching backwards from the last + // edge until we find an edge which isn't outside. + i=nu[up]-1; + lp=ed[up][i]; + lw=m_test(lp,l); + while(lw==-1) { + i--; + + // If i reaches zero, then we have a point in + // the plane all of whose edges are outside + // the cutting space, so we just exit + if(i==0) return true; + lp=ed[up][i]; + lw=m_test(lp,l); + } + + // Now search forwards from zero + j=1; + qp=ed[up][j]; + qw=m_test(qp,q); + while(qw==-1) { + j++; + qp=ed[up][j]; + qw=m_test(qp,l); + } + + // Compute the number of edges for the new vertex. In + // general it will be the number of outside edges + // found, plus two. But we need to recognize the + // special case when all but one edge is outside, and + // the remaining one is on the plane. For that case we + // have to reduce the edge count by one to prevent + // doubling up. + if(i==j&&qw==0) { + double_edge=true; + nu[p]=nu[up]; + } else { + nu[p]=nu[up]-i+j+1; + } + + // Add memory to store the vertex if it doesn't exist + // already + k=1; + while(nu[p]>=current_vertex_order) add_memory_vorder(vc); + if(mec[nu[p]]==mem[nu[p]]) add_memory(vc,nu[p],stackp2); + + // Copy the edges of the original vertex into the new + // one. Delete the edges of the original vertex, and + // update the relational table. + vc.n_set_pointer(p,nu[p]); + ed[p]=mep[nu[p]]+((nu[p]<<1)+1)*mec[nu[p]]++; + ed[p][nu[p]<<1]=p; + us=i++; + while(i<nu[up]) { + qp=ed[up][i]; + qs=ed[up][nu[up]+i]; + vc.n_copy(p,k,up,i); + ed[p][k]=qp; + ed[p][nu[p]+k]=qs; + ed[qp][qs]=p; + ed[qp][nu[qp]+qs]=k; + ed[up][i]=-1; + i++;k++; + } + i=0; + while(i<j) { + qp=ed[up][i]; + qs=ed[up][nu[up]+i]; + vc.n_copy(p,k,up,i); + ed[p][k]=qp; + ed[p][nu[p]+k]=qs; + ed[qp][qs]=p; + ed[qp][nu[qp]+qs]=k; + ed[up][i]=-1; + i++;k++; + } + qs=j; + } + if(!double_edge) { + vc.n_copy(p,k,up,qs); + vc.n_set(p,0,p_id); + } else vc.n_copy(p,0,up,qs); + + // Add this point to the auxiliary delete stack + if(stackp2==stacke2) add_memory_ds2(stackp2); + *(stackp2++)=up; + + // Look at the edges on either side of the group that was + // detected. We're going to commence facet computation by + // moving along one of them. We are going to end up coming back + // along the other one. + cs=k; + qp=up;q=u; + i=ed[up][us]; + us=ed[up][nu[up]+us]; + up=i; + ed[qp][nu[qp]<<1]=-p; + + } else { + + // The search algorithm found an intersected edge between the + // points lp and up. Create a new vertex between them which + // lies on the cutting plane. Since u and l differ by at least + // the tolerance, this division should never screw up. + if(stackp==stacke) add_memory_ds(stackp); + *(stackp++)=up; + r=u/(u-l);l=1-r; + pts[3*p]=pts[3*lp]*r+pts[3*up]*l; + pts[3*p+1]=pts[3*lp+1]*r+pts[3*up+1]*l; + pts[3*p+2]=pts[3*lp+2]*r+pts[3*up+2]*l; + + // This point will always have three edges. Connect one of them + // to lp. + nu[p]=3; + if(mec[3]==mem[3]) add_memory(vc,3,stackp2); + vc.n_set_pointer(p,3); + vc.n_set(p,0,p_id); + vc.n_copy(p,1,up,us); + vc.n_copy(p,2,lp,ls); + ed[p]=mep[3]+7*mec[3]++; + ed[p][6]=p; + ed[up][us]=-1; + ed[lp][ls]=p; + ed[lp][nu[lp]+ls]=1; + ed[p][1]=lp; + ed[p][nu[p]+1]=ls; + cs=2; + + // Set the direction to move in + qs=cycle_up(us,up); + qp=up;q=u; + } + + // When the code reaches here, we have initialized the first point, and + // we have a direction for moving it to construct the rest of the facet + cp=p;rp=p;p++; + while(qp!=up||qs!=us) { + + // We're currently tracing round an intersected facet. Keep + // moving around it until we find a point or edge which + // intersects the plane. + lp=ed[qp][qs]; + lw=m_test(lp,l); + + if(lw==1) { + + // The point is still in the cutting space. Just add it + // to the delete stack and keep moving. + qs=cycle_up(ed[qp][nu[qp]+qs],lp); + qp=lp; + q=l; + if(stackp==stacke) add_memory_ds(stackp); + *(stackp++)=qp; + + } else if(lw==-1) { + + // The point is outside of the cutting space, so we've + // found an intersected edge. Introduce a regular point + // at the point of intersection. Connect it to the + // point we just tested. Also connect it to the previous + // new point in the facet we're constructing. + if(p==current_vertices) add_memory_vertices(vc); + r=q/(q-l);l=1-r; + pts[3*p]=pts[3*lp]*r+pts[3*qp]*l; + pts[3*p+1]=pts[3*lp+1]*r+pts[3*qp+1]*l; + pts[3*p+2]=pts[3*lp+2]*r+pts[3*qp+2]*l; + nu[p]=3; + if(mec[3]==mem[3]) add_memory(vc,3,stackp2); + ls=ed[qp][qs+nu[qp]]; + vc.n_set_pointer(p,3); + vc.n_set(p,0,p_id); + vc.n_copy(p,1,qp,qs); + vc.n_copy(p,2,lp,ls); + ed[p]=mep[3]+7*mec[3]++; + *ed[p]=cp; + ed[p][1]=lp; + ed[p][3]=cs; + ed[p][4]=ls; + ed[p][6]=p; + ed[lp][ls]=p; + ed[lp][nu[lp]+ls]=1; + ed[cp][cs]=p; + ed[cp][nu[cp]+cs]=0; + ed[qp][qs]=-1; + qs=cycle_up(qs,qp); + cp=p++; + cs=2; + } else { + + // We've found a point which is on the cutting plane. + // We're going to introduce a new point right here, but + // first we need to figure out the number of edges it + // has. + if(p==current_vertices) add_memory_vertices(vc); + + // If the previous vertex detected a double edge, our + // new vertex will have one less edge. + k=double_edge?0:1; + qs=ed[qp][nu[qp]+qs]; + qp=lp; + iqs=qs; + + // Start testing the edges of the current point until + // we find one which isn't outside the cutting space + do { + k++; + qs=cycle_up(qs,qp); + lp=ed[qp][qs]; + lw=m_test(lp,l); + } while (lw==-1); + + // Now we need to find out whether this marginal vertex + // we are on has been visited before, because if that's + // the case, we need to add vertices to the existing + // new vertex, rather than creating a fresh one. We also + // need to figure out whether we're in a case where we + // might be creating a duplicate edge. + j=-ed[qp][nu[qp]<<1]; + if(qp==up&&qs==us) { + + // If we're heading into the final part of the + // new facet, then we never worry about the + // duplicate edge calculation. + new_double_edge=false; + if(j>0) k+=nu[j]; + } else { + if(j>0) { + + // This vertex was visited before, so + // count those vertices to the ones we + // already have. + k+=nu[j]; + + // The only time when we might make a + // duplicate edge is if the point we're + // going to move to next is also a + // marginal point, so test for that + // first. + if(lw==0) { + + // Now see whether this marginal point + // has been visited before. + i=-ed[lp][nu[lp]<<1]; + if(i>0) { + + // Now see if the last edge of that other + // marginal point actually ends up here. + if(ed[i][nu[i]-1]==j) { + new_double_edge=true; + k-=1; + } else new_double_edge=false; + } else { + + // That marginal point hasn't been visited + // before, so we probably don't have to worry + // about duplicate edges, except in the + // case when that's the way into the end + // of the facet, because that way always creates + // an edge. + if(j==rp&&lp==up&&ed[qp][nu[qp]+qs]==us) { + new_double_edge=true; + k-=1; + } else new_double_edge=false; + } + } else new_double_edge=false; + } else { + + // The vertex hasn't been visited + // before, but let's see if it's + // marginal + if(lw==0) { + + // If it is, we need to check + // for the case that it's a + // small branch, and that we're + // heading right back to where + // we came from + i=-ed[lp][nu[lp]<<1]; + if(i==cp) { + new_double_edge=true; + k-=1; + } else new_double_edge=false; + } else new_double_edge=false; + } + } + + // k now holds the number of edges of the new vertex + // we are forming. Add memory for it if it doesn't exist + // already. + while(k>=current_vertex_order) add_memory_vorder(vc); + if(mec[k]==mem[k]) add_memory(vc,k,stackp2); + + // Now create a new vertex with order k, or augment + // the existing one + if(j>0) { + + // If we're augmenting a vertex but we don't + // actually need any more edges, just skip this + // routine to avoid memory confusion + if(nu[j]!=k) { + // Allocate memory and copy the edges + // of the previous instance into it + vc.n_set_aux1(k); + edp=mep[k]+((k<<1)+1)*mec[k]++; + i=0; + while(i<nu[j]) { + vc.n_copy_aux1(j,i); + edp[i]=ed[j][i]; + edp[k+i]=ed[j][nu[j]+i]; + i++; + } + edp[k<<1]=j; + + // Remove the previous instance with + // fewer vertices from the memory + // structure + edd=mep[nu[j]]+((nu[j]<<1)+1)*--mec[nu[j]]; + if(edd!=ed[j]) { + for(lw=0;lw<=(nu[j]<<1);lw++) ed[j][lw]=edd[lw]; + vc.n_set_aux2_copy(j,nu[j]); + vc.n_copy_pointer(edd[nu[j]<<1],j); + ed[edd[nu[j]<<1]]=ed[j]; + } + vc.n_set_to_aux1(j); + ed[j]=edp; + } else i=nu[j]; + } else { + + // Allocate a new vertex of order k + vc.n_set_pointer(p,k); + ed[p]=mep[k]+((k<<1)+1)*mec[k]++; + ed[p][k<<1]=p; + if(stackp2==stacke2) add_memory_ds2(stackp2); + *(stackp2++)=qp; + pts[3*p]=pts[3*qp]; + pts[3*p+1]=pts[3*qp+1]; + pts[3*p+2]=pts[3*qp+2]; + ed[qp][nu[qp]<<1]=-p; + j=p++; + i=0; + } + nu[j]=k; + + // Unless the previous case was a double edge, connect + // the first available edge of the new vertex to the + // last one in the facet + if(!double_edge) { + ed[j][i]=cp; + ed[j][nu[j]+i]=cs; + vc.n_set(j,i,p_id); + ed[cp][cs]=j; + ed[cp][nu[cp]+cs]=i; + i++; + } + + // Copy in the edges of the underlying vertex, + // and do one less if this was a double edge + qs=iqs; + while(i<(new_double_edge?k:k-1)) { + qs=cycle_up(qs,qp); + lp=ed[qp][qs];ls=ed[qp][nu[qp]+qs]; + vc.n_copy(j,i,qp,qs); + ed[j][i]=lp; + ed[j][nu[j]+i]=ls; + ed[lp][ls]=j; + ed[lp][nu[lp]+ls]=i; + ed[qp][qs]=-1; + i++; + } + qs=cycle_up(qs,qp); + cs=i; + cp=j; + vc.n_copy(j,new_double_edge?0:cs,qp,qs); + + // Update the double_edge flag, to pass it + // to the next instance of this routine + double_edge=new_double_edge; + } + } + + // Connect the final created vertex to the initial one + ed[cp][cs]=rp; + *ed[rp]=cp; + ed[cp][nu[cp]+cs]=0; + ed[rp][nu[rp]]=cs; + + // Delete points: first, remove any duplicates + dsp=ds; + while(dsp<stackp) { + j=*dsp; + if(ed[j][nu[j]]!=-1) { + ed[j][nu[j]]=-1; + dsp++; + } else *dsp=*(--stackp); + } + + // Add the points in the auxiliary delete stack, + // and reset their back pointers + for(dsp=ds2;dsp<stackp2;dsp++) { + j=*dsp; + ed[j][nu[j]<<1]=j; + if(ed[j][nu[j]]!=-1) { + ed[j][nu[j]]=-1; + if(stackp==stacke) add_memory_ds(stackp); + *(stackp++)=j; + } + } + + // Scan connections and add in extras + for(dsp=ds;dsp<stackp;dsp++) { + cp=*dsp; + for(edp=ed[cp];edp<ed[cp]+nu[cp];edp++) { + qp=*edp; + if(qp!=-1&&ed[qp][nu[qp]]!=-1) { + if(stackp==stacke) { + int dis=stackp-dsp; + add_memory_ds(stackp); + dsp=ds+dis; + } + *(stackp++)=qp; + ed[qp][nu[qp]]=-1; + } + } + } + up=0; + + // Delete them from the array structure + while(stackp>ds) { + --p; + while(ed[p][nu[p]]==-1) { + j=nu[p]; + edp=ed[p];edd=(mep[j]+((j<<1)+1)*--mec[j]); + while(edp<ed[p]+(j<<1)+1) *(edp++)=*(edd++); + vc.n_set_aux2_copy(p,j); + vc.n_copy_pointer(ed[p][(j<<1)],p); + ed[ed[p][(j<<1)]]=ed[p]; + --p; + } + up=*(--stackp); + if(up<p) { + + // Vertex management + pts[3*up]=pts[3*p]; + pts[3*up+1]=pts[3*p+1]; + pts[3*up+2]=pts[3*p+2]; + + // Memory management + j=nu[up]; + edp=ed[up];edd=(mep[j]+((j<<1)+1)*--mec[j]); + while(edp<ed[up]+(j<<1)+1) *(edp++)=*(edd++); + vc.n_set_aux2_copy(up,j); + vc.n_copy_pointer(ed[up][j<<1],up); + vc.n_copy_pointer(up,p); + ed[ed[up][j<<1]]=ed[up]; + + // Edge management + ed[up]=ed[p]; + nu[up]=nu[p]; + for(i=0;i<nu[up];i++) ed[ed[up][i]][ed[up][nu[up]+i]]=up; + ed[up][nu[up]<<1]=up; + } else up=p++; + } + + // Check for any vertices of zero order + if(*mec>0) voro_fatal_error("Zero order vertex formed",VOROPP_INTERNAL_ERROR); + + // Collapse any order 2 vertices and exit + return collapse_order2(vc); +} + +/** During the creation of a new facet in the plane routine, it is possible + * that some order two vertices may arise. This routine removes them. + * Suppose an order two vertex joins c and d. If there's a edge between + * c and d already, then the order two vertex is just removed; otherwise, + * the order two vertex is removed and c and d are joined together directly. + * It is possible this process will create order two or order one vertices, + * and the routine is continually run until all of them are removed. + * \return False if the vertex removal was unsuccessful, indicative of the cell + * reducing to zero volume and disappearing; true if the vertex removal + * was successful. */ +template<class vc_class> +inline bool voronoicell_base::collapse_order2(vc_class &vc) { + if(!collapse_order1(vc)) return false; + int a,b,i,j,k,l; + while(mec[2]>0) { + + // Pick a order 2 vertex and read in its edges + i=--mec[2]; + j=mep[2][5*i];k=mep[2][5*i+1]; + if(j==k) { +#if VOROPP_VERBOSE >=1 + fputs("Order two vertex joins itself",stderr); +#endif + return false; + } + + // Scan the edges of j to see if joins k + for(l=0;l<nu[j];l++) { + if(ed[j][l]==k) break; + } + + // If j doesn't already join k, join them together. + // Otherwise delete the connection to the current + // vertex from j and k. + a=mep[2][5*i+2];b=mep[2][5*i+3];i=mep[2][5*i+4]; + if(l==nu[j]) { + ed[j][a]=k; + ed[k][b]=j; + ed[j][nu[j]+a]=b; + ed[k][nu[k]+b]=a; + } else { + if(!delete_connection(vc,j,a,false)) return false; + if(!delete_connection(vc,k,b,true)) return false; + } + + // Compact the memory + --p; + if(up==i) up=0; + if(p!=i) { + if(up==p) up=i; + pts[3*i]=pts[3*p]; + pts[3*i+1]=pts[3*p+1]; + pts[3*i+2]=pts[3*p+2]; + for(k=0;k<nu[p];k++) ed[ed[p][k]][ed[p][nu[p]+k]]=i; + vc.n_copy_pointer(i,p); + ed[i]=ed[p]; + nu[i]=nu[p]; + ed[i][nu[i]<<1]=i; + } + + // Collapse any order 1 vertices if they were created + if(!collapse_order1(vc)) return false; + } + return true; +} + +/** Order one vertices can potentially be created during the order two collapse + * routine. This routine keeps removing them until there are none left. + * \return False if the vertex removal was unsuccessful, indicative of the cell + * having zero volume and disappearing; true if the vertex removal was + * successful. */ +template<class vc_class> +inline bool voronoicell_base::collapse_order1(vc_class &vc) { + int i,j,k; + while(mec[1]>0) { + up=0; +#if VOROPP_VERBOSE >=1 + fputs("Order one collapse\n",stderr); +#endif + i=--mec[1]; + j=mep[1][3*i];k=mep[1][3*i+1]; + i=mep[1][3*i+2]; + if(!delete_connection(vc,j,k,false)) return false; + --p; + if(up==i) up=0; + if(p!=i) { + if(up==p) up=i; + pts[3*i]=pts[3*p]; + pts[3*i+1]=pts[3*p+1]; + pts[3*i+2]=pts[3*p+2]; + for(k=0;k<nu[p];k++) ed[ed[p][k]][ed[p][nu[p]+k]]=i; + vc.n_copy_pointer(i,p); + ed[i]=ed[p]; + nu[i]=nu[p]; + ed[i][nu[i]<<1]=i; + } + } + return true; +} + +/** This routine deletes the kth edge of vertex j and reorganizes the memory. + * If the neighbor computation is enabled, we also have to supply an handedness + * flag to decide whether to preserve the plane on the left or right of the + * connection. + * \return False if a zero order vertex was formed, indicative of the cell + * disappearing; true if the vertex removal was successful. */ +template<class vc_class> +inline bool voronoicell_base::delete_connection(vc_class &vc,int j,int k,bool hand) { + int q=hand?k:cycle_up(k,j); + int i=nu[j]-1,l,*edp,*edd,m; +#if VOROPP_VERBOSE >=1 + if(i<1) { + fputs("Zero order vertex formed\n",stderr); + return false; + } +#endif + if(mec[i]==mem[i]) add_memory(vc,i,ds2); + vc.n_set_aux1(i); + for(l=0;l<q;l++) vc.n_copy_aux1(j,l); + while(l<i) { + vc.n_copy_aux1_shift(j,l); + l++; + } + edp=mep[i]+((i<<1)+1)*mec[i]++; + edp[i<<1]=j; + for(l=0;l<k;l++) { + edp[l]=ed[j][l]; + edp[l+i]=ed[j][l+nu[j]]; + } + while(l<i) { + m=ed[j][l+1]; + edp[l]=m; + k=ed[j][l+nu[j]+1]; + edp[l+i]=k; + ed[m][nu[m]+k]--; + l++; + } + + edd=mep[nu[j]]+((nu[j]<<1)+1)*--mec[nu[j]]; + for(l=0;l<=(nu[j]<<1);l++) ed[j][l]=edd[l]; + vc.n_set_aux2_copy(j,nu[j]); + vc.n_set_to_aux2(edd[nu[j]<<1]); + vc.n_set_to_aux1(j); + ed[edd[nu[j]<<1]]=edd; + ed[j]=edp; + nu[j]=i; + return true; +} + +/** Calculates the volume of the Voronoi cell, by decomposing the cell into + * tetrahedra extending outward from the zeroth vertex, whose volumes are + * evaluated using a scalar triple product. + * \return A floating point number holding the calculated volume. */ +double voronoicell_base::volume() { + const double fe=1/48.0; + double vol=0; + int i,j,k,l,m,n; + double ux,uy,uz,vx,vy,vz,wx,wy,wz; + for(i=1;i<p;i++) { + ux=*pts-pts[3*i]; + uy=pts[1]-pts[3*i+1]; + uz=pts[2]-pts[3*i+2]; + for(j=0;j<nu[i];j++) { + k=ed[i][j]; + if(k>=0) { + ed[i][j]=-1-k; + l=cycle_up(ed[i][nu[i]+j],k); + vx=pts[3*k]-*pts; + vy=pts[3*k+1]-pts[1]; + vz=pts[3*k+2]-pts[2]; + m=ed[k][l];ed[k][l]=-1-m; + while(m!=i) { + n=cycle_up(ed[k][nu[k]+l],m); + wx=pts[3*m]-*pts; + wy=pts[3*m+1]-pts[1]; + wz=pts[3*m+2]-pts[2]; + vol+=ux*vy*wz+uy*vz*wx+uz*vx*wy-uz*vy*wx-uy*vx*wz-ux*vz*wy; + k=m;l=n;vx=wx;vy=wy;vz=wz; + m=ed[k][l];ed[k][l]=-1-m; + } + } + } + } + reset_edges(); + return vol*fe; +} + +/** Calculates the areas of each face of the Voronoi cell and prints the + * results to an output stream. + * \param[out] v the vector to store the results in. */ +void voronoicell_base::face_areas(vector<double> &v) { + double area; + v.clear(); + int i,j,k,l,m,n; + double ux,uy,uz,vx,vy,vz,wx,wy,wz; + for(i=1;i<p;i++) for(j=0;j<nu[i];j++) { + k=ed[i][j]; + if(k>=0) { + area=0; + ed[i][j]=-1-k; + l=cycle_up(ed[i][nu[i]+j],k); + m=ed[k][l];ed[k][l]=-1-m; + while(m!=i) { + n=cycle_up(ed[k][nu[k]+l],m); + ux=pts[3*k]-pts[3*i]; + uy=pts[3*k+1]-pts[3*i+1]; + uz=pts[3*k+2]-pts[3*i+2]; + vx=pts[3*m]-pts[3*i]; + vy=pts[3*m+1]-pts[3*i+1]; + vz=pts[3*m+2]-pts[3*i+2]; + wx=uy*vz-uz*vy; + wy=uz*vx-ux*vz; + wz=ux*vy-uy*vx; + area+=sqrt(wx*wx+wy*wy+wz*wz); + k=m;l=n; + m=ed[k][l];ed[k][l]=-1-m; + } + v.push_back(0.125*area); + } + } + reset_edges(); +} + + +/** Calculates the total surface area of the Voronoi cell. + * \return The computed area. */ +double voronoicell_base::surface_area() { + double area=0; + int i,j,k,l,m,n; + double ux,uy,uz,vx,vy,vz,wx,wy,wz; + for(i=1;i<p;i++) for(j=0;j<nu[i];j++) { + k=ed[i][j]; + if(k>=0) { + ed[i][j]=-1-k; + l=cycle_up(ed[i][nu[i]+j],k); + m=ed[k][l];ed[k][l]=-1-m; + while(m!=i) { + n=cycle_up(ed[k][nu[k]+l],m); + ux=pts[3*k]-pts[3*i]; + uy=pts[3*k+1]-pts[3*i+1]; + uz=pts[3*k+2]-pts[3*i+2]; + vx=pts[3*m]-pts[3*i]; + vy=pts[3*m+1]-pts[3*i+1]; + vz=pts[3*m+2]-pts[3*i+2]; + wx=uy*vz-uz*vy; + wy=uz*vx-ux*vz; + wz=ux*vy-uy*vx; + area+=sqrt(wx*wx+wy*wy+wz*wz); + k=m;l=n; + m=ed[k][l];ed[k][l]=-1-m; + } + } + } + reset_edges(); + return 0.125*area; +} + + +/** Calculates the centroid of the Voronoi cell, by decomposing the cell into + * tetrahedra extending outward from the zeroth vertex. + * \param[out] (cx,cy,cz) references to floating point numbers in which to + * pass back the centroid vector. */ +void voronoicell_base::centroid(double &cx,double &cy,double &cz) { + double tvol,vol=0;cx=cy=cz=0; + int i,j,k,l,m,n; + double ux,uy,uz,vx,vy,vz,wx,wy,wz; + for(i=1;i<p;i++) { + ux=*pts-pts[3*i]; + uy=pts[1]-pts[3*i+1]; + uz=pts[2]-pts[3*i+2]; + for(j=0;j<nu[i];j++) { + k=ed[i][j]; + if(k>=0) { + ed[i][j]=-1-k; + l=cycle_up(ed[i][nu[i]+j],k); + vx=pts[3*k]-*pts; + vy=pts[3*k+1]-pts[1]; + vz=pts[3*k+2]-pts[2]; + m=ed[k][l];ed[k][l]=-1-m; + while(m!=i) { + n=cycle_up(ed[k][nu[k]+l],m); + wx=pts[3*m]-*pts; + wy=pts[3*m+1]-pts[1]; + wz=pts[3*m+2]-pts[2]; + tvol=ux*vy*wz+uy*vz*wx+uz*vx*wy-uz*vy*wx-uy*vx*wz-ux*vz*wy; + vol+=tvol; + cx+=(wx+vx-ux)*tvol; + cy+=(wy+vy-uy)*tvol; + cz+=(wz+vz-uz)*tvol; + k=m;l=n;vx=wx;vy=wy;vz=wz; + m=ed[k][l];ed[k][l]=-1-m; + } + } + } + } + reset_edges(); + if(vol>tolerance_sq) { + vol=0.125/vol; + cx=cx*vol+0.5*(*pts); + cy=cy*vol+0.5*pts[1]; + cz=cz*vol+0.5*pts[2]; + } else cx=cy=cz=0; +} + +/** Computes the maximum radius squared of a vertex from the center of the + * cell. It can be used to determine when enough particles have been testing an + * all planes that could cut the cell have been considered. + * \return The maximum radius squared of a vertex.*/ +double voronoicell_base::max_radius_squared() { + double r,s,*ptsp=pts+3,*ptse=pts+3*p; + r=*pts*(*pts)+pts[1]*pts[1]+pts[2]*pts[2]; + while(ptsp<ptse) { + s=*ptsp*(*ptsp);ptsp++; + s+=*ptsp*(*ptsp);ptsp++; + s+=*ptsp*(*ptsp);ptsp++; + if(s>r) r=s; + } + return r; +} + +/** Calculates the total edge distance of the Voronoi cell. + * \return A floating point number holding the calculated distance. */ +double voronoicell_base::total_edge_distance() { + int i,j,k; + double dis=0,dx,dy,dz; + for(i=0;i<p-1;i++) for(j=0;j<nu[i];j++) { + k=ed[i][j]; + if(k>i) { + dx=pts[3*k]-pts[3*i]; + dy=pts[3*k+1]-pts[3*i+1]; + dz=pts[3*k+2]-pts[3*i+2]; + dis+=sqrt(dx*dx+dy*dy+dz*dz); + } + } + return 0.5*dis; +} + +/** Outputs the edges of the Voronoi cell in POV-Ray format to an open file + * stream, displacing the cell by given vector. + * \param[in] (x,y,z) a displacement vector to be added to the cell's position. + * \param[in] fp a file handle to write to. */ +void voronoicell_base::draw_pov(double x,double y,double z,FILE* fp) { + int i,j,k;double *ptsp=pts,*pt2; + char posbuf1[128],posbuf2[128]; + for(i=0;i<p;i++,ptsp+=3) { + sprintf(posbuf1,"%g,%g,%g",x+*ptsp*0.5,y+ptsp[1]*0.5,z+ptsp[2]*0.5); + fprintf(fp,"sphere{<%s>,r}\n",posbuf1); + for(j=0;j<nu[i];j++) { + k=ed[i][j]; + if(k<i) { + pt2=pts+3*k; + sprintf(posbuf2,"%g,%g,%g",x+*pt2*0.5,y+0.5*pt2[1],z+0.5*pt2[2]); + if(strcmp(posbuf1,posbuf2)!=0) fprintf(fp,"cylinder{<%s>,<%s>,r}\n",posbuf1,posbuf2); + } + } + } +} + +/** Outputs the edges of the Voronoi cell in gnuplot format to an output stream. + * \param[in] (x,y,z) a displacement vector to be added to the cell's position. + * \param[in] fp a file handle to write to. */ +void voronoicell_base::draw_gnuplot(double x,double y,double z,FILE *fp) { + int i,j,k,l,m; + for(i=1;i<p;i++) for(j=0;j<nu[i];j++) { + k=ed[i][j]; + if(k>=0) { + fprintf(fp,"%g %g %g\n",x+0.5*pts[3*i],y+0.5*pts[3*i+1],z+0.5*pts[3*i+2]); + l=i;m=j; + do { + ed[k][ed[l][nu[l]+m]]=-1-l; + ed[l][m]=-1-k; + l=k; + fprintf(fp,"%g %g %g\n",x+0.5*pts[3*k],y+0.5*pts[3*k+1],z+0.5*pts[3*k+2]); + } while (search_edge(l,m,k)); + fputs("\n\n",fp); + } + } + reset_edges(); +} + +inline bool voronoicell_base::search_edge(int l,int &m,int &k) { + for(m=0;m<nu[l];m++) { + k=ed[l][m]; + if(k>=0) return true; + } + return false; +} + +/** Outputs the Voronoi cell in the POV mesh2 format, described in section + * 1.3.2.2 of the POV-Ray documentation. The mesh2 output consists of a list of + * vertex vectors, followed by a list of triangular faces. The routine also + * makes use of the optional inside_vector specification, which makes the mesh + * object solid, so the the POV-Ray Constructive Solid Geometry (CSG) can be + * applied. + * \param[in] (x,y,z) a displacement vector to be added to the cell's position. + * \param[in] fp a file handle to write to. */ +void voronoicell_base::draw_pov_mesh(double x,double y,double z,FILE *fp) { + int i,j,k,l,m,n; + double *ptsp=pts; + fprintf(fp,"mesh2 {\nvertex_vectors {\n%d\n",p); + for(i=0;i<p;i++,ptsp+=3) fprintf(fp,",<%g,%g,%g>\n",x+*ptsp*0.5,y+ptsp[1]*0.5,z+ptsp[2]*0.5); + fprintf(fp,"}\nface_indices {\n%d\n",(p-2)<<1); + for(i=1;i<p;i++) for(j=0;j<nu[i];j++) { + k=ed[i][j]; + if(k>=0) { + ed[i][j]=-1-k; + l=cycle_up(ed[i][nu[i]+j],k); + m=ed[k][l];ed[k][l]=-1-m; + while(m!=i) { + n=cycle_up(ed[k][nu[k]+l],m); + fprintf(fp,",<%d,%d,%d>\n",i,k,m); + k=m;l=n; + m=ed[k][l];ed[k][l]=-1-m; + } + } + } + fputs("}\ninside_vector <0,0,1>\n}\n",fp); + reset_edges(); +} + +/** Several routines in the class that gather cell-based statistics internally + * track their progress by flipping edges to negative so that they know what + * parts of the cell have already been tested. This function resets them back + * to positive. When it is called, it assumes that every edge in the routine + * should have already been flipped to negative, and it bails out with an + * internal error if it encounters a positive edge. */ +inline void voronoicell_base::reset_edges() { + int i,j; + for(i=0;i<p;i++) for(j=0;j<nu[i];j++) { + if(ed[i][j]>=0) voro_fatal_error("Edge reset routine found a previously untested edge",VOROPP_INTERNAL_ERROR); + ed[i][j]=-1-ed[i][j]; + } +} + +/** Checks to see if a given vertex is inside, outside or within the test + * plane. If the point is far away from the test plane, the routine immediately + * returns whether it is inside or outside. If the routine is close the the + * plane and within the specified tolerance, then the special check_marginal() + * routine is called. + * \param[in] n the vertex to test. + * \param[out] ans the result of the scalar product used in evaluating the + * location of the point. + * \return -1 if the point is inside the plane, 1 if the point is outside the + * plane, or 0 if the point is within the plane. */ +inline int voronoicell_base::m_test(int n,double &ans) { + double *pp=pts+n+(n<<1); + ans=*(pp++)*px; + ans+=*(pp++)*py; + ans+=*pp*pz-prsq; + if(ans<-tolerance2) { + return -1; + } else if(ans>tolerance2) { + return 1; + } + return check_marginal(n,ans); +} + +/** Checks to see if a given vertex is inside, outside or within the test + * plane, for the case when the point has been detected to be very close to the + * plane. The routine ensures that the returned results are always consistent + * with previous tests, by keeping a table of any marginal results. The routine + * first sees if the vertex is in the table, and if it finds a previously + * computed result it uses that. Otherwise, it computes a result for this + * vertex and adds it the table. + * \param[in] n the vertex to test. + * \param[in] ans the result of the scalar product used in evaluating + * the location of the point. + * \return -1 if the point is inside the plane, 1 if the point is outside the + * plane, or 0 if the point is within the plane. */ +int voronoicell_base::check_marginal(int n,double &ans) { + int i; + for(i=0;i<n_marg;i+=2) if(marg[i]==n) return marg[i+1]; + if(n_marg==current_marginal) { + current_marginal<<=1; + if(current_marginal>max_marginal) + voro_fatal_error("Marginal case buffer allocation exceeded absolute maximum",VOROPP_MEMORY_ERROR); +#if VOROPP_VERBOSE >=2 + fprintf(stderr,"Marginal cases buffer scaled up to %d\n",i); +#endif + int *pmarg=new int[current_marginal]; + for(int j=0;j<n_marg;j++) pmarg[j]=marg[j]; + delete [] marg; + marg=pmarg; + } + marg[n_marg++]=n; + marg[n_marg++]=ans>tolerance?1:(ans<-tolerance?-1:0); + return marg[n_marg-1]; +} + +/** For each face of the Voronoi cell, this routine prints the out the normal + * vector of the face, and scales it to the distance from the cell center to + * that plane. + * \param[out] v the vector to store the results in. */ +void voronoicell_base::normals(vector<double> &v) { + int i,j,k; + v.clear(); + for(i=1;i<p;i++) for(j=0;j<nu[i];j++) { + k=ed[i][j]; + if(k>=0) normals_search(v,i,j,k); + } + reset_edges(); +} + +/** This inline routine is called by normals(). It attempts to construct a + * single normal vector that is associated with a particular face. It first + * traces around the face, trying to find two vectors along the face edges + * whose vector product is above the numerical tolerance. It then constructs + * the normal vector using this product. If the face is too small, and none of + * the vector products are large enough, the routine may return (0,0,0) as the + * normal vector. + * \param[in] v the vector to store the results in. + * \param[in] i the initial vertex of the face to test. + * \param[in] j the index of an edge of the vertex. + * \param[in] k the neighboring vertex of i, set to ed[i][j]. */ +inline void voronoicell_base::normals_search(vector<double> &v,int i,int j,int k) { + ed[i][j]=-1-k; + int l=cycle_up(ed[i][nu[i]+j],k),m; + double ux,uy,uz,vx,vy,vz,wx,wy,wz,wmag; + do { + m=ed[k][l];ed[k][l]=-1-m; + ux=pts[3*m]-pts[3*k]; + uy=pts[3*m+1]-pts[3*k+1]; + uz=pts[3*m+2]-pts[3*k+2]; + + // Test to see if the length of this edge is above the tolerance + if(ux*ux+uy*uy+uz*uz>tolerance_sq) { + while(m!=i) { + l=cycle_up(ed[k][nu[k]+l],m); + k=m;m=ed[k][l];ed[k][l]=-1-m; + vx=pts[3*m]-pts[3*k]; + vy=pts[3*m+1]-pts[3*k+1]; + vz=pts[3*m+2]-pts[3*k+2]; + + // Construct the vector product of this edge with + // the previous one + wx=uz*vy-uy*vz; + wy=ux*vz-uz*vx; + wz=uy*vx-ux*vy; + wmag=wx*wx+wy*wy+wz*wz; + + // Test to see if this vector product of the + // two edges is above the tolerance + if(wmag>tolerance_sq) { + + // Construct the normal vector and print it + wmag=1/sqrt(wmag); + v.push_back(wx*wmag); + v.push_back(wy*wmag); + v.push_back(wz*wmag); + + // Mark all of the remaining edges of this + // face and exit + while(m!=i) { + l=cycle_up(ed[k][nu[k]+l],m); + k=m;m=ed[k][l];ed[k][l]=-1-m; + } + return; + } + } + v.push_back(0); + v.push_back(0); + v.push_back(0); + return; + } + l=cycle_up(ed[k][nu[k]+l],m); + k=m; + } while (k!=i); + v.push_back(0); + v.push_back(0); + v.push_back(0); +} + + +/** Returns the number of faces of a computed Voronoi cell. + * \return The number of faces. */ +int voronoicell_base::number_of_faces() { + int i,j,k,l,m,s=0; + for(i=1;i<p;i++) for(j=0;j<nu[i];j++) { + k=ed[i][j]; + if(k>=0) { + s++; + ed[i][j]=-1-k; + l=cycle_up(ed[i][nu[i]+j],k); + do { + m=ed[k][l]; + ed[k][l]=-1-m; + l=cycle_up(ed[k][nu[k]+l],m); + k=m; + } while (k!=i); + + } + } + reset_edges(); + return s; +} + +/** Returns a vector of the vertex orders. + * \param[out] v the vector to store the results in. */ +void voronoicell_base::vertex_orders(vector<int> &v) { + v.resize(p); + for(int i=0;i<p;i++) v[i]=nu[i]; +} + +/** Outputs the vertex orders. + * \param[out] fp the file handle to write to. */ +void voronoicell_base::output_vertex_orders(FILE *fp) { + if(p>0) { + fprintf(fp,"%d",*nu); + for(int *nup=nu+1;nup<nu+p;nup++) fprintf(fp," %d",*nup); + } +} + +/** Returns a vector of the vertex vectors using the local coordinate system. + * \param[out] v the vector to store the results in. */ +void voronoicell_base::vertices(vector<double> &v) { + v.resize(3*p); + double *ptsp=pts; + for(int i=0;i<3*p;i+=3) { + v[i]=*(ptsp++)*0.5; + v[i+1]=*(ptsp++)*0.5; + v[i+2]=*(ptsp++)*0.5; + } +} + +/** Outputs the vertex vectors using the local coordinate system. + * \param[out] fp the file handle to write to. */ +void voronoicell_base::output_vertices(FILE *fp) { + if(p>0) { + fprintf(fp,"(%g,%g,%g)",*pts*0.5,pts[1]*0.5,pts[2]*0.5); + for(double *ptsp=pts+3;ptsp<pts+3*p;ptsp+=3) fprintf(fp," (%g,%g,%g)",*ptsp*0.5,ptsp[1]*0.5,ptsp[2]*0.5); + } +} + + +/** Returns a vector of the vertex vectors in the global coordinate system. + * \param[out] v the vector to store the results in. + * \param[in] (x,y,z) the position vector of the particle in the global + * coordinate system. */ +void voronoicell_base::vertices(double x,double y,double z,vector<double> &v) { + v.resize(3*p); + double *ptsp=pts; + for(int i=0;i<3*p;i+=3) { + v[i]=x+*(ptsp++)*0.5; + v[i+1]=y+*(ptsp++)*0.5; + v[i+2]=z+*(ptsp++)*0.5; + } +} + +/** Outputs the vertex vectors using the global coordinate system. + * \param[out] fp the file handle to write to. + * \param[in] (x,y,z) the position vector of the particle in the global + * coordinate system. */ +void voronoicell_base::output_vertices(double x,double y,double z,FILE *fp) { + if(p>0) { + fprintf(fp,"(%g,%g,%g)",x+*pts*0.5,y+pts[1]*0.5,z+pts[2]*0.5); + for(double *ptsp=pts+3;ptsp<pts+3*p;ptsp+=3) fprintf(fp," (%g,%g,%g)",x+*ptsp*0.5,y+ptsp[1]*0.5,z+ptsp[2]*0.5); + } +} + +/** This routine returns the perimeters of each face. + * \param[out] v the vector to store the results in. */ +void voronoicell_base::face_perimeters(vector<double> &v) { + v.clear(); + int i,j,k,l,m; + double dx,dy,dz,perim; + for(i=1;i<p;i++) for(j=0;j<nu[i];j++) { + k=ed[i][j]; + if(k>=0) { + dx=pts[3*k]-pts[3*i]; + dy=pts[3*k+1]-pts[3*i+1]; + dz=pts[3*k+2]-pts[3*i+2]; + perim=sqrt(dx*dx+dy*dy+dz*dz); + ed[i][j]=-1-k; + l=cycle_up(ed[i][nu[i]+j],k); + do { + m=ed[k][l]; + dx=pts[3*m]-pts[3*k]; + dy=pts[3*m+1]-pts[3*k+1]; + dz=pts[3*m+2]-pts[3*k+2]; + perim+=sqrt(dx*dx+dy*dy+dz*dz); + ed[k][l]=-1-m; + l=cycle_up(ed[k][nu[k]+l],m); + k=m; + } while (k!=i); + v.push_back(0.5*perim); + } + } + reset_edges(); +} + +/** For each face, this routine outputs a bracketed sequence of numbers + * containing a list of all the vertices that make up that face. + * \param[out] v the vector to store the results in. */ +void voronoicell_base::face_vertices(vector<int> &v) { + int i,j,k,l,m,vp(0),vn; + v.clear(); + for(i=1;i<p;i++) for(j=0;j<nu[i];j++) { + k=ed[i][j]; + if(k>=0) { + v.push_back(0); + v.push_back(i); + ed[i][j]=-1-k; + l=cycle_up(ed[i][nu[i]+j],k); + do { + v.push_back(k); + m=ed[k][l]; + ed[k][l]=-1-m; + l=cycle_up(ed[k][nu[k]+l],m); + k=m; + } while (k!=i); + vn=v.size(); + v[vp]=vn-vp-1; + vp=vn; + } + } + reset_edges(); +} + +/** Outputs a list of the number of edges in each face. + * \param[out] v the vector to store the results in. */ +void voronoicell_base::face_orders(vector<int> &v) { + int i,j,k,l,m,q; + v.clear(); + for(i=1;i<p;i++) for(j=0;j<nu[i];j++) { + k=ed[i][j]; + if(k>=0) { + q=1; + ed[i][j]=-1-k; + l=cycle_up(ed[i][nu[i]+j],k); + do { + q++; + m=ed[k][l]; + ed[k][l]=-1-m; + l=cycle_up(ed[k][nu[k]+l],m); + k=m; + } while (k!=i); + v.push_back(q);; + } + } + reset_edges(); +} + +/** Computes the number of edges that each face has and outputs a frequency + * table of the results. + * \param[out] v the vector to store the results in. */ +void voronoicell_base::face_freq_table(vector<int> &v) { + int i,j,k,l,m,q; + v.clear(); + for(i=1;i<p;i++) for(j=0;j<nu[i];j++) { + k=ed[i][j]; + if(k>=0) { + q=1; + ed[i][j]=-1-k; + l=cycle_up(ed[i][nu[i]+j],k); + do { + q++; + m=ed[k][l]; + ed[k][l]=-1-m; + l=cycle_up(ed[k][nu[k]+l],m); + k=m; + } while (k!=i); + if((unsigned int) q>=v.size()) v.resize(q+1,0); + v[q]++; + } + } + reset_edges(); +} + +/** This routine tests to see whether the cell intersects a plane by starting + * from the guess point up. If up intersects, then it immediately returns true. + * Otherwise, it calls the plane_intersects_track() routine. + * \param[in] (x,y,z) the normal vector to the plane. + * \param[in] rsq the distance along this vector of the plane. + * \return False if the plane does not intersect the plane, true if it does. */ +bool voronoicell_base::plane_intersects(double x,double y,double z,double rsq) { + double g=x*pts[3*up]+y*pts[3*up+1]+z*pts[3*up+2]; + if(g<rsq) return plane_intersects_track(x,y,z,rsq,g); + return true; +} + +/** This routine tests to see if a cell intersects a plane. It first tests a + * random sample of approximately sqrt(p)/4 points. If any of those are + * intersect, then it immediately returns true. Otherwise, it takes the closest + * point and passes that to plane_intersect_track() routine. + * \param[in] (x,y,z) the normal vector to the plane. + * \param[in] rsq the distance along this vector of the plane. + * \return False if the plane does not intersect the plane, true if it does. */ +bool voronoicell_base::plane_intersects_guess(double x,double y,double z,double rsq) { + up=0; + double g=x*pts[3*up]+y*pts[3*up+1]+z*pts[3*up+2]; + if(g<rsq) { + int ca=1,cc=p>>3,mp=1; + double m; + while(ca<cc) { + m=x*pts[3*mp]+y*pts[3*mp+1]+z*pts[3*mp+2]; + if(m>g) { + if(m>rsq) return true; + g=m;up=mp; + } + ca+=mp++; + } + return plane_intersects_track(x,y,z,rsq,g); + } + return true; +} + +/* This routine tests to see if a cell intersects a plane, by tracing over the cell from + * vertex to vertex, starting at up. It is meant to be called either by plane_intersects() + * or plane_intersects_track(), when those routines cannot immediately resolve the case. + * \param[in] (x,y,z) the normal vector to the plane. + * \param[in] rsq the distance along this vector of the plane. + * \param[in] g the distance of up from the plane. + * \return False if the plane does not intersect the plane, true if it does. */ +inline bool voronoicell_base::plane_intersects_track(double x,double y,double z,double rsq,double g) { + int count=0,ls,us,tp; + double t; + + // The test point is outside of the cutting space + for(us=0;us<nu[up];us++) { + tp=ed[up][us]; + t=x*pts[3*tp]+y*pts[3*tp+1]+z*pts[3*tp+2]; + if(t>g) { + ls=ed[up][nu[up]+us]; + up=tp; + while (t<rsq) { + if(++count>=p) { +#if VOROPP_VERBOSE >=1 + fputs("Bailed out of convex calculation",stderr); +#endif + for(tp=0;tp<p;tp++) if(x*pts[3*tp]+y*pts[3*tp+1]+z*pts[3*tp+2]>rsq) return true; + return false; + } + + // Test all the neighbors of the current point + // and find the one which is closest to the + // plane + for(us=0;us<ls;us++) { + tp=ed[up][us]; + g=x*pts[3*tp]+y*pts[3*tp+1]+z*pts[3*tp+2]; + if(g>t) break; + } + if(us==ls) { + us++; + while(us<nu[up]) { + tp=ed[up][us]; + g=x*pts[3*tp]+y*pts[3*tp+1]+z*pts[3*tp+2]; + if(g>t) break; + us++; + } + if(us==nu[up]) return false; + } + ls=ed[up][nu[up]+us];up=tp;t=g; + } + return true; + } + } + return false; +} + +/** Counts the number of edges of the Voronoi cell. + * \return the number of edges. */ +int voronoicell_base::number_of_edges() { + int edges=0,*nup=nu; + while(nup<nu+p) edges+=*(nup++); + return edges>>1; +} + +/** Outputs a custom string of information about the Voronoi cell. The string + * of information follows a similar style as the C printf command, and detailed + * information about its format is available at + * http://math.lbl.gov/voro++/doc/custom.html. + * \param[in] format the custom string to print. + * \param[in] i the ID of the particle associated with this Voronoi cell. + * \param[in] (x,y,z) the position of the particle associated with this Voronoi + * cell. + * \param[in] r a radius associated with the particle. + * \param[in] fp the file handle to write to. */ +void voronoicell_base::output_custom(const char *format,int i,double x,double y,double z,double r,FILE *fp) { + char *fmp=(const_cast<char*>(format)); + vector<int> vi; + vector<double> vd; + while(*fmp!=0) { + if(*fmp=='%') { + fmp++; + switch(*fmp) { + + // Particle-related output + case 'i': fprintf(fp,"%d",i);break; + case 'x': fprintf(fp,"%g",x);break; + case 'y': fprintf(fp,"%g",y);break; + case 'z': fprintf(fp,"%g",z);break; + case 'q': fprintf(fp,"%g %g %g",x,y,z);break; + case 'r': fprintf(fp,"%g",r);break; + + // Vertex-related output + case 'w': fprintf(fp,"%d",p);break; + case 'p': output_vertices(fp);break; + case 'P': output_vertices(x,y,z,fp);break; + case 'o': output_vertex_orders(fp);break; + case 'm': fprintf(fp,"%g",0.25*max_radius_squared());break; + + // Edge-related output + case 'g': fprintf(fp,"%d",number_of_edges());break; + case 'E': fprintf(fp,"%g",total_edge_distance());break; + case 'e': face_perimeters(vd);voro_print_vector(vd,fp);break; + + // Face-related output + case 's': fprintf(fp,"%d",number_of_faces());break; + case 'F': fprintf(fp,"%g",surface_area());break; + case 'A': { + face_freq_table(vi); + voro_print_vector(vi,fp); + } break; + case 'a': face_orders(vi);voro_print_vector(vi,fp);break; + case 'f': face_areas(vd);voro_print_vector(vd,fp);break; + case 't': { + face_vertices(vi); + voro_print_face_vertices(vi,fp); + } break; + case 'l': normals(vd); + voro_print_positions(vd,fp); + break; + case 'n': neighbors(vi); + voro_print_vector(vi,fp); + break; + + // Volume-related output + case 'v': fprintf(fp,"%g",volume());break; + case 'c': { + double cx,cy,cz; + centroid(cx,cy,cz); + fprintf(fp,"%g %g %g",cx,cy,cz); + } break; + case 'C': { + double cx,cy,cz; + centroid(cx,cy,cz); + fprintf(fp,"%g %g %g",x+cx,y+cy,z+cz); + } break; + + // End-of-string reached + case 0: fmp--;break; + + // The percent sign is not part of a + // control sequence + default: putc('%',fp);putc(*fmp,fp); + } + } else putc(*fmp,fp); + fmp++; + } + fputs("\n",fp); +} + +/** This initializes the class to be a rectangular box. It calls the base class + * initialization routine to set up the edge and vertex information, and then + * sets up the neighbor information, with initial faces being assigned ID + * numbers from -1 to -6. + * \param[in] (xmin,xmax) the minimum and maximum x coordinates. + * \param[in] (ymin,ymax) the minimum and maximum y coordinates. + * \param[in] (zmin,zmax) the minimum and maximum z coordinates. */ +void voronoicell_neighbor::init(double xmin,double xmax,double ymin,double ymax,double zmin,double zmax) { + init_base(xmin,xmax,ymin,ymax,zmin,zmax); + int *q=mne[3]; + *q=-5;q[1]=-3;q[2]=-1; + q[3]=-5;q[4]=-2;q[5]=-3; + q[6]=-5;q[7]=-1;q[8]=-4; + q[9]=-5;q[10]=-4;q[11]=-2; + q[12]=-6;q[13]=-1;q[14]=-3; + q[15]=-6;q[16]=-3;q[17]=-2; + q[18]=-6;q[19]=-4;q[20]=-1; + q[21]=-6;q[22]=-2;q[23]=-4; + *ne=q;ne[1]=q+3;ne[2]=q+6;ne[3]=q+9; + ne[4]=q+12;ne[5]=q+15;ne[6]=q+18;ne[7]=q+21; +} + +/** This initializes the class to be an octahedron. It calls the base class + * initialization routine to set up the edge and vertex information, and then + * sets up the neighbor information, with the initial faces being assigned ID + * numbers from -1 to -8. + * \param[in] l The distance from the octahedron center to a vertex. Six + * vertices are initialized at (-l,0,0), (l,0,0), (0,-l,0), + * (0,l,0), (0,0,-l), and (0,0,l). */ +void voronoicell_neighbor::init_octahedron(double l) { + init_octahedron_base(l); + int *q=mne[4]; + *q=-5;q[1]=-6;q[2]=-7;q[3]=-8; + q[4]=-1;q[5]=-2;q[6]=-3;q[7]=-4; + q[8]=-6;q[9]=-5;q[10]=-2;q[11]=-1; + q[12]=-8;q[13]=-7;q[14]=-4;q[15]=-3; + q[16]=-5;q[17]=-8;q[18]=-3;q[19]=-2; + q[20]=-7;q[21]=-6;q[22]=-1;q[23]=-4; + *ne=q;ne[1]=q+4;ne[2]=q+8;ne[3]=q+12;ne[4]=q+16;ne[5]=q+20; +} + +/** This initializes the class to be a tetrahedron. It calls the base class + * initialization routine to set up the edge and vertex information, and then + * sets up the neighbor information, with the initial faces being assigned ID + * numbers from -1 to -4. + * \param (x0,y0,z0) a position vector for the first vertex. + * \param (x1,y1,z1) a position vector for the second vertex. + * \param (x2,y2,z2) a position vector for the third vertex. + * \param (x3,y3,z3) a position vector for the fourth vertex. */ +void voronoicell_neighbor::init_tetrahedron(double x0,double y0,double z0,double x1,double y1,double z1,double x2,double y2,double z2,double x3,double y3,double z3) { + init_tetrahedron_base(x0,y0,z0,x1,y1,z1,x2,y2,z2,x3,y3,z3); + int *q=mne[3]; + *q=-4;q[1]=-3;q[2]=-2; + q[3]=-3;q[4]=-4;q[5]=-1; + q[6]=-4;q[7]=-2;q[8]=-1; + q[9]=-2;q[10]=-3;q[11]=-1; + *ne=q;ne[1]=q+3;ne[2]=q+6;ne[3]=q+9; +} + +/** This routine checks to make sure the neighbor information of each face is + * consistent. */ +void voronoicell_neighbor::check_facets() { + int i,j,k,l,m,q; + for(i=1;i<p;i++) for(j=0;j<nu[i];j++) { + k=ed[i][j]; + if(k>=0) { + ed[i][j]=-1-k; + q=ne[i][j]; + l=cycle_up(ed[i][nu[i]+j],k); + do { + m=ed[k][l]; + ed[k][l]=-1-m; + if(ne[k][l]!=q) fprintf(stderr,"Facet error at (%d,%d)=%d, started from (%d,%d)=%d\n",k,l,ne[k][l],i,j,q); + l=cycle_up(ed[k][nu[k]+l],m); + k=m; + } while (k!=i); + } + } + reset_edges(); +} + +/** The class constructor allocates memory for storing neighbor information. */ +voronoicell_neighbor::voronoicell_neighbor() { + int i; + mne=new int*[current_vertex_order]; + ne=new int*[current_vertices]; + for(i=0;i<3;i++) mne[i]=new int[init_n_vertices*i]; + mne[3]=new int[init_3_vertices*3]; + for(i=4;i<current_vertex_order;i++) mne[i]=new int[init_n_vertices*i]; +} + +/** The class destructor frees the dynamically allocated memory for storing + * neighbor information. */ +voronoicell_neighbor::~voronoicell_neighbor() { + for(int i=current_vertex_order-1;i>=0;i--) if(mem[i]>0) delete [] mne[i]; + delete [] mne; + delete [] ne; +} + +/** Computes a vector list of neighbors. */ +void voronoicell_neighbor::neighbors(vector<int> &v) { + v.clear(); + int i,j,k,l,m; + for(i=1;i<p;i++) for(j=0;j<nu[i];j++) { + k=ed[i][j]; + if(k>=0) { + v.push_back(ne[i][j]); + ed[i][j]=-1-k; + l=cycle_up(ed[i][nu[i]+j],k); + do { + m=ed[k][l]; + ed[k][l]=-1-m; + l=cycle_up(ed[k][nu[k]+l],m); + k=m; + } while (k!=i); + } + } + reset_edges(); +} + +/** Prints the vertices, their edges, the relation table, and also notifies if + * any memory errors are visible. */ +void voronoicell_base::print_edges() { + int j; + double *ptsp=pts; + for(int i=0;i<p;i++,ptsp+=3) { + printf("%d %d ",i,nu[i]); + for(j=0;j<nu[i];j++) printf(" %d",ed[i][j]); + printf(" "); + while(j<(nu[i]<<1)) printf(" %d",ed[i][j]); + printf(" %d",ed[i][j]); + print_edges_neighbors(i); + printf(" %g %g %g %p",*ptsp,ptsp[1],ptsp[2],(void*) ed[i]); + if(ed[i]>=mep[nu[i]]+mec[nu[i]]*((nu[i]<<1)+1)) puts(" Memory error"); + else puts(""); + } +} + +/** This prints out the neighbor information for vertex i. */ +void voronoicell_neighbor::print_edges_neighbors(int i) { + if(nu[i]>0) { + int j=0; + printf(" ("); + while(j<nu[i]-1) printf("%d,",ne[i][j++]); + printf("%d)",ne[i][j]); + } else printf(" ()"); +} + +// Explicit instantiation +template bool voronoicell_base::nplane(voronoicell&,double,double,double,double,int); +template bool voronoicell_base::nplane(voronoicell_neighbor&,double,double,double,double,int); +template void voronoicell_base::check_memory_for_copy(voronoicell&,voronoicell_base*); +template void voronoicell_base::check_memory_for_copy(voronoicell_neighbor&,voronoicell_base*); + +} diff --git a/contrib/voro++/src/cell.hh b/contrib/voro++/src/cell.hh new file mode 100644 index 0000000000000000000000000000000000000000..a920b88c6f153b877a96bf042c6ab14410b42fbb --- /dev/null +++ b/contrib/voro++/src/cell.hh @@ -0,0 +1,518 @@ +// Voro++, a 3D cell-based Voronoi library +// +// Author : Chris H. Rycroft (LBL / UC Berkeley) +// Email : chr@alum.mit.edu +// Date : August 30th 2011 + +/** \file cell.hh + * \brief Header file for the voronoicell and related classes. */ + +#ifndef VOROPP_CELL_HH +#define VOROPP_CELL_HH + +#include <cstdio> +#include <cstdlib> +#include <cmath> +#include <vector> +using namespace std; + +#include "config.hh" +#include "common.hh" + +namespace voro { + +/** \brief A class representing a single Voronoi cell. + * + * This class represents a single Voronoi cell, as a collection of vertices + * that are connected by edges. The class contains routines for initializing + * the Voronoi cell to be simple shapes such as a box, tetrahedron, or octahedron. + * It the contains routines for recomputing the cell based on cutting it + * by a plane, which forms the key routine for the Voronoi cell computation. + * It contains numerous routine for computing statistics about the Voronoi cell, + * and it can output the cell in several formats. + * + * This class is not intended for direct use, but forms the base of the + * voronoicell and voronoicell_neighbor classes, which extend it based on + * whether neighboring particle ID information needs to be tracked. */ +class voronoicell_base { + public: + /** This holds the current size of the arrays ed and nu, which + * hold the vertex information. If more vertices are created + * than can fit in this array, then it is dynamically extended + * using the add_memory_vertices routine. */ + int current_vertices; + /** This holds the current maximum allowed order of a vertex, + * which sets the size of the mem, mep, and mec arrays. If a + * vertex is created with more vertices than this, the arrays + * are dynamically extended using the add_memory_vorder routine. + */ + int current_vertex_order; + /** This sets the size of the main delete stack. */ + int current_delete_size; + /** This sets the size of the auxiliary delete stack. */ + int current_delete2_size; + /** This sets the total number of vertices in the current cell. + */ + int p; + /** This is the index of particular point in the cell, which is + * used to start the tracing routines for plane intersection + * and cutting. These routines will work starting from any + * point, but it's often most efficient to start from the last + * point considered, since in many cases, the cell construction + * algorithm may consider many planes with similar vectors + * concurrently. */ + int up; + /** This is a two dimensional array that holds information + * about the edge connections of the vertices that make up the + * cell. The two dimensional array is not allocated in the + * usual method. To account for the fact the different vertices + * have different orders, and thus require different amounts of + * storage, the elements of ed[i] point to one-dimensional + * arrays in the mep[] array of different sizes. + * + * More specifically, if vertex i has order m, then ed[i] + * points to a one-dimensional array in mep[m] that has 2*m+1 + * entries. The first m elements hold the neighboring edges, so + * that the jth edge of vertex i is held in ed[i][j]. The next + * m elements hold a table of relations which is redundant but + * helps speed up the computation. It satisfies the relation + * ed[ed[i][j]][ed[i][m+j]]=i. The final entry holds a back + * pointer, so that ed[i+2*m]=i. The back pointers are used + * when rearranging the memory. */ + int **ed; + /** This array holds the order of the vertices in the Voronoi + * cell. This array is dynamically allocated, with its current + * size held by current_vertices. */ + int *nu; + /** This in an array with size 3*current_vertices for holding + * the positions of the vertices. */ + double *pts; + voronoicell_base(); + ~voronoicell_base(); + void init_base(double xmin,double xmax,double ymin,double ymax,double zmin,double zmax); + void init_octahedron_base(double l); + void init_tetrahedron_base(double x0,double y0,double z0,double x1,double y1,double z1,double x2,double y2,double z2,double x3,double y3,double z3); + void translate(double x,double y,double z); + void draw_pov(double x,double y,double z,FILE *fp=stdout); + /** Outputs the cell in POV-Ray format, using cylinders for edges + * and spheres for vertices, to a given file. + * \param[in] (x,y,z) a displacement to add to the cell's + * position. + * \param[in] filename the name of the file to write to. */ + inline void draw_pov(double x,double y,double z,const char *filename) { + FILE *fp=safe_fopen(filename,"w"); + draw_pov(x,y,z,fp); + fclose(fp); + }; + void draw_pov_mesh(double x,double y,double z,FILE *fp=stdout); + /** Outputs the cell in POV-Ray format as a mesh2 object to a + * given file. + * \param[in] (x,y,z) a displacement to add to the cell's + * position. + * \param[in] filename the name of the file to write to. */ + inline void draw_pov_mesh(double x,double y,double z,const char *filename) { + FILE *fp=safe_fopen(filename,"w"); + draw_pov_mesh(x,y,z,fp); + fclose(fp); + } + void draw_gnuplot(double x,double y,double z,FILE *fp=stdout); + /** Outputs the cell in Gnuplot format a given file. + * \param[in] (x,y,z) a displacement to add to the cell's + * position. + * \param[in] filename the name of the file to write to. */ + inline void draw_gnuplot(double x,double y,double z,const char *filename) { + FILE *fp=safe_fopen(filename,"w"); + draw_gnuplot(x,y,z,fp); + fclose(fp); + } + double volume(); + double max_radius_squared(); + double total_edge_distance(); + double surface_area(); + void centroid(double &cx,double &cy,double &cz); + int number_of_faces(); + int number_of_edges(); + void vertex_orders(vector<int> &v); + void output_vertex_orders(FILE *fp=stdout); + void vertices(vector<double> &v); + void output_vertices(FILE *fp=stdout); + void vertices(double x,double y,double z,vector<double> &v); + void output_vertices(double x,double y,double z,FILE *fp=stdout); + void face_areas(vector<double> &v); + /** Outputs the areas of the faces. + * \param[in] fp the file handle to write to. */ + inline void output_face_areas(FILE *fp=stdout) { + vector<double> v;face_areas(v); + voro_print_vector(v,fp); + } + void face_orders(vector<int> &v); + /** Outputs a list of the number of sides of each face. + * \param[in] fp the file handle to write to. */ + inline void output_face_orders(FILE *fp=stdout) { + vector<int> v;face_orders(v); + voro_print_vector(v,fp); + } + void face_freq_table(vector<int> &v); + /** Outputs a */ + inline void output_face_freq_table(FILE *fp=stdout) { + vector<int> v;face_freq_table(v); + voro_print_vector(v,fp); + } + void face_vertices(vector<int> &v); + /** Outputs the */ + inline void output_face_vertices(FILE *fp=stdout) { + vector<int> v;face_vertices(v); + voro_print_face_vertices(v,fp); + } + void face_perimeters(vector<double> &v); + /** Outputs a list of the perimeters of each face. + * \param[in] fp the file handle to write to. */ + inline void output_face_perimeters(FILE *fp=stdout) { + vector<double> v;face_perimeters(v); + voro_print_vector(v,fp); + } + void normals(vector<double> &v); + /** Outputs a list of the perimeters of each face. + * \param[in] fp the file handle to write to. */ + inline void output_normals(FILE *fp=stdout) { + vector<double> v;normals(v); + voro_print_positions(v,fp); + } + /** Outputs a custom string of information about the Voronoi + * cell to a file. It assumes the cell is at (0,0,0) and has a + * the default_radius associated with it. + * \param[in] format the custom format string to use. + * \param[in] fp the file handle to write to. */ + inline void output_custom(const char *format,FILE *fp=stdout) {output_custom(format,0,0,0,0,default_radius,fp);} + void output_custom(const char *format,int i,double x,double y,double z,double r,FILE *fp=stdout); + template<class vc_class> + bool nplane(vc_class &vc,double x,double y,double z,double rs,int p_id); + bool plane_intersects(double x,double y,double z,double rs); + bool plane_intersects_guess(double x,double y,double z,double rs); + void construct_relations(); + void check_relations(); + void check_duplicates(); + void print_edges(); + /** Returns a list of IDs of neighboring particles + * corresponding to each face. + * \param[out] v a reference to a vector in which to return the + * results. If no neighbor information is + * available, a blank vector is returned. */ + virtual void neighbors(vector<int> &v) {v.clear();} + /** This is a virtual function that is overridden by a routine + * to print a list of IDs of neighboring particles + * corresponding to each face. By default, when no neighbor + * information is available, the routine does nothing. + * \param[in] fp the file handle to write to. */ + virtual void output_neighbors(FILE *fp=stdout) {} + /** This a virtual function that is overridden by a routine to + * print the neighboring particle IDs for a given vertex. By + * default, when no neighbor information is available, the + * routine does nothing. + * \param[in] i the vertex to consider. */ + virtual void print_edges_neighbors(int i) {}; + /** This is a simple inline function for picking out the index + * of the next edge counterclockwise at the current vertex. + * \param[in] a the index of an edge of the current vertex. + * \param[in] p the number of the vertex. + * \return 0 if a=nu[p]-1, or a+1 otherwise. */ + inline int cycle_up(int a,int p) {return a==nu[p]-1?0:a+1;} + /** This is a simple inline function for picking out the index + * of the next edge clockwise from the current vertex. + * \param[in] a the index of an edge of the current vertex. + * \param[in] p the number of the vertex. + * \return nu[p]-1 if a=0, or a-1 otherwise. */ + inline int cycle_down(int a,int p) {return a==0?nu[p]-1:a-1;} + protected: + /** This a one dimensional array that holds the current sizes + * of the memory allocations for them mep array.*/ + int *mem; + /** This is a one dimensional array that holds the current + * number of vertices of order p that are stored in the mep[p] + * array. */ + int *mec; + /** This is a two dimensional array for holding the information + * about the edges of the Voronoi cell. mep[p] is a + * one-dimensional array for holding the edge information about + * all vertices of order p, with each vertex holding 2*p+1 + * integers of information. The total number of vertices held + * on mep[p] is stored in mem[p]. If the space runs out, the + * code allocates more using the add_memory() routine. */ + int **mep; + inline void reset_edges(); + template<class vc_class> + void check_memory_for_copy(vc_class &vc,voronoicell_base* vb); + void copy(voronoicell_base* vb); + private: + /** This is the delete stack, used to store the vertices which + * are going to be deleted during the plane cutting procedure. + */ + int *ds,*stacke; + /** This is the auxiliary delete stack, which has size set by + * current_delete2_size. */ + int *ds2,*stacke2; + /** This stores the current memory allocation for the marginal + * cases. */ + int current_marginal; + /** This stores the total number of marginal points which are + * currently in the buffer. */ + int n_marg; + /** This array contains a list of the marginal points, and also + * the outcomes of the marginal tests. */ + int *marg; + /** The x coordinate of the normal vector to the test plane. */ + double px; + /** The y coordinate of the normal vector to the test plane. */ + double py; + /** The z coordinate of the normal vector to the test plane. */ + double pz; + /** The magnitude of the normal vector to the test plane. */ + double prsq; + template<class vc_class> + void add_memory(vc_class &vc,int i,int *stackp2); + template<class vc_class> + void add_memory_vertices(vc_class &vc); + template<class vc_class> + void add_memory_vorder(vc_class &vc); + void add_memory_ds(int *&stackp); + void add_memory_ds2(int *&stackp2); + template<class vc_class> + inline bool collapse_order1(vc_class &vc); + template<class vc_class> + inline bool collapse_order2(vc_class &vc); + template<class vc_class> + inline bool delete_connection(vc_class &vc,int j,int k,bool hand); + template<class vc_class> + inline bool search_for_outside_edge(vc_class &vc,int &up); + template<class vc_class> + inline void add_to_stack(vc_class &vc,int lp,int *&stackp2); + inline bool plane_intersects_track(double x,double y,double z,double rs,double g); + inline void normals_search(vector<double> &v,int i,int j,int k); + inline bool search_edge(int l,int &m,int &k); + inline int m_test(int n,double &ans); + int check_marginal(int n,double &ans); + friend class voronoicell; + friend class voronoicell_neighbor; +}; + +/** \brief Extension of the voronoicell_base class to represent a Voronoi + * cell without neighbor information. + * + * This class is an extension of the voronoicell_base class, in cases when + * is not necessary to track the IDs of neighboring particles associated + * with each face of the Voronoi cell. */ +class voronoicell : public voronoicell_base { + public: + using voronoicell_base::nplane; + /** Copies the information from another voronoicell class into + * this class, extending memory allocation if necessary. + * \param[in] c the class to copy. */ + inline void operator=(voronoicell &c) { + voronoicell_base* vb((voronoicell_base*) &c); + check_memory_for_copy(*this,vb);copy(vb); + } + /** Cuts a Voronoi cell using by the plane corresponding to the + * perpendicular bisector of a particle. + * \param[in] (x,y,z) the position of the particle. + * \param[in] rsq the modulus squared of the vector. + * \param[in] p_id the plane ID, ignored for this case where no + * neighbor tracking is enabled. + * \return False if the plane cut deleted the cell entirely, + * true otherwise. */ + inline bool nplane(double x,double y,double z,double rsq,int p_id) { + return nplane(*this,x,y,z,rsq,0); + } + /** Cuts a Voronoi cell using by the plane corresponding to the + * perpendicular bisector of a particle. + * \param[in] (x,y,z) the position of the particle. + * \param[in] p_id the plane ID, ignored for this case where no + * neighbor tracking is enabled. + * \return False if the plane cut deleted the cell entirely, + * true otherwise. */ + inline bool nplane(double x,double y,double z,int p_id) { + double rsq=x*x+y*y+z*z; + return nplane(*this,x,y,z,rsq,0); + } + /** Cuts a Voronoi cell using by the plane corresponding to the + * perpendicular bisector of a particle. + * \param[in] (x,y,z) the position of the particle. + * \param[in] rsq the modulus squared of the vector. + * \return False if the plane cut deleted the cell entirely, + * true otherwise. */ + inline bool plane(double x,double y,double z,double rsq) { + return nplane(*this,x,y,z,rsq,0); + } + /** Cuts a Voronoi cell using by the plane corresponding to the + * perpendicular bisector of a particle. + * \param[in] (x,y,z) the position of the particle. + * \return False if the plane cut deleted the cell entirely, + * true otherwise. */ + inline bool plane(double x,double y,double z) { + double rsq=x*x+y*y+z*z; + return nplane(*this,x,y,z,rsq,0); + } + /** Initializes the Voronoi cell to be rectangular box with the + * given dimensions. + * \param[in] (xmin,xmax) the minimum and maximum x coordinates. + * \param[in] (ymin,ymax) the minimum and maximum y coordinates. + * \param[in] (zmin,zmax) the minimum and maximum z coordinates. */ + inline void init(double xmin,double xmax,double ymin,double ymax,double zmin,double zmax) { + init_base(xmin,xmax,ymin,ymax,zmin,zmax); + } + /** Initializes the cell to be an octahedron with vertices at + * (l,0,0), (-l,0,0), (0,l,0), (0,-l,0), (0,0,l), and (0,0,-l). + * \param[in] l a parameter setting the size of the octahedron. + */ + inline void init_octahedron(double l) { + init_octahedron_base(l); + } + /** Initializes the cell to be a tetrahedron. + * \param[in] (x0,y0,z0) the coordinates of the first vertex. + * \param[in] (x1,y1,z1) the coordinates of the second vertex. + * \param[in] (x2,y2,z2) the coordinates of the third vertex. + * \param[in] (x3,y3,z3) the coordinates of the fourth vertex. + */ + inline void init_tetrahedron(double x0,double y0,double z0,double x1,double y1,double z1,double x2,double y2,double z2,double x3,double y3,double z3) { + init_tetrahedron_base(x0,y0,z0,x1,y1,z1,x2,y2,z2,x3,y3,z3); + } + private: + inline void n_allocate(int i,int m) {}; + inline void n_add_memory_vertices(int i) {}; + inline void n_add_memory_vorder(int i) {}; + inline void n_set_pointer(int p,int n) {}; + inline void n_copy(int a,int b,int c,int d) {}; + inline void n_set(int a,int b,int c) {}; + inline void n_set_aux1(int k) {}; + inline void n_copy_aux1(int a,int b) {}; + inline void n_copy_aux1_shift(int a,int b) {}; + inline void n_set_aux2_copy(int a,int b) {}; + inline void n_copy_pointer(int a,int b) {}; + inline void n_set_to_aux1(int j) {}; + inline void n_set_to_aux2(int j) {}; + inline void n_allocate_aux1(int i) {}; + inline void n_switch_to_aux1(int i) {}; + inline void n_copy_to_aux1(int i,int m) {}; + inline void n_set_to_aux1_offset(int k,int m) {}; + inline void n_neighbors(vector<int> &v) {v.clear();}; + friend class voronoicell_base; +}; + +/** \brief Extension of the voronoicell_base class to represent a Voronoi cell + * with neighbor information. + * + * This class is an extension of the voronoicell_base class, in cases when the + * IDs of neighboring particles associated with each face of the Voronoi cell. + * It contains additional data structures mne and ne for storing this + * information. */ +class voronoicell_neighbor : public voronoicell_base { + public: + using voronoicell_base::nplane; + /** This two dimensional array holds the neighbor information + * associated with each vertex. mne[p] is a one dimensional + * array which holds all of the neighbor information for + * vertices of order p. */ + int **mne; + /** This is a two dimensional array that holds the neighbor + * information associated with each vertex. ne[i] points to a + * one-dimensional array in mne[nu[i]]. ne[i][j] holds the + * neighbor information associated with the jth edge of vertex + * i. It is set to the ID number of the plane that made the + * face that is clockwise from the jth edge. */ + int **ne; + voronoicell_neighbor(); + ~voronoicell_neighbor(); + void operator=(voronoicell &c); + void operator=(voronoicell_neighbor &c); + /** Cuts the Voronoi cell by a particle whose center is at a + * separation of (x,y,z) from the cell center. The value of rsq + * should be initially set to \f$x^2+y^2+z^2\f$. + * \param[in] (x,y,z) the normal vector to the plane. + * \param[in] rsq the distance along this vector of the plane. + * \param[in] p_id the plane ID (for neighbor tracking only). + * \return False if the plane cut deleted the cell entirely, + * true otherwise. */ + inline bool nplane(double x,double y,double z,double rsq,int p_id) { + return nplane(*this,x,y,z,rsq,p_id); + } + /** This routine calculates the modulus squared of the vector + * before passing it to the main nplane() routine with full + * arguments. + * \param[in] (x,y,z) the vector to cut the cell by. + * \param[in] p_id the plane ID (for neighbor tracking only). + * \return False if the plane cut deleted the cell entirely, + * true otherwise. */ + inline bool nplane(double x,double y,double z,int p_id) { + double rsq=x*x+y*y+z*z; + return nplane(*this,x,y,z,rsq,p_id); + } + /** This version of the plane routine just makes up the plane + * ID to be zero. It will only be referenced if neighbor + * tracking is enabled. + * \param[in] (x,y,z) the vector to cut the cell by. + * \param[in] rsq the modulus squared of the vector. + * \return False if the plane cut deleted the cell entirely, + * true otherwise. */ + inline bool plane(double x,double y,double z,double rsq) { + return nplane(*this,x,y,z,rsq,0); + } + /** Cuts a Voronoi cell using the influence of a particle at + * (x,y,z), first calculating the modulus squared of this + * vector before passing it to the main nplane() routine. Zero + * is supplied as the plane ID, which will be ignored unless + * neighbor tracking is enabled. + * \param[in] (x,y,z) the vector to cut the cell by. + * \return False if the plane cut deleted the cell entirely, + * true otherwise. */ + inline bool plane(double x,double y,double z) { + double rsq=x*x+y*y+z*z; + return nplane(*this,x,y,z,rsq,0); + } + void init(double xmin,double xmax,double ymin,double ymax,double zmin,double zmax); + void init_octahedron(double l); + void init_tetrahedron(double x0,double y0,double z0,double x1,double y1,double z1,double x2,double y2,double z2,double x3,double y3,double z3); + void check_facets(); + virtual void neighbors(vector<int> &v); + virtual void print_edges_neighbors(int i); + virtual void output_neighbors(FILE *fp=stdout) { + vector<int> v;neighbors(v); + voro_print_vector(v,fp); + } + private: + int *paux1; + int *paux2; + inline void n_allocate(int i,int m) {mne[i]=new int[m*i];} + inline void n_add_memory_vertices(int i) { + int **pp=new int*[i]; + for(int j=0;j<current_vertices;j++) pp[j]=ne[j]; + delete [] ne;ne=pp; + } + inline void n_add_memory_vorder(int i) { + int **p2=new int*[i]; + for(int j=0;j<current_vertex_order;j++) p2[j]=mne[j]; + delete [] mne;mne=p2; + } + inline void n_set_pointer(int p,int n) { + ne[p]=mne[n]+n*mec[n]; + } + inline void n_copy(int a,int b,int c,int d) {ne[a][b]=ne[c][d];} + inline void n_set(int a,int b,int c) {ne[a][b]=c;} + inline void n_set_aux1(int k) {paux1=mne[k]+k*mec[k];} + inline void n_copy_aux1(int a,int b) {paux1[b]=ne[a][b];} + inline void n_copy_aux1_shift(int a,int b) {paux1[b]=ne[a][b+1];} + inline void n_set_aux2_copy(int a,int b) { + paux2=mne[b]+b*mec[b]; + for(int i=0;i<b;i++) ne[a][i]=paux2[i]; + } + inline void n_copy_pointer(int a,int b) {ne[a]=ne[b];} + inline void n_set_to_aux1(int j) {ne[j]=paux1;} + inline void n_set_to_aux2(int j) {ne[j]=paux2;} + inline void n_allocate_aux1(int i) {paux1=new int[i*mem[i]];} + inline void n_switch_to_aux1(int i) {delete [] mne[i];mne[i]=paux1;} + inline void n_copy_to_aux1(int i,int m) {paux1[m]=mne[i][m];} + inline void n_set_to_aux1_offset(int k,int m) {ne[k]=paux1+m;} + friend class voronoicell_base; +}; + +} + +#endif diff --git a/contrib/voro++/src/cmd_line.cc b/contrib/voro++/src/cmd_line.cc new file mode 100644 index 0000000000000000000000000000000000000000..f83a77aa16b752de7f49af8d6b8c47774b200145 --- /dev/null +++ b/contrib/voro++/src/cmd_line.cc @@ -0,0 +1,497 @@ +// Voro++, a 3D cell-based Voronoi library +// +// Author : Chris H. Rycroft (LBL / UC Berkeley) +// Email : chr@alum.mit.edu +// Date : August 30th 2011 + +/** \file cmd_line.cc + * \brief Source code for the command-line utility. */ + +#include <cstring> +#include "voro++.hh" +using namespace voro; + +enum blocks_mode { + none, + length_scale, + specified +}; + +// A maximum allowed number of regions, to prevent enormous amounts of memory +// being allocated +const int max_regions=16777216; + +// This message gets displayed if the user requests the help flag +void help_message() { + puts("Voro++ version 0.4.4, by Chris H. Rycroft (UC Berkeley/LBL)\n\n" + "Syntax: voro++ [options] <x_min> <x_max> <y_min>\n" + " <y_max> <z_min> <z_max> <filename>\n\n" + "By default, the utility reads in the input file of particle IDs and positions,\n" + "computes the Voronoi cell for each, and then creates <filename.vol> with an\n" + "additional column containing the volume of each Voronoi cell.\n\n" + "Available options:\n" + " -c <str> : Specify a custom output string\n" + " -g : Turn on the gnuplot output to <filename.gnu>\n" + " -h/--help : Print this information\n" + " -hc : Print information about custom output\n" + " -l <len> : Manually specify a length scale to configure the internal\n" + " computational grid\n" + " -m <mem> : Manually choose the memory allocation per grid block\n" + " (default 8)\n" + " -n [3] : Manually specify the internal grid size\n" + " -o : Ensure that the output file has the same order as the input\n" + " file\n" + " -p : Make container periodic in all three directions\n" + " -px : Make container periodic in the x direction\n" + " -py : Make container periodic in the y direction\n" + " -pz : Make container periodic in the z direction\n" + " -r : Assume the input file has an extra coordinate for radii\n" + " -v : Verbose output\n" + " --version : Print version information\n" + " -wb [6] : Add six plane wall objects to make rectangular box containing\n" + " the space x1<x<x2, x3<y<x4, x5<z<x6\n" + " -wc [7] : Add a cylinder wall object, centered on (x1,x2,x3),\n" + " pointing in (x4,x5,x6), radius x7\n" + " -wo [7] : Add a conical wall object, apex at (x1,x2,x3), axis\n" + " along (x4,x5,x6), angle x7 in radians\n" + " -ws [4] : Add a sphere wall object, centered on (x1,x2,x3),\n" + " with radius x4\n" + " -wp [4] : Add a plane wall object, with normal (x1,x2,x3),\n" + " and displacement x4\n" + " -y : Save POV-Ray particles to <filename_p.pov> and POV-Ray Voronoi\n" + " cells to <filename_v.pov>\n" + " -yp : Save only POV-Ray particles to <filename_p.pov>\n" + " -yv : Save only POV-Ray Voronoi cells to <filename_v.pov>"); +} + +// This message gets displayed if the user requests information about doing +// custom output +void custom_output_message() { + puts("The \"-c\" option allows a string to be specified that will customize the output\n" + "file to contain a variety of statistics about each computed Voronoi cell. The\n" + "string is similar to the standard C printf() function, made up of text with\n" + "additional control sequences that begin with percentage signs that are expanded\n" + "to different statistics. See http://math.lbl.gov/voro++/doc/custom.html for more\n" + "information.\n" + "\nParticle-related:\n" + " %i The particle ID number\n" + " %x The x coordinate of the particle\n" + " %y The y coordinate of the particle\n" + " %z The z coordinate of the particle\n" + " %q The position vector of the particle, short for \"%x %y %z\"\n" + " %r The radius of the particle (only printed if -p enabled)\n" + "\nVertex-related:\n" + " %w The number of vertices in the Voronoi cell\n" + " %p A list of the vertices of the Voronoi cell in the format (x,y,z),\n" + " relative to the particle center\n" + " %P A list of the vertices of the Voronoi cell in the format (x,y,z),\n" + " relative to the global coordinate system\n" + " %o A list of the orders of each vertex\n" + " %m The maximum radius squared of a vertex position, relative to the\n" + " particle center\n" + "\nEdge-related:\n" + " %g The number of edges of the Voronoi cell\n" + " %E The total edge distance\n" + " %e A list of perimeters of each face\n" + "\nFace-related:\n" + " %s The number of faces of the Voronoi cell\n" + " %F The total surface area of the Voronoi cell\n" + " %A A frequency table of the number of edges for each face\n" + " %a A list of the number of edges for each face\n" + " %f A list of areas of each face\n" + " %t A list of bracketed sequences of vertices that make up each face\n" + " %l A list of normal vectors for each face\n" + " %n A list of neighboring particle or wall IDs corresponding to each face\n" + "\nVolume-related:\n" + " %v The volume of the Voronoi cell\n" + " %c The centroid of the Voronoi cell, relative to the particle center\n" + " %C The centroid of the Voronoi cell, in the global coordinate system"); +} + +// Ths message is displayed if the user requests version information +void version_message() { + puts("Voro++ version 0.4.4 (January 17th 2012)"); +} + +// Prints an error message. This is called when the program is unable to make +// sense of the command-line options. +void error_message() { + fputs("voro++: Unrecognized command-line options; type \"voro++ -h\" for more\ninformation.\n",stderr); +} + +// Carries out the Voronoi computation and outputs the results to the requested +// files +template<class c_loop,class c_class> +void cmd_line_output(c_loop &vl,c_class &con,const char* format,FILE* outfile,FILE* gnu_file,FILE* povp_file,FILE* povv_file,bool verbose,double &vol,int &vcc,int &tp) { + int pid,ps=con.ps;double x,y,z,r; + if(con.contains_neighbor(format)) { + voronoicell_neighbor c; + if(vl.start()) do if(con.compute_cell(c,vl)) { + vl.pos(pid,x,y,z,r); + if(outfile!=NULL) c.output_custom(format,pid,x,y,z,r,outfile); + if(gnu_file!=NULL) c.draw_gnuplot(x,y,z,gnu_file); + if(povp_file!=NULL) { + fprintf(povp_file,"// id %d\n",pid); + if(ps==4) fprintf(povp_file,"sphere{<%g,%g,%g>,%g}\n",x,y,z,r); + else fprintf(povp_file,"sphere{<%g,%g,%g>,s}\n",x,y,z); + } + if(povv_file!=NULL) { + fprintf(povv_file,"// cell %d\n",pid); + c.draw_pov(x,y,z,povv_file); + } + if(verbose) {vol+=c.volume();vcc++;} + } while(vl.inc()); + } else { + voronoicell c; + if(vl.start()) do if(con.compute_cell(c,vl)) { + vl.pos(pid,x,y,z,r); + if(outfile!=NULL) c.output_custom(format,pid,x,y,z,r,outfile); + if(gnu_file!=NULL) c.draw_gnuplot(x,y,z,gnu_file); + if(povp_file!=NULL) { + fprintf(povp_file,"// id %d\n",pid); + if(ps==4) fprintf(povp_file,"sphere{<%g,%g,%g>,%g}\n",x,y,z,r); + else fprintf(povp_file,"sphere{<%g,%g,%g>,s}\n",x,y,z); + } + if(povv_file!=NULL) { + fprintf(povv_file,"// cell %d\n",pid); + c.draw_pov(x,y,z,povv_file); + } + if(verbose) {vol+=c.volume();vcc++;} + } while(vl.inc()); + } + if(verbose) tp=con.total_particles(); +} + +int main(int argc,char **argv) { + int i=1,j=-7,custom_output=0,nx,ny,nz,init_mem(8); + double ls=0; + blocks_mode bm=none; + bool gnuplot_output=false,povp_output=false,povv_output=false,polydisperse=false; + bool xperiodic=false,yperiodic=false,zperiodic=false,ordered=false,verbose=false; + pre_container *pcon=NULL;pre_container_poly *pconp=NULL; + wall_list wl; + + // If there's one argument, check to see if it's requesting help. + // Otherwise, bail out with an error. + if(argc==2) { + if(strcmp(argv[1],"-h")==0||strcmp(argv[1],"--help")==0) { + help_message();return 0; + } else if(strcmp(argv[1],"-hc")==0) { + custom_output_message();return 0; + } else if(strcmp(argv[1],"--version")==0) { + version_message();return 0; + } else { + error_message(); + return VOROPP_CMD_LINE_ERROR; + } + } + + // If there aren't enough command-line arguments, then bail out + // with an error. + if(argc<7) { + error_message(); + return VOROPP_CMD_LINE_ERROR; + } + + // We have enough arguments. Now start searching for command-line + // options. + while(i<argc-7) { + if(strcmp(argv[i],"-c")==0) { + if(i>=argc-8) {error_message();wl.deallocate();return VOROPP_CMD_LINE_ERROR;} + if(custom_output==0) { + custom_output=++i; + } else { + fputs("voro++: multiple custom output strings detected\n",stderr); + wl.deallocate(); + return VOROPP_CMD_LINE_ERROR; + } + } else if(strcmp(argv[i],"-g")==0) { + gnuplot_output=true; + } else if(strcmp(argv[i],"-h")==0||strcmp(argv[i],"--help")==0) { + help_message();wl.deallocate();return 0; + } else if(strcmp(argv[i],"-hc")==0) { + custom_output_message();wl.deallocate();return 0; + } else if(strcmp(argv[i],"-l")==0) { + if(i>=argc-8) {error_message();wl.deallocate();return VOROPP_CMD_LINE_ERROR;} + if(bm!=none) { + fputs("voro++: Conflicting options about grid setup (-l/-n)\n",stderr); + wl.deallocate(); + return VOROPP_CMD_LINE_ERROR; + } + bm=length_scale; + i++;ls=atof(argv[i]); + } else if(strcmp(argv[i],"-m")==0) { + i++;init_mem=atoi(argv[i]); + } else if(strcmp(argv[i],"-n")==0) { + if(i>=argc-10) {error_message();wl.deallocate();return VOROPP_CMD_LINE_ERROR;} + if(bm!=none) { + fputs("voro++: Conflicting options about grid setup (-l/-n)\n",stderr); + wl.deallocate(); + return VOROPP_CMD_LINE_ERROR; + } + bm=specified; + i++; + nx=atoi(argv[i++]); + ny=atoi(argv[i++]); + nz=atoi(argv[i]); + if(nx<=0||ny<=0||nz<=0) { + fputs("voro++: Computational grid specified with -n must be greater than one\n" + "in each direction\n",stderr); + wl.deallocate(); + return VOROPP_CMD_LINE_ERROR; + } + } else if(strcmp(argv[i],"-o")==0) { + ordered=true; + } else if(strcmp(argv[i],"-p")==0) { + xperiodic=yperiodic=zperiodic=true; + } else if(strcmp(argv[i],"-px")==0) { + xperiodic=true; + } else if(strcmp(argv[i],"-py")==0) { + yperiodic=true; + } else if(strcmp(argv[i],"-pz")==0) { + zperiodic=true; + } else if(strcmp(argv[i],"-r")==0) { + polydisperse=true; + } else if(strcmp(argv[i],"-v")==0) { + verbose=true; + } else if(strcmp(argv[i],"--version")==0) { + version_message(); + wl.deallocate(); + return 0; + } else if(strcmp(argv[i],"-wb")==0) { + if(i>=argc-13) {error_message();wl.deallocate();return VOROPP_CMD_LINE_ERROR;} + i++; + double w0=atof(argv[i++]),w1=atof(argv[i++]); + double w2=atof(argv[i++]),w3=atof(argv[i++]); + double w4=atof(argv[i++]),w5=atof(argv[i]); + wl.add_wall(new wall_plane(-1,0,0,-w0,j));j--; + wl.add_wall(new wall_plane(1,0,0,w1,j));j--; + wl.add_wall(new wall_plane(0,-1,0,-w2,j));j--; + wl.add_wall(new wall_plane(0,1,0,w3,j));j--; + wl.add_wall(new wall_plane(0,0,-1,-w4,j));j--; + wl.add_wall(new wall_plane(0,0,1,w5,j));j--; + } else if(strcmp(argv[i],"-ws")==0) { + if(i>=argc-11) {error_message();wl.deallocate();return VOROPP_CMD_LINE_ERROR;} + i++; + double w0=atof(argv[i++]),w1=atof(argv[i++]); + double w2=atof(argv[i++]),w3=atof(argv[i]); + wl.add_wall(new wall_sphere(w0,w1,w2,w3,j)); + j--; + } else if(strcmp(argv[i],"-wp")==0) { + if(i>=argc-11) {error_message();wl.deallocate();return VOROPP_CMD_LINE_ERROR;} + i++; + double w0=atof(argv[i++]),w1=atof(argv[i++]); + double w2=atof(argv[i++]),w3=atof(argv[i]); + wl.add_wall(new wall_plane(w0,w1,w2,w3,j)); + j--; + } else if(strcmp(argv[i],"-wc")==0) { + if(i>=argc-14) {error_message();wl.deallocate();return VOROPP_CMD_LINE_ERROR;} + i++; + double w0=atof(argv[i++]),w1=atof(argv[i++]); + double w2=atof(argv[i++]),w3=atof(argv[i++]); + double w4=atof(argv[i++]),w5=atof(argv[i++]); + double w6=atof(argv[i]); + wl.add_wall(new wall_cylinder(w0,w1,w2,w3,w4,w5,w6,j)); + j--; + } else if(strcmp(argv[i],"-wo")==0) { + if(i>=argc-14) {error_message();wl.deallocate();return VOROPP_CMD_LINE_ERROR;} + i++; + double w0=atof(argv[i++]),w1=atof(argv[i++]); + double w2=atof(argv[i++]),w3=atof(argv[i++]); + double w4=atof(argv[i++]),w5=atof(argv[i++]); + double w6=atof(argv[i]); + wl.add_wall(new wall_cone(w0,w1,w2,w3,w4,w5,w6,j)); + j--; + } else if(strcmp(argv[i],"-y")==0) { + povp_output=povv_output=true; + } else if(strcmp(argv[i],"-yp")==0) { + povp_output=true; + } else if(strcmp(argv[i],"-yv")==0) { + povv_output=true; + } else { + wl.deallocate(); + error_message(); + return VOROPP_CMD_LINE_ERROR; + } + i++; + } + + // Check the memory guess is positive + if(init_mem<=0) { + fputs("voro++: The memory allocation must be positive\n",stderr); + wl.deallocate(); + return VOROPP_CMD_LINE_ERROR; + } + + // Read in the dimensions of the test box, and estimate the number of + // boxes to divide the region up into + double ax=atof(argv[i]),bx=atof(argv[i+1]); + double ay=atof(argv[i+2]),by=atof(argv[i+3]); + double az=atof(argv[i+4]),bz=atof(argv[i+5]); + + // Check that for each coordinate, the minimum value is smaller + // than the maximum value + if(bx<ax) { + fputs("voro++: Minimum x coordinate exceeds maximum x coordinate\n",stderr); + wl.deallocate(); + return VOROPP_CMD_LINE_ERROR; + } + if(by<ay) { + fputs("voro++: Minimum y coordinate exceeds maximum y coordinate\n",stderr); + wl.deallocate(); + return VOROPP_CMD_LINE_ERROR; + } + if(bz<az) { + fputs("voro++: Minimum z coordinate exceeds maximum z coordinate\n",stderr); + wl.deallocate(); + return VOROPP_CMD_LINE_ERROR; + } + + if(bm==none) { + if(polydisperse) { + pconp=new pre_container_poly(ax,bx,ay,by,az,bz,xperiodic,yperiodic,zperiodic); + pconp->import(argv[i+6]); + pconp->guess_optimal(nx,ny,nz); + } else { + pcon=new pre_container(ax,bx,ay,by,az,bz,xperiodic,yperiodic,zperiodic); + pcon->import(argv[i+6]); + pcon->guess_optimal(nx,ny,nz); + } + } else { + double nxf,nyf,nzf; + if(bm==length_scale) { + + // Check that the length scale is positive and + // reasonably large + if(ls<tolerance) { + fputs("voro++: ",stderr); + if(ls<0) { + fputs("The length scale must be positive\n",stderr); + } else { + fprintf(stderr,"The length scale is smaller than the safe limit of %g. Either\nincrease the particle length scale, or recompile with a different limit.\n",tolerance); + } + wl.deallocate(); + return VOROPP_CMD_LINE_ERROR; + } + ls=0.6/ls; + nxf=(bx-ax)*ls+1; + nyf=(by-ay)*ls+1; + nzf=(bz-az)*ls+1; + + nx=int(nxf);ny=int(nyf);nz=int(nzf); + } else { + nxf=nx;nyf=ny;nzf=nz; + } + + // Compute the number regions based on the length scale + // provided. If the total number exceeds a cutoff then bail + // out, to prevent making a massive memory allocation. Do this + // test using floating point numbers, since huge integers could + // potentially wrap around to negative values. + if(nxf*nyf*nzf>max_regions) { + fprintf(stderr,"voro++: Number of computational blocks exceeds the maximum allowed of %d.\n" + "Either increase the particle length scale, or recompile with an increased\nmaximum.",max_regions); + wl.deallocate(); + return VOROPP_MEMORY_ERROR; + } + } + + // Check that the output filename is a sensible length + int flen=strlen(argv[i+6]); + if(flen>4096) { + fputs("voro++: Filename too long\n",stderr); + wl.deallocate(); + return VOROPP_CMD_LINE_ERROR; + } + + // Open files for output + char *buffer=new char[flen+7]; + sprintf(buffer,"%s.vol",argv[i+6]); + FILE *outfile=safe_fopen(buffer,"w"),*gnu_file,*povp_file,*povv_file; + if(gnuplot_output) { + sprintf(buffer,"%s.gnu",argv[i+6]); + gnu_file=safe_fopen(buffer,"w"); + } else gnu_file=NULL; + if(povp_output) { + sprintf(buffer,"%s_p.pov",argv[i+6]); + povp_file=safe_fopen(buffer,"w"); + } else povp_file=NULL; + if(povv_output) { + sprintf(buffer,"%s_v.pov",argv[i+6]); + povv_file=safe_fopen(buffer,"w"); + } else povv_file=NULL; + delete [] buffer; + + const char *c_str=(custom_output==0?(polydisperse?"%i %q %v %r":"%i %q %v"):argv[custom_output]); + + // Now switch depending on whether polydispersity was enabled, and + // whether output ordering is requested + double vol=0;int tp=0,vcc=0; + if(polydisperse) { + if(ordered) { + particle_order vo; + container_poly con(ax,bx,ay,by,az,bz,nx,ny,nz,xperiodic,yperiodic,zperiodic,init_mem); + con.add_wall(wl); + if(bm==none) { + pconp->setup(vo,con);delete pconp; + } else con.import(vo,argv[i+6]); + + c_loop_order vlo(con,vo); + cmd_line_output(vlo,con,c_str,outfile,gnu_file,povp_file,povv_file,verbose,vol,vcc,tp); + } else { + container_poly con(ax,bx,ay,by,az,bz,nx,ny,nz,xperiodic,yperiodic,zperiodic,init_mem); + con.add_wall(wl); + + if(bm==none) { + pconp->setup(con);delete pconp; + } else con.import(argv[i+6]); + + c_loop_all vla(con); + cmd_line_output(vla,con,c_str,outfile,gnu_file,povp_file,povv_file,verbose,vol,vcc,tp); + } + } else { + if(ordered) { + particle_order vo; + container con(ax,bx,ay,by,az,bz,nx,ny,nz,xperiodic,yperiodic,zperiodic,init_mem); + con.add_wall(wl); + if(bm==none) { + pcon->setup(vo,con);delete pcon; + } else con.import(vo,argv[i+6]); + + c_loop_order vlo(con,vo); + cmd_line_output(vlo,con,c_str,outfile,gnu_file,povp_file,povv_file,verbose,vol,vcc,tp); + } else { + container con(ax,bx,ay,by,az,bz,nx,ny,nz,xperiodic,yperiodic,zperiodic,init_mem); + con.add_wall(wl); + if(bm==none) { + pcon->setup(con);delete pcon; + } else con.import(argv[i+6]); + c_loop_all vla(con); + cmd_line_output(vla,con,c_str,outfile,gnu_file,povp_file,povv_file,verbose,vol,vcc,tp); + } + } + + // Print information if verbose output requested + if(verbose) { + printf("Container geometry : [%g:%g] [%g:%g] [%g:%g]\n" + "Computational grid size : %d by %d by %d (%s)\n" + "Filename : %s\n" + "Output string : %s%s\n",ax,bx,ay,by,az,bz,nx,ny,nz, + bm==none?"estimated from file":(bm==length_scale? + "estimated using length scale":"directly specified"), + argv[i+6],c_str,custom_output==0?" (default)":""); + printf("Total imported particles : %d (%.2g per grid block)\n" + "Total V. cells computed : %d\n" + "Total container volume : %g\n" + "Total V. cell volume : %g\n",tp,((double) tp)/(nx*ny*nz), + vcc,(bx-ax)*(by-ay)*(bz-az),vol); + } + + // Close output files + fclose(outfile); + if(gnu_file!=NULL) fclose(gnu_file); + if(povp_file!=NULL) fclose(povp_file); + if(povv_file!=NULL) fclose(povv_file); + return 0; +} + diff --git a/contrib/voro++/src/common.cc b/contrib/voro++/src/common.cc new file mode 100644 index 0000000000000000000000000000000000000000..457c687426a658451ec7209aa7851a65deaba1ca --- /dev/null +++ b/contrib/voro++/src/common.cc @@ -0,0 +1,90 @@ +// Voro++, a 3D cell-based Voronoi library +// +// Author : Chris H. Rycroft (LBL / UC Berkeley) +// Email : chr@alum.mit.edu +// Date : August 30th 2011 + +/** \file common.cc + * \brief Implementations of the small helper functions. */ + +#include "common.hh" + +namespace voro { + +/** \brief Prints a vector of integers. + * + * Prints a vector of integers. + * \param[in] v the vector to print. + * \param[in] fp the file stream to print to. */ +void voro_print_vector(vector<int> &v,FILE *fp) { + int k=0,s=v.size(); + while(k+4<s) { + fprintf(fp,"%d %d %d %d ",v[k],v[k+1],v[k+2],v[k+3]); + k+=4; + } + if(k+3<=s) { + if(k+4==s) fprintf(fp,"%d %d %d %d",v[k],v[k+1],v[k+2],v[k+3]); + else fprintf(fp,"%d %d %d",v[k],v[k+1],v[k+2]); + } else { + if(k+2==s) fprintf(fp,"%d %d",v[k],v[k+1]); + else fprintf(fp,"%d",v[k]); + } +} + +/** \brief Prints a vector of doubles. + * + * Prints a vector of doubles. + * \param[in] v the vector to print. + * \param[in] fp the file stream to print to. */ +void voro_print_vector(vector<double> &v,FILE *fp) { + int k=0,s=v.size(); + while(k+4<s) { + fprintf(fp,"%g %g %g %g ",v[k],v[k+1],v[k+2],v[k+3]); + k+=4; + } + if(k+3<=s) { + if(k+4==s) fprintf(fp,"%g %g %g %g",v[k],v[k+1],v[k+2],v[k+3]); + else fprintf(fp,"%g %g %g",v[k],v[k+1],v[k+2]); + } else { + if(k+2==s) fprintf(fp,"%g %g",v[k],v[k+1]); + else fprintf(fp,"%g",v[k]); + } +} + +/** \brief Prints a vector a face vertex information. + * + * Prints a vector of face vertex information. A value is read, which + * corresponds to the number of vertices in the next face. The routine reads + * this number of values and prints them as a bracked list. This is repeated + * until the end of the vector is reached. + * \param[in] v the vector to interpret and print. + * \param[in] fp the file stream to print to. */ +void voro_print_face_vertices(vector<int> &v,FILE *fp) { + int j,k=0,l; + if(v.size()>0) { + l=v[k++]; + if(l<=1) { + if(l==1) fprintf(fp,"(%d)",v[k++]); + else fputs("()",fp); + } else { + j=k+l; + fprintf(fp,"(%d",v[k++]); + while(k<j) fprintf(fp,",%d",v[k++]); + fputs(")",fp); + } + while((unsigned int) k<v.size()) { + l=v[k++]; + if(l<=1) { + if(l==1) fprintf(fp," (%d)",v[k++]); + else fputs(" ()",fp); + } else { + j=k+l; + fprintf(fp," (%d",v[k++]); + while(k<j) fprintf(fp,",%d",v[k++]); + fputs(")",fp); + } + } + } +} + +} diff --git a/contrib/voro++/src/common.hh b/contrib/voro++/src/common.hh new file mode 100644 index 0000000000000000000000000000000000000000..4b205379b736560e59702b387778f4fc23a25156 --- /dev/null +++ b/contrib/voro++/src/common.hh @@ -0,0 +1,68 @@ +// Voro++, a 3D cell-based Voronoi library +// +// Author : Chris H. Rycroft (LBL / UC Berkeley) +// Email : chr@alum.mit.edu +// Date : August 30th 2011 + +/** \file common.hh + * \brief Header file for the small helper functions. */ + +#ifndef VOROPP_COMMON_HH +#define VOROPP_COMMON_HH + +#include <cstdio> +#include <cstdlib> +#include <vector> +using namespace std; + +#include "config.hh" + +namespace voro { + +/** \brief Function for printing fatal error messages and exiting. + * + * Function for printing fatal error messages and exiting. + * \param[in] p a pointer to the message to print. + * \param[in] status the status code to return with. */ +inline void voro_fatal_error(const char *p,int status) { + fprintf(stderr,"voro++: %s\n",p); + exit(status); +} + +/** \brief Prints a vector of positions. + * + * Prints a vector of positions as bracketed triplets. + * \param[in] v the vector to print. + * \param[in] fp the file stream to print to. */ +inline void voro_print_positions(vector<double> &v,FILE *fp=stdout) { + if(v.size()>0) { + fprintf(fp,"(%g,%g,%g)",v[0],v[1],v[2]); + for(int k=3;(unsigned int) k<v.size();k+=3) { + fprintf(fp," (%g,%g,%g)",v[k],v[k+1],v[k+2]); + } + } +} + +/** \brief Opens a file and checks the operation was successful. + * + * Opens a file, and checks the return value to ensure that the operation + * was successful. + * \param[in] filename the file to open. + * \param[in] mode the cstdio fopen mode to use. + * \return The file handle. */ +inline FILE* safe_fopen(const char *filename,const char *mode) { + FILE *fp=fopen(filename,mode); + if(fp==NULL) { + fprintf(stderr,"voro++: Unable to open file '%s'\n",filename); + exit(VOROPP_FILE_ERROR); + } + return fp; +} + +void voro_print_vector(vector<int> &v,FILE *fp=stdout); +void voro_print_vector(vector<double> &v,FILE *fp=stdout); +void voro_print_face_vertices(vector<int> &v,FILE *fp=stdout); + +} + +#endif diff --git a/contrib/voro++/src/config.hh b/contrib/voro++/src/config.hh new file mode 100644 index 0000000000000000000000000000000000000000..093cd76cd8c486c08901ad2c93000e186a5740dd --- /dev/null +++ b/contrib/voro++/src/config.hh @@ -0,0 +1,127 @@ +// Voro++, a 3D cell-based Voronoi library +// +// Author : Chris H. Rycroft (LBL / UC Berkeley) +// Email : chr@alum.mit.edu +// Date : August 30th 2011 + +/** \file config.hh + * \brief Master configuration file for setting various compile-time options. */ + +#ifndef VOROPP_CONFIG_HH +#define VOROPP_CONFIG_HH + +namespace voro { + +// These constants set the initial memory allocation for the Voronoi cell +/** The initial memory allocation for the number of vertices. */ +const int init_vertices=256; +/** The initial memory allocation for the maximum vertex order. */ +const int init_vertex_order=64; +/** The initial memory allocation for the number of regular vertices of order + * 3. */ +const int init_3_vertices=256; +/** The initial memory allocation for the number of vertices of higher order. + */ +const int init_n_vertices=8; +/** The initial buffer size for marginal cases used by the suretest class. */ +const int init_marginal=64; +/** The initial size for the delete stack. */ +const int init_delete_size=256; +/** The initial size for the auxiliary delete stack. */ +const int init_delete2_size=256; +/** The initial size for the wall pointer array. */ +const int init_wall_size=32; +/** The default initial size for the ordering class. */ +const int init_ordering_size=4096; +/** The initial size of the pre_container chunk index. */ +const int init_chunk_size=256; + +// If the initial memory is too small, the program dynamically allocates more. +// However, if the limits below are reached, then the program bails out. +/** The maximum memory allocation for the number of vertices. */ +const int max_vertices=16777216; +/** The maximum memory allocation for the maximum vertex order. */ +const int max_vertex_order=2048; +/** The maximum memory allocation for the any particular order of vertex. */ +const int max_n_vertices=16777216; +/** The maximum buffer size for marginal cases used by the suretest class. */ +const int max_marginal=16777216; +/** The maximum size for the delete stack. */ +const int max_delete_size=16777216; +/** The maximum size for the auxiliary delete stack. */ +const int max_delete2_size=16777216; +/** The maximum amount of particle memory allocated for a single region. */ +const int max_particle_memory=16777216; +/** The maximum size for the wall pointer array. */ +const int max_wall_size=2048; +/** The maximum size for the ordering class. */ +const int max_ordering_size=67108864; +/** The maximum size for the pre_container chunk index. */ +const int max_chunk_size=65536; + +/** The chunk size in the pre_container classes. */ +const int pre_container_chunk_size=1024; + +#ifndef VOROPP_VERBOSE +/** Voro++ can print a number of different status and debugging messages to + * notify the user of special behavior, and this macro sets the amount which + * are displayed. At level 0, no messages are printed. At level 1, messages + * about unusual cases during cell construction are printed, such as when the + * plane routine bails out due to floating point problems. At level 2, general + * messages about memory expansion are printed. At level 3, technical details + * about memory management are printed. */ +#define VOROPP_VERBOSE 0 +#endif + +/** If a point is within this distance of a cutting plane, then the code + * assumes that point exactly lies on the plane. */ +const double tolerance=1e-11; + +/** If a point is within this distance of a cutting plane, then the code stores + * whether this point is inside, outside, or exactly on the cutting plane in + * the marginal cases buffer, to prevent the test giving a different result on + * a subsequent evaluation due to floating point rounding errors. */ +const double tolerance2=2e-11; + +/** The square of the tolerance, used when deciding whether some squared + * quantities are large enough to be used. */ +const double tolerance_sq=tolerance*tolerance; + +/** A large number that is used in the computation. */ +const double large_number=1e30; + +/** A radius to use as a placeholder when no other information is available. */ +const double default_radius=0.5; + +/** The maximum number of shells of periodic images to test over. */ +const int max_unit_voro_shells=10; + +/** A guess for the optimal number of particles per block, used to set up the + * container grid. */ +const double optimal_particles=5.6; + +/** If this is set to 1, then the code reports any instances of particles being + * put outside of the container geometry. */ +#define VOROPP_REPORT_OUT_OF_BOUNDS 0 + +/** Voro++ returns this status code if there is a file-related error, such as + * not being able to open file. */ +#define VOROPP_FILE_ERROR 1 + +/** Voro++ returns this status code if there is a memory allocation error, if + * one of the safe memory limits is exceeded. */ +#define VOROPP_MEMORY_ERROR 2 + +/** Voro++ returns this status code if there is any type of internal error, if + * it detects that representation of the Voronoi cell is inconsistent. This + * status code will generally indicate a bug, and the developer should be + * contacted. */ +#define VOROPP_INTERNAL_ERROR 3 + +/** Voro++ returns this status code if it could not interpret the command line + * arguments passed to the command line utility. */ +#define VOROPP_CMD_LINE_ERROR 4 + +} + +#endif diff --git a/contrib/voro++/src/container.cc b/contrib/voro++/src/container.cc new file mode 100644 index 0000000000000000000000000000000000000000..f47495aac6597efc7e7d7111cfc373f9ec519a03 --- /dev/null +++ b/contrib/voro++/src/container.cc @@ -0,0 +1,549 @@ +// Voro++, a 3D cell-based Voronoi library +// +// Author : Chris H. Rycroft (LBL / UC Berkeley) +// Email : chr@alum.mit.edu +// Date : August 30th 2011 + +/** \file container.cc + * \brief Function implementations for the container and related classes. */ + +#include "container.hh" + +namespace voro { + +/** The class constructor sets up the geometry of container, initializing the + * minimum and maximum coordinates in each direction, and setting whether each + * direction is periodic or not. It divides the container into a rectangular + * grid of blocks, and allocates memory for each of these for storing particle + * positions and IDs. + * \param[in] (ax_,bx_) the minimum and maximum x coordinates. + * \param[in] (ay_,by_) the minimum and maximum y coordinates. + * \param[in] (az_,bz_) the minimum and maximum z coordinates. + * \param[in] (nx_,ny_,nz_) the number of grid blocks in each of the three + * coordinate directions. + * \param[in] (xperiodic_,yperiodic_,zperiodic_) flags setting whether the + * container is periodic in each + * coordinate direction. + * \param[in] init_mem the initial memory allocation for each block. + * \param[in] ps_ the number of floating point entries to store for each + * particle. */ +container_base::container_base(double ax_,double bx_,double ay_,double by_,double az_,double bz_, + int nx_,int ny_,int nz_,bool xperiodic_,bool yperiodic_,bool zperiodic_,int init_mem,int ps_) + : voro_base(nx_,ny_,nz_,(bx_-ax_)/nx_,(by_-ay_)/ny_,(bz_-az_)/nz_), + ax(ax_), bx(bx_), ay(ay_), by(by_), az(az_), bz(bz_), + xperiodic(xperiodic_), yperiodic(yperiodic_), zperiodic(zperiodic_), + id(new int*[nxyz]), p(new double*[nxyz]), co(new int[nxyz]), mem(new int[nxyz]), ps(ps_) { + int l; + for(l=0;l<nxyz;l++) co[l]=0; + for(l=0;l<nxyz;l++) mem[l]=init_mem; + for(l=0;l<nxyz;l++) id[l]=new int[init_mem]; + for(l=0;l<nxyz;l++) p[l]=new double[ps*init_mem]; +} + +/** The container destructor frees the dynamically allocated memory. */ +container_base::~container_base() { + int l; + for(l=0;l<nxyz;l++) delete [] p[l]; + for(l=0;l<nxyz;l++) delete [] id[l]; + delete [] id; + delete [] p; + delete [] co; + delete [] mem; +} + +/** The class constructor sets up the geometry of container. + * \param[in] (ax_,bx_) the minimum and maximum x coordinates. + * \param[in] (ay_,by_) the minimum and maximum y coordinates. + * \param[in] (az_,bz_) the minimum and maximum z coordinates. + * \param[in] (nx_,ny_,nz_) the number of grid blocks in each of the three + * coordinate directions. + * \param[in] (xperiodic_,yperiodic_,zperiodic_) flags setting whether the + * container is periodic in each + * coordinate direction. + * \param[in] init_mem the initial memory allocation for each block. */ +container::container(double ax_,double bx_,double ay_,double by_,double az_,double bz_, + int nx_,int ny_,int nz_,bool xperiodic_,bool yperiodic_,bool zperiodic_,int init_mem) + : container_base(ax_,bx_,ay_,by_,az_,bz_,nx_,ny_,nz_,xperiodic_,yperiodic_,zperiodic_,init_mem,3), + vc(*this,xperiodic_?2*nx_+1:nx_,yperiodic_?2*ny_+1:ny_,zperiodic_?2*nz_+1:nz_) {} + +/** The class constructor sets up the geometry of container. + * \param[in] (ax_,bx_) the minimum and maximum x coordinates. + * \param[in] (ay_,by_) the minimum and maximum y coordinates. + * \param[in] (az_,bz_) the minimum and maximum z coordinates. + * \param[in] (nx_,ny_,nz_) the number of grid blocks in each of the three + * coordinate directions. + * \param[in] (xperiodic_,yperiodic_,zperiodic_) flags setting whether the + * container is periodic in each + * coordinate direction. + * \param[in] init_mem the initial memory allocation for each block. */ +container_poly::container_poly(double ax_,double bx_,double ay_,double by_,double az_,double bz_, + int nx_,int ny_,int nz_,bool xperiodic_,bool yperiodic_,bool zperiodic_,int init_mem) + : container_base(ax_,bx_,ay_,by_,az_,bz_,nx_,ny_,nz_,xperiodic_,yperiodic_,zperiodic_,init_mem,4), + vc(*this,xperiodic_?2*nx_+1:nx_,yperiodic_?2*ny_+1:ny_,zperiodic_?2*nz_+1:nz_) {ppr=p;} + +/** Put a particle into the correct region of the container. + * \param[in] n the numerical ID of the inserted particle. + * \param[in] (x,y,z) the position vector of the inserted particle. */ +void container::put(int n,double x,double y,double z) { + int ijk; + if(put_locate_block(ijk,x,y,z)) { + id[ijk][co[ijk]]=n; + double *pp=p[ijk]+3*co[ijk]++; + *(pp++)=x;*(pp++)=y;*pp=z; + } +} + +/** Put a particle into the correct region of the container. + * \param[in] n the numerical ID of the inserted particle. + * \param[in] (x,y,z) the position vector of the inserted particle. + * \param[in] r the radius of the particle. */ +void container_poly::put(int n,double x,double y,double z,double r) { + int ijk; + if(put_locate_block(ijk,x,y,z)) { + id[ijk][co[ijk]]=n; + double *pp=p[ijk]+4*co[ijk]++; + *(pp++)=x;*(pp++)=y;*(pp++)=z;*pp=r; + if(max_radius<r) max_radius=r; + } +} + +/** Put a particle into the correct region of the container, also recording + * into which region it was stored. + * \param[in] vo the ordering class in which to record the region. + * \param[in] n the numerical ID of the inserted particle. + * \param[in] (x,y,z) the position vector of the inserted particle. */ +void container::put(particle_order &vo,int n,double x,double y,double z) { + int ijk; + if(put_locate_block(ijk,x,y,z)) { + id[ijk][co[ijk]]=n; + vo.add(ijk,co[ijk]); + double *pp=p[ijk]+3*co[ijk]++; + *(pp++)=x;*(pp++)=y;*pp=z; + } +} + +/** Put a particle into the correct region of the container, also recording + * into which region it was stored. + * \param[in] vo the ordering class in which to record the region. + * \param[in] n the numerical ID of the inserted particle. + * \param[in] (x,y,z) the position vector of the inserted particle. + * \param[in] r the radius of the particle. */ +void container_poly::put(particle_order &vo,int n,double x,double y,double z,double r) { + int ijk; + if(put_locate_block(ijk,x,y,z)) { + id[ijk][co[ijk]]=n; + vo.add(ijk,co[ijk]); + double *pp=p[ijk]+4*co[ijk]++; + *(pp++)=x;*(pp++)=y;*(pp++)=z;*pp=r; + if(max_radius<r) max_radius=r; + } +} + +/** This routine takes a particle position vector, tries to remap it into the + * primary domain. If successful, it computes the region into which it can be + * stored and checks that there is enough memory within this region to store + * it. + * \param[out] ijk the region index. + * \param[in,out] (x,y,z) the particle position, remapped into the primary + * domain if necessary. + * \return True if the particle can be successfully placed into the container, + * false otherwise. */ +inline bool container_base::put_locate_block(int &ijk,double &x,double &y,double &z) { + if(put_remap(ijk,x,y,z)) { + if(co[ijk]==mem[ijk]) add_particle_memory(ijk); + return true; + } +#if VOROPP_REPORT_OUT_OF_BOUNDS ==1 + fprintf(stderr,"Out of bounds: (x,y,z)=(%g,%g,%g)\n",x,y,z); +#endif + return false; +} + +/** Takes a particle position vector and computes the region index into which + * it should be stored. If the container is periodic, then the routine also + * maps the particle position to ensure it is in the primary domain. If the + * container is not periodic, the routine bails out. + * \param[out] ijk the region index. + * \param[in,out] (x,y,z) the particle position, remapped into the primary + * domain if necessary. + * \return True if the particle can be successfully placed into the container, + * false otherwise. */ +inline bool container_base::put_remap(int &ijk,double &x,double &y,double &z) { + int l; + + ijk=step_int((x-ax)*xsp); + if(xperiodic) {l=step_mod(ijk,nx);x+=boxx*(l-ijk);ijk=l;} + else if(ijk<0||ijk>=nx) return false; + + int j=step_int((y-ay)*ysp); + if(yperiodic) {l=step_mod(j,ny);y+=boxy*(l-j);j=l;} + else if(j<0||j>=ny) return false; + + int k=step_int((z-az)*zsp); + if(zperiodic) {l=step_mod(k,nz);z+=boxz*(l-k);k=l;} + else if(k<0||k>=nz) return false; + + ijk+=nx*j+nxy*k; + return true; +} + +/** Takes a position vector and attempts to remap it into the primary domain. + * \param[out] (ai,aj,ak) the periodic image displacement that the vector is in, + * with (0,0,0) corresponding to the primary domain. + * \param[out] (ci,cj,ck) the index of the block that the position vector is + * within, once it has been remapped. + * \param[in,out] (x,y,z) the position vector to consider, which is remapped + * into the primary domain during the routine. + * \param[out] ijk the block index that the vector is within. + * \return True if the particle is within the container or can be remapped into + * it, false if it lies outside of the container bounds. */ +inline bool container_base::remap(int &ai,int &aj,int &ak,int &ci,int &cj,int &ck,double &x,double &y,double &z,int &ijk) { + ci=step_int((x-ax)*xsp); + if(ci<0||ci>=nx) { + if(xperiodic) {ai=step_div(ci,nx);x-=ai*(bx-ax);ci-=ai*nx;} + else return false; + } else ai=0; + + cj=step_int((y-ay)*ysp); + if(cj<0||cj>=ny) { + if(yperiodic) {aj=step_div(cj,ny);y-=aj*(by-ay);cj-=aj*ny;} + else return false; + } else aj=0; + + ck=step_int((z-az)*zsp); + if(ck<0||ck>=nz) { + if(zperiodic) {ak=step_div(ck,nz);z-=ak*(bz-az);ck-=ak*nz;} + else return false; + } else ak=0; + + ijk=ci+nx*cj+nxy*ck; + return true; +} + +/** Takes a vector and finds the particle whose Voronoi cell contains that + * vector. This is equivalent to finding the particle which is nearest to the + * vector. Additional wall classes are not considered by this routine. + * \param[in] (x,y,z) the vector to test. + * \param[out] (rx,ry,rz) the position of the particle whose Voronoi cell + * contains the vector. If the container is periodic, + * this may point to a particle in a periodic image of + * the primary domain. + * \param[out] pid the ID of the particle. + * \return True if a particle was found. If the container has no particles, + * then the search will not find a Voronoi cell and false is returned. */ +bool container::find_voronoi_cell(double x,double y,double z,double &rx,double &ry,double &rz,int &pid) { + int ai,aj,ak,ci,cj,ck,ijk; + particle_record w; + double mrs; + + // If the given vector lies outside the domain, but the container + // is periodic, then remap it back into the domain + if(!remap(ai,aj,ak,ci,cj,ck,x,y,z,ijk)) return false; + vc.find_voronoi_cell(x,y,z,ci,cj,ck,ijk,w,mrs); + + if(w.ijk!=-1) { + + // Assemble the position vector of the particle to be returned, + // applying a periodic remapping if necessary + if(xperiodic) {ci+=w.di;if(ci<0||ci>=nx) ai+=step_div(ci,nx);} + if(yperiodic) {cj+=w.dj;if(cj<0||cj>=ny) aj+=step_div(cj,ny);} + if(zperiodic) {ck+=w.dk;if(ck<0||ck>=nz) ak+=step_div(ck,nz);} + rx=p[w.ijk][3*w.l]+ai*(bx-ax); + ry=p[w.ijk][3*w.l+1]+aj*(by-ay); + rz=p[w.ijk][3*w.l+2]+ak*(bz-az); + pid=id[w.ijk][w.l]; + return true; + } + + // If no particle if found then just return false + return false; +} + +/** Takes a vector and finds the particle whose Voronoi cell contains that + * vector. Additional wall classes are not considered by this routine. + * \param[in] (x,y,z) the vector to test. + * \param[out] (rx,ry,rz) the position of the particle whose Voronoi cell + * contains the vector. If the container is periodic, + * this may point to a particle in a periodic image of + * the primary domain. + * \param[out] pid the ID of the particle. + * \return True if a particle was found. If the container has no particles, + * then the search will not find a Voronoi cell and false is returned. */ +bool container_poly::find_voronoi_cell(double x,double y,double z,double &rx,double &ry,double &rz,int &pid) { + int ai,aj,ak,ci,cj,ck,ijk; + particle_record w; + double mrs; + + // If the given vector lies outside the domain, but the container + // is periodic, then remap it back into the domain + if(!remap(ai,aj,ak,ci,cj,ck,x,y,z,ijk)) return false; + vc.find_voronoi_cell(x,y,z,ci,cj,ck,ijk,w,mrs); + + if(w.ijk!=-1) { + + // Assemble the position vector of the particle to be returned, + // applying a periodic remapping if necessary + if(xperiodic) {ci+=w.di;if(ci<0||ci>=nx) ai+=step_div(ci,nx);} + if(yperiodic) {cj+=w.dj;if(cj<0||cj>=ny) aj+=step_div(cj,ny);} + if(zperiodic) {ck+=w.dk;if(ck<0||ck>=nz) ak+=step_div(ck,nz);} + rx=p[w.ijk][4*w.l]+ai*(bx-ax); + ry=p[w.ijk][4*w.l+1]+aj*(by-ay); + rz=p[w.ijk][4*w.l+2]+ak*(bz-az); + pid=id[w.ijk][w.l]; + return true; + } + + // If no particle if found then just return false + return false; +} + +/** Increase memory for a particular region. + * \param[in] i the index of the region to reallocate. */ +void container_base::add_particle_memory(int i) { + int l,nmem=mem[i]<<1; + + // Carry out a check on the memory allocation size, and + // print a status message if requested + if(nmem>max_particle_memory) + voro_fatal_error("Absolute maximum memory allocation exceeded",VOROPP_MEMORY_ERROR); +#if VOROPP_VERBOSE >=3 + fprintf(stderr,"Particle memory in region %d scaled up to %d\n",i,nmem); +#endif + + // Allocate new memory and copy in the contents of the old arrays + int *idp=new int[nmem]; + for(l=0;l<co[i];l++) idp[l]=id[i][l]; + double *pp=new double[ps*nmem]; + for(l=0;l<ps*co[i];l++) pp[l]=p[i][l]; + + // Update pointers and delete old arrays + mem[i]=nmem; + delete [] id[i];id[i]=idp; + delete [] p[i];p[i]=pp; +} + +/** Import a list of particles from an open file stream into the container. + * Entries of four numbers (Particle ID, x position, y position, z position) + * are searched for. If the file cannot be successfully read, then the routine + * causes a fatal error. + * \param[in] fp the file handle to read from. */ +void container::import(FILE *fp) { + int i,j; + double x,y,z; + while((j=fscanf(fp,"%d %lg %lg %lg",&i,&x,&y,&z))==4) put(i,x,y,z); + if(j!=EOF) voro_fatal_error("File import error",VOROPP_FILE_ERROR); +} + +/** Import a list of particles from an open file stream, also storing the order + * of that the particles are read. Entries of four numbers (Particle ID, x + * position, y position, z position) are searched for. If the file cannot be + * successfully read, then the routine causes a fatal error. + * \param[in,out] vo a reference to an ordering class to use. + * \param[in] fp the file handle to read from. */ +void container::import(particle_order &vo,FILE *fp) { + int i,j; + double x,y,z; + while((j=fscanf(fp,"%d %lg %lg %lg",&i,&x,&y,&z))==4) put(vo,i,x,y,z); + if(j!=EOF) voro_fatal_error("File import error",VOROPP_FILE_ERROR); +} + +/** Import a list of particles from an open file stream into the container. + * Entries of five numbers (Particle ID, x position, y position, z position, + * radius) are searched for. If the file cannot be successfully read, then the + * routine causes a fatal error. + * \param[in] fp the file handle to read from. */ +void container_poly::import(FILE *fp) { + int i,j; + double x,y,z,r; + while((j=fscanf(fp,"%d %lg %lg %lg %lg",&i,&x,&y,&z,&r))==5) put(i,x,y,z,r); + if(j!=EOF) voro_fatal_error("File import error",VOROPP_FILE_ERROR); +} + +/** Import a list of particles from an open file stream, also storing the order + * of that the particles are read. Entries of four numbers (Particle ID, x + * position, y position, z position, radius) are searched for. If the file + * cannot be successfully read, then the routine causes a fatal error. + * \param[in,out] vo a reference to an ordering class to use. + * \param[in] fp the file handle to read from. */ +void container_poly::import(particle_order &vo,FILE *fp) { + int i,j; + double x,y,z,r; + while((j=fscanf(fp,"%d %lg %lg %lg %lg",&i,&x,&y,&z,&r))==5) put(vo,i,x,y,z,r); + if(j!=EOF) voro_fatal_error("File import error",VOROPP_FILE_ERROR); +} + +/** Outputs the a list of all the container regions along with the number of + * particles stored within each. */ +void container_base::region_count() { + int i,j,k,*cop=co; + for(k=0;k<nz;k++) for(j=0;j<ny;j++) for(i=0;i<nx;i++) + printf("Region (%d,%d,%d): %d particles\n",i,j,k,*(cop++)); +} + +/** Clears a container of particles. */ +void container::clear() { + for(int *cop=co;cop<co+nxyz;cop++) *cop=0; +} + +/** Clears a container of particles, also clearing resetting the maximum radius + * to zero. */ +void container_poly::clear() { + for(int *cop=co;cop<co+nxyz;cop++) *cop=0; + max_radius=0; +} + +/** Computes all the Voronoi cells and saves customized information about them. + * \param[in] format the custom output string to use. + * \param[in] fp a file handle to write to. */ +void container::print_custom(const char *format,FILE *fp) { + c_loop_all vl(*this); + print_custom(vl,format,fp); +} + +/** Computes all the Voronoi cells and saves customized + * information about them. + * \param[in] format the custom output string to use. + * \param[in] fp a file handle to write to. */ +void container_poly::print_custom(const char *format,FILE *fp) { + c_loop_all vl(*this); + print_custom(vl,format,fp); +} + +/** Computes all the Voronoi cells and saves customized information about them. + * \param[in] format the custom output string to use. + * \param[in] filename the name of the file to write to. */ +void container::print_custom(const char *format,const char *filename) { + FILE *fp=safe_fopen(filename,"w"); + print_custom(format,fp); + fclose(fp); +} + +/** Computes all the Voronoi cells and saves customized + * information about them + * \param[in] format the custom output string to use. + * \param[in] filename the name of the file to write to. */ +void container_poly::print_custom(const char *format,const char *filename) { + FILE *fp=safe_fopen(filename,"w"); + print_custom(format,fp); + fclose(fp); +} + +/** Computes all of the Voronoi cells in the container, but does nothing + * with the output. It is useful for measuring the pure computation time + * of the Voronoi algorithm, without any additional calculations such as + * volume evaluation or cell output. */ +void container::compute_all_cells() { + voronoicell c; + c_loop_all vl(*this); + if(vl.start()) do compute_cell(c,vl); + while(vl.inc()); +} + +/** Computes all of the Voronoi cells in the container, but does nothing + * with the output. It is useful for measuring the pure computation time + * of the Voronoi algorithm, without any additional calculations such as + * volume evaluation or cell output. */ +void container_poly::compute_all_cells() { + voronoicell c; + c_loop_all vl(*this); + if(vl.start()) do compute_cell(c,vl);while(vl.inc()); +} + +/** Calculates all of the Voronoi cells and sums their volumes. In most cases + * without walls, the sum of the Voronoi cell volumes should equal the volume + * of the container to numerical precision. + * \return The sum of all of the computed Voronoi volumes. */ +double container::sum_cell_volumes() { + voronoicell c; + double vol=0; + c_loop_all vl(*this); + if(vl.start()) do if(compute_cell(c,vl)) vol+=c.volume();while(vl.inc()); + return vol; +} + +/** Calculates all of the Voronoi cells and sums their volumes. In most cases + * without walls, the sum of the Voronoi cell volumes should equal the volume + * of the container to numerical precision. + * \return The sum of all of the computed Voronoi volumes. */ +double container_poly::sum_cell_volumes() { + voronoicell c; + double vol=0; + c_loop_all vl(*this); + if(vl.start()) do if(compute_cell(c,vl)) vol+=c.volume();while(vl.inc()); + return vol; +} + +/** This function tests to see if a given vector lies within the container + * bounds and any walls. + * \param[in] (x,y,z) the position vector to be tested. + * \return True if the point is inside the container, false if the point is + * outside. */ +bool container_base::point_inside(double x,double y,double z) { + if(x<ax||x>bx||y<ay||y>by||z<az||z>bz) return false; + return point_inside_walls(x,y,z); +} + +/** Draws an outline of the domain in gnuplot format. + * \param[in] fp the file handle to write to. */ +void container_base::draw_domain_gnuplot(FILE *fp) { + fprintf(fp,"%g %g %g\n%g %g %g\n%g %g %g\n%g %g %g\n",ax,ay,az,bx,ay,az,bx,by,az,ax,by,az); + fprintf(fp,"%g %g %g\n%g %g %g\n%g %g %g\n%g %g %g\n",ax,by,bz,bx,by,bz,bx,ay,bz,ax,ay,bz); + fprintf(fp,"%g %g %g\n\n%g %g %g\n%g %g %g\n\n",ax,by,bz,ax,ay,az,ax,ay,bz); + fprintf(fp,"%g %g %g\n%g %g %g\n\n%g %g %g\n%g %g %g\n\n",bx,ay,az,bx,ay,bz,bx,by,az,bx,by,bz); +} + +/** Draws an outline of the domain in POV-Ray format. + * \param[in] fp the file handle to write to. */ +void container_base::draw_domain_pov(FILE *fp) { + fprintf(fp,"cylinder{<%g,%g,%g>,<%g,%g,%g>,rr}\n" + "cylinder{<%g,%g,%g>,<%g,%g,%g>,rr}\n",ax,ay,az,bx,ay,az,ax,by,az,bx,by,az); + fprintf(fp,"cylinder{<%g,%g,%g>,<%g,%g,%g>,rr}\n" + "cylinder{<%g,%g,%g>,<%g,%g,%g>,rr}\n",ax,by,bz,bx,by,bz,ax,ay,bz,bx,ay,bz); + fprintf(fp,"cylinder{<%g,%g,%g>,<%g,%g,%g>,rr}\n" + "cylinder{<%g,%g,%g>,<%g,%g,%g>,rr}\n",ax,ay,az,ax,by,az,bx,ay,az,bx,by,az); + fprintf(fp,"cylinder{<%g,%g,%g>,<%g,%g,%g>,rr}\n" + "cylinder{<%g,%g,%g>,<%g,%g,%g>,rr}\n",bx,ay,bz,bx,by,bz,ax,ay,bz,ax,by,bz); + fprintf(fp,"cylinder{<%g,%g,%g>,<%g,%g,%g>,rr}\n" + "cylinder{<%g,%g,%g>,<%g,%g,%g>,rr}\n",ax,ay,az,ax,ay,bz,bx,ay,az,bx,ay,bz); + fprintf(fp,"cylinder{<%g,%g,%g>,<%g,%g,%g>,rr}\n" + "cylinder{<%g,%g,%g>,<%g,%g,%g>,rr}\n",bx,by,az,bx,by,bz,ax,by,az,ax,by,bz); + fprintf(fp,"sphere{<%g,%g,%g>,rr}\nsphere{<%g,%g,%g>,rr}\n" + "sphere{<%g,%g,%g>,rr}\nsphere{<%g,%g,%g>,rr}\n",ax,ay,az,bx,ay,az,ax,by,az,bx,by,az); + fprintf(fp,"sphere{<%g,%g,%g>,rr}\nsphere{<%g,%g,%g>,rr}\n" + "sphere{<%g,%g,%g>,rr}\nsphere{<%g,%g,%g>,rr}\n",ax,ay,bz,bx,ay,bz,ax,by,bz,bx,by,bz); +} + + +/** The wall_list constructor sets up an array of pointers to wall classes. */ +wall_list::wall_list() : walls(new wall*[init_wall_size]), wep(walls), wel(walls+init_wall_size), + current_wall_size(init_wall_size) {} + +/** The wall_list destructor frees the array of pointers to the wall classes. + */ +wall_list::~wall_list() { + delete [] walls; +} + +/** Adds all of the walls on another wall_list to this class. + * \param[in] wl a reference to the wall class. */ +void wall_list::add_wall(wall_list &wl) { + for(wall **wp=wl.walls;wp<wl.wep;wp++) add_wall(*wp); +} + +/** Deallocates all of the wall classes pointed to by the wall_list. */ +void wall_list::deallocate() { + for(wall **wp=walls;wp<wep;wp++) delete *wp; +} + +/** Increases the memory allocation for the walls array. */ +void wall_list::increase_wall_memory() { + current_wall_size<<=1; + if(current_wall_size>max_wall_size) + voro_fatal_error("Wall memory allocation exceeded absolute maximum",VOROPP_MEMORY_ERROR); + wall **nwalls=new wall*[current_wall_size],**nwp=nwalls,**wp=walls; + while(wp<wep) *(nwp++)=*(wp++); + delete [] walls; + walls=nwalls;wel=walls+current_wall_size;wep=nwp; +} + +} diff --git a/contrib/voro++/src/container.hh b/contrib/voro++/src/container.hh new file mode 100644 index 0000000000000000000000000000000000000000..c494f152487807d95b645c160101153bd06502b0 --- /dev/null +++ b/contrib/voro++/src/container.hh @@ -0,0 +1,690 @@ +// Voro++, a 3D cell-based Voronoi library +// +// Author : Chris H. Rycroft (LBL / UC Berkeley) +// Email : chr@alum.mit.edu +// Date : August 30th 2011 + +/** \file container.hh + * \brief Header file for the container_base and related classes. */ + +#ifndef VOROPP_CONTAINER_HH +#define VOROPP_CONTAINER_HH + +#include <cstdio> +#include <cstdlib> +#include <cmath> +#include <vector> +using namespace std; + +#include "config.hh" +#include "common.hh" +#include "v_base.hh" +#include "cell.hh" +#include "c_loops.hh" +#include "v_compute.hh" +#include "rad_option.hh" + +namespace voro { + +/** \brief Pure virtual class from which wall objects are derived. + * + * This is a pure virtual class for a generic wall object. A wall object + * can be specified by deriving a new class from this and specifying the + * functions.*/ +class wall { + public: + virtual ~wall() {} + /** A pure virtual function for testing whether a point is + * inside the wall object. */ + virtual bool point_inside(double x,double y,double z) = 0; + /** A pure virtual function for cutting a cell without + * neighbor-tracking with a wall. */ + virtual bool cut_cell(voronoicell &c,double x,double y,double z) = 0; + /** A pure virtual function for cutting a cell with + * neighbor-tracking enabled with a wall. */ + virtual bool cut_cell(voronoicell_neighbor &c,double x,double y,double z) = 0; +}; + +/** \brief A class for storing a list of pointers to walls. + * + * This class stores a list of pointers to wall classes. It contains several + * simple routines that make use of the wall classes (such as telling whether a + * given position is inside all of the walls or not). It can be used by itself, + * but also forms part of container_base, for associating walls with this + * class. */ +class wall_list { + public: + /** An array holding pointers to wall objects. */ + wall **walls; + /** A pointer to the next free position to add a wall pointer. + */ + wall **wep; + wall_list(); + ~wall_list(); + /** Adds a wall to the list. + * \param[in] w the wall to add. */ + inline void add_wall(wall *w) { + if(wep==wel) increase_wall_memory(); + *(wep++)=w; + } + /** Adds a wall to the list. + * \param[in] w a reference to the wall to add. */ + inline void add_wall(wall &w) {add_wall(&w);} + void add_wall(wall_list &wl); + /** Determines whether a given position is inside all of the + * walls on the list. + * \param[in] (x,y,z) the position to test. + * \return True if it is inside, false if it is outside. */ + inline bool point_inside_walls(double x,double y,double z) { + for(wall **wp=walls;wp<wep;wp++) if(!((*wp)->point_inside(x,y,z))) return false; + return true; + } + /** Cuts a Voronoi cell by all of the walls currently on + * the list. + * \param[in] c a reference to the Voronoi cell class. + * \param[in] (x,y,z) the position of the cell. + * \return True if the cell still exists, false if the cell is + * deleted. */ + template<class c_class> + bool apply_walls(c_class &c,double x,double y,double z) { + for(wall **wp=walls;wp<wep;wp++) if(!((*wp)->cut_cell(c,x,y,z))) return false; + return true; + } + void deallocate(); + protected: + void increase_wall_memory(); + /** A pointer to the limit of the walls array, used to + * determine when array is full. */ + wall **wel; + /** The current amount of memory allocated for walls. */ + int current_wall_size; +}; + +/** \brief Class for representing a particle system in a three-dimensional + * rectangular box. + * + * This class represents a system of particles in a three-dimensional + * rectangular box. Any combination of non-periodic and periodic coordinates + * can be used in the three coordinate directions. The class is not intended + * for direct use, but instead forms the base of the container and + * container_poly classes that add specialized routines for computing the + * regular and radical Voronoi tessellations respectively. It contains routines + * that are commonly between these two classes, such as those for drawing the + * domain, and placing particles within the internal data structure. + * + * The class is derived from the wall_list class, which encapsulates routines + * for associating walls with the container, and the voro_base class, which + * encapsulates routines about the underlying computational grid. */ +class container_base : public voro_base, public wall_list { + public: + /** The minimum x coordinate of the container. */ + const double ax; + /** The maximum x coordinate of the container. */ + const double bx; + /** The minimum y coordinate of the container. */ + const double ay; + /** The maximum y coordinate of the container. */ + const double by; + /** The minimum z coordinate of the container. */ + const double az; + /** The maximum z coordinate of the container. */ + const double bz; + /** A boolean value that determines if the x coordinate in + * periodic or not. */ + const bool xperiodic; + /** A boolean value that determines if the y coordinate in + * periodic or not. */ + const bool yperiodic; + /** A boolean value that determines if the z coordinate in + * periodic or not. */ + const bool zperiodic; + /** This array holds the numerical IDs of each particle in each + * computational box. */ + int **id; + /** A two dimensional array holding particle positions. For the + * derived container_poly class, this also holds particle + * radii. */ + double **p; + /** This array holds the number of particles within each + * computational box of the container. */ + int *co; + /** This array holds the maximum amount of particle memory for + * each computational box of the container. If the number of + * particles in a particular box ever approaches this limit, + * more is allocated using the add_particle_memory() function. + */ + int *mem; + /** The amount of memory in the array structure for each + * particle. This is set to 3 when the basic class is + * initialized, so that the array holds (x,y,z) positions. If + * the container class is initialized as part of the derived + * class container_poly, then this is set to 4, to also hold + * the particle radii. */ + const int ps; + container_base(double ax_,double bx_,double ay_,double by_,double az_,double bz_, + int nx_,int ny_,int nz_,bool xperiodic_,bool yperiodic_,bool zperiodic_, + int init_mem,int ps_); + ~container_base(); + bool point_inside(double x,double y,double z); + void region_count(); + /** Initializes the Voronoi cell prior to a compute_cell + * operation for a specific particle being carried out by a + * voro_compute class. The cell is initialized to fill the + * entire container. For non-periodic coordinates, this is set + * by the position of the walls. For periodic coordinates, the + * space is equally divided in either direction from the + * particle's initial position. Plane cuts made by any walls + * that have been added are then applied to the cell. + * \param[in,out] c a reference to a voronoicell object. + * \param[in] ijk the block that the particle is within. + * \param[in] q the index of the particle within its block. + * \param[in] (ci,cj,ck) the coordinates of the block in the + * container coordinate system. + * \param[out] (i,j,k) the coordinates of the test block + * relative to the voro_compute + * coordinate system. + * \param[out] (x,y,z) the position of the particle. + * \param[out] disp a block displacement used internally by the + * compute_cell routine. + * \return False if the plane cuts applied by walls completely + * removed the cell, true otherwise. */ + template<class v_cell> + inline bool initialize_voronoicell(v_cell &c,int ijk,int q,int ci,int cj,int ck, + int &i,int &j,int &k,double &x,double &y,double &z,int &disp) { + double x1,x2,y1,y2,z1,z2,*pp=p[ijk]+ps*q; + x=*(pp++);y=*(pp++);z=*pp; + if(xperiodic) {x1=-(x2=0.5*(bx-ax));i=nx;} else {x1=ax-x;x2=bx-x;i=ci;} + if(yperiodic) {y1=-(y2=0.5*(by-ay));j=ny;} else {y1=ay-y;y2=by-y;j=cj;} + if(zperiodic) {z1=-(z2=0.5*(bz-az));k=nz;} else {z1=az-z;z2=bz-z;k=ck;} + c.init(x1,x2,y1,y2,z1,z2); + if(!apply_walls(c,x,y,z)) return false; + disp=ijk-i-nx*(j+ny*k); + return true; + } + /** Initializes parameters for a find_voronoi_cell call within + * the voro_compute template. + * \param[in] (ci,cj,ck) the coordinates of the test block in + * the container coordinate system. + * \param[in] ijk the index of the test block + * \param[out] (i,j,k) the coordinates of the test block + * relative to the voro_compute + * coordinate system. + * \param[out] disp a block displacement used internally by the + * find_voronoi_cell routine. */ + inline void initialize_search(int ci,int cj,int ck,int ijk,int &i,int &j,int &k,int &disp) { + i=xperiodic?nx:ci; + j=yperiodic?ny:cj; + k=zperiodic?nz:ck; + disp=ijk-i-nx*(j+ny*k); + } + /** Returns the position of a particle currently being computed + * relative to the computational block that it is within. It is + * used to select the optimal worklist entry to use. + * \param[in] (x,y,z) the position of the particle. + * \param[in] (ci,cj,ck) the block that the particle is within. + * \param[out] (fx,fy,fz) the position relative to the block. + */ + inline void frac_pos(double x,double y,double z,double ci,double cj,double ck, + double &fx,double &fy,double &fz) { + fx=x-ax-boxx*ci; + fy=y-ay-boxy*cj; + fz=z-az-boxz*ck; + } + /** Calculates the index of block in the container structure + * corresponding to given coordinates. + * \param[in] (ci,cj,ck) the coordinates of the original block + * in the current computation, relative + * to the container coordinate system. + * \param[in] (ei,ej,ek) the displacement of the current block + * from the original block. + * \param[in,out] (qx,qy,qz) the periodic displacement that + * must be added to the particles + * within the computed block. + * \param[in] disp a block displacement used internally by the + * find_voronoi_cell and compute_cell routines. + * \return The block index. */ + inline int region_index(int ci,int cj,int ck,int ei,int ej,int ek,double &qx,double &qy,double &qz,int &disp) { + if(xperiodic) {if(ci+ei<nx) {ei+=nx;qx=-(bx-ax);} else if(ci+ei>=(nx<<1)) {ei-=nx;qx=bx-ax;} else qx=0;} + if(yperiodic) {if(cj+ej<ny) {ej+=ny;qy=-(by-ay);} else if(cj+ej>=(ny<<1)) {ej-=ny;qy=by-ay;} else qy=0;} + if(zperiodic) {if(ck+ek<nz) {ek+=nz;qz=-(bz-az);} else if(ck+ek>=(nz<<1)) {ek-=nz;qz=bz-az;} else qz=0;} + return disp+ei+nx*(ej+ny*ek); + } + void draw_domain_gnuplot(FILE *fp=stdout); + /** Draws an outline of the domain in Gnuplot format. + * \param[in] filename the filename to write to. */ + inline void draw_domain_gnuplot(const char* filename) { + FILE *fp=safe_fopen(filename,"w"); + draw_domain_gnuplot(fp); + fclose(fp); + } + void draw_domain_pov(FILE *fp=stdout); + /** Draws an outline of the domain in Gnuplot format. + * \param[in] filename the filename to write to. */ + inline void draw_domain_pov(const char* filename) { + FILE *fp=safe_fopen(filename,"w"); + draw_domain_pov(fp); + fclose(fp); + } + /** Sums up the total number of stored particles. + * \return The number of particles. */ + inline int total_particles() { + int tp=*co; + for(int *cop=co+1;cop<co+nxyz;cop++) tp+=*cop; + return tp; + } + protected: + void add_particle_memory(int i); + inline bool put_locate_block(int &ijk,double &x,double &y,double &z); + inline bool put_remap(int &ijk,double &x,double &y,double &z); + inline bool remap(int &ai,int &aj,int &ak,int &ci,int &cj,int &ck,double &x,double &y,double &z,int &ijk); +}; + +/** \brief Extension of the container_base class for computing regular Voronoi + * tessellations. + * + * This class is an extension of the container_base class that has routines + * specifically for computing the regular Voronoi tessellation with no + * dependence on particle radii. */ +class container : public container_base, public radius_mono { + public: + container(double ax_,double bx_,double ay_,double by_,double az_,double bz_, + int nx_,int ny_,int nz_,bool xperiodic_,bool yperiodic_,bool zperiodic_,int init_mem); + void clear(); + void put(int n,double x,double y,double z); + void put(particle_order &vo,int n,double x,double y,double z); + void import(FILE *fp=stdin); + void import(particle_order &vo,FILE *fp=stdin); + /** Imports a list of particles from an open file stream into + * the container. Entries of four numbers (Particle ID, x + * position, y position, z position) are searched for. If the + * file cannot be successfully read, then the routine causes a + * fatal error. + * \param[in] filename the name of the file to open and read + * from. */ + inline void import(const char* filename) { + FILE *fp=safe_fopen(filename,"r"); + import(fp); + fclose(fp); + } + /** Imports a list of particles from an open file stream into + * the container. Entries of four numbers (Particle ID, x + * position, y position, z position) are searched for. In + * addition, the order in which particles are read is saved + * into an ordering class. If the file cannot be successfully + * read, then the routine causes a fatal error. + * \param[in,out] vo the ordering class to use. + * \param[in] filename the name of the file to open and read + * from. */ + inline void import(particle_order &vo,const char* filename) { + FILE *fp=safe_fopen(filename,"r"); + import(vo,fp); + fclose(fp); + } + void compute_all_cells(); + double sum_cell_volumes(); + /** Dumps particle IDs and positions to a file. + * \param[in] vl the loop class to use. + * \param[in] fp a file handle to write to. */ + template<class c_loop> + void draw_particles(c_loop &vl,FILE *fp) { + double *pp; + if(vl.start()) do { + pp=p[vl.ijk]+3*vl.q; + fprintf(fp,"%d %g %g %g\n",id[vl.ijk][vl.q],*pp,pp[1],pp[2]); + } while(vl.inc()); + } + /** Dumps all of the particle IDs and positions to a file. + * \param[in] fp a file handle to write to. */ + inline void draw_particles(FILE *fp=stdout) { + c_loop_all vl(*this); + draw_particles(vl,fp); + } + /** Dumps all of the particle IDs and positions to a file. + * \param[in] filename the name of the file to write to. */ + inline void draw_particles(const char *filename) { + FILE *fp=safe_fopen(filename,"w"); + draw_particles(fp); + fclose(fp); + } + /** Dumps particle positions in POV-Ray format. + * \param[in] vl the loop class to use. + * \param[in] fp a file handle to write to. */ + template<class c_loop> + void draw_particles_pov(c_loop &vl,FILE *fp) { + double *pp; + if(vl.start()) do { + pp=p[vl.ijk]+3*vl.q; + fprintf(fp,"// id %d\nsphere{<%g,%g,%g>,s}\n", + id[vl.ijk][vl.q],*pp,pp[1],pp[2]); + } while(vl.inc()); + } + /** Dumps all particle positions in POV-Ray format. + * \param[in] fp a file handle to write to. */ + inline void draw_particles_pov(FILE *fp=stdout) { + c_loop_all vl(*this); + draw_particles_pov(vl,fp); + } + /** Dumps all particle positions in POV-Ray format. + * \param[in] filename the name of the file to write to. */ + inline void draw_particles_pov(const char *filename) { + FILE *fp=safe_fopen(filename,"w"); + draw_particles_pov(fp); + fclose(fp); + } + /** Computes Voronoi cells and saves the output in gnuplot + * format. + * \param[in] vl the loop class to use. + * \param[in] fp a file handle to write to. */ + template<class c_loop> + void draw_cells_gnuplot(c_loop &vl,FILE *fp) { + voronoicell c;double *pp; + if(vl.start()) do if(compute_cell(c,vl)) { + pp=p[vl.ijk]+ps*vl.q; + c.draw_gnuplot(*pp,pp[1],pp[2],fp); + } while(vl.inc()); + } + /** Computes all Voronoi cells and saves the output in gnuplot + * format. + * \param[in] fp a file handle to write to. */ + inline void draw_cells_gnuplot(FILE *fp=stdout) { + c_loop_all vl(*this); + draw_cells_gnuplot(vl,fp); + } + /** Computes all Voronoi cells and saves the output in gnuplot + * format. + * \param[in] filename the name of the file to write to. */ + inline void draw_cells_gnuplot(const char *filename) { + FILE *fp=safe_fopen(filename,"w"); + draw_cells_gnuplot(fp); + fclose(fp); + } + /** Computes Voronoi cells and saves the output in POV-Ray + * format. + * \param[in] vl the loop class to use. + * \param[in] fp a file handle to write to. */ + template<class c_loop> + void draw_cells_pov(c_loop &vl,FILE *fp) { + voronoicell c;double *pp; + if(vl.start()) do if(compute_cell(c,vl)) { + fprintf(fp,"// cell %d\n",id[vl.ijk][vl.q]); + pp=p[vl.ijk]+ps*vl.q; + c.draw_pov(*pp,pp[1],pp[2],fp); + } while(vl.inc()); + } + /** Computes all Voronoi cells and saves the output in POV-Ray + * format. + * \param[in] fp a file handle to write to. */ + inline void draw_cells_pov(FILE *fp=stdout) { + c_loop_all vl(*this); + draw_cells_pov(vl,fp); + } + /** Computes all Voronoi cells and saves the output in POV-Ray + * format. + * \param[in] filename the name of the file to write to. */ + inline void draw_cells_pov(const char *filename) { + FILE *fp=safe_fopen(filename,"w"); + draw_cells_pov(fp); + fclose(fp); + } + /** Computes the Voronoi cells and saves customized information + * about them. + * \param[in] vl the loop class to use. + * \param[in] format the custom output string to use. + * \param[in] fp a file handle to write to. */ + template<class c_loop> + void print_custom(c_loop &vl,const char *format,FILE *fp) { + int ijk,q;double *pp; + if(contains_neighbor(format)) { + voronoicell_neighbor c; + if(vl.start()) do if(compute_cell(c,vl)) { + ijk=vl.ijk;q=vl.q;pp=p[ijk]+ps*q; + c.output_custom(format,id[ijk][q],*pp,pp[1],pp[2],default_radius,fp); + } while(vl.inc()); + } else { + voronoicell c; + if(vl.start()) do if(compute_cell(c,vl)) { + ijk=vl.ijk;q=vl.q;pp=p[ijk]+ps*q; + c.output_custom(format,id[ijk][q],*pp,pp[1],pp[2],default_radius,fp); + } while(vl.inc()); + } + } + void print_custom(const char *format,FILE *fp=stdout); + void print_custom(const char *format,const char *filename); + bool find_voronoi_cell(double x,double y,double z,double &rx,double &ry,double &rz,int &pid); + /** Computes the Voronoi cell for a particle currently being + * referenced by a loop class. + * \param[out] c a Voronoi cell class in which to store the + * computed cell. + * \param[in] vl the loop class to use. + * \return True if the cell was computed. If the cell cannot be + * computed, if it is removed entirely by a wall or boundary + * condition, then the routine returns false. */ + template<class v_cell,class c_loop> + inline bool compute_cell(v_cell &c,c_loop &vl) { + return vc.compute_cell(c,vl.ijk,vl.q,vl.i,vl.j,vl.k); + } + /** Computes the Voronoi cell for given particle. + * \param[out] c a Voronoi cell class in which to store the + * computed cell. + * \param[in] ijk the block that the particle is within. + * \param[in] q the index of the particle within the block. + * \return True if the cell was computed. If the cell cannot be + * computed, if it is removed entirely by a wall or boundary + * condition, then the routine returns false. */ + template<class v_cell> + inline bool compute_cell(v_cell &c,int ijk,int q) { + int k=ijk/nxy,ijkt=ijk-nxy*k,j=ijkt/nx,i=ijkt-j*nx; + return vc.compute_cell(c,ijk,q,i,j,k); + } + private: + voro_compute<container> vc; + friend class voro_compute<container>; +}; + +/** \brief Extension of the container_base class for computing radical Voronoi + * tessellations. + * + * This class is an extension of container_base class that has routines + * specifically for computing the radical Voronoi tessellation that depends on + * the particle radii. */ +class container_poly : public container_base, public radius_poly { + public: + container_poly(double ax_,double bx_,double ay_,double by_,double az_,double bz_, + int nx_,int ny_,int nz_,bool xperiodic_,bool yperiodic_,bool zperiodic_,int init_mem); + void clear(); + void put(int n,double x,double y,double z,double r); + void put(particle_order &vo,int n,double x,double y,double z,double r); + void import(FILE *fp=stdin); + void import(particle_order &vo,FILE *fp=stdin); + /** Imports a list of particles from an open file stream into + * the container_poly class. Entries of five numbers (Particle + * ID, x position, y position, z position, radius) are searched + * for. If the file cannot be successfully read, then the + * routine causes a fatal error. + * \param[in] filename the name of the file to open and read + * from. */ + inline void import(const char* filename) { + FILE *fp=safe_fopen(filename,"r"); + import(fp); + fclose(fp); + } + /** Imports a list of particles from an open file stream into + * the container_poly class. Entries of five numbers (Particle + * ID, x position, y position, z position, radius) are searched + * for. In addition, the order in which particles are read is + * saved into an ordering class. If the file cannot be + * successfully read, then the routine causes a fatal error. + * \param[in,out] vo the ordering class to use. + * \param[in] filename the name of the file to open and read + * from. */ + inline void import(particle_order &vo,const char* filename) { + FILE *fp=safe_fopen(filename,"r"); + import(vo,fp); + fclose(fp); + } + void compute_all_cells(); + double sum_cell_volumes(); + /** Dumps particle IDs, positions and radii to a file. + * \param[in] vl the loop class to use. + * \param[in] fp a file handle to write to. */ + template<class c_loop> + void draw_particles(c_loop &vl,FILE *fp) { + double *pp; + if(vl.start()) do { + pp=p[vl.ijk]+4*vl.q; + fprintf(fp,"%d %g %g %g %g\n",id[vl.ijk][vl.q],*pp,pp[1],pp[2],pp[3]); + } while(vl.inc()); + } + /** Dumps all of the particle IDs, positions and radii to a + * file. + * \param[in] fp a file handle to write to. */ + inline void draw_particles(FILE *fp=stdout) { + c_loop_all vl(*this); + draw_particles(vl,fp); + } + /** Dumps all of the particle IDs, positions and radii to a + * file. + * \param[in] filename the name of the file to write to. */ + inline void draw_particles(const char *filename) { + FILE *fp=safe_fopen(filename,"w"); + draw_particles(fp); + fclose(fp); + } + /** Dumps particle positions in POV-Ray format. + * \param[in] vl the loop class to use. + * \param[in] fp a file handle to write to. */ + template<class c_loop> + void draw_particles_pov(c_loop &vl,FILE *fp) { + double *pp; + if(vl.start()) do { + pp=p[vl.ijk]+4*vl.q; + fprintf(fp,"// id %d\nsphere{<%g,%g,%g>,%g}\n", + id[vl.ijk][vl.q],*pp,pp[1],pp[2],pp[3]); + } while(vl.inc()); + } + /** Dumps all the particle positions in POV-Ray format. + * \param[in] fp a file handle to write to. */ + inline void draw_particles_pov(FILE *fp=stdout) { + c_loop_all vl(*this); + draw_particles_pov(vl,fp); + } + /** Dumps all the particle positions in POV-Ray format. + * \param[in] filename the name of the file to write to. */ + inline void draw_particles_pov(const char *filename) { + FILE *fp=safe_fopen(filename,"w"); + draw_particles_pov(fp); + fclose(fp); + } + /** Computes Voronoi cells and saves the output in gnuplot + * format. + * \param[in] vl the loop class to use. + * \param[in] fp a file handle to write to. */ + template<class c_loop> + void draw_cells_gnuplot(c_loop &vl,FILE *fp) { + voronoicell c;double *pp; + if(vl.start()) do if(compute_cell(c,vl)) { + pp=p[vl.ijk]+ps*vl.q; + c.draw_gnuplot(*pp,pp[1],pp[2],fp); + } while(vl.inc()); + } + /** Compute all Voronoi cells and saves the output in gnuplot + * format. + * \param[in] fp a file handle to write to. */ + inline void draw_cells_gnuplot(FILE *fp=stdout) { + c_loop_all vl(*this); + draw_cells_gnuplot(vl,fp); + } + /** Compute all Voronoi cells and saves the output in gnuplot + * format. + * \param[in] filename the name of the file to write to. */ + inline void draw_cells_gnuplot(const char *filename) { + FILE *fp=safe_fopen(filename,"w"); + draw_cells_gnuplot(fp); + fclose(fp); + } + /** Computes Voronoi cells and saves the output in POV-Ray + * format. + * \param[in] vl the loop class to use. + * \param[in] fp a file handle to write to. */ + template<class c_loop> + void draw_cells_pov(c_loop &vl,FILE *fp) { + voronoicell c;double *pp; + if(vl.start()) do if(compute_cell(c,vl)) { + fprintf(fp,"// cell %d\n",id[vl.ijk][vl.q]); + pp=p[vl.ijk]+ps*vl.q; + c.draw_pov(*pp,pp[1],pp[2],fp); + } while(vl.inc()); + } + /** Computes all Voronoi cells and saves the output in POV-Ray + * format. + * \param[in] fp a file handle to write to. */ + inline void draw_cells_pov(FILE *fp=stdout) { + c_loop_all vl(*this); + draw_cells_pov(vl,fp); + } + /** Computes all Voronoi cells and saves the output in POV-Ray + * format. + * \param[in] filename the name of the file to write to. */ + inline void draw_cells_pov(const char *filename) { + FILE *fp=safe_fopen(filename,"w"); + draw_cells_pov(fp); + fclose(fp); + } + /** Computes the Voronoi cells and saves customized information + * about them. + * \param[in] vl the loop class to use. + * \param[in] format the custom output string to use. + * \param[in] fp a file handle to write to. */ + template<class c_loop> + void print_custom(c_loop &vl,const char *format,FILE *fp) { + int ijk,q;double *pp; + if(contains_neighbor(format)) { + voronoicell_neighbor c; + if(vl.start()) do if(compute_cell(c,vl)) { + ijk=vl.ijk;q=vl.q;pp=p[ijk]+ps*q; + c.output_custom(format,id[ijk][q],*pp,pp[1],pp[2],pp[3],fp); + } while(vl.inc()); + } else { + voronoicell c; + if(vl.start()) do if(compute_cell(c,vl)) { + ijk=vl.ijk;q=vl.q;pp=p[ijk]+ps*q; + c.output_custom(format,id[ijk][q],*pp,pp[1],pp[2],pp[3],fp); + } while(vl.inc()); + } + } + /** Computes the Voronoi cell for a particle currently being + * referenced by a loop class. + * \param[out] c a Voronoi cell class in which to store the + * computed cell. + * \param[in] vl the loop class to use. + * \return True if the cell was computed. If the cell cannot be + * computed, if it is removed entirely by a wall or boundary + * condition, then the routine returns false. */ + template<class v_cell,class c_loop> + inline bool compute_cell(v_cell &c,c_loop &vl) { + return vc.compute_cell(c,vl.ijk,vl.q,vl.i,vl.j,vl.k); + } + /** Computes the Voronoi cell for given particle. + * \param[out] c a Voronoi cell class in which to store the + * computed cell. + * \param[in] ijk the block that the particle is within. + * \param[in] q the index of the particle within the block. + * \return True if the cell was computed. If the cell cannot be + * computed, if it is removed entirely by a wall or boundary + * condition, then the routine returns false. */ + template<class v_cell> + inline bool compute_cell(v_cell &c,int ijk,int q) { + int k=ijk/nxy,ijkt=ijk-nxy*k,j=ijkt/nx,i=ijkt-j*nx; + return vc.compute_cell(c,ijk,q,i,j,k); + } + void print_custom(const char *format,FILE *fp=stdout); + void print_custom(const char *format,const char *filename); + bool find_voronoi_cell(double x,double y,double z,double &rx,double &ry,double &rz,int &pid); + private: + voro_compute<container_poly> vc; + friend class voro_compute<container_poly>; +}; + +} + +#endif diff --git a/contrib/voro++/src/container_prd.cc b/contrib/voro++/src/container_prd.cc new file mode 100644 index 0000000000000000000000000000000000000000..7d1b13347acb688c77b081067da3c071ac87f14c --- /dev/null +++ b/contrib/voro++/src/container_prd.cc @@ -0,0 +1,766 @@ +// Voro++, a 3D cell-based Voronoi library +// +// Author : Chris H. Rycroft (LBL / UC Berkeley) +// Email : chr@alum.mit.edu +// Date : August 30th 2011 + +/** \file container_prd.cc + * \brief Function implementations for the container_periodic_base and + * related classes. */ + +#include "container_prd.hh" + +namespace voro { + +/** The class constructor sets up the geometry of container, initializing the + * minimum and maximum coordinates in each direction, and setting whether each + * direction is periodic or not. It divides the container into a rectangular + * grid of blocks, and allocates memory for each of these for storing particle + * positions and IDs. + * \param[in] (bx_) The x coordinate of the first unit vector. + * \param[in] (bxy_,by_) The x and y coordinates of the second unit vector. + * \param[in] (bxz_,byz_,bz_) The x, y, and z coordinates of the third unit + * vector. + * \param[in] (nx_,ny_,nz_) the number of grid blocks in each of the three + * coordinate directions. + * \param[in] init_mem_ the initial memory allocation for each block. + * \param[in] ps_ the number of floating point entries to store for each + * particle. */ +container_periodic_base::container_periodic_base(double bx_,double bxy_,double by_, + double bxz_,double byz_,double bz_,int nx_,int ny_,int nz_,int init_mem_,int ps_) + : unitcell(bx_,bxy_,by_,bxz_,byz_,bz_), voro_base(nx_,ny_,nz_,bx_/nx_,by_/ny_,bz_/nz_), + ey(int(max_uv_y*ysp+1)), ez(int(max_uv_z*zsp+1)), wy(ny+ey), wz(nz+ez), + oy(ny+2*ey), oz(nz+2*ez), oxyz(nx*oy*oz), id(new int*[oxyz]), p(new double*[oxyz]), + co(new int[oxyz]), mem(new int[oxyz]), img(new char[oxyz]), init_mem(init_mem_), ps(ps_) { + int i,j,k,l; + + // Clear the global arrays + int *pp=co;while(pp<co+oxyz) *(pp++)=0; + pp=mem;while(pp<mem+oxyz) *(pp++)=0; + char *cp=img;while(cp<img+oxyz) *(cp++)=0; + + // Set up memory for the blocks in the primary domain + for(k=ez;k<wz;k++) for(j=ey;j<wy;j++) for(i=0;i<nx;i++) { + l=i+nx*(j+oy*k); + mem[l]=init_mem; + id[l]=new int[init_mem]; + p[l]=new double[ps*init_mem]; + } +} + +/** The container destructor frees the dynamically allocated memory. */ +container_periodic_base::~container_periodic_base() { + int l; + for(l=0;l<oxyz;l++) if(mem[l]>0) delete [] p[l]; + for(l=0;l<oxyz;l++) if(mem[l]>0) delete [] id[l]; + delete [] p; + delete [] id; + delete [] mem; + delete [] co; +} + +/** The class constructor sets up the geometry of container. + * \param[in] (bx_) The x coordinate of the first unit vector. + * \param[in] (bxy_,by_) The x and y coordinates of the second unit vector. + * \param[in] (bxz_,byz_,bz_) The x, y, and z coordinates of the third unit + * vector. + * \param[in] (nx_,ny_,nz_) the number of grid blocks in each of the three + * coordinate directions. + * \param[in] init_mem_ the initial memory allocation for each block. */ +container_periodic::container_periodic(double bx_,double bxy_,double by_,double bxz_,double byz_,double bz_, + int nx_,int ny_,int nz_,int init_mem_) + : container_periodic_base(bx_,bxy_,by_,bxz_,byz_,bz_,nx_,ny_,nz_,init_mem_,3), + vc(*this,2*nx_+1,2*ey+1,2*ez+1) {} + +/** The class constructor sets up the geometry of container. + * \param[in] (bx_) The x coordinate of the first unit vector. + * \param[in] (bxy_,by_) The x and y coordinates of the second unit vector. + * \param[in] (bxz_,byz_,bz_) The x, y, and z coordinates of the third unit + * vector. + * \param[in] (nx_,ny_,nz_) the number of grid blocks in each of the three + * coordinate directions. + * \param[in] init_mem_ the initial memory allocation for each block. */ +container_periodic_poly::container_periodic_poly(double bx_,double bxy_,double by_,double bxz_,double byz_,double bz_, + int nx_,int ny_,int nz_,int init_mem_) + : container_periodic_base(bx_,bxy_,by_,bxz_,byz_,bz_,nx_,ny_,nz_,init_mem_,4), + vc(*this,2*nx_+1,2*ey+1,2*ez+1) {ppr=p;} + +/** Put a particle into the correct region of the container. + * \param[in] n the numerical ID of the inserted particle. + * \param[in] (x,y,z) the position vector of the inserted particle. */ +void container_periodic::put(int n,double x,double y,double z) { + int ijk; + put_locate_block(ijk,x,y,z); + id[ijk][co[ijk]]=n; + double *pp=p[ijk]+3*co[ijk]++; + *(pp++)=x;*(pp++)=y;*pp=z; +} + +/** Put a particle into the correct region of the container. + * \param[in] n the numerical ID of the inserted particle. + * \param[in] (x,y,z) the position vector of the inserted particle. + * \param[in] r the radius of the particle. */ +void container_periodic_poly::put(int n,double x,double y,double z,double r) { + int ijk; + put_locate_block(ijk,x,y,z); + id[ijk][co[ijk]]=n; + double *pp=p[ijk]+4*co[ijk]++; + *(pp++)=x;*(pp++)=y;*(pp++)=z;*pp=r; + if(max_radius<r) max_radius=r; +} + +/** Put a particle into the correct region of the container. + * \param[in] n the numerical ID of the inserted particle. + * \param[in] (x,y,z) the position vector of the inserted particle. + * \param[out] (ai,aj,ak) the periodic image displacement that the particle is + * in, with (0,0,0) corresponding to the primary domain. + */ +void container_periodic::put(int n,double x,double y,double z,int &ai,int &aj,int &ak) { + int ijk; + put_locate_block(ijk,x,y,z,ai,aj,ak); + id[ijk][co[ijk]]=n; + double *pp=p[ijk]+3*co[ijk]++; + *(pp++)=x;*(pp++)=y;*pp=z; +} + +/** Put a particle into the correct region of the container. + * \param[in] n the numerical ID of the inserted particle. + * \param[in] (x,y,z) the position vector of the inserted particle. + * \param[in] r the radius of the particle. + * \param[out] (ai,aj,ak) the periodic image displacement that the particle is + * in, with (0,0,0) corresponding to the primary domain. + */ +void container_periodic_poly::put(int n,double x,double y,double z,double r,int &ai,int &aj,int &ak) { + int ijk; + put_locate_block(ijk,x,y,z,ai,aj,ak); + id[ijk][co[ijk]]=n; + double *pp=p[ijk]+4*co[ijk]++; + *(pp++)=x;*(pp++)=y;*(pp++)=z;*pp=r; + if(max_radius<r) max_radius=r; +} + +/** Put a particle into the correct region of the container, also recording + * into which region it was stored. + * \param[in] vo the ordering class in which to record the region. + * \param[in] n the numerical ID of the inserted particle. + * \param[in] (x,y,z) the position vector of the inserted particle. */ +void container_periodic::put(particle_order &vo,int n,double x,double y,double z) { + int ijk; + put_locate_block(ijk,x,y,z); + id[ijk][co[ijk]]=n; + vo.add(ijk,co[ijk]); + double *pp=p[ijk]+3*co[ijk]++; + *(pp++)=x;*(pp++)=y;*pp=z; +} + +/** Put a particle into the correct region of the container, also recording + * into which region it was stored. + * \param[in] vo the ordering class in which to record the region. + * \param[in] n the numerical ID of the inserted particle. + * \param[in] (x,y,z) the position vector of the inserted particle. + * \param[in] r the radius of the particle. */ +void container_periodic_poly::put(particle_order &vo,int n,double x,double y,double z,double r) { + int ijk; + put_locate_block(ijk,x,y,z); + id[ijk][co[ijk]]=n; + vo.add(ijk,co[ijk]); + double *pp=p[ijk]+4*co[ijk]++; + *(pp++)=x;*(pp++)=y;*(pp++)=z;*pp=r; + if(max_radius<r) max_radius=r; +} + +/** Takes a particle position vector and computes the region index into which + * it should be stored. If the container is periodic, then the routine also + * maps the particle position to ensure it is in the primary domain. If the + * container is not periodic, the routine bails out. + * \param[out] ijk the region index. + * \param[in,out] (x,y,z) the particle position, remapped into the primary + * domain if necessary. + * \return True if the particle can be successfully placed into the container, + * false otherwise. */ +void container_periodic_base::put_locate_block(int &ijk,double &x,double &y,double &z) { + + // Remap particle in the z direction if necessary + int k=step_int(z*zsp); + if(k<0||k>=nz) { + int ak=step_div(k,nz); + z-=ak*bz;y-=ak*byz;x-=ak*bxz;k-=ak*nz; + } + + // Remap particle in the y direction if necessary + int j=step_int(y*ysp); + if(j<0||j>=ny) { + int aj=step_div(j,ny); + y-=aj*by;x-=aj*bxy;j-=aj*ny; + } + + // Remap particle in the x direction if necessary + ijk=step_int(x*xsp); + if(ijk<0||ijk>=nx) { + int ai=step_div(ijk,nx); + x-=ai*bx;ijk-=ai*nx; + } + + // Compute the block index and check memory allocation + j+=ey;k+=ez; + ijk+=nx*(j+oy*k); + if(co[ijk]==mem[ijk]) add_particle_memory(ijk); +} + +/** Takes a particle position vector and computes the region index into which + * it should be stored. If the container is periodic, then the routine also + * maps the particle position to ensure it is in the primary domain. If the + * container is not periodic, the routine bails out. + * \param[out] ijk the region index. + * \param[in,out] (x,y,z) the particle position, remapped into the primary + * domain if necessary. + * \param[out] (ai,aj,ak) the periodic image displacement that the particle is + * in, with (0,0,0) corresponding to the primary domain. + * \return True if the particle can be successfully placed into the container, + * false otherwise. */ +void container_periodic_base::put_locate_block(int &ijk,double &x,double &y,double &z,int &ai,int &aj,int &ak) { + + // Remap particle in the z direction if necessary + int k=step_int(z*zsp); + if(k<0||k>=nz) { + ak=step_div(k,nz); + z-=ak*bz;y-=ak*byz;x-=ak*bxz;k-=ak*nz; + } else ak=0; + + // Remap particle in the y direction if necessary + int j=step_int(y*ysp); + if(j<0||j>=ny) { + aj=step_div(j,ny); + y-=aj*by;x-=aj*bxy;j-=aj*ny; + } else aj=0; + + // Remap particle in the x direction if necessary + ijk=step_int(x*xsp); + if(ijk<0||ijk>=nx) { + ai=step_div(ijk,nx); + x-=ai*bx;ijk-=ai*nx; + } else ai=0; + + // Compute the block index and check memory allocation + j+=ey;k+=ez; + ijk+=nx*(j+oy*k); + if(co[ijk]==mem[ijk]) add_particle_memory(ijk); +} + +/** Takes a position vector and remaps it into the primary domain. + * \param[out] (ai,aj,ak) the periodic image displacement that the vector is in, + * with (0,0,0) corresponding to the primary domain. + * \param[out] (ci,cj,ck) the index of the block that the position vector is + * within, once it has been remapped. + * \param[in,out] (x,y,z) the position vector to consider, which is remapped + * into the primary domain during the routine. + * \param[out] ijk the block index that the vector is within. */ +inline void container_periodic_base::remap(int &ai,int &aj,int &ak,int &ci,int &cj,int &ck,double &x,double &y,double &z,int &ijk) { + + // Remap particle in the z direction if necessary + ck=step_int(z*zsp); + if(ck<0||ck>=nz) { + ak=step_div(ck,nz); + z-=ak*bz;y-=ak*byz;x-=ak*bxz;ck-=ak*nz; + } else ak=0; + + // Remap particle in the y direction if necessary + cj=step_int(y*ysp); + if(cj<0||cj>=ny) { + aj=step_div(cj,ny); + y-=aj*by;x-=aj*bxy;cj-=aj*ny; + } else aj=0; + + // Remap particle in the x direction if necessary + ci=step_int(x*xsp); + if(ci<0||ci>=nx) { + ai=step_div(ci,nx); + x-=ai*bx;ci-=ai*nx; + } else ai=0; + + cj+=ey;ck+=ez; + ijk=ci+nx*(cj+oy*ck); +} + +/** Takes a vector and finds the particle whose Voronoi cell contains that + * vector. This is equivalent to finding the particle which is nearest to the + * vector. + * \param[in] (x,y,z) the vector to test. + * \param[out] (rx,ry,rz) the position of the particle whose Voronoi cell + * contains the vector. This may point to a particle in + * a periodic image of the primary domain. + * \param[out] pid the ID of the particle. + * \return True if a particle was found. If the container has no particles, + * then the search will not find a Voronoi cell and false is returned. */ +bool container_periodic::find_voronoi_cell(double x,double y,double z,double &rx,double &ry,double &rz,int &pid) { + int ai,aj,ak,ci,cj,ck,ijk; + particle_record w; + double mrs; + + // Remap the vector into the primary domain and then search for the + // Voronoi cell that it is within + remap(ai,aj,ak,ci,cj,ck,x,y,z,ijk); + vc.find_voronoi_cell(x,y,z,ci,cj,ck,ijk,w,mrs); + + if(w.ijk!=-1) { + + // Assemble the position vector of the particle to be returned, + // applying a periodic remapping if necessary + ci+=w.di;if(ci<0||ci>=nx) ai+=step_div(ci,nx); + rx=p[w.ijk][3*w.l]+ak*bxz+aj*bxy+ai*bx; + ry=p[w.ijk][3*w.l+1]+ak*byz+aj*by; + rz=p[w.ijk][3*w.l+2]+ak*bz; + pid=id[w.ijk][w.l]; + return true; + } + return false; +} + +/** Takes a vector and finds the particle whose Voronoi cell contains that + * vector. Additional wall classes are not considered by this routine. + * \param[in] (x,y,z) the vector to test. + * \param[out] (rx,ry,rz) the position of the particle whose Voronoi cell + * contains the vector. If the container is periodic, + * this may point to a particle in a periodic image of + * the primary domain. + * \param[out] pid the ID of the particle. + * \return True if a particle was found. If the container has no particles, + * then the search will not find a Voronoi cell and false is returned. */ +bool container_periodic_poly::find_voronoi_cell(double x,double y,double z,double &rx,double &ry,double &rz,int &pid) { + int ai,aj,ak,ci,cj,ck,ijk; + particle_record w; + double mrs; + + // Remap the vector into the primary domain and then search for the + // Voronoi cell that it is within + remap(ai,aj,ak,ci,cj,ck,x,y,z,ijk); + vc.find_voronoi_cell(x,y,z,ci,cj,ck,ijk,w,mrs); + + if(w.ijk!=-1) { + + // Assemble the position vector of the particle to be returned, + // applying a periodic remapping if necessary + ci+=w.di;if(ci<0||ci>=nx) ai+=step_div(ci,nx); + rx=p[w.ijk][4*w.l]+ak*bxz+aj*bxy+ai*bx; + ry=p[w.ijk][4*w.l+1]+ak*byz+aj*by; + rz=p[w.ijk][4*w.l+2]+ak*bz; + pid=id[w.ijk][w.l]; + return true; + } + return false; +} + +/** Increase memory for a particular region. + * \param[in] i the index of the region to reallocate. */ +void container_periodic_base::add_particle_memory(int i) { + + // Handle the case when no memory has been allocated for this block + if(mem[i]==0) { + mem[i]=init_mem; + id[i]=new int[init_mem]; + p[i]=new double[ps*init_mem]; + return; + } + + // Otherwise, double the memory allocation for this block. Carry out a + // check on the memory allocation size, and print a status message if + // requested. + int l,nmem(mem[i]<<1); + if(nmem>max_particle_memory) + voro_fatal_error("Absolute maximum memory allocation exceeded",VOROPP_MEMORY_ERROR); +#if VOROPP_VERBOSE >=3 + fprintf(stderr,"Particle memory in region %d scaled up to %d\n",i,nmem); +#endif + + // Allocate new memory and copy in the contents of the old arrays + int *idp=new int[nmem]; + for(l=0;l<co[i];l++) idp[l]=id[i][l]; + double *pp=new double[ps*nmem]; + for(l=0;l<ps*co[i];l++) pp[l]=p[i][l]; + + // Update pointers and delete old arrays + mem[i]=nmem; + delete [] id[i];id[i]=idp; + delete [] p[i];p[i]=pp; +} + +/** Import a list of particles from an open file stream into the container. + * Entries of four numbers (Particle ID, x position, y position, z position) + * are searched for. If the file cannot be successfully read, then the routine + * causes a fatal error. + * \param[in] fp the file handle to read from. */ +void container_periodic::import(FILE *fp) { + int i,j; + double x,y,z; + while((j=fscanf(fp,"%d %lg %lg %lg",&i,&x,&y,&z))==4) put(i,x,y,z); + if(j!=EOF) voro_fatal_error("File import error",VOROPP_FILE_ERROR); +} + +/** Import a list of particles from an open file stream, also storing the order + * of that the particles are read. Entries of four numbers (Particle ID, x + * position, y position, z position) are searched for. If the file cannot be + * successfully read, then the routine causes a fatal error. + * \param[in,out] vo a reference to an ordering class to use. + * \param[in] fp the file handle to read from. */ +void container_periodic::import(particle_order &vo,FILE *fp) { + int i,j; + double x,y,z; + while((j=fscanf(fp,"%d %lg %lg %lg",&i,&x,&y,&z))==4) put(vo,i,x,y,z); + if(j!=EOF) voro_fatal_error("File import error",VOROPP_FILE_ERROR); +} + +/** Import a list of particles from an open file stream into the container. + * Entries of five numbers (Particle ID, x position, y position, z position, + * radius) are searched for. If the file cannot be successfully read, then the + * routine causes a fatal error. + * \param[in] fp the file handle to read from. */ +void container_periodic_poly::import(FILE *fp) { + int i,j; + double x,y,z,r; + while((j=fscanf(fp,"%d %lg %lg %lg %lg",&i,&x,&y,&z,&r))==5) put(i,x,y,z,r); + if(j!=EOF) voro_fatal_error("File import error",VOROPP_FILE_ERROR); +} + +/** Import a list of particles from an open file stream, also storing the order + * of that the particles are read. Entries of four numbers (Particle ID, x + * position, y position, z position, radius) are searched for. If the file + * cannot be successfully read, then the routine causes a fatal error. + * \param[in,out] vo a reference to an ordering class to use. + * \param[in] fp the file handle to read from. */ +void container_periodic_poly::import(particle_order &vo,FILE *fp) { + int i,j; + double x,y,z,r; + while((j=fscanf(fp,"%d %lg %lg %lg %lg",&i,&x,&y,&z,&r))==5) put(vo,i,x,y,z,r); + if(j!=EOF) voro_fatal_error("File import error",VOROPP_FILE_ERROR); +} + +/** Outputs the a list of all the container regions along with the number of + * particles stored within each. */ +void container_periodic_base::region_count() { + int i,j,k,*cop=co; + for(k=0;k<nz;k++) for(j=0;j<ny;j++) for(i=0;i<nx;i++) + printf("Region (%d,%d,%d): %d particles\n",i,j,k,*(cop++)); +} + +/** Clears a container of particles. */ +void container_periodic::clear() { + for(int *cop=co;cop<co+nxyz;cop++) *cop=0; +} + +/** Clears a container of particles, also clearing resetting the maximum radius + * to zero. */ +void container_periodic_poly::clear() { + for(int *cop=co;cop<co+nxyz;cop++) *cop=0; + max_radius=0; +} + +/** Computes all the Voronoi cells and saves customized information about them. + * \param[in] format the custom output string to use. + * \param[in] fp a file handle to write to. */ +void container_periodic::print_custom(const char *format,FILE *fp) { + c_loop_all_periodic vl(*this); + print_custom(vl,format,fp); +} + +/** Computes all the Voronoi cells and saves customized + * information about them. + * \param[in] format the custom output string to use. + * \param[in] fp a file handle to write to. */ +void container_periodic_poly::print_custom(const char *format,FILE *fp) { + c_loop_all_periodic vl(*this); + print_custom(vl,format,fp); +} + +/** Computes all the Voronoi cells and saves customized information about them. + * \param[in] format the custom output string to use. + * \param[in] filename the name of the file to write to. */ +void container_periodic::print_custom(const char *format,const char *filename) { + FILE *fp=safe_fopen(filename,"w"); + print_custom(format,fp); + fclose(fp); +} + +/** Computes all the Voronoi cells and saves customized + * information about them + * \param[in] format the custom output string to use. + * \param[in] filename the name of the file to write to. */ +void container_periodic_poly::print_custom(const char *format,const char *filename) { + FILE *fp=safe_fopen(filename,"w"); + print_custom(format,fp); + fclose(fp); +} + +/** Computes all of the Voronoi cells in the container, but does nothing + * with the output. It is useful for measuring the pure computation time + * of the Voronoi algorithm, without any additional calculations such as + * volume evaluation or cell output. */ +void container_periodic::compute_all_cells() { + voronoicell c; + c_loop_all_periodic vl(*this); + if(vl.start()) do compute_cell(c,vl); + while(vl.inc()); +} + +/** Computes all of the Voronoi cells in the container, but does nothing + * with the output. It is useful for measuring the pure computation time + * of the Voronoi algorithm, without any additional calculations such as + * volume evaluation or cell output. */ +void container_periodic_poly::compute_all_cells() { + voronoicell c; + c_loop_all_periodic vl(*this); + if(vl.start()) do compute_cell(c,vl);while(vl.inc()); +} + +/** Calculates all of the Voronoi cells and sums their volumes. In most cases + * without walls, the sum of the Voronoi cell volumes should equal the volume + * of the container to numerical precision. + * \return The sum of all of the computed Voronoi volumes. */ +double container_periodic::sum_cell_volumes() { + voronoicell c; + double vol=0; + c_loop_all_periodic vl(*this); + if(vl.start()) do if(compute_cell(c,vl)) vol+=c.volume();while(vl.inc()); + return vol; +} + +/** Calculates all of the Voronoi cells and sums their volumes. In most cases + * without walls, the sum of the Voronoi cell volumes should equal the volume + * of the container to numerical precision. + * \return The sum of all of the computed Voronoi volumes. */ +double container_periodic_poly::sum_cell_volumes() { + voronoicell c; + double vol=0; + c_loop_all_periodic vl(*this); + if(vl.start()) do if(compute_cell(c,vl)) vol+=c.volume();while(vl.inc()); + return vol; +} + +/** This routine creates all periodic images of the particles. It is meant for + * diagnostic purposes only, since usually periodic images are dynamically + * created in when they are referenced. */ +void container_periodic_base::create_all_images() { + int i,j,k; + for(k=0;k<oz;k++) for(j=0;j<oy;j++) for(i=0;i<nx;i++) create_periodic_image(i,j,k); +} + +/** Checks that the particles within each block lie within that block's bounds. + * This is useful for diagnosing problems with periodic image computation. */ +void container_periodic_base::check_compartmentalized() { + int c,l,i,j,k; + double mix,miy,miz,max,may,maz,*pp; + for(k=l=0;k<oz;k++) for(j=0;j<oy;j++) for(i=0;i<nx;i++,l++) if(mem[l]>0) { + + // Compute the block's bounds, adding in a small tolerance + mix=i*boxx-tolerance;max=mix+boxx+tolerance; + miy=(j-ey)*boxy-tolerance;may=miy+boxy+tolerance; + miz=(k-ez)*boxz-tolerance;maz=miz+boxz+tolerance; + + // Print entries for any particles that lie outside the block's + // bounds + for(pp=p[l],c=0;c<co[l];c++,pp+=ps) if(*pp<mix||*pp>max||pp[1]<miy||pp[1]>may||pp[2]<miz||pp[2]>maz) + printf("%d %d %d %d %f %f %f %f %f %f %f %f %f\n", + id[l][c],i,j,k,*pp,pp[1],pp[2],mix,max,miy,may,miz,maz); + } +} + +/** Creates particles within an image block that is aligned with the primary + * domain in the z axis. In this case, the image block may be comprised of + * particles from two primary blocks. The routine considers these two primary + * blocks, and adds the needed particles to the image. The remaining particles + * from the primary blocks are also filled into the neighboring images. + * \param[in] (di,dj,dk) the index of the block to consider. The z index must + * satisfy ez<=dk<wz. */ +void container_periodic_base::create_side_image(int di,int dj,int dk) { + int l,dijk=di+nx*(dj+oy*dk),odijk,ima=step_div(dj-ey,ny); + int qua=di+step_int(-ima*bxy*xsp),quadiv=step_div(qua,nx); + int fi=qua-quadiv*nx,fijk=fi+nx*(dj-ima*ny+oy*dk); + double dis=ima*bxy+quadiv*bx,switchx=di*boxx-ima*bxy-quadiv*bx,adis; + + // Left image computation + if((img[dijk]&1)==0) { + if(di>0) { + odijk=dijk-1;adis=dis; + } else { + odijk=dijk+nx-1;adis=dis+bx; + } + img[odijk]|=2; + for(l=0;l<co[fijk];l++) { + if(p[fijk][ps*l]>switchx) put_image(dijk,fijk,l,dis,by*ima,0); + else put_image(odijk,fijk,l,adis,by*ima,0); + } + } + + // Right image computation + if((img[dijk]&2)==0) { + if(fi==nx-1) { + fijk+=1-nx;switchx+=(1-nx)*boxx;dis+=bx; + } else { + fijk++;switchx+=boxx; + } + if(di==nx-1) { + odijk=dijk-nx+1;adis=dis-bx; + } else { + odijk=dijk+1;adis=dis; + } + img[odijk]|=1; + for(l=0;l<co[fijk];l++) { + if(p[fijk][ps*l]<switchx) put_image(dijk,fijk,l,dis,by*ima,0); + else put_image(odijk,fijk,l,adis,by*ima,0); + } + } + + // All contributions to the block now added, so set both two bits of + // the image information + img[dijk]=3; +} + +/** Creates particles within an image block that is not aligned with the + * primary domain in the z axis. In this case, the image block may be comprised + * of particles from four primary blocks. The routine considers these four + * primary blocks, and adds the needed particles to the image. The remaining + * particles from the primary blocks are also filled into the neighboring + * images. + * \param[in] (di,dj,dk) the index of the block to consider. The z index must + * satisfy dk<ez or dk>=wz. */ +void container_periodic_base::create_vertical_image(int di,int dj,int dk) { + int l,dijk=di+nx*(dj+oy*dk),dijkl,dijkr,ima=step_div(dk-ez,nz); + int qj=dj+step_int(-ima*byz*ysp),qjdiv=step_div(qj-ey,ny); + int qi=di+step_int((-ima*bxz-qjdiv*bxy)*xsp),qidiv=step_div(qi,nx); + int fi=qi-qidiv*nx,fj=qj-qjdiv*ny,fijk=fi+nx*(fj+oy*(dk-ima*nz)),fijk2; + double disy=ima*byz+qjdiv*by,switchy=(dj-ey)*boxy-ima*byz-qjdiv*by; + double disx=ima*bxz+qjdiv*bxy+qidiv*bx,switchx=di*boxx-ima*bxz-qjdiv*bxy-qidiv*bx; + double switchx2,disxl,disxr,disx2,disxr2; + + if(di==0) {dijkl=dijk+nx-1;disxl=disx+bx;} + else {dijkl=dijk-1;disxl=disx;} + + if(di==nx-1) {dijkr=dijk-nx+1;disxr=disx-bx;} + else {dijkr=dijk+1;disxr=disx;} + + // Down-left image computation + bool y_exist=dj!=0; + if((img[dijk]&1)==0) { + img[dijkl]|=2; + if(y_exist) { + img[dijkl-nx]|=8; + img[dijk-nx]|=4; + } + for(l=0;l<co[fijk];l++) { + if(p[fijk][ps*l+1]>switchy) { + if(p[fijk][ps*l]>switchx) put_image(dijk,fijk,l,disx,disy,bz*ima); + else put_image(dijkl,fijk,l,disxl,disy,bz*ima); + } else { + if(!y_exist) continue; + if(p[fijk][ps*l]>switchx) put_image(dijk-nx,fijk,l,disx,disy,bz*ima); + else put_image(dijkl-nx,fijk,l,disxl,disy,bz*ima); + } + } + } + + // Down-right image computation + if((img[dijk]&2)==0) { + if(fi==nx-1) { + fijk2=fijk+1-nx;switchx2=switchx+(1-nx)*boxx;disx2=disx+bx;disxr2=disxr+bx; + } else { + fijk2=fijk+1;switchx2=switchx+boxx;disx2=disx;disxr2=disxr; + } + img[dijkr]|=1; + if(y_exist) { + img[dijkr-nx]|=4; + img[dijk-nx]|=8; + } + for(l=0;l<co[fijk2];l++) { + if(p[fijk2][ps*l+1]>switchy) { + if(p[fijk2][ps*l]>switchx2) put_image(dijkr,fijk2,l,disxr2,disy,bz*ima); + else put_image(dijk,fijk2,l,disx2,disy,bz*ima); + } else { + if(!y_exist) continue; + if(p[fijk2][ps*l]>switchx2) put_image(dijkr-nx,fijk2,l,disxr2,disy,bz*ima); + else put_image(dijk-nx,fijk2,l,disx2,disy,bz*ima); + } + } + } + + // Recomputation of some intermediate quantities for boundary cases + if(fj==wy-1) { + fijk+=nx*(1-ny)-fi; + switchy+=(1-ny)*boxy; + disy+=by; + qi=di+step_int(-(ima*bxz+(qjdiv+1)*bxy)*xsp); + int dqidiv=step_div(qi,nx)-qidiv;qidiv+=dqidiv; + fi=qi-qidiv*nx; + fijk+=fi; + disx+=bxy+bx*dqidiv; + disxl+=bxy+bx*dqidiv; + disxr+=bxy+bx*dqidiv; + switchx-=bxy+bx*dqidiv; + } else { + fijk+=nx;switchy+=boxy; + } + + // Up-left image computation + y_exist=dj!=oy-1; + if((img[dijk]&4)==0) { + img[dijkl]|=8; + if(y_exist) { + img[dijkl+nx]|=2; + img[dijk+nx]|=1; + } + for(l=0;l<co[fijk];l++) { + if(p[fijk][ps*l+1]>switchy) { + if(!y_exist) continue; + if(p[fijk][ps*l]>switchx) put_image(dijk+nx,fijk,l,disx,disy,bz*ima); + else put_image(dijkl+nx,fijk,l,disxl,disy,bz*ima); + } else { + if(p[fijk][ps*l]>switchx) put_image(dijk,fijk,l,disx,disy,bz*ima); + else put_image(dijkl,fijk,l,disxl,disy,bz*ima); + } + } + } + + // Up-right image computation + if((img[dijk]&8)==0) { + if(fi==nx-1) { + fijk2=fijk+1-nx;switchx2=switchx+(1-nx)*boxx;disx2=disx+bx;disxr2=disxr+bx; + } else { + fijk2=fijk+1;switchx2=switchx+boxx;disx2=disx;disxr2=disxr; + } + img[dijkr]|=4; + if(y_exist) { + img[dijkr+nx]|=1; + img[dijk+nx]|=2; + } + for(l=0;l<co[fijk2];l++) { + if(p[fijk2][ps*l+1]>switchy) { + if(!y_exist) continue; + if(p[fijk2][ps*l]>switchx2) put_image(dijkr+nx,fijk2,l,disxr2,disy,bz*ima); + else put_image(dijk+nx,fijk2,l,disx2,disy,bz*ima); + } else { + if(p[fijk2][ps*l]>switchx2) put_image(dijkr,fijk2,l,disxr2,disy,bz*ima); + else put_image(dijk,fijk2,l,disx2,disy,bz*ima); + } + } + } + + // All contributions to the block now added, so set all four bits of + // the image information + img[dijk]=15; +} + +/** Copies a particle position from the primary domain into an image block. + * \param[in] reg the block index within the primary domain that the particle + * is within. + * \param[in] fijk the index of the image block. + * \param[in] l the index of the particle entry within the primary block. + * \param[in] (dx,dy,dz) the displacement vector to add to the particle. */ +void container_periodic_base::put_image(int reg,int fijk,int l,double dx,double dy,double dz) { + if(co[reg]==mem[reg]) add_particle_memory(reg); + double *p1=p[reg]+ps*co[reg],*p2=p[fijk]+ps*l; + *(p1++)=*(p2++)+dx; + *(p1++)=*(p2++)+dy; + *p1=*p2+dz; + if(ps==4) *(++p1)=*(++p2); + id[reg][co[reg]++]=id[fijk][l]; +} + +} diff --git a/contrib/voro++/src/container_prd.hh b/contrib/voro++/src/container_prd.hh new file mode 100644 index 0000000000000000000000000000000000000000..e513e875729bba57c8151025062fdd9b180250c0 --- /dev/null +++ b/contrib/voro++/src/container_prd.hh @@ -0,0 +1,619 @@ +// Voro++, a 3D cell-based Voronoi library +// +// Author : Chris H. Rycroft (LBL / UC Berkeley) +// Email : chr@alum.mit.edu +// Date : August 30th 2011 + +/** \file container_prd.hh + * \brief Header file for the container_periodic_base and related classes. */ + +#ifndef VOROPP_CONTAINER_PRD_HH +#define VOROPP_CONTAINER_PRD_HH + +#include <cstdio> +#include <cstdlib> +#include <cmath> +#include <vector> +using namespace std; + +#include "config.hh" +#include "common.hh" +#include "v_base.hh" +#include "cell.hh" +#include "c_loops.hh" +#include "v_compute.hh" +#include "unitcell.hh" +#include "rad_option.hh" + +namespace voro { + +/** \brief Class for representing a particle system in a 3D periodic + * non-orthogonal periodic domain. + * + * This class represents a particle system in a three-dimensional + * non-orthogonal periodic domain. The domain is defined by three periodicity + * vectors (bx,0,0), (bxy,by,0), and (bxz,byz,bz) that represent a + * parallelepiped. Internally, the class stores particles in the box 0<x<bx, + * 0<y<by, 0<z<bz, and constructs periodic images of particles that displaced + * by the three periodicity vectors when they are necessary for the + * computation. The internal memory structure for this class is significantly + * different from the container_base class in order to handle the dynamic + * construction of these periodic images. + * + * The class is derived from the unitcell class, which encapsulates information + * about the domain geometry, and the voro_base class, which encapsulates + * information about the underlying computational grid. */ +class container_periodic_base : public unitcell, public voro_base { + public: + /** The lower y index (inclusive) of the primary domain within + * the block structure. */ + int ey; + /** The lower z index (inclusive) of the primary domain within + * the block structure. */ + int ez; + /** The upper y index (exclusive) of the primary domain within + * the block structure. */ + int wy; + /** The upper z index (exclusive) of the primary domain within + * the block structure. */ + int wz; + /** The total size of the block structure (including images) in + * the y direction. */ + int oy; + /** The total size of the block structure (including images) in + * the z direction. */ + int oz; + /** The total number of blocks. */ + int oxyz; + /** This array holds the numerical IDs of each particle in each + * computational box. */ + int **id; + /** A two dimensional array holding particle positions. For the + * derived container_poly class, this also holds particle + * radii. */ + double **p; + /** This array holds the number of particles within each + * computational box of the container. */ + int *co; + /** This array holds the maximum amount of particle memory for + * each computational box of the container. If the number of + * particles in a particular box ever approaches this limit, + * more is allocated using the add_particle_memory() function. + */ + int *mem; + /** An array holding information about periodic image + * construction at a given location. */ + char *img; + /** The initial amount of memory to allocate for particles + * for each block. */ + const int init_mem; + /** The amount of memory in the array structure for each + * particle. This is set to 3 when the basic class is + * initialized, so that the array holds (x,y,z) positions. If + * the container class is initialized as part of the derived + * class container_poly, then this is set to 4, to also hold + * the particle radii. */ + const int ps; + container_periodic_base(double bx_,double bxy_,double by_,double bxz_,double byz_,double bz_, + int nx_,int ny_,int nz_,int init_mem_,int ps); + ~container_periodic_base(); + /** Prints all particles in the container, including those that + * have been constructed in image blocks. */ + inline void print_all_particles() { + int ijk,q; + for(ijk=0;ijk<oxyz;ijk++) for(q=0;q<co[ijk];q++) + printf("%d %g %g %g\n",id[ijk][q],p[ijk][ps*q],p[ijk][ps*q+1],p[ijk][ps*q+2]); + } + void region_count(); + /** Initializes the Voronoi cell prior to a compute_cell + * operation for a specific particle being carried out by a + * voro_compute class. The cell is initialized to be the + * pre-computed unit Voronoi cell based on planes formed by + * periodic images of the particle. + * \param[in,out] c a reference to a voronoicell object. + * \param[in] ijk the block that the particle is within. + * \param[in] q the index of the particle within its block. + * \param[in] (ci,cj,ck) the coordinates of the block in the + * container coordinate system. + * \param[out] (i,j,k) the coordinates of the test block + * relative to the voro_compute + * coordinate system. + * \param[out] (x,y,z) the position of the particle. + * \param[out] disp a block displacement used internally by the + * compute_cell routine. + * \return False if the plane cuts applied by walls completely + * removed the cell, true otherwise. */ + template<class v_cell> + inline bool initialize_voronoicell(v_cell &c,int ijk,int q,int ci,int cj,int ck,int &i,int &j,int &k,double &x,double &y,double &z,int &disp) { + c=unit_voro; + double *pp=p[ijk]+ps*q; + x=*(pp++);y=*(pp++);z=*pp; + i=nx;j=ey;k=ez; + return true; + } + /** Initializes parameters for a find_voronoi_cell call within + * the voro_compute template. + * \param[in] (ci,cj,ck) the coordinates of the test block in + * the container coordinate system. + * \param[in] ijk the index of the test block + * \param[out] (i,j,k) the coordinates of the test block + * relative to the voro_compute + * coordinate system. + * \param[out] disp a block displacement used internally by the + * find_voronoi_cell routine (but not needed + * in this instance.) */ + inline void initialize_search(int ci,int cj,int ck,int ijk,int &i,int &j,int &k,int &disp) { + i=nx;j=ey;k=ez; + } + /** Returns the position of a particle currently being computed + * relative to the computational block that it is within. It is + * used to select the optimal worklist entry to use. + * \param[in] (x,y,z) the position of the particle. + * \param[in] (ci,cj,ck) the block that the particle is within. + * \param[out] (fx,fy,fz) the position relative to the block. + */ + inline void frac_pos(double x,double y,double z,double ci,double cj,double ck,double &fx,double &fy,double &fz) { + fx=x-boxx*ci; + fy=y-boxy*(cj-ey); + fz=z-boxz*(ck-ez); + } + /** Calculates the index of block in the container structure + * corresponding to given coordinates. + * \param[in] (ci,cj,ck) the coordinates of the original block + * in the current computation, relative + * to the container coordinate system. + * \param[in] (ei,ej,ek) the displacement of the current block + * from the original block. + * \param[in,out] (qx,qy,qz) the periodic displacement that + * must be added to the particles + * within the computed block. + * \param[in] disp a block displacement used internally by the + * find_voronoi_cell and compute_cell routines + * (but not needed in this instance.) + * \return The block index. */ + inline int region_index(int ci,int cj,int ck,int ei,int ej,int ek,double &qx,double &qy,double &qz,int &disp) { + int qi=ci+(ei-nx),qj=cj+(ej-ey),qk=ck+(ek-ez); + int iv(step_div(qi,nx));if(iv!=0) {qx=iv*bx;qi-=nx*iv;} else qx=0; + create_periodic_image(qi,qj,qk); + return qi+nx*(qj+oy*qk); + } + void create_all_images(); + void check_compartmentalized(); + protected: + void add_particle_memory(int i); + void put_locate_block(int &ijk,double &x,double &y,double &z); + void put_locate_block(int &ijk,double &x,double &y,double &z,int &ai,int &aj,int &ak); + /** Creates particles within an image block by copying them + * from the primary domain and shifting them. If the given + * block is aligned with the primary domain in the z-direction, + * the routine calls the simpler create_side_image routine + * where the image block may comprise of particles from up to + * two primary blocks. Otherwise is calls the more complex + * create_vertical_image where the image block may comprise of + * particles from up to four primary blocks. + * \param[in] (di,dj,dk) the coordinates of the image block to + * create. */ + inline void create_periodic_image(int di,int dj,int dk) { + if(di<0||di>=nx||dj<0||dj>=oy||dk<0||dk>=oz) + voro_fatal_error("Constructing periodic image for nonexistent point",VOROPP_INTERNAL_ERROR); + if(dk>=ez&&dk<wz) { + if(dj<ey||dj>=wy) create_side_image(di,dj,dk); + } else create_vertical_image(di,dj,dk); + } + void create_side_image(int di,int dj,int dk); + void create_vertical_image(int di,int dj,int dk); + void put_image(int reg,int fijk,int l,double dx,double dy,double dz); + inline void remap(int &ai,int &aj,int &ak,int &ci,int &cj,int &ck,double &x,double &y,double &z,int &ijk); +}; + +/** \brief Extension of the container_periodic_base class for computing regular + * Voronoi tessellations. + * + * This class is an extension of the container_periodic_base that has routines + * specifically for computing the regular Voronoi tessellation with no + * dependence on particle radii. */ +class container_periodic : public container_periodic_base, public radius_mono { + public: + container_periodic(double bx_,double bxy_,double by_,double bxz_,double byz_,double bz_, + int nx_,int ny_,int nz_,int init_mem_); + void clear(); + void put(int n,double x,double y,double z); + void put(int n,double x,double y,double z,int &ai,int &aj,int &ak); + void put(particle_order &vo,int n,double x,double y,double z); + void import(FILE *fp=stdin); + void import(particle_order &vo,FILE *fp=stdin); + /** Imports a list of particles from an open file stream into + * the container. Entries of four numbers (Particle ID, x + * position, y position, z position) are searched for. If the + * file cannot be successfully read, then the routine causes a + * fatal error. + * \param[in] filename the name of the file to open and read + * from. */ + inline void import(const char* filename) { + FILE *fp=safe_fopen(filename,"r"); + import(fp); + fclose(fp); + } + /** Imports a list of particles from an open file stream into + * the container. Entries of four numbers (Particle ID, x + * position, y position, z position) are searched for. In + * addition, the order in which particles are read is saved + * into an ordering class. If the file cannot be successfully + * read, then the routine causes a fatal error. + * \param[in,out] vo the ordering class to use. + * \param[in] filename the name of the file to open and read + * from. */ + inline void import(particle_order &vo,const char* filename) { + FILE *fp=safe_fopen(filename,"r"); + import(vo,fp); + fclose(fp); + } + void compute_all_cells(); + double sum_cell_volumes(); + /** Dumps particle IDs and positions to a file. + * \param[in] vl the loop class to use. + * \param[in] fp a file handle to write to. */ + template<class c_loop> + void draw_particles(c_loop &vl,FILE *fp) { + double *pp; + if(vl.start()) do { + pp=p[vl.ijk]+3*vl.q; + fprintf(fp,"%d %g %g %g\n",id[vl.ijk][vl.q],*pp,pp[1],pp[2]); + } while(vl.inc()); + } + /** Dumps all of the particle IDs and positions to a file. + * \param[in] fp a file handle to write to. */ + inline void draw_particles(FILE *fp=stdout) { + c_loop_all_periodic vl(*this); + draw_particles(vl,fp); + } + /** Dumps all of the particle IDs and positions to a file. + * \param[in] filename the name of the file to write to. */ + inline void draw_particles(const char *filename) { + FILE *fp=safe_fopen(filename,"w"); + draw_particles(fp); + fclose(fp); + } + /** Dumps particle positions in POV-Ray format. + * \param[in] vl the loop class to use. + * \param[in] fp a file handle to write to. */ + template<class c_loop> + void draw_particles_pov(c_loop &vl,FILE *fp) { + double *pp; + if(vl.start()) do { + pp=p[vl.ijk]+3*vl.q; + fprintf(fp,"// id %d\nsphere{<%g,%g,%g>,s}\n", + id[vl.ijk][vl.q],*pp,pp[1],pp[2]); + } while(vl.inc()); + } + /** Dumps all particle positions in POV-Ray format. + * \param[in] fp a file handle to write to. */ + inline void draw_particles_pov(FILE *fp=stdout) { + c_loop_all_periodic vl(*this); + draw_particles_pov(vl,fp); + } + /** Dumps all particle positions in POV-Ray format. + * \param[in] filename the name of the file to write to. */ + inline void draw_particles_pov(const char *filename) { + FILE *fp=safe_fopen(filename,"w"); + draw_particles_pov(fp); + fclose(fp); + } + /** Computes Voronoi cells and saves the output in gnuplot + * format. + * \param[in] vl the loop class to use. + * \param[in] fp a file handle to write to. */ + template<class c_loop> + void draw_cells_gnuplot(c_loop &vl,FILE *fp) { + voronoicell c;double *pp; + if(vl.start()) do if(compute_cell(c,vl)) { + pp=p[vl.ijk]+ps*vl.q; + c.draw_gnuplot(*pp,pp[1],pp[2],fp); + } while(vl.inc()); + } + /** Computes all Voronoi cells and saves the output in gnuplot + * format. + * \param[in] fp a file handle to write to. */ + inline void draw_cells_gnuplot(FILE *fp=stdout) { + c_loop_all_periodic vl(*this); + draw_cells_gnuplot(vl,fp); + } + /** Compute all Voronoi cells and saves the output in gnuplot + * format. + * \param[in] filename the name of the file to write to. */ + inline void draw_cells_gnuplot(const char *filename) { + FILE *fp=safe_fopen(filename,"w"); + draw_cells_gnuplot(fp); + fclose(fp); + } + /** Computes Voronoi cells and saves the output in POV-Ray + * format. + * \param[in] vl the loop class to use. + * \param[in] fp a file handle to write to. */ + template<class c_loop> + void draw_cells_pov(c_loop &vl,FILE *fp) { + voronoicell c;double *pp; + if(vl.start()) do if(compute_cell(c,vl)) { + fprintf(fp,"// cell %d\n",id[vl.ijk][vl.q]); + pp=p[vl.ijk]+ps*vl.q; + c.draw_pov(*pp,pp[1],pp[2],fp); + } while(vl.inc()); + } + /** Computes all Voronoi cells and saves the output in POV-Ray + * format. + * \param[in] fp a file handle to write to. */ + inline void draw_cells_pov(FILE *fp=stdout) { + c_loop_all_periodic vl(*this); + draw_cells_pov(vl,fp); + } + /** Computes all Voronoi cells and saves the output in POV-Ray + * format. + * \param[in] filename the name of the file to write to. */ + inline void draw_cells_pov(const char *filename) { + FILE *fp=safe_fopen(filename,"w"); + draw_cells_pov(fp); + fclose(fp); + } + /** Computes the Voronoi cells and saves customized information + * about them. + * \param[in] vl the loop class to use. + * \param[in] format the custom output string to use. + * \param[in] fp a file handle to write to. */ + template<class c_loop> + void print_custom(c_loop &vl,const char *format,FILE *fp) { + int ijk,q;double *pp; + if(contains_neighbor(format)) { + voronoicell_neighbor c; + if(vl.start()) do if(compute_cell(c,vl)) { + ijk=vl.ijk;q=vl.q;pp=p[ijk]+ps*q; + c.output_custom(format,id[ijk][q],*pp,pp[1],pp[2],default_radius,fp); + } while(vl.inc()); + } else { + voronoicell c; + if(vl.start()) do if(compute_cell(c,vl)) { + ijk=vl.ijk;q=vl.q;pp=p[ijk]+ps*q; + c.output_custom(format,id[ijk][q],*pp,pp[1],pp[2],default_radius,fp); + } while(vl.inc()); + } + } + void print_custom(const char *format,FILE *fp=stdout); + void print_custom(const char *format,const char *filename); + bool find_voronoi_cell(double x,double y,double z,double &rx,double &ry,double &rz,int &pid); + /** Computes the Voronoi cell for a particle currently being + * referenced by a loop class. + * \param[out] c a Voronoi cell class in which to store the + * computed cell. + * \param[in] vl the loop class to use. + * \return True if the cell was computed. If the cell cannot be + * computed because it was removed entirely for some reason, + * then the routine returns false. */ + template<class v_cell,class c_loop> + inline bool compute_cell(v_cell &c,c_loop &vl) { + return vc.compute_cell(c,vl.ijk,vl.q,vl.i,vl.j,vl.k); + } + /** Computes the Voronoi cell for given particle. + * \param[out] c a Voronoi cell class in which to store the + * computed cell. + * \param[in] ijk the block that the particle is within. + * \param[in] q the index of the particle within the block. + * \return True if the cell was computed. If the cell cannot be + * computed because it was removed entirely for some reason, + * then the routine returns false. */ + template<class v_cell> + inline bool compute_cell(v_cell &c,int ijk,int q) { + int k(ijk/(nx*oy)),ijkt(ijk-(nx*oy)*k),j(ijkt/nx),i(ijkt-j*nx); + return vc.compute_cell(c,ijk,q,i,j,k); + } + private: + voro_compute<container_periodic> vc; + friend class voro_compute<container_periodic>; +}; + +/** \brief Extension of the container_periodic_base class for computing radical + * Voronoi tessellations. + * + * This class is an extension of container_periodic_base that has routines + * specifically for computing the radical Voronoi tessellation that depends + * on the particle radii. */ +class container_periodic_poly : public container_periodic_base, public radius_poly { + public: + container_periodic_poly(double bx_,double bxy_,double by_,double bxz_,double byz_,double bz_, + int nx_,int ny_,int nz_,int init_mem_); + void clear(); + void put(int n,double x,double y,double z,double r); + void put(int n,double x,double y,double z,double r,int &ai,int &aj,int &ak); + void put(particle_order &vo,int n,double x,double y,double z,double r); + void import(FILE *fp=stdin); + void import(particle_order &vo,FILE *fp=stdin); + /** Imports a list of particles from an open file stream into + * the container_poly class. Entries of five numbers (Particle + * ID, x position, y position, z position, radius) are searched + * for. If the file cannot be successfully read, then the + * routine causes a fatal error. + * \param[in] filename the name of the file to open and read + * from. */ + inline void import(const char* filename) { + FILE *fp=safe_fopen(filename,"r"); + import(fp); + fclose(fp); + } + /** Imports a list of particles from an open file stream into + * the container_poly class. Entries of five numbers (Particle + * ID, x position, y position, z position, radius) are searched + * for. In addition, the order in which particles are read is + * saved into an ordering class. If the file cannot be + * successfully read, then the routine causes a fatal error. + * \param[in,out] vo the ordering class to use. + * \param[in] filename the name of the file to open and read + * from. */ + inline void import(particle_order &vo,const char* filename) { + FILE *fp=safe_fopen(filename,"r"); + import(vo,fp); + fclose(fp); + } + void compute_all_cells(); + double sum_cell_volumes(); + /** Dumps particle IDs, positions and radii to a file. + * \param[in] vl the loop class to use. + * \param[in] fp a file handle to write to. */ + template<class c_loop> + void draw_particles(c_loop &vl,FILE *fp) { + double *pp; + if(vl.start()) do { + pp=p[vl.ijk]+4*vl.q; + fprintf(fp,"%d %g %g %g %g\n",id[vl.ijk][vl.q],*pp,pp[1],pp[2],pp[3]); + } while(vl.inc()); + } + /** Dumps all of the particle IDs, positions and radii to a + * file. + * \param[in] fp a file handle to write to. */ + inline void draw_particles(FILE *fp=stdout) { + c_loop_all_periodic vl(*this); + draw_particles(vl,fp); + } + /** Dumps all of the particle IDs, positions and radii to a + * file. + * \param[in] filename the name of the file to write to. */ + inline void draw_particles(const char *filename) { + FILE *fp=safe_fopen(filename,"w"); + draw_particles(fp); + fclose(fp); + } + /** Dumps particle positions in POV-Ray format. + * \param[in] vl the loop class to use. + * \param[in] fp a file handle to write to. */ + template<class c_loop> + void draw_particles_pov(c_loop &vl,FILE *fp) { + double *pp; + if(vl.start()) do { + pp=p[vl.ijk]+4*vl.q; + fprintf(fp,"// id %d\nsphere{<%g,%g,%g>,%g}\n", + id[vl.ijk][vl.q],*pp,pp[1],pp[2],pp[3]); + } while(vl.inc()); + } + /** Dumps all the particle positions in POV-Ray format. + * \param[in] fp a file handle to write to. */ + inline void draw_particles_pov(FILE *fp=stdout) { + c_loop_all_periodic vl(*this); + draw_particles_pov(vl,fp); + } + /** Dumps all the particle positions in POV-Ray format. + * \param[in] filename the name of the file to write to. */ + inline void draw_particles_pov(const char *filename) { + FILE *fp(safe_fopen(filename,"w")); + draw_particles_pov(fp); + fclose(fp); + } + /** Computes Voronoi cells and saves the output in gnuplot + * format. + * \param[in] vl the loop class to use. + * \param[in] fp a file handle to write to. */ + template<class c_loop> + void draw_cells_gnuplot(c_loop &vl,FILE *fp) { + voronoicell c;double *pp; + if(vl.start()) do if(compute_cell(c,vl)) { + pp=p[vl.ijk]+ps*vl.q; + c.draw_gnuplot(*pp,pp[1],pp[2],fp); + } while(vl.inc()); + } + /** Compute all Voronoi cells and saves the output in gnuplot + * format. + * \param[in] fp a file handle to write to. */ + inline void draw_cells_gnuplot(FILE *fp=stdout) { + c_loop_all_periodic vl(*this); + draw_cells_gnuplot(vl,fp); + } + /** Compute all Voronoi cells and saves the output in gnuplot + * format. + * \param[in] filename the name of the file to write to. */ + inline void draw_cells_gnuplot(const char *filename) { + FILE *fp(safe_fopen(filename,"w")); + draw_cells_gnuplot(fp); + fclose(fp); + } + /** Computes Voronoi cells and saves the output in POV-Ray + * format. + * \param[in] vl the loop class to use. + * \param[in] fp a file handle to write to. */ + template<class c_loop> + void draw_cells_pov(c_loop &vl,FILE *fp) { + voronoicell c;double *pp; + if(vl.start()) do if(compute_cell(c,vl)) { + fprintf(fp,"// cell %d\n",id[vl.ijk][vl.q]); + pp=p[vl.ijk]+ps*vl.q; + c.draw_pov(*pp,pp[1],pp[2],fp); + } while(vl.inc()); + } + /** Computes all Voronoi cells and saves the output in POV-Ray + * format. + * \param[in] fp a file handle to write to. */ + inline void draw_cells_pov(FILE *fp=stdout) { + c_loop_all_periodic vl(*this); + draw_cells_pov(vl,fp); + } + /** Computes all Voronoi cells and saves the output in POV-Ray + * format. + * \param[in] filename the name of the file to write to. */ + inline void draw_cells_pov(const char *filename) { + FILE *fp(safe_fopen(filename,"w")); + draw_cells_pov(fp); + fclose(fp); + } + /** Computes the Voronoi cells and saves customized information + * about them. + * \param[in] vl the loop class to use. + * \param[in] format the custom output string to use. + * \param[in] fp a file handle to write to. */ + template<class c_loop> + void print_custom(c_loop &vl,const char *format,FILE *fp) { + int ijk,q;double *pp; + if(contains_neighbor(format)) { + voronoicell_neighbor c; + if(vl.start()) do if(compute_cell(c,vl)) { + ijk=vl.ijk;q=vl.q;pp=p[ijk]+ps*q; + c.output_custom(format,id[ijk][q],*pp,pp[1],pp[2],pp[3],fp); + } while(vl.inc()); + } else { + voronoicell c; + if(vl.start()) do if(compute_cell(c,vl)) { + ijk=vl.ijk;q=vl.q;pp=p[ijk]+ps*q; + c.output_custom(format,id[ijk][q],*pp,pp[1],pp[2],pp[3],fp); + } while(vl.inc()); + } + } + /** Computes the Voronoi cell for a particle currently being + * referenced by a loop class. + * \param[out] c a Voronoi cell class in which to store the + * computed cell. + * \param[in] vl the loop class to use. + * \return True if the cell was computed. If the cell cannot be + * computed because it was removed entirely for some reason, + * then the routine returns false. */ + template<class v_cell,class c_loop> + inline bool compute_cell(v_cell &c,c_loop &vl) { + return vc.compute_cell(c,vl.ijk,vl.q,vl.i,vl.j,vl.k); + } + /** Computes the Voronoi cell for given particle. + * \param[out] c a Voronoi cell class in which to store the + * computed cell. + * \param[in] ijk the block that the particle is within. + * \param[in] q the index of the particle within the block. + * \return True if the cell was computed. If the cell cannot be + * computed because it was removed entirely for some reason, + * then the routine returns false. */ + template<class v_cell> + inline bool compute_cell(v_cell &c,int ijk,int q) { + int k(ijk/(nx*oy)),ijkt(ijk-(nx*oy)*k),j(ijkt/nx),i(ijkt-j*nx); + return vc.compute_cell(c,ijk,q,i,j,k); + } + void print_custom(const char *format,FILE *fp=stdout); + void print_custom(const char *format,const char *filename); + bool find_voronoi_cell(double x,double y,double z,double &rx,double &ry,double &rz,int &pid); + private: + voro_compute<container_periodic_poly> vc; + friend class voro_compute<container_periodic_poly>; +}; + +} + +#endif diff --git a/contrib/voro++/src/pre_container.cc b/contrib/voro++/src/pre_container.cc new file mode 100644 index 0000000000000000000000000000000000000000..c6e055efa276c19350080a166b9b2f84a5075d80 --- /dev/null +++ b/contrib/voro++/src/pre_container.cc @@ -0,0 +1,238 @@ +// Voro++, a 3D cell-based Voronoi library +// +// Author : Chris H. Rycroft (LBL / UC Berkeley) +// Email : chr@alum.mit.edu +// Date : August 30th 2011 + +/** \file pre_container.cc + * \brief Function implementations for the pre_container and related classes. + */ + +#include <cstdio> +#include <cmath> +using namespace std; + +#include "config.hh" +#include "pre_container.hh" + +namespace voro { + +/** The class constructor sets up the geometry of container, initializing the + * minimum and maximum coordinates in each direction. It allocates an initial + * chunk into which to store particle information. + * \param[in] (ax_,bx_) the minimum and maximum x coordinates. + * \param[in] (ay_,by_) the minimum and maximum y coordinates. + * \param[in] (az_,bz_) the minimum and maximum z coordinates. + * \param[in] (xperiodic_,yperiodic_,zperiodic_ ) flags setting whether the + * container is periodic in each + * coordinate direction. + * \param[in] ps_ the number of floating point entries to store for each + * particle. */ +pre_container_base::pre_container_base(double ax_,double bx_,double ay_,double by_,double az_,double bz_, + bool xperiodic_,bool yperiodic_,bool zperiodic_,int ps_) : + ax(ax_), bx(bx_), ay(ay_), by(by_), az(az_), bz(bz_), + xperiodic(xperiodic_), yperiodic(yperiodic_), zperiodic(zperiodic_), ps(ps_), + index_sz(init_chunk_size), pre_id(new int*[index_sz]), end_id(pre_id), + pre_p(new double*[index_sz]), end_p(pre_p) { + ch_id=*end_id=new int[pre_container_chunk_size]; + l_id=end_id+index_sz;e_id=ch_id+pre_container_chunk_size; + ch_p=*end_p=new double[ps*pre_container_chunk_size]; +} + +/** The destructor frees the dynamically allocated memory. */ +pre_container_base::~pre_container_base() { + delete [] *end_p; + delete [] *end_id; + while (end_id!=pre_id) { + end_p--; + delete [] *end_p; + end_id--; + delete [] *end_id; + } + delete [] pre_p; + delete [] pre_id; +} + +/** Makes a guess at the optimal grid of blocks to use, computing in + * a way that + * \param[out] (nx,ny,nz) the number of blocks to use. */ +void pre_container_base::guess_optimal(int &nx,int &ny,int &nz) { + double dx(bx-ax),dy(by-ay),dz(bz-az); + double ilscale(pow(total_particles()/(optimal_particles*dx*dy*dz),1/3.0)); + nx=int(dx*ilscale+1); + ny=int(dy*ilscale+1); + nz=int(dz*ilscale+1); +} + +/** Stores a particle ID and position, allocating a new memory chunk if + * necessary. For coordinate directions in which the container is not periodic, + * the routine checks to make sure that the particle is within the container + * bounds. If the particle is out of bounds, it is not stored. + * \param[in] n the numerical ID of the inserted particle. + * \param[in] (x,y,z) the position vector of the inserted particle. */ +void pre_container::put(int n,double x,double y,double z) { + if((xperiodic||(x>=ax&&x<=bx))&&(yperiodic||(y>=ay&&y<=by))&&(zperiodic||(z>=az&&z<=bz))) { + if(ch_id==e_id) new_chunk(); + *(ch_id++)=n; + *(ch_p++)=x;*(ch_p++)=y;*(ch_p++)=z; + } +#if VOROPP_REPORT_OUT_OF_BOUNDS ==1 + else fprintf(stderr,"Out of bounds: (x,y,z)=(%g,%g,%g)\n",x,y,z); +#endif +} + +/** Stores a particle ID and position, allocating a new memory chunk if necessary. + * \param[in] n the numerical ID of the inserted particle. + * \param[in] (x,y,z) the position vector of the inserted particle. + * \param[in] r the radius of the particle. */ +void pre_container_poly::put(int n,double x,double y,double z,double r) { + if((xperiodic||(x>=ax&&x<=bx))&&(yperiodic||(y>=ay&&y<=by))&&(zperiodic||(z>=az&&z<=bz))) { + if(ch_id==e_id) new_chunk(); + *(ch_id++)=n; + *(ch_p++)=x;*(ch_p++)=y;*(ch_p++)=z;*(ch_p++)=r; + } +#if VOROPP_REPORT_OUT_OF_BOUNDS ==1 + else fprintf(stderr,"Out of bounds: (x,y,z)=(%g,%g,%g)\n",x,y,z); +#endif +} + +/** Transfers the particles stored within the class to a container class. + * \param[in] con the container class to transfer to. */ +void pre_container::setup(container &con) { + int **c_id=pre_id,*idp,*ide,n; + double **c_p=pre_p,*pp,x,y,z; + while(c_id<end_id) { + idp=*(c_id++);ide=idp+pre_container_chunk_size; + pp=*(c_p++); + while(idp<ide) { + n=*(idp++);x=*(pp++);y=*(pp++);z=*(pp++); + con.put(n,x,y,z); + } + } + idp=*c_id; + pp=*c_p; + while(idp<ch_id) { + n=*(idp++);x=*(pp++);y=*(pp++);z=*(pp++); + con.put(n,x,y,z); + } +} + +/** Transfers the particles stored within the class to a container_poly class. + * \param[in] con the container_poly class to transfer to. */ +void pre_container_poly::setup(container_poly &con) { + int **c_id=pre_id,*idp,*ide,n; + double **c_p=pre_p,*pp,x,y,z,r; + while(c_id<end_id) { + idp=*(c_id++);ide=idp+pre_container_chunk_size; + pp=*(c_p++); + while(idp<ide) { + n=*(idp++);x=*(pp++);y=*(pp++);z=*(pp++);r=*(pp++); + con.put(n,x,y,z,r); + } + } + idp=*c_id; + pp=*c_p; + while(idp<ch_id) { + n=*(idp++);x=*(pp++);y=*(pp++);z=*(pp++);r=*(pp++); + con.put(n,x,y,z,r); + } +} + +/** Transfers the particles stored within the class to a container class, also + * recording the order in which particles were stored. + * \param[in] vo the ordering class to use. + * \param[in] con the container class to transfer to. */ +void pre_container::setup(particle_order &vo,container &con) { + int **c_id=pre_id,*idp,*ide,n; + double **c_p=pre_p,*pp,x,y,z; + while(c_id<end_id) { + idp=*(c_id++);ide=idp+pre_container_chunk_size; + pp=*(c_p++); + while(idp<ide) { + n=*(idp++);x=*(pp++);y=*(pp++);z=*(pp++); + con.put(vo,n,x,y,z); + } + } + idp=*c_id; + pp=*c_p; + while(idp<ch_id) { + n=*(idp++);x=*(pp++);y=*(pp++);z=*(pp++); + con.put(vo,n,x,y,z); + } +} + +/** Transfers the particles stored within the class to a container_poly class, + * also recording the order in which particles were stored. + * \param[in] vo the ordering class to use. + * \param[in] con the container_poly class to transfer to. */ +void pre_container_poly::setup(particle_order &vo,container_poly &con) { + int **c_id=pre_id,*idp,*ide,n; + double **c_p=pre_p,*pp,x,y,z,r; + while(c_id<end_id) { + idp=*(c_id++);ide=idp+pre_container_chunk_size; + pp=*(c_p++); + while(idp<ide) { + n=*(idp++);x=*(pp++);y=*(pp++);z=*(pp++);r=*(pp++); + con.put(vo,n,x,y,z,r); + } + } + idp=*c_id; + pp=*c_p; + while(idp<ch_id) { + n=*(idp++);x=*(pp++);y=*(pp++);z=*(pp++);r=*(pp++); + con.put(vo,n,x,y,z,r); + } +} + +/** Import a list of particles from an open file stream into the container. + * Entries of four numbers (Particle ID, x position, y position, z position) + * are searched for. If the file cannot be successfully read, then the routine + * causes a fatal error. + * \param[in] fp the file handle to read from. */ +void pre_container::import(FILE *fp) { + int i,j; + double x,y,z; + while((j=fscanf(fp,"%d %lg %lg %lg",&i,&x,&y,&z))==4) put(i,x,y,z); + if(j!=EOF) voro_fatal_error("File import error",VOROPP_FILE_ERROR); +} + +/** Import a list of particles from an open file stream, also storing the order + * of that the particles are read. Entries of four numbers (Particle ID, x + * position, y position, z position) are searched for. If the file cannot be + * successfully read, then the routine causes a fatal error. + * \param[in] fp the file handle to read from. */ +void pre_container_poly::import(FILE *fp) { + int i,j; + double x,y,z,r; + while((j=fscanf(fp,"%d %lg %lg %lg %lg",&i,&x,&y,&z,&r))==5) put(i,x,y,z,r); + if(j!=EOF) voro_fatal_error("File import error",VOROPP_FILE_ERROR); +} + +/** Allocates a new chunk of memory for storing particles. */ +void pre_container_base::new_chunk() { + end_id++;end_p++; + if(end_id==l_id) extend_chunk_index(); + ch_id=*end_id=new int[pre_container_chunk_size]; + e_id=ch_id+pre_container_chunk_size; + ch_p=*end_p=new double[ps*pre_container_chunk_size]; +} + +/** Extends the index of chunks. */ +void pre_container_base::extend_chunk_index() { + index_sz<<=1; + if(index_sz>max_chunk_size) + voro_fatal_error("Absolute memory limit on chunk index reached",VOROPP_MEMORY_ERROR); +#if VOROPP_VERBOSE >=2 + fprintf(stderr,"Pre-container chunk index scaled up to %d\n",index_sz); +#endif + int **n_id=new int*[index_sz],**p_id=n_id,**c_id=pre_id; + double **n_p=new double*[index_sz],**p_p=n_p,**c_p=pre_p; + while(c_id<end_id) { + *(p_id++)=*(c_id++); + *(p_p++)=*(c_p++); + } + delete [] pre_id;pre_id=n_id;end_id=p_id;l_id=pre_id+index_sz; + delete [] pre_p;pre_p=n_p;end_p=p_p; +} + +} diff --git a/contrib/voro++/src/pre_container.hh b/contrib/voro++/src/pre_container.hh new file mode 100644 index 0000000000000000000000000000000000000000..1acd23882adb8a3fb11f4983599ae65407f5b7d5 --- /dev/null +++ b/contrib/voro++/src/pre_container.hh @@ -0,0 +1,160 @@ +// Voro++, a 3D cell-based Voronoi library +// +// Author : Chris H. Rycroft (LBL / UC Berkeley) +// Email : chr@alum.mit.edu +// Date : August 30th 2011 + +/** \file pre_container.hh + * \brief Header file for the pre_container and related classes. */ + +#ifndef VOROPP_PRE_CONTAINER_HH +#define VOROPP_PRE_CONTAINER_HH + +#include "c_loops.hh" +#include "container.hh" + +namespace voro { + +/** \brief A class for storing an arbitrary number of particles, prior to setting + * up a container geometry. + * + * The pre_container_base class can dynamically import and store an arbitrary + * number of particles. Once the particles have been read in, an appropriate + * container class can be set up with the optimal grid size, and the particles + * can be transferred. + * + * The pre_container_base class is not intended for direct use, but forms the + * base of the pre_container and pre_container_poly classes, that add routines + * depending on whether particle radii need to be tracked or not. */ +class pre_container_base { + public: + /** The minimum x coordinate of the container. */ + const double ax; + /** The maximum x coordinate of the container. */ + const double bx; + /** The minimum y coordinate of the container. */ + const double ay; + /** The maximum y coordinate of the container. */ + const double by; + /** The minimum z coordinate of the container. */ + const double az; + /** The maximum z coordinate of the container. */ + const double bz; + /** A boolean value that determines if the x coordinate in + * periodic or not. */ + const bool xperiodic; + /** A boolean value that determines if the y coordinate in + * periodic or not. */ + const bool yperiodic; + /** A boolean value that determines if the z coordinate in + * periodic or not. */ + const bool zperiodic; + void guess_optimal(int &nx,int &ny,int &nz); + pre_container_base(double ax_,double bx_,double ay_,double by_,double az_,double bz_,bool xperiodic_,bool yperiodic_,bool zperiodic_,int ps_); + ~pre_container_base(); + /** Calculates and returns the total number of particles stored + * within the class. + * \return The number of particles. */ + inline int total_particles() { + return (end_id-pre_id)*pre_container_chunk_size+(ch_id-*end_id); + } + protected: + /** The number of doubles associated with a single particle + * (three for the standard container, four when radius + * information is stored). */ + const int ps; + void new_chunk(); + void extend_chunk_index(); + /** The size of the chunk index. */ + int index_sz; + /** A pointer to the chunk index to store the integer particle + * IDs. */ + int **pre_id; + /** A pointer to the last allocated integer ID chunk. */ + int **end_id; + /** A pointer to the end of the integer ID chunk index, used to + * determine when the chunk index is full. */ + int **l_id; + /** A pointer to the next available slot on the current + * particle ID chunk. */ + int *ch_id; + /** A pointer to the end of the current integer chunk. */ + int *e_id; + /** A pointer to the chunk index to store the floating point + * information associated with particles. */ + double **pre_p; + /** A pointer to the last allocated chunk of floating point + * information. */ + double **end_p; + /** A pointer to the next available slot on the current + * floating point chunk. */ + double *ch_p; +}; + +/** \brief A class for storing an arbitrary number of particles without radius + * information, prior to setting up a container geometry. + * + * The pre_container class is an extension of the pre_container_base class for + * cases when no particle radius information is available. */ +class pre_container : public pre_container_base { + public: + /** The class constructor sets up the geometry of container, + * initializing the minimum and maximum coordinates in each + * direction. + * \param[in] (ax_,bx_) the minimum and maximum x coordinates. + * \param[in] (ay_,by_) the minimum and maximum y coordinates. + * \param[in] (az_,bz_) the minimum and maximum z coordinates. + * \param[in] (xperiodic_,yperiodic_,zperiodic_ ) flags setting whether the + * container is periodic in + * each coordinate direction. */ + pre_container(double ax_,double bx_,double ay_,double by_,double az_,double bz_, + bool xperiodic_,bool yperiodic_,bool zperiodic_) + : pre_container_base(ax_,bx_,ay_,by_,az_,bz_,xperiodic_,yperiodic_,zperiodic_,3) {}; + void put(int n,double x,double y,double z); + void import(FILE *fp=stdin); + /** Imports particles from a file. + * \param[in] filename the name of the file to read from. */ + inline void import(const char* filename) { + FILE *fp=safe_fopen(filename,"r"); + import(fp); + fclose(fp); + } + void setup(container &con); + void setup(particle_order &vo,container &con); +}; + +/** \brief A class for storing an arbitrary number of particles with radius + * information, prior to setting up a container geometry. + * + * The pre_container_poly class is an extension of the pre_container_base class + * for cases when particle radius information is available. */ +class pre_container_poly : public pre_container_base { + public: + /** The class constructor sets up the geometry of container, + * initializing the minimum and maximum coordinates in each + * direction. + * \param[in] (ax_,bx_) the minimum and maximum x coordinates. + * \param[in] (ay_,by_) the minimum and maximum y coordinates. + * \param[in] (az_,bz_) the minimum and maximum z coordinates. + * \param[in] (xperiodic_,yperiodic_,zperiodic_ ) flags setting whether the + * container is periodic in + * each coordinate direction. */ + pre_container_poly(double ax_,double bx_,double ay_,double by_,double az_,double bz_, + bool xperiodic_,bool yperiodic_,bool zperiodic_) + : pre_container_base(ax_,bx_,ay_,by_,az_,bz_,xperiodic_,yperiodic_,zperiodic_,4) {}; + void put(int n,double x,double y,double z,double r); + void import(FILE *fp=stdin); + /** Imports particles from a file. + * \param[in] filename the name of the file to read from. */ + inline void import(const char* filename) { + FILE *fp=safe_fopen(filename,"r"); + import(fp); + fclose(fp); + } + void setup(container_poly &con); + void setup(particle_order &vo,container_poly &con); +}; + +} + +#endif diff --git a/contrib/voro++/src/rad_option.hh b/contrib/voro++/src/rad_option.hh new file mode 100644 index 0000000000000000000000000000000000000000..c7f388cead80260fe3c32588ae1dede15d52f355 --- /dev/null +++ b/contrib/voro++/src/rad_option.hh @@ -0,0 +1,156 @@ +// Voro++, a 3D cell-based Voronoi library +// +// Author : Chris H. Rycroft (LBL / UC Berkeley) +// Email : chr@alum.mit.edu +// Date : August 30th 2011 + +/** \file rad_option.hh + * \brief Header file for the classes encapsulating functionality for the + * regular and radical Voronoi tessellations. */ + +#ifndef VOROPP_RAD_OPTION_HH +#define VOROPP_RAD_OPTION_HH + +namespace voro { + +/** \brief Class containing all of the routines that are specific to computing + * the regular Voronoi tessellation. + * + * The container and container_periodic classes are derived from this class, + * and during the Voronoi cell computation, these routines are used to create + * the regular Voronoi tessellation. */ +class radius_mono { + protected: + /** This is called prior to computing a Voronoi cell for a + * given particle to initialize any required constants. + * \param[in] ijk the block that the particle is within. + * \param[in] s the index of the particle within the block. */ + inline void r_init(int ijk,int s) {} + /** Sets a required constant to be used when carrying out a + * plane bounds check. */ + inline void r_prime(double rv) {} + /** Carries out a radius bounds check. + * \param[in] crs the radius squared to be tested. + * \param[in] mrs the current maximum distance to a Voronoi + * vertex multiplied by two. + * \return True if particles at this radius could not possibly + * cut the cell, false otherwise. */ + inline bool r_ctest(double crs,double mrs) {return crs>mrs;} + /** Scales a plane displacement during a plane bounds check. + * \param[in] lrs the plane displacement. + * \return The scaled value. */ + inline double r_cutoff(double lrs) {return lrs;} + /** Adds the maximum radius squared to a given value. + * \param[in] rs the value to consider. + * \return The value with the radius squared added. */ + inline double r_max_add(double rs) {return rs;} + /** Subtracts the radius squared of a particle from a given + * value. + * \param[in] rs the value to consider. + * \param[in] ijk the block that the particle is within. + * \param[in] q the index of the particle within the block. + * \return The value with the radius squared subtracted. */ + inline double r_current_sub(double rs,int ijk,int q) {return rs;} + /** Scales a plane displacement prior to use in the plane cutting + * algorithm. + * \param[in] rs the initial plane displacement. + * \param[in] ijk the block that the particle is within. + * \param[in] q the index of the particle within the block. + * \return The scaled plane displacement. */ + inline double r_scale(double rs,int ijk,int q) {return rs;} + /** Scales a plane displacement prior to use in the plane + * cutting algorithm, and also checks if it could possibly cut + * the cell. + * \param[in,out] rs the plane displacement to be scaled. + * \param[in] mrs the current maximum distance to a Voronoi + * vertex multiplied by two. + * \param[in] ijk the block that the particle is within. + * \param[in] q the index of the particle within the block. + * \return True if the cell could possibly cut the cell, false + * otherwise. */ + inline bool r_scale_check(double &rs,double mrs,int ijk,int q) {return rs<mrs;} +}; + +/** \brief Class containing all of the routines that are specific to computing + * the radical Voronoi tessellation. + * + * The container_poly and container_periodic_poly classes are derived from this + * class, and during the Voronoi cell computation, these routines are used to + * create the radical Voronoi tessellation. */ +class radius_poly { + public: + /** A two-dimensional array holding particle positions and radii. */ + double **ppr; + /** The current maximum radius of any particle, used to + * determine when to cut off the radical Voronoi computation. + * */ + double max_radius; + /** The class constructor sets the maximum particle radius to + * be zero. */ + radius_poly() : max_radius(0) {} + protected: + /** This is called prior to computing a Voronoi cell for a + * given particle to initialize any required constants. + * \param[in] ijk the block that the particle is within. + * \param[in] s the index of the particle within the block. */ + inline void r_init(int ijk,int s) { + r_rad=ppr[ijk][4*s+3]*ppr[ijk][4*s+3]; + r_mul=r_rad-max_radius*max_radius; + } + /** Sets a required constant to be used when carrying out a + * plane bounds check. */ + inline void r_prime(double rv) {r_val=1+r_mul/rv;} + /** Carries out a radius bounds check. + * \param[in] crs the radius squared to be tested. + * \param[in] mrs the current maximum distance to a Voronoi + * vertex multiplied by two. + * \return True if particles at this radius could not possibly + * cut the cell, false otherwise. */ + inline bool r_ctest(double crs,double mrs) {return crs+r_mul>sqrt(mrs*crs);} + /** Scales a plane displacement during a plane bounds check. + * \param[in] lrs the plane displacement. + * \return The scaled value. */ + inline double r_cutoff(double lrs) {return lrs*r_val;} + /** Adds the maximum radius squared to a given value. + * \param[in] rs the value to consider. + * \return The value with the radius squared added. */ + inline double r_max_add(double rs) {return rs+max_radius*max_radius;} + /** Subtracts the radius squared of a particle from a given + * value. + * \param[in] rs the value to consider. + * \param[in] ijk the block that the particle is within. + * \param[in] q the index of the particle within the block. + * \return The value with the radius squared subtracted. */ + inline double r_current_sub(double rs,int ijk,int q) { + return rs-ppr[ijk][4*q+3]*ppr[ijk][4*q+3]; + } + /** Scales a plane displacement prior to use in the plane cutting + * algorithm. + * \param[in] rs the initial plane displacement. + * \param[in] ijk the block that the particle is within. + * \param[in] q the index of the particle within the block. + * \return The scaled plane displacement. */ + inline double r_scale(double rs,int ijk,int q) { + return rs+r_rad-ppr[ijk][4*q+3]*ppr[ijk][4*q+3]; + } + /** Scales a plane displacement prior to use in the plane + * cutting algorithm, and also checks if it could possibly cut + * the cell. + * \param[in,out] rs the plane displacement to be scaled. + * \param[in] mrs the current maximum distance to a Voronoi + * vertex multiplied by two. + * \param[in] ijk the block that the particle is within. + * \param[in] q the index of the particle within the block. + * \return True if the cell could possibly cut the cell, false + * otherwise. */ + inline bool r_scale_check(double &rs,double mrs,int ijk,int q) { + double trs=rs; + rs+=r_rad-ppr[ijk][4*q+3]*ppr[ijk][4*q+3]; + return rs<sqrt(mrs*trs); + } + private: + double r_rad,r_mul,r_val; +}; + +} +#endif diff --git a/contrib/voro++/src/unitcell.cc b/contrib/voro++/src/unitcell.cc new file mode 100644 index 0000000000000000000000000000000000000000..389d73ace4804ec2936c86d63f65b484b8684bc3 --- /dev/null +++ b/contrib/voro++/src/unitcell.cc @@ -0,0 +1,231 @@ +// Voro++, a 3D cell-based Voronoi library +// +// Author : Chris H. Rycroft (LBL / UC Berkeley) +// Email : chr@alum.mit.edu +// Date : August 30th 2011 + +/** \file unitcell.cc + * \brief Function implementations for the unitcell class. */ + +#include <queue> +using namespace std; + +#include "unitcell.hh" +#include "cell.hh" + +namespace voro { + +/** Initializes the unit cell class for a particular non-orthogonal periodic + * geometry, corresponding to a parallelepiped with sides given by three + * vectors. The class constructs the unit Voronoi cell corresponding to this + * geometry. + * \param[in] (bx_) The x coordinate of the first unit vector. + * \param[in] (bxy_,by_) The x and y coordinates of the second unit vector. + * \param[in] (bxz_,byz_,bz_) The x, y, and z coordinates of the third unit + * vector. */ +unitcell::unitcell(double bx_,double bxy_,double by_,double bxz_,double byz_,double bz_) + : bx(bx_), bxy(bxy_), by(by_), bxz(bxz_), byz(byz_), bz(bz_) { + int i,j,l=1; + + // Initialize the Voronoi cell to be a very large rectangular box + const double ucx=max_unit_voro_shells*bx,ucy=max_unit_voro_shells*by,ucz=max_unit_voro_shells*bz; + unit_voro.init(-ucx,ucx,-ucy,ucy,-ucz,ucz); + + // Repeatedly cut the cell by shells of periodic image particles + while(l<2*max_unit_voro_shells) { + + // Check to see if any of the planes from the current shell + // will cut the cell + if(unit_voro_intersect(l)) { + + // If they do, apply the plane cuts from the current + // shell + unit_voro_apply(l,0,0); + for(i=1;i<l;i++) { + unit_voro_apply(l,i,0); + unit_voro_apply(-l,i,0); + } + for(i=-l;i<=l;i++) unit_voro_apply(i,l,0); + for(i=1;i<l;i++) for(j=-l+1;j<=l;j++) { + unit_voro_apply(l,j,i); + unit_voro_apply(-j,l,i); + unit_voro_apply(-l,-j,i); + unit_voro_apply(j,-l,i); + } + for(i=-l;i<=l;i++) for(j=-l;j<=l;j++) unit_voro_apply(i,j,l); + } else { + + // Calculate a bound on the maximum y and z coordinates + // that could possibly cut the cell. This is based upon + // a geometric result that particles with z>l can't cut + // a cell lying within the paraboloid + // z<=(l*l-x*x-y*y)/(2*l). It is always a tighter bound + // than the one based on computing the maximum radius + // of a Voronoi cell vertex. + max_uv_y=max_uv_z=0; + double y,z,q,*pts=unit_voro.pts,*pp=pts; + while(pp<pts+3*unit_voro.p) { + q=*(pp++);y=*(pp++);z=*(pp++);q=sqrt(q*q+y*y+z*z); + if(y+q>max_uv_y) max_uv_y=y+q; + if(z+q>max_uv_z) max_uv_z=z+q; + } + max_uv_z*=0.5; + max_uv_y*=0.5; + return; + } + l++; + } + + // If the routine makes it here, then the unit cell still hasn't been + // completely bounded by the plane cuts. Give the memory error code, + // because this is mainly a case of hitting a safe limit, than any + // inherent problem. + voro_fatal_error("Periodic cell computation failed",VOROPP_MEMORY_ERROR); +} + +/** Applies a pair of opposing plane cuts from a periodic image point + * to the unit Voronoi cell. + * \param[in] (i,j,k) the index of the periodic image to consider. */ +inline void unitcell::unit_voro_apply(int i,int j,int k) { + double x=i*bx+j*bxy+k*bxz,y=j*by+k*byz,z=k*bz; + unit_voro.plane(x,y,z); + unit_voro.plane(-x,-y,-z); +} + +/** Calculates whether the unit Voronoi cell intersects a given periodic image + * of the domain. + * \param[in] (dx,dy,dz) the displacement of the periodic image. + * \param[out] vol the proportion of the unit cell volume within this image, + * only computed in the case that the two intersect. + * \return True if they intersect, false otherwise. */ +bool unitcell::intersects_image(double dx,double dy,double dz,double &vol) { + const double bxinv=1/bx,byinv=1/by,bzinv=1/bz,ivol=bxinv*byinv*bzinv; + voronoicell c; + c=unit_voro; + dx*=2;dy*=2;dz*=2; + if(!c.plane(0,0,bzinv,dz+1)) return false; + if(!c.plane(0,0,-bzinv,-dz+1)) return false; + if(!c.plane(0,byinv,-byz*byinv*bzinv,dy+1)) return false; + if(!c.plane(0,-byinv,byz*byinv*bzinv,-dy+1)) return false; + if(!c.plane(bxinv,-bxy*bxinv*byinv,(bxy*byz-by*bxz)*ivol,dx+1)) return false; + if(!c.plane(-bxinv,bxy*bxinv*byinv,(-bxy*byz+by*bxz)*ivol,-dx+1)) return false; + vol=c.volume()*ivol; + return true; +} + +/** Computes a list of periodic domain images that intersect the unit Voronoi cell. + * \param[out] vi a vector containing triplets (i,j,k) corresponding to domain + * images that intersect the unit Voronoi cell, when it is + * centered in the middle of the primary domain. + * \param[out] vd a vector containing the fraction of the Voronoi cell volume + * within each corresponding image listed in vi. */ +void unitcell::images(vector<int> &vi,vector<double> &vd) { + const int ms2=max_unit_voro_shells*2+1,mss=ms2*ms2*ms2; + bool *a=new bool[mss],*ac=a+max_unit_voro_shells*(1+ms2*(1+ms2)),*ap=a; + int i,j,k; + double vol; + + // Initialize mask + while(ap<ac) *(ap++)=true; + *(ap++)=false; + while(ap<a+mss) *(ap++)=true; + + // Set up the queue and add (0,0,0) image to it + queue<int> q; + q.push(0);q.push(0);q.push(0); + + while(!q.empty()) { + + // Read the next entry on the queue + i=q.front();q.pop(); + j=q.front();q.pop(); + k=q.front();q.pop(); + + // Check intersection of this image + if(intersects_image(i,j,k,vol)) { + + // Add this entry to the output vectors + vi.push_back(i); + vi.push_back(j); + vi.push_back(k); + vd.push_back(vol); + + // Add neighbors to the queue if they have not been + // tested + ap=ac+i+ms2*(j+ms2*k); + if(k>-max_unit_voro_shells&&*(ap-ms2*ms2)) {q.push(i);q.push(j);q.push(k-1);*(ap-ms2*ms2)=false;} + if(j>-max_unit_voro_shells&&*(ap-ms2)) {q.push(i);q.push(j-1);q.push(k);*(ap-ms2)=false;} + if(i>-max_unit_voro_shells&&*(ap-1)) {q.push(i-1);q.push(j);q.push(k);*(ap-1)=false;} + if(i<max_unit_voro_shells&&*(ap+1)) {q.push(i+1);q.push(j);q.push(k);*(ap+1)=false;} + if(j<max_unit_voro_shells&&*(ap+ms2)) {q.push(i);q.push(j+1);q.push(k);*(ap+ms2)=false;} + if(k<max_unit_voro_shells&&*(ap+ms2*ms2)) {q.push(i);q.push(j);q.push(k+1);*(ap+ms2*ms2)=false;} + } + } + + // Remove mask memory + delete [] a; +} + +/** Tests to see if a shell of periodic images could possibly cut the periodic + * unit cell. + * \param[in] l the index of the shell to consider. + * \return True if a point in the shell cuts the cell, false otherwise. */ +bool unitcell::unit_voro_intersect(int l) { + int i,j; + if(unit_voro_test(l,0,0)) return true; + for(i=1;i<l;i++) { + if(unit_voro_test(l,i,0)) return true; + if(unit_voro_test(-l,i,0)) return true; + } + for(i=-l;i<=l;i++) if(unit_voro_test(i,l,0)) return true; + for(i=1;i<l;i++) for(j=-l+1;j<=l;j++) { + if(unit_voro_test(l,j,i)) return true; + if(unit_voro_test(-j,l,i)) return true; + if(unit_voro_test(-l,-j,i)) return true; + if(unit_voro_test(j,-l,i)) return true; + } + for(i=-l;i<=l;i++) for(j=-l;j<=l;j++) if(unit_voro_test(i,j,l)) return true; + return false; +} + +/** Tests to see if a plane cut from a particular periodic image will cut th + * unit Voronoi cell. + * \param[in] (i,j,k) the index of the periodic image to consider. + * \return True if the image cuts the cell, false otherwise. */ +inline bool unitcell::unit_voro_test(int i,int j,int k) { + double x=i*bx+j*bxy+k*bxz,y=j*by+k*byz,z=k*bz; + double rsq=x*x+y*y+z*z; + return unit_voro.plane_intersects(x,y,z,rsq); +} + +/** Draws the periodic domain in gnuplot format. + * \param[in] fp the file handle to write to. */ +void unitcell::draw_domain_gnuplot(FILE *fp) { + fprintf(fp,"0 0 0\n%g 0 0\n%g %g 0\n%g %g 0\n",bx,bx+bxy,by,bxy,by); + fprintf(fp,"%g %g %g\n%g %g %g\n%g %g %g\n%g %g %g\n",bxy+bxz,by+byz,bz,bx+bxy+bxz,by+byz,bz,bx+bxz,byz,bz,bxz,byz,bz); + fprintf(fp,"0 0 0\n%g %g 0\n\n%g %g %g\n%g %g %g\n\n",bxy,by,bxz,byz,bz,bxy+bxz,by+byz,bz); + fprintf(fp,"%g 0 0\n%g %g %g\n\n%g %g 0\n%g %g %g\n\n",bx,bx+bxz,byz,bz,bx+bxy,by,bx+bxy+bxz,by+byz,bz); +} + +/** Draws the periodic domain in POV-Ray format. + * \param[in] fp the file handle to write to. */ +void unitcell::draw_domain_pov(FILE *fp) { + fprintf(fp,"cylinder{0,0,0>,<%g,0,0>,rr}\n" + "cylinder{<%g,%g,0>,<%g,%g,0>,rr}\n",bx,bxy,by,bx+bxy,by); + fprintf(fp,"cylinder{<%g,%g,%g>,<%g,%g,%g>,rr}\n" + "cylinder{<%g,%g,%g>,<%g,%g,%g>,rr}\n",bxz,byz,bz,bx+bxz,byz,bz,bxy+bxz,by+byz,bz,bx+bxy+bxz,by+byz,bz); + fprintf(fp,"cylinder{<0,0,0>,<%g,%g,0>,rr}\n" + "cylinder{<%g,0,0>,<%g,%g,0>,rr}\n",bxy,by,bx,bx+bxy,by); + fprintf(fp,"cylinder{<%g,%g,%g>,<%g,%g,%g>,rr}\n" + "cylinder{<%g,%g,%g>,<%g,%g,%g>,rr}\n",bxz,byz,bz,bxy+bxz,by+byz,bz,bx+bxz,byz,bz,bx+bxy+bxz,by+byz,bz); + fprintf(fp,"cylinder{<0,0,0>,<%g,%g,%g>,rr}\n" + "cylinder{<%g,0,0>,<%g,%g,%g>,rr}\n",bxz,byz,bz,bx,bx+bxz,byz,bz); + fprintf(fp,"cylinder{<%g,%g,0>,<%g,%g,%g>,rr}\n" + "cylinder{<%g,%g,0>,<%g,%g,%g>,rr}\n",bxy,by,bxy+bxz,by+byz,bz,bx+bxy,by,bx+bxy+bxz,by+byz,bz); + fprintf(fp,"sphere{<0,0,0>,rr}\nsphere{<%g,0,0>,rr}\n" + "sphere{<%g,%g,0>,rr}\nsphere{<%g,%g,0>,rr}\n",bx,bxy,by,bx+bxy,by); + fprintf(fp,"sphere{<%g,%g,%g>,rr}\nsphere{<%g,%g,%g>,rr}\n" + "sphere{<%g,%g,%g>,rr}\nsphere{<%g,%g,%g>,rr}\n",bxz,byz,bz,bx+bxz,byz,bz,bxy+bxz,by+byz,bz,bx+bxy+bxz,by+byz,bz); +} + +} diff --git a/contrib/voro++/src/unitcell.hh b/contrib/voro++/src/unitcell.hh new file mode 100644 index 0000000000000000000000000000000000000000..5c6785e369940ca31beac231e77c9d53f82272f6 --- /dev/null +++ b/contrib/voro++/src/unitcell.hh @@ -0,0 +1,80 @@ +// Voro++, a 3D cell-based Voronoi library +// +// Author : Chris H. Rycroft (LBL / UC Berkeley) +// Email : chr@alum.mit.edu +// Date : August 30th 2011 + +/** \file unitcell.hh + * \brief Header file for the unitcell class. */ + +#ifndef VOROPP_UNITCELL_HH +#define VOROPP_UNITCELL_HH + +#include <vector> +using namespace std; + +#include "config.hh" +#include "cell.hh" + +namespace voro { + +/** \brief Class for computation of the unit Voronoi cell associated with + * a 3D non-rectangular periodic domain. */ +class unitcell { + public: + /** The x coordinate of the first vector defining the periodic + * domain. */ + const double bx; + /** The x coordinate of the second vector defining the periodic + * domain. */ + const double bxy; + /** The y coordinate of the second vector defining the periodic + * domain. */ + const double by; + /** The x coordinate of the third vector defining the periodic + * domain. */ + const double bxz; + /** The y coordinate of the third vector defining the periodic + * domain. */ + const double byz; + /** The z coordinate of the third vector defining the periodic + * domain. */ + const double bz; + /** The computed unit Voronoi cell corresponding the given + * 3D non-rectangular periodic domain geometry. */ + voronoicell unit_voro; + unitcell(double bx_,double bxy_,double by_,double bxz_,double byz_,double bz_); + /** Draws an outline of the domain in Gnuplot format. + * \param[in] filename the filename to write to. */ + inline void draw_domain_gnuplot(const char* filename) { + FILE *fp(safe_fopen(filename,"w")); + draw_domain_gnuplot(fp); + fclose(fp); + } + void draw_domain_gnuplot(FILE *fp=stdout); + /** Draws an outline of the domain in Gnuplot format. + * \param[in] filename the filename to write to. */ + inline void draw_domain_pov(const char* filename) { + FILE *fp(safe_fopen(filename,"w")); + draw_domain_pov(fp); + fclose(fp); + } + void draw_domain_pov(FILE *fp=stdout); + bool intersects_image(double dx,double dy,double dz,double &vol); + void images(vector<int> &vi,vector<double> &vd); + protected: + /** The maximum y-coordinate that could possibly cut the + * computed unit Voronoi cell. */ + double max_uv_y; + /** The maximum z-coordinate that could possibly cut the + * computed unit Voronoi cell. */ + double max_uv_z; + private: + inline void unit_voro_apply(int i,int j,int k); + bool unit_voro_intersect(int l); + inline bool unit_voro_test(int i,int j,int k); +}; + +} + +#endif diff --git a/contrib/voro++/src/v_base.cc b/contrib/voro++/src/v_base.cc new file mode 100644 index 0000000000000000000000000000000000000000..56cb98ca0a06790edb36c1b20666f58364c478c5 --- /dev/null +++ b/contrib/voro++/src/v_base.cc @@ -0,0 +1,118 @@ +// Voro++, a 3D cell-based Voronoi library +// +// Author : Chris H. Rycroft (LBL / UC Berkeley) +// Email : chr@alum.mit.edu +// Date : August 30th 2011 + +/** \file v_base.cc + * \brief Function implementations for the base Voronoi container class. */ + +#include "v_base.hh" +#include "config.hh" + +namespace voro { + +/** This function is called during container construction. The routine scans + * all of the worklists in the wl[] array. For a given worklist of blocks + * labeled \f$w_1\f$ to \f$w_n\f$, it computes a sequence \f$r_0\f$ to + * \f$r_n\f$ so that $r_i$ is the minimum distance to all the blocks + * \f$w_{j}\f$ where \f$j>i\f$ and all blocks outside the worklist. The values + * of \f$r_n\f$ is calculated first, as the minimum distance to any block in + * the shell surrounding the worklist. The \f$r_i\f$ are then computed in + * reverse order by considering the distance to \f$w_{i+1}\f$. */ +voro_base::voro_base(int nx_,int ny_,int nz_,double boxx_,double boxy_,double boxz_) : + nx(nx_), ny(ny_), nz(nz_), nxy(nx_*ny_), nxyz(nxy*nz_), boxx(boxx_), boxy(boxy_), boxz(boxz_), + xsp(1/boxx_), ysp(1/boxy_), zsp(1/boxz_), mrad(new double[wl_hgridcu*wl_seq_length]) { + const unsigned int b1=1<<21,b2=1<<22,b3=1<<24,b4=1<<25,b5=1<<27,b6=1<<28; + const double xstep=boxx/wl_fgrid,ystep=boxy/wl_fgrid,zstep=boxz/wl_fgrid; + int i,j,k,lx,ly,lz,q; + unsigned int f,*e=const_cast<unsigned int*> (wl); + double xlo,ylo,zlo,xhi,yhi,zhi,minr,*radp=mrad; + for(zlo=0,zhi=zstep,lz=0;lz<wl_hgrid;zlo=zhi,zhi+=zstep,lz++) { + for(ylo=0,yhi=ystep,ly=0;ly<wl_hgrid;ylo=yhi,yhi+=ystep,ly++) { + for(xlo=0,xhi=xstep,lx=0;lx<wl_hgrid;xlo=xhi,xhi+=xstep,lx++) { + minr=large_number; + for(q=e[0]+1;q<wl_seq_length;q++) { + f=e[q]; + i=(f&127)-64; + j=(f>>7&127)-64; + k=(f>>14&127)-64; + if((f&b2)==b2) { + compute_minimum(minr,xlo,xhi,ylo,yhi,zlo,zhi,i-1,j,k); + if((f&b1)==0) compute_minimum(minr,xlo,xhi,ylo,yhi,zlo,zhi,i+1,j,k); + } else if((f&b1)==b1) compute_minimum(minr,xlo,xhi,ylo,yhi,zlo,zhi,i+1,j,k); + if((f&b4)==b4) { + compute_minimum(minr,xlo,xhi,ylo,yhi,zlo,zhi,i,j-1,k); + if((f&b3)==0) compute_minimum(minr,xlo,xhi,ylo,yhi,zlo,zhi,i,j+1,k); + } else if((f&b3)==b3) compute_minimum(minr,xlo,xhi,ylo,yhi,zlo,zhi,i,j+1,k); + if((f&b6)==b6) { + compute_minimum(minr,xlo,xhi,ylo,yhi,zlo,zhi,i,j,k-1); + if((f&b5)==0) compute_minimum(minr,xlo,xhi,ylo,yhi,zlo,zhi,i,j,k+1); + } else if((f&b5)==b5) compute_minimum(minr,xlo,xhi,ylo,yhi,zlo,zhi,i,j,k+1); + } + q--; + while(q>0) { + radp[q]=minr; + f=e[q]; + i=(f&127)-64; + j=(f>>7&127)-64; + k=(f>>14&127)-64; + compute_minimum(minr,xlo,xhi,ylo,yhi,zlo,zhi,i,j,k); + q--; + } + *radp=minr; + e+=wl_seq_length; + radp+=wl_seq_length; + } + } + } +} + +/** Computes the minimum distance from a subregion to a given block. If this distance + * is smaller than the value of minr, then it passes + * \param[in,out] minr a pointer to the current minimum distance. If the distance + * computed in this function is smaller, then this distance is + * set to the new one. + * \param[out] (xlo,ylo,zlo) the lower coordinates of the subregion being + * considered. + * \param[out] (xhi,yhi,zhi) the upper coordinates of the subregion being + * considered. + * \param[in] (ti,tj,tk) the coordinates of the block. */ +void voro_base::compute_minimum(double &minr,double &xlo,double &xhi,double &ylo,double &yhi,double &zlo,double &zhi,int ti,int tj,int tk) { + double radsq,temp; + if(ti>0) {temp=boxx*ti-xhi;radsq=temp*temp;} + else if(ti<0) {temp=xlo-boxx*(1+ti);radsq=temp*temp;} + else radsq=0; + + if(tj>0) {temp=boxy*tj-yhi;radsq+=temp*temp;} + else if(tj<0) {temp=ylo-boxy*(1+tj);radsq+=temp*temp;} + + if(tk>0) {temp=boxz*tk-zhi;radsq+=temp*temp;} + else if(tk<0) {temp=zlo-boxz*(1+tk);radsq+=temp*temp;} + + if(radsq<minr) minr=radsq; +} + +/** Checks to see whether "%n" appears in a format sequence to determine + * whether neighbor information is required or not. + * \param[in] format the format string to check. + * \return True if a "%n" is found, false otherwise. */ +bool voro_base::contains_neighbor(const char *format) { + char *fmp=(const_cast<char*>(format)); + + // Check to see if "%n" appears in the format sequence + while(*fmp!=0) { + if(*fmp=='%') { + fmp++; + if(*fmp=='n') return true; + else if(*fmp==0) return false; + } + fmp++; + } + + return false; +} + +#include "v_base_wl.cc" + +} diff --git a/contrib/voro++/src/v_base.hh b/contrib/voro++/src/v_base.hh new file mode 100644 index 0000000000000000000000000000000000000000..0436a75d824389e789f352c7d0791eb275049c2b --- /dev/null +++ b/contrib/voro++/src/v_base.hh @@ -0,0 +1,88 @@ +// Voro++, a 3D cell-based Voronoi library +// +// Author : Chris H. Rycroft (LBL / UC Berkeley) +// Email : chr@alum.mit.edu +// Date : August 30th 2011 + +/** \file v_base.hh + * \brief Header file for the base Voronoi container class. */ + +#ifndef VOROPP_V_BASE_HH +#define VOROPP_V_BASE_HH + +#include "worklist.hh" + +namespace voro { + +/** \brief Class containing data structures common across all particle container classes. + * + * This class contains constants and data structures that are common across all + * particle container classes. It contains constants setting the size of the + * underlying subgrid of blocks that forms the basis of the Voronoi cell + * computations. It also constructs bound tables that are used in the Voronoi + * cell computation, and contains a number of routines that are common across + * all container classes. */ +class voro_base { + public: + /** The number of blocks in the x direction. */ + const int nx; + /** The number of blocks in the y direction. */ + const int ny; + /** The number of blocks in the z direction. */ + const int nz; + /** A constant, set to the value of nx multiplied by ny, which + * is used in the routines that step through blocks in + * sequence. */ + const int nxy; + /** A constant, set to the value of nx*ny*nz, which is used in + * the routines that step through blocks in sequence. */ + const int nxyz; + /** The size of a computational block in the x direction. */ + const double boxx; + /** The size of a computational block in the y direction. */ + const double boxy; + /** The size of a computational block in the z direction. */ + const double boxz; + /** The inverse box length in the x direction. */ + const double xsp; + /** The inverse box length in the y direction. */ + const double ysp; + /** The inverse box length in the z direction. */ + const double zsp; + /** An array to hold the minimum distances associated with the + * worklists. This array is initialized during container + * construction, by the initialize_radii() routine. */ + double *mrad; + /** The pre-computed block worklists. */ + static const unsigned int wl[wl_seq_length*wl_hgridcu]; + bool contains_neighbor(const char* format); + voro_base(int nx_,int ny_,int nz_,double boxx_,double boxy_,double boxz_); + ~voro_base() {delete [] mrad;} + protected: + /** A custom int function that returns consistent stepping + * for negative numbers, so that (-1.5, -0.5, 0.5, 1.5) maps + * to (-2,-1,0,1). + * \param[in] a the number to consider. + * \return The value of the custom int operation. */ + inline int step_int(double a) {return a<0?int(a)-1:int(a);} + /** A custom modulo function that returns consistent stepping + * for negative numbers. For example, (-2,-1,0,1,2) step_mod 2 + * is (0,1,0,1,0). + * \param[in] (a,b) the input integers. + * \return The value of a modulo b, consistent for negative + * numbers. */ + inline int step_mod(int a,int b) {return a>=0?a%b:b-1-(b-1-a)%b;} + /** A custom integer division function that returns consistent + * stepping for negative numbers. For example, (-2,-1,0,1,2) + * step_div 2 is (-1,-1,0,0,1). + * \param[in] (a,b) the input integers. + * \return The value of a div b, consistent for negative + * numbers. */ + inline int step_div(int a,int b) {return a>=0?a/b:-1+(a+1)/b;} + private: + void compute_minimum(double &minr,double &xlo,double &xhi,double &ylo,double &yhi,double &zlo,double &zhi,int ti,int tj,int tk); +}; + +} + +#endif diff --git a/contrib/voro++/src/v_base_wl.cc b/contrib/voro++/src/v_base_wl.cc new file mode 100644 index 0000000000000000000000000000000000000000..85c6d533eb6f5c86af9c95f1d0d7f56d8f00edbf --- /dev/null +++ b/contrib/voro++/src/v_base_wl.cc @@ -0,0 +1,79 @@ +// Voro++, a 3D cell-based Voronoi library +// +// Author : Chris H. Rycroft (LBL / UC Berkeley) +// Email : chr@alum.mit.edu +// Date : August 30th 2011 + +/** \file v_base_wl.cc + * \brief The table of block worklists that are used during the cell + * computation, which is part of the voro_base class. + * + * This file is automatically generated by worklist_gen.pl and it is not + * intended to be edited by hand. */ + +const unsigned int voro_base::wl[wl_seq_length*wl_hgridcu]={ + 7,0x10203f,0x101fc0,0xfe040,0xfe03f,0x101fbf,0xfdfc0,0xfdfbf,0x10fe0bf,0x11020bf,0x11020c0,0x10fe0c0,0x2fe041,0x302041,0x301fc1,0x2fdfc1,0x8105fc0,0x8106040,0x810603f,0x8105fbf,0x701fbe,0x70203e,0x6fe03e,0x6fdfbe,0x30fdf3f,0x3101f3f,0x3101f40,0x30fdf40,0x180f9fc0,0x180fa040,0x180fa03f,0x180f9fbf,0x12fe0c1,0x13020c1,0x91060c0,0x91060bf,0x8306041,0x8305fc1,0x3301f41,0x32fdf41,0x182f9fc1,0x182fa041,0x190fa0c0,0x190fa0bf,0x16fe0be,0x17020be,0x870603e,0x8705fbe,0xb105f3f,0xb105f40,0x3701f3e,0x36fdf3e,0x186f9fbe,0x186fa03e,0x1b0f9f3f,0x1b0f9f40,0x93060c1,0x192fa0c1,0x97060be,0xb305f41,0x1b2f9f41,0x196fa0be,0xb705f3e,0x1b6f9f3e, + 11,0x101fc0,0xfe040,0xfdfc0,0x10203f,0x101fbf,0xfe03f,0xfdfbf,0xfdfc1,0x101fc1,0x102041,0xfe041,0x10fe0c0,0x11020c0,0x8106040,0x8105fc0,0x8105fbf,0x810603f,0x11020bf,0x10fe0bf,0x180fa040,0x180f9fc0,0x30fdf40,0x3101f40,0x3101f3f,0x30fdf3f,0x180f9fbf,0x180fa03f,0x6fe03e,0x70203e,0x701fbe,0x6fdfbe,0x8105fc1,0x8106041,0x11020c1,0x10fe0c1,0x180fa041,0x180f9fc1,0x30fdf41,0x3101f41,0x91060c0,0x91060bf,0x190fa0c0,0x190fa0bf,0xb105f40,0xb105f3f,0x8705fbe,0x870603e,0x97020be,0x16fe0be,0x1b0f9f40,0x1b0f9f3f,0x36fdf3e,0xb701f3e,0x1b6f9fbe,0x196fa03e,0x93060c1,0xb305f41,0x192fa0c1,0x1b2f9f41,0x1b2fdfc2,0xb301fc2,0x9302042,0x192fe042, + 11,0x101fc0,0xfe040,0xfdfc0,0xfdfbf,0x101fbf,0x10203f,0xfe03f,0xfe041,0x102041,0x101fc1,0xfdfc1,0x8105fc0,0x8106040,0x11020c0,0x10fe0c0,0x10fe0bf,0x11020bf,0x810603f,0x8105fbf,0x3101f40,0x30fdf40,0x180f9fc0,0x180fa040,0x180fa03f,0x180f9fbf,0x30fdf3f,0x3101f3f,0x8105fc1,0x8106041,0x11020c1,0x10fe0c1,0x180fa041,0x180f9fc1,0x30fdf41,0x3101f41,0x701fbe,0x70203e,0x6fe03e,0x6fdfbe,0x91060c0,0x91060bf,0xb105f40,0xb105f3f,0x190fa0c0,0x190fa0bf,0x93060c1,0x1b0f9f40,0x1b0f9f3f,0xb305f41,0x192fa0c1,0x16fe0be,0x17020be,0x970603e,0x8705fbe,0xb701f3e,0x36fdf3e,0x1b2f9f41,0x1b2fdfc2,0x192fe042,0x9302042,0xb301fc2,0x1b6f9fbe,0x196fa03e, + 11,0x101fc0,0xfe040,0xfdfc0,0xfdfbf,0x101fbf,0x10203f,0xfe03f,0xfe041,0x102041,0x101fc1,0xfdfc1,0x8105fc0,0x8106040,0x11020c0,0x10fe0c0,0x10fe0bf,0x11020bf,0x810603f,0x8105fbf,0x3101f40,0x30fdf40,0x180f9fc0,0x180fa040,0x10fe0c1,0x11020c1,0x8106041,0x8105fc1,0x3101f3f,0x30fdf3f,0x180f9fbf,0x180fa03f,0x180fa041,0x180f9fc1,0x30fdf41,0x3101f41,0x91060c0,0x91060bf,0x70203e,0x701fbe,0x6fdfbe,0x6fe03e,0x190fa0c0,0xb105f40,0xb105f3f,0x93060c1,0x190fa0bf,0x192fa0c1,0x1b0f9f40,0x1b0f9f3f,0xb305f41,0xb301fc2,0x9302042,0x192fe042,0x1b2fdfc2,0x1b2f9f41,0x16fe0be,0x17020be,0x970603e,0x8705fbe,0xb701f3e,0x36fdf3e,0x1b6f9fbe,0x196fa03e, + 11,0x10203f,0xfe040,0xfe03f,0x101fc0,0x101fbf,0xfdfc0,0xfdfbf,0xfe0bf,0x1020bf,0x1020c0,0xfe0c0,0x2fe041,0x302041,0x8106040,0x810603f,0x8105fbf,0x8105fc0,0x301fc1,0x2fdfc1,0x180fa040,0x180fa03f,0x6fe03e,0x70203e,0x701fbe,0x6fdfbe,0x180f9fbf,0x180f9fc0,0x30fdf40,0x3101f40,0x3101f3f,0x30fdf3f,0x81060bf,0x81060c0,0x3020c1,0x2fe0c1,0x180fa0c0,0x180fa0bf,0x6fe0be,0x7020be,0x8306041,0x8305fc1,0x182fa041,0x182f9fc1,0x870603e,0x8705fbe,0xb105f3f,0xb105f40,0xb301f41,0x32fdf41,0x186fa03e,0x186f9fbe,0x36fdf3e,0xb701f3e,0x1b6f9f3f,0x1b2f9f40,0x93060c1,0x97060be,0x192fa0c1,0x196fa0be,0x196fe13f,0x970213f,0x9302140,0x192fe140, + 9,0xfe040,0x10203f,0x101fc0,0xfdfc0,0xfe03f,0xfdfbf,0x101fbf,0x102041,0xfe041,0x10fe0c0,0x11020c0,0x11020bf,0x10fe0bf,0xfdfc1,0x101fc1,0x8106040,0x810603f,0x8105fc0,0x8105fbf,0x180fa040,0x180f9fc0,0x180fa03f,0x180f9fbf,0x10fe0c1,0x11020c1,0x70203e,0x6fe03e,0x6fdfbe,0x701fbe,0x3101f3f,0x3101f40,0x30fdf40,0x30fdf3f,0x8106041,0x91060c0,0x91060bf,0x8305fc1,0x180fa041,0x190fa0c0,0x190fa0bf,0x180f9fc1,0x30fdf41,0x3301f41,0x17020be,0x16fe0be,0x93060c1,0x870603e,0x8705fbe,0xb105f3f,0xb105f40,0x192fa0c1,0x1b0f9f40,0x1b0f9f3f,0x186f9fbe,0x196fa03e,0x1b6fdf3e,0xb701f3e,0x97060be,0xb305f41,0x1b2f9f41,0x1b2fdfc2,0x192fe042,0xa302042, + 11,0xfe040,0x101fc0,0xfdfc0,0xfe03f,0x10203f,0x101fbf,0xfdfbf,0xfe041,0x102041,0x101fc1,0xfdfc1,0x10fe0c0,0x11020c0,0x11020bf,0x10fe0bf,0x8106040,0x8105fc0,0x810603f,0x8105fbf,0x11020c1,0x10fe0c1,0x180fa040,0x180f9fc0,0x180fa03f,0x180f9fbf,0x30fdf40,0x3101f40,0x8106041,0x8105fc1,0x3101f3f,0x30fdf3f,0x91060c0,0x91060bf,0x180fa041,0x180f9fc1,0x6fe03e,0x70203e,0x701fbe,0x6fdfbe,0x190fa0c0,0x190fa0bf,0x30fdf41,0x3101f41,0x93060c1,0x192fa0c1,0xb105f40,0xb105f3f,0x17020be,0x16fe0be,0x970603e,0x8705fbe,0x1b0f9f40,0x1b0f9f3f,0x186f9fbe,0x196fa03e,0xb305f41,0xb301fc2,0x9302042,0x192fe042,0x1b2fdfc2,0x1b2f9f41,0x1b6fdf3e,0xb701f3e, + 11,0xfe040,0x101fc0,0xfdfc0,0xfe03f,0x10203f,0x101fbf,0xfdfbf,0xfe041,0x102041,0x101fc1,0xfdfc1,0x10fe0c0,0x11020c0,0x11020bf,0x10fe0bf,0x8106040,0x8105fc0,0x11020c1,0x10fe0c1,0x810603f,0x8105fbf,0x180fa040,0x180f9fc0,0x8106041,0x8105fc1,0x3101f40,0x180fa03f,0x180f9fbf,0x30fdf40,0x180fa041,0x180f9fc1,0x91060c0,0x3101f3f,0x30fdf3f,0x30fdf41,0x3101f41,0x91060bf,0x190fa0c0,0x91060c1,0x190fa0bf,0x186fe03e,0x70203e,0x3701fbe,0x1b6fdfbe,0x190fa0c1,0x182fe042,0xb105f40,0xb105f3f,0x302042,0x3301fc2,0x1b2fdfc2,0x1b0f9f40,0x1b6f9f3f,0xb105f41,0x17020be,0x196fe0be,0x970603e,0xb705fbe,0x1b2f9f41,0x192fe0c2,0x13020c2,0x9306042,0xb305fc2, + 11,0x10203f,0xfe040,0xfe03f,0xfdfbf,0x101fbf,0x101fc0,0xfdfc0,0xfe0c0,0x1020c0,0x1020bf,0xfe0bf,0x810603f,0x8106040,0x302041,0x2fe041,0x2fdfc1,0x301fc1,0x8105fc0,0x8105fbf,0x70203e,0x6fe03e,0x180fa03f,0x180fa040,0x180f9fc0,0x180f9fbf,0x6fdfbe,0x701fbe,0x81060bf,0x81060c0,0x3020c1,0x2fe0c1,0x180fa0c0,0x180fa0bf,0x6fe0be,0x7020be,0x3101f3f,0x3101f40,0x30fdf40,0x30fdf3f,0x8306041,0x8305fc1,0x870603e,0x8705fbe,0x182fa041,0x182f9fc1,0x93060c1,0x186fa03e,0x186f9fbe,0x97060be,0x192fa0c1,0x32fdf41,0x3301f41,0xb305f40,0xb105f3f,0xb701f3e,0x36fdf3e,0x196fa0be,0x196fe13f,0x192fe140,0x9302140,0x970213f,0x1b6f9f3f,0x1b2f9f40, + 11,0xfe040,0x10203f,0xfe03f,0xfdfc0,0x101fc0,0x101fbf,0xfdfbf,0xfe0c0,0x1020c0,0x1020bf,0xfe0bf,0x2fe041,0x302041,0x301fc1,0x2fdfc1,0x8106040,0x810603f,0x8105fc0,0x8105fbf,0x3020c1,0x2fe0c1,0x180fa040,0x180fa03f,0x180f9fc0,0x180f9fbf,0x6fe03e,0x70203e,0x81060c0,0x81060bf,0x701fbe,0x6fdfbe,0x8306041,0x8305fc1,0x180fa0c0,0x180fa0bf,0x30fdf40,0x3101f40,0x3101f3f,0x30fdf3f,0x182fa041,0x182f9fc1,0x6fe0be,0x7020be,0x93060c1,0x192fa0c1,0x870603e,0x8705fbe,0x3301f41,0x32fdf41,0xb305f40,0xb105f3f,0x186fa03e,0x186f9fbe,0x1b0f9f3f,0x1b2f9f40,0x97060be,0x970213f,0x9302140,0x192fe140,0x196fe13f,0x196fa0be,0x1b6fdf3e,0xb701f3e, + 15,0xfe040,0xfe03f,0x10203f,0x101fc0,0xfdfc0,0xfdfbf,0x101fbf,0x102041,0xfe041,0xfe0c0,0x1020c0,0x1020bf,0xfe0bf,0xfdfc1,0x101fc1,0x8106040,0x1020c1,0xfe0c1,0x810603f,0x8105fc0,0x8105fbf,0x180fa040,0x180fa03f,0x180f9fc0,0x180f9fbf,0x8106041,0x81060c0,0x81060bf,0x8105fc1,0x180fa041,0x180fa0c0,0x180fa0bf,0x6fe03e,0x70203e,0x3101f40,0x30fdf40,0x180f9fc1,0x30fdf3f,0x3101f3f,0x3701fbe,0x36fdfbe,0x93060c1,0x192fa0c1,0x6fe0be,0x7020be,0x3101f41,0x30fdf41,0xb305f40,0xb105f3f,0x970603e,0xb705fbe,0x196fa03e,0x186f9fbe,0x1b2f9f40,0x1b6f9f3f,0x192fe042,0x9302042,0xb301fc2,0x1b2fdfc2,0x192fe140,0x9302140,0x970213f,0x196fe13f, + 15,0xfe040,0xfdfc0,0x101fc0,0x10203f,0xfe03f,0xfdfbf,0x101fbf,0x102041,0xfe041,0xfdfc1,0x101fc1,0x1020c0,0xfe0c0,0xfe0bf,0x1020bf,0x1020c1,0xfe0c1,0x8106040,0x8105fc0,0x810603f,0x8105fbf,0x180fa040,0x180f9fc0,0x8106041,0x8105fc1,0x81060c0,0x180fa03f,0x180f9fbf,0x180fa041,0x180f9fc1,0x180fa0c0,0x81060bf,0x91060c1,0x3101f40,0x30fdf40,0x30fdf3f,0x180fa0bf,0x190fa0c1,0x3101f3f,0x3101f41,0x30fdf41,0x186fe03e,0x70203e,0x3701fbe,0x1b6fdfbe,0x186fe0be,0x7020be,0x8302042,0x182fe042,0x1b2fdfc2,0xb301fc2,0xb105f40,0xb705f3f,0xb305f41,0x1b2f9f40,0x1b6f9f3f,0x192fe140,0x9302140,0x93020c2,0x192fe0c2,0x196fe13f,0x970213f,0xa70603e, + 11,0x10203f,0xfe040,0xfe03f,0xfdfbf,0x101fbf,0x101fc0,0xfdfc0,0xfe0c0,0x1020c0,0x1020bf,0xfe0bf,0x810603f,0x8106040,0x302041,0x2fe041,0x2fdfc1,0x301fc1,0x8105fc0,0x8105fbf,0x70203e,0x6fe03e,0x180fa03f,0x180fa040,0x2fe0c1,0x3020c1,0x81060c0,0x81060bf,0x701fbe,0x6fdfbe,0x180f9fbf,0x180f9fc0,0x180fa0c0,0x180fa0bf,0x6fe0be,0x7020be,0x8306041,0x8305fc1,0x3101f40,0x3101f3f,0x30fdf3f,0x30fdf40,0x182fa041,0x870603e,0x8705fbe,0x93060c1,0x182f9fc1,0x192fa0c1,0x186fa03e,0x186f9fbe,0x97060be,0x970213f,0x9302140,0x192fe140,0x196fe13f,0x196fa0be,0x32fdf41,0x3301f41,0xb305f40,0xb105f3f,0xb701f3e,0x36fdf3e,0x1b6f9f3f,0x1b2f9f40, + 11,0xfe040,0x10203f,0xfe03f,0xfdfc0,0x101fc0,0x101fbf,0xfdfbf,0xfe0c0,0x1020c0,0x1020bf,0xfe0bf,0x2fe041,0x302041,0x301fc1,0x2fdfc1,0x8106040,0x810603f,0x3020c1,0x2fe0c1,0x8105fc0,0x8105fbf,0x180fa040,0x180fa03f,0x81060c0,0x81060bf,0x70203e,0x180f9fc0,0x180f9fbf,0x6fe03e,0x180fa0c0,0x180fa0bf,0x8306041,0x701fbe,0x6fdfbe,0x6fe0be,0x7020be,0x8305fc1,0x182fa041,0x83060c1,0x182f9fc1,0x1b0fdf40,0x3101f40,0x3701f3f,0x1b6fdf3f,0x182fa0c1,0x190fe140,0x870603e,0x8705fbe,0x1102140,0x170213f,0x196fe13f,0x186fa03e,0x1b6f9fbe,0x87060be,0x3301f41,0x1b2fdf41,0xb305f40,0xb705f3f,0x196fa0be,0x192fe141,0x1302141,0x9306140,0x970613f, + 15,0xfe040,0xfe03f,0x10203f,0x101fc0,0xfdfc0,0xfdfbf,0x101fbf,0x1020c0,0xfe0c0,0xfe0bf,0x1020bf,0x102041,0xfe041,0xfdfc1,0x101fc1,0x1020c1,0xfe0c1,0x8106040,0x810603f,0x8105fc0,0x8105fbf,0x180fa040,0x180fa03f,0x81060c0,0x81060bf,0x8106041,0x180f9fc0,0x180f9fbf,0x180fa0c0,0x180fa0bf,0x180fa041,0x8105fc1,0x83060c1,0x70203e,0x6fe03e,0x6fdfbe,0x180f9fc1,0x182fa0c1,0x701fbe,0x7020be,0x6fe0be,0x1b0fdf40,0x3101f40,0x3701f3f,0x1b6fdf3f,0x1b0fdf41,0x3101f41,0x9102140,0x190fe140,0x196fe13f,0x970213f,0x870603e,0xb705fbe,0x97060be,0x196fa03e,0x1b6f9fbe,0x192fe042,0x9302042,0x9302141,0x192fe141,0x1b2fdfc2,0xb301fc2,0xb505f40, + 17,0xfe040,0xfe03f,0x10203f,0x101fc0,0xfdfc0,0xfe041,0x102041,0x1020c0,0xfe0c0,0xfdfbf,0x101fbf,0x1020bf,0xfe0bf,0xfdfc1,0x101fc1,0x1020c1,0xfe0c1,0x8106040,0x810603f,0x8105fc0,0x8106041,0x81060c0,0x180fa040,0x180fa03f,0x180f9fc0,0x8105fbf,0x81060bf,0x8105fc1,0x180fa041,0x180fa0c0,0x180f9fbf,0x81060c1,0x180fa0bf,0x180f9fc1,0x180fa0c1,0x186fe03e,0x70203e,0x3101f40,0x1b0fdf40,0x1b0fdf3f,0x3101f3f,0x3701fbe,0x1b6fdfbe,0x186fe0be,0x7020be,0x9102140,0x190fe140,0x182fe042,0x8302042,0x3101f41,0x1b0fdf41,0x1b2fdfc2,0xb301fc2,0x83020c2,0x182fe0c2,0x196fe13f,0x970213f,0x9302141,0x192fe141,0x970603e,0xb305f40,0xb105f3f,0xb705fbe, + 11,0x10203f,0x101fc0,0x101fbf,0xfe040,0xfe03f,0xfdfc0,0xfdfbf,0x105fbf,0x10603f,0x106040,0x105fc0,0x301fc1,0x302041,0x11020c0,0x11020bf,0x10fe0bf,0x10fe0c0,0x2fe041,0x2fdfc1,0x3101f40,0x3101f3f,0x701fbe,0x70203e,0x6fe03e,0x6fdfbe,0x30fdf3f,0x30fdf40,0x180f9fc0,0x180fa040,0x180fa03f,0x180f9fbf,0x11060bf,0x11060c0,0x306041,0x305fc1,0x3105f40,0x3105f3f,0x705fbe,0x70603e,0x13020c1,0x12fe0c1,0x3301f41,0x32fdf41,0x17020be,0x16fe0be,0x190fa0bf,0x190fa0c0,0x192fa041,0x182f9fc1,0x3701f3e,0x36fdf3e,0x186f9fbe,0x196fa03e,0x1b6f9f3f,0x1b2f9f40,0x93060c1,0x97060be,0xb305f41,0xb705f3e,0xb709fbf,0x970a03f,0x930a040,0xb309fc0, + 9,0x101fc0,0x10203f,0xfe040,0xfdfc0,0x101fbf,0xfdfbf,0xfe03f,0x102041,0x101fc1,0x8105fc0,0x8106040,0x810603f,0x8105fbf,0xfdfc1,0xfe041,0x11020c0,0x11020bf,0x10fe0c0,0x10fe0bf,0x3101f40,0x30fdf40,0x3101f3f,0x30fdf3f,0x8105fc1,0x8106041,0x70203e,0x701fbe,0x6fdfbe,0x6fe03e,0x180fa03f,0x180fa040,0x180f9fc0,0x180f9fbf,0x11020c1,0x91060c0,0x91060bf,0x12fe0c1,0x3101f41,0xb105f40,0xb105f3f,0x30fdf41,0x180f9fc1,0x182fa041,0x870603e,0x8705fbe,0x93060c1,0x17020be,0x16fe0be,0x190fa0bf,0x190fa0c0,0xb305f41,0x1b0f9f40,0x1b0f9f3f,0x36fdf3e,0xb701f3e,0x1b6f9fbe,0x196fa03e,0x97060be,0x192fa0c1,0x1b2f9f41,0x1b2fdfc2,0xb301fc2,0x11302042, + 11,0x101fc0,0xfe040,0xfdfc0,0x101fbf,0x10203f,0xfe03f,0xfdfbf,0x101fc1,0x102041,0xfe041,0xfdfc1,0x8105fc0,0x8106040,0x810603f,0x8105fbf,0x11020c0,0x10fe0c0,0x11020bf,0x10fe0bf,0x8106041,0x8105fc1,0x3101f40,0x30fdf40,0x3101f3f,0x30fdf3f,0x180f9fc0,0x180fa040,0x11020c1,0x10fe0c1,0x180fa03f,0x180f9fbf,0x91060c0,0x91060bf,0x3101f41,0x30fdf41,0x701fbe,0x70203e,0x6fe03e,0x6fdfbe,0xb105f40,0xb105f3f,0x180f9fc1,0x180fa041,0x93060c1,0xb305f41,0x190fa0c0,0x190fa0bf,0x870603e,0x8705fbe,0x97020be,0x16fe0be,0x1b0f9f40,0x1b0f9f3f,0x36fdf3e,0xb701f3e,0x192fa0c1,0x192fe042,0x9302042,0xb301fc2,0x1b2fdfc2,0x1b2f9f41,0x1b6f9fbe,0x196fa03e, + 11,0x101fc0,0xfe040,0xfdfc0,0x101fbf,0x10203f,0xfe03f,0xfdfbf,0x101fc1,0x102041,0xfe041,0xfdfc1,0x8105fc0,0x8106040,0x810603f,0x8105fbf,0x11020c0,0x10fe0c0,0x8106041,0x8105fc1,0x11020bf,0x10fe0bf,0x3101f40,0x30fdf40,0x11020c1,0x10fe0c1,0x180fa040,0x3101f3f,0x30fdf3f,0x180f9fc0,0x3101f41,0x30fdf41,0x91060c0,0x180fa03f,0x180f9fbf,0x180f9fc1,0x180fa041,0x91060bf,0xb105f40,0x91060c1,0xb105f3f,0x3701fbe,0x70203e,0x186fe03e,0x1b6fdfbe,0xb105f41,0x3301fc2,0x190fa0c0,0x190fa0bf,0x302042,0x182fe042,0x1b2fdfc2,0x1b0f9f40,0x1b6f9f3f,0x190fa0c1,0x870603e,0xb705fbe,0x97020be,0x196fe0be,0x1b2f9f41,0xb305fc2,0x8306042,0x93020c2,0x192fe0c2, + 9,0x10203f,0x101fc0,0xfe040,0xfe03f,0x101fbf,0xfdfbf,0xfdfc0,0x1020c0,0x1020bf,0x810603f,0x8106040,0x8105fc0,0x8105fbf,0xfe0bf,0xfe0c0,0x302041,0x301fc1,0x2fe041,0x2fdfc1,0x70203e,0x6fe03e,0x701fbe,0x6fdfbe,0x81060bf,0x81060c0,0x3101f40,0x3101f3f,0x30fdf3f,0x30fdf40,0x180f9fc0,0x180fa040,0x180fa03f,0x180f9fbf,0x3020c1,0x8306041,0x8305fc1,0x12fe0c1,0x7020be,0x870603e,0x8705fbe,0x6fe0be,0x180fa0bf,0x190fa0c0,0xb105f40,0xb105f3f,0x93060c1,0x3301f41,0x32fdf41,0x182f9fc1,0x182fa041,0x97060be,0x186fa03e,0x186f9fbe,0x36fdf3e,0xb701f3e,0x1b6f9f3f,0x1b2f9f40,0xb305f41,0x192fa0c1,0x196fa0be,0x196fe13f,0x970213f,0x11302140, + 7,0x10203f,0x101fc0,0xfe040,0xfe03f,0x101fbf,0xfdfc0,0xfdfbf,0x302041,0x1020c0,0x8106040,0x810603f,0x1020bf,0xfe0c0,0x2fe041,0x301fc1,0x8105fc0,0x8105fbf,0xfe0bf,0x2fdfc1,0x3020c1,0x8306041,0x81060c0,0x81060bf,0x2fe0c1,0x8305fc1,0x3101f40,0x3101f3f,0x701fbe,0x70203e,0x6fe03e,0x180fa03f,0x180fa040,0x180f9fc0,0x30fdf40,0x30fdf3f,0x6fdfbe,0x180f9fbf,0x180fa0c0,0x182fa041,0x93060c1,0x870603e,0x7020be,0x6fe0be,0x180fa0bf,0x182f9fc1,0x32fdf41,0x3301f41,0xb105f40,0xb105f3f,0x8705fbe,0x97060be,0x192fa0c1,0xb305f41,0xb701f3e,0x36fdf3e,0x1b0f9f3f,0x1b2f9f40,0x1b6f9fbe,0x196fa03e,0x196fe13f,0x9302140,0x970213f,0x192fe140, + 11,0x101fc0,0xfe040,0xfdfc0,0x10203f,0x101fbf,0xfe03f,0xfdfbf,0x102041,0x101fc1,0xfe041,0xfdfc1,0x11020c0,0x8106040,0x8105fc0,0x10fe0c0,0x11020bf,0x810603f,0x8105fbf,0x10fe0bf,0x11020c1,0x8106041,0x8105fc1,0x10fe0c1,0x91060c0,0x91060bf,0x3101f40,0x30fdf40,0x180f9fc0,0x180fa040,0x180fa03f,0x180f9fbf,0x30fdf3f,0x3101f3f,0x701fbe,0x70203e,0x6fe03e,0x6fdfbe,0x93060c1,0x3101f41,0x30fdf41,0x180f9fc1,0x180fa041,0x190fa0c0,0x190fa0bf,0xb105f40,0xb105f3f,0x8705fbe,0x870603e,0x17020be,0x16fe0be,0x192fa0c1,0xb305f41,0xb301fc2,0x9302042,0x192fe042,0x1b2fdfc2,0x1b2f9f40,0x1b0f9f3f,0x186f9fbe,0x196fa03e,0x97060be,0xb701f3e,0x1b6fdf3e, + 11,0x101fc0,0xfe040,0xfdfc0,0x10203f,0x101fbf,0xfe03f,0xfdfbf,0x102041,0x101fc1,0xfe041,0xfdfc1,0x11020c0,0x8106040,0x8105fc0,0x10fe0c0,0x11020bf,0x810603f,0x8105fbf,0x10fe0bf,0x11020c1,0x8106041,0x8105fc1,0x10fe0c1,0x91060c0,0x91060bf,0x3101f40,0x30fdf40,0x180f9fc0,0x180fa040,0x180fa03f,0x180f9fbf,0x30fdf3f,0x3101f3f,0x3101f41,0x91060c1,0x180fa041,0x180f9fc1,0x30fdf41,0xb105f40,0x70203e,0x3701fbe,0x186fe03e,0x1b6fdfbe,0x190fa0c0,0x190fa0bf,0x190fa0c1,0xb105f3f,0xb105f41,0x3301fc2,0x302042,0x182fe042,0x1b2fdfc2,0x1b0f9f40,0x17020be,0x970603e,0xb705fbe,0x196fe0be,0x1b6f9f3f,0x1b2f9f41,0x13020c2,0x9306042,0xb305fc2,0x192fe0c2, + 11,0x10203f,0xfe040,0xfe03f,0x101fbf,0x101fc0,0xfdfc0,0xfdfbf,0x1020bf,0x1020c0,0xfe0c0,0xfe0bf,0x810603f,0x8106040,0x8105fc0,0x8105fbf,0x302041,0x2fe041,0x301fc1,0x2fdfc1,0x81060c0,0x81060bf,0x70203e,0x6fe03e,0x701fbe,0x6fdfbe,0x180fa03f,0x180fa040,0x3020c1,0x2fe0c1,0x180f9fc0,0x180f9fbf,0x8306041,0x8305fc1,0x7020be,0x6fe0be,0x3101f3f,0x3101f40,0x30fdf40,0x30fdf3f,0x870603e,0x8705fbe,0x180fa0bf,0x180fa0c0,0x93060c1,0x97060be,0x182fa041,0x182f9fc1,0xb105f40,0xb105f3f,0xb301f41,0x32fdf41,0x186fa03e,0x186f9fbe,0x36fdf3e,0xb701f3e,0x192fa0c1,0x192fe140,0x9302140,0x970213f,0x196fe13f,0x196fa0be,0x1b6f9f3f,0x1b2f9f40, + 11,0x10203f,0xfe040,0xfe03f,0x101fc0,0x101fbf,0xfdfc0,0xfdfbf,0x1020c0,0x1020bf,0xfe0c0,0xfe0bf,0x302041,0x8106040,0x810603f,0x2fe041,0x301fc1,0x8105fc0,0x8105fbf,0x2fdfc1,0x3020c1,0x81060c0,0x81060bf,0x2fe0c1,0x8306041,0x8305fc1,0x70203e,0x6fe03e,0x180fa03f,0x180fa040,0x180f9fc0,0x180f9fbf,0x6fdfbe,0x701fbe,0x3101f3f,0x3101f40,0x30fdf40,0x30fdf3f,0x93060c1,0x7020be,0x6fe0be,0x180fa0bf,0x180fa0c0,0x182fa041,0x182f9fc1,0x870603e,0x8705fbe,0xb105f3f,0xb105f40,0x3301f41,0x32fdf41,0x192fa0c1,0x97060be,0x970213f,0x9302140,0x192fe140,0x196fe13f,0x196fa03e,0x186f9fbe,0x1b0f9f3f,0x1b2f9f40,0xb305f41,0xb701f3e,0x1b6fdf3e, + 15,0xfe040,0x10203f,0x101fc0,0xfdfc0,0xfe03f,0x101fbf,0xfdfbf,0x102041,0x1020c0,0xfe0c0,0xfe041,0x101fc1,0xfdfc1,0x1020bf,0xfe0bf,0x8106040,0x810603f,0x8105fc0,0x8105fbf,0x1020c1,0xfe0c1,0x8106041,0x81060c0,0x81060bf,0x8105fc1,0x180fa040,0x180f9fc0,0x180fa03f,0x180f9fbf,0x93060c1,0x70203e,0x6fe03e,0x3101f40,0x1b0fdf40,0x3101f3f,0x3701fbe,0x6fdfbe,0x1b6fdf3f,0x180fa041,0x180fa0c0,0x180fa0bf,0x180f9fc1,0x1b0fdf41,0x3101f41,0x7020be,0x6fe0be,0x870603e,0x8705fbe,0xb105f40,0xb705f3f,0x192fa0c1,0x192fe140,0x9302140,0x970213f,0x97060be,0x9302042,0x192fe042,0xb301fc2,0xb305f41,0x1b2fdfc2,0x196fe13f,0x196fa03e,0x1b6f9fbe, + 14,0xfe040,0x101fc0,0xfdfc0,0x10203f,0xfe03f,0x101fbf,0xfdfbf,0x102041,0xfe041,0x101fc1,0xfdfc1,0x1020c0,0xfe0c0,0x1020bf,0x8106040,0xfe0bf,0x8105fc0,0x1020c1,0xfe0c1,0x810603f,0x8105fbf,0x8106041,0x8105fc1,0x81060c0,0x81060bf,0x91060c1,0x180fa040,0x180f9fc0,0x180fa03f,0x180f9fbf,0x180fa041,0x180f9fc1,0x1b0fdf40,0x3101f40,0x3101f3f,0x1b0fdf3f,0x180fa0c0,0x190fa0bf,0x186fe03e,0x70203e,0x3701fbe,0x3101f41,0x1b0fdf41,0x1b6fdfbe,0x190fa0c1,0x182fe042,0x302042,0xb105f40,0xb105f3f,0x3301fc2,0x1b2fdfc2,0x7020be,0x196fe0be,0x970603e,0xb705fbe,0xb105f41,0x9302140,0x192fe140,0x13020c2,0x192fe0c2,0x9306042,0xb305fc2,0x1170213f, + 11,0x10203f,0xfe040,0xfe03f,0x101fbf,0x101fc0,0xfdfc0,0xfdfbf,0x1020bf,0x1020c0,0xfe0c0,0xfe0bf,0x810603f,0x8106040,0x8105fc0,0x8105fbf,0x302041,0x2fe041,0x81060c0,0x81060bf,0x301fc1,0x2fdfc1,0x70203e,0x6fe03e,0x3020c1,0x2fe0c1,0x180fa040,0x701fbe,0x6fdfbe,0x180fa03f,0x7020be,0x6fe0be,0x8306041,0x180f9fc0,0x180f9fbf,0x180fa0bf,0x180fa0c0,0x8305fc1,0x870603e,0x83060c1,0x8705fbe,0x3701f3f,0x3101f40,0x1b0fdf40,0x1b6fdf3f,0x87060be,0x170213f,0x182fa041,0x182f9fc1,0x1102140,0x190fe140,0x196fe13f,0x186fa03e,0x1b6f9fbe,0x182fa0c1,0xb105f40,0xb705f3f,0xb301f41,0x1b2fdf41,0x196fa0be,0x970613f,0x9106140,0x9302141,0x192fe141, + 11,0x10203f,0xfe040,0xfe03f,0x101fc0,0x101fbf,0xfdfc0,0xfdfbf,0x1020c0,0x1020bf,0xfe0c0,0xfe0bf,0x302041,0x8106040,0x810603f,0x2fe041,0x301fc1,0x8105fc0,0x8105fbf,0x2fdfc1,0x3020c1,0x81060c0,0x81060bf,0x2fe0c1,0x8306041,0x8305fc1,0x70203e,0x6fe03e,0x180fa03f,0x180fa040,0x180f9fc0,0x180f9fbf,0x6fdfbe,0x701fbe,0x7020be,0x83060c1,0x180fa0c0,0x180fa0bf,0x6fe0be,0x870603e,0x3101f40,0x3701f3f,0x1b0fdf40,0x1b6fdf3f,0x182fa041,0x182f9fc1,0x182fa0c1,0x8705fbe,0x87060be,0x170213f,0x1102140,0x190fe140,0x196fe13f,0x186fa03e,0x3301f41,0xb305f40,0xb705f3f,0x1b2fdf41,0x1b6f9fbe,0x196fa0be,0x1302141,0x9306140,0x970613f,0x192fe141, + 14,0xfe040,0x10203f,0xfe03f,0x101fc0,0xfdfc0,0x101fbf,0xfdfbf,0x1020c0,0xfe0c0,0x1020bf,0xfe0bf,0x102041,0xfe041,0x101fc1,0x8106040,0xfdfc1,0x810603f,0x1020c1,0xfe0c1,0x8105fc0,0x8105fbf,0x81060c0,0x81060bf,0x8106041,0x8105fc1,0x83060c1,0x180fa040,0x180fa03f,0x180f9fc0,0x180f9fbf,0x180fa0c0,0x180fa0bf,0x186fe03e,0x70203e,0x701fbe,0x186fdfbe,0x180fa041,0x182f9fc1,0x1b0fdf40,0x3101f40,0x3701f3f,0x7020be,0x186fe0be,0x1b6fdf3f,0x182fa0c1,0x190fe140,0x1102140,0x870603e,0x8705fbe,0x170213f,0x196fe13f,0x3101f41,0x1b2fdf41,0xb305f40,0xb705f3f,0x87060be,0x9302042,0x192fe042,0x1302141,0x192fe141,0x9306140,0x970613f,0x13301fc2, + 17,0xfe040,0x10203f,0x101fc0,0xfdfc0,0xfe03f,0x1020c0,0x102041,0xfe041,0xfe0c0,0x101fbf,0xfdfbf,0x1020bf,0xfe0bf,0x101fc1,0xfdfc1,0x1020c1,0xfe0c1,0x8106040,0x810603f,0x8105fc0,0x8106041,0x81060c0,0x8105fbf,0x81060bf,0x8105fc1,0x81060c1,0x180fa040,0x180f9fc0,0x180fa03f,0x180fa0c0,0x180fa041,0x180f9fbf,0x180fa0bf,0x180f9fc1,0x180fa0c1,0x70203e,0x186fe03e,0x3101f40,0x1b0fdf40,0x3101f3f,0x3701fbe,0x186fdfbe,0x1b6fdf3f,0x3101f41,0x1b0fdf41,0x8302042,0x182fe042,0x9102140,0x7020be,0x186fe0be,0x190fe140,0x970213f,0x196fe13f,0x9102141,0xb301fc2,0x1b2fdfc2,0x93020c2,0x182fe0c2,0x192fe141,0x970603e,0xb305f40,0xb105f3f,0xb705fbe, + 11,0x10203f,0x101fc0,0x101fbf,0xfdfbf,0xfe03f,0xfe040,0xfdfc0,0x105fc0,0x106040,0x10603f,0x105fbf,0x11020bf,0x11020c0,0x302041,0x301fc1,0x2fdfc1,0x2fe041,0x10fe0c0,0x10fe0bf,0x70203e,0x701fbe,0x3101f3f,0x3101f40,0x30fdf40,0x30fdf3f,0x6fdfbe,0x6fe03e,0x11060bf,0x11060c0,0x306041,0x305fc1,0x3105f40,0x3105f3f,0x705fbe,0x70603e,0x180fa03f,0x180fa040,0x180f9fc0,0x180f9fbf,0x13020c1,0x12fe0c1,0x17020be,0x16fe0be,0x3301f41,0x32fdf41,0x93060c1,0x3701f3e,0x36fdf3e,0x97060be,0xb305f41,0x182f9fc1,0x182fa041,0x192fa0c0,0x190fa0bf,0x196fa03e,0x186f9fbe,0xb705f3e,0xb709fbf,0xb309fc0,0x930a040,0x970a03f,0x1b6f9f3f,0x1b2f9f40, + 11,0x101fc0,0x10203f,0x101fbf,0xfdfc0,0xfe040,0xfe03f,0xfdfbf,0x105fc0,0x106040,0x10603f,0x105fbf,0x301fc1,0x302041,0x2fe041,0x2fdfc1,0x11020c0,0x11020bf,0x10fe0c0,0x10fe0bf,0x306041,0x305fc1,0x3101f40,0x3101f3f,0x30fdf40,0x30fdf3f,0x701fbe,0x70203e,0x11060c0,0x11060bf,0x6fe03e,0x6fdfbe,0x13020c1,0x12fe0c1,0x3105f40,0x3105f3f,0x180f9fc0,0x180fa040,0x180fa03f,0x180f9fbf,0x3301f41,0x32fdf41,0x705fbe,0x70603e,0x93060c1,0xb305f41,0x17020be,0x16fe0be,0x182fa041,0x182f9fc1,0x192fa0c0,0x190fa0bf,0x3701f3e,0x36fdf3e,0x1b0f9f3f,0x1b2f9f40,0x97060be,0x970a03f,0x930a040,0xb309fc0,0xb709fbf,0xb705f3e,0x1b6f9fbe,0x196fa03e, + 15,0x101fc0,0x101fbf,0x10203f,0xfe040,0xfdfc0,0xfdfbf,0xfe03f,0x102041,0x101fc1,0x105fc0,0x106040,0x10603f,0x105fbf,0xfdfc1,0xfe041,0x11020c0,0x106041,0x105fc1,0x11020bf,0x10fe0c0,0x10fe0bf,0x3101f40,0x3101f3f,0x30fdf40,0x30fdf3f,0x11020c1,0x11060c0,0x11060bf,0x10fe0c1,0x3101f41,0x3105f40,0x3105f3f,0x701fbe,0x70203e,0x180fa040,0x180f9fc0,0x30fdf41,0x180f9fbf,0x180fa03f,0x186fe03e,0x186fdfbe,0x93060c1,0xb305f41,0x705fbe,0x70603e,0x180fa041,0x180f9fc1,0x192fa0c0,0x190fa0bf,0x97020be,0x196fe0be,0xb701f3e,0x36fdf3e,0x1b2f9f40,0x1b6f9f3f,0xb301fc2,0x9302042,0x192fe042,0x1b2fdfc2,0xb309fc0,0x930a040,0x970a03f,0xb709fbf, + 15,0x101fc0,0xfdfc0,0xfe040,0x10203f,0x101fbf,0xfdfbf,0xfe03f,0x102041,0x101fc1,0xfdfc1,0xfe041,0x106040,0x105fc0,0x105fbf,0x10603f,0x106041,0x105fc1,0x11020c0,0x10fe0c0,0x11020bf,0x10fe0bf,0x3101f40,0x30fdf40,0x11020c1,0x10fe0c1,0x11060c0,0x3101f3f,0x30fdf3f,0x3101f41,0x30fdf41,0x3105f40,0x11060bf,0x91060c1,0x180fa040,0x180f9fc0,0x180f9fbf,0x3105f3f,0xb105f41,0x180fa03f,0x180fa041,0x180f9fc1,0x3701fbe,0x70203e,0x186fe03e,0x1b6fdfbe,0x3705fbe,0x70603e,0x1302042,0x3301fc2,0x1b2fdfc2,0x192fe042,0x190fa0c0,0x196fa0bf,0x192fa0c1,0x1b2f9f40,0x1b6f9f3f,0xb309fc0,0x930a040,0x9306042,0xb305fc2,0xb709fbf,0x970a03f,0x117020be, + 11,0x10203f,0x101fc0,0x101fbf,0xfe03f,0xfe040,0xfdfc0,0xfdfbf,0x10603f,0x106040,0x105fc0,0x105fbf,0x11020bf,0x11020c0,0x10fe0c0,0x10fe0bf,0x302041,0x301fc1,0x2fe041,0x2fdfc1,0x11060c0,0x11060bf,0x70203e,0x701fbe,0x6fe03e,0x6fdfbe,0x3101f3f,0x3101f40,0x306041,0x305fc1,0x30fdf40,0x30fdf3f,0x13020c1,0x12fe0c1,0x70603e,0x705fbe,0x180fa03f,0x180fa040,0x180f9fc0,0x180f9fbf,0x17020be,0x16fe0be,0x3105f3f,0x3105f40,0x93060c1,0x97060be,0x3301f41,0x32fdf41,0x190fa0c0,0x190fa0bf,0x192fa041,0x182f9fc1,0x3701f3e,0x36fdf3e,0x186f9fbe,0x196fa03e,0xb305f41,0xb309fc0,0x930a040,0x970a03f,0xb709fbf,0xb705f3e,0x1b6f9f3f,0x1b2f9f40, + 11,0x10203f,0x101fc0,0x101fbf,0xfe040,0xfe03f,0xfdfc0,0xfdfbf,0x106040,0x10603f,0x105fc0,0x105fbf,0x302041,0x11020c0,0x11020bf,0x301fc1,0x2fe041,0x10fe0c0,0x10fe0bf,0x2fdfc1,0x306041,0x11060c0,0x11060bf,0x305fc1,0x13020c1,0x12fe0c1,0x70203e,0x701fbe,0x3101f3f,0x3101f40,0x30fdf40,0x30fdf3f,0x6fdfbe,0x6fe03e,0x180fa03f,0x180fa040,0x180f9fc0,0x180f9fbf,0x93060c1,0x70603e,0x705fbe,0x3105f3f,0x3105f40,0x3301f41,0x32fdf41,0x17020be,0x16fe0be,0x190fa0bf,0x190fa0c0,0x182fa041,0x182f9fc1,0xb305f41,0x97060be,0x970a03f,0x930a040,0xb309fc0,0xb709fbf,0xb701f3e,0x36fdf3e,0x1b0f9f3f,0x1b2f9f40,0x192fa0c1,0x196fa03e,0x1b6f9fbe, + 15,0x101fc0,0x10203f,0xfe040,0xfdfc0,0x101fbf,0xfe03f,0xfdfbf,0x102041,0x106040,0x105fc0,0x101fc1,0xfe041,0xfdfc1,0x10603f,0x105fbf,0x11020c0,0x11020bf,0x10fe0c0,0x10fe0bf,0x106041,0x105fc1,0x11020c1,0x11060c0,0x11060bf,0x10fe0c1,0x3101f40,0x30fdf40,0x3101f3f,0x30fdf3f,0x93060c1,0x70203e,0x701fbe,0x180fa040,0x1b0f9fc0,0x180fa03f,0x186fe03e,0x6fdfbe,0x1b6f9fbf,0x3101f41,0x3105f40,0x3105f3f,0x30fdf41,0x1b0f9fc1,0x180fa041,0x70603e,0x705fbe,0x17020be,0x16fe0be,0x190fa0c0,0x196fa0bf,0xb305f41,0xb309fc0,0x930a040,0x970a03f,0x97060be,0x9302042,0xb301fc2,0x192fe042,0x192fa0c1,0x1b2fdfc2,0xb709fbf,0xb701f3e,0x1b6fdf3e, + 14,0x101fc0,0xfe040,0xfdfc0,0x10203f,0x101fbf,0xfe03f,0xfdfbf,0x102041,0x101fc1,0xfe041,0xfdfc1,0x106040,0x105fc0,0x10603f,0x11020c0,0x105fbf,0x10fe0c0,0x106041,0x105fc1,0x11020bf,0x10fe0bf,0x11020c1,0x10fe0c1,0x11060c0,0x11060bf,0x91060c1,0x3101f40,0x30fdf40,0x3101f3f,0x30fdf3f,0x3101f41,0x30fdf41,0x1b0f9fc0,0x180fa040,0x180fa03f,0x1b0f9fbf,0x3105f40,0xb105f3f,0x3701fbe,0x70203e,0x186fe03e,0x180fa041,0x1b0f9fc1,0x1b6fdfbe,0xb105f41,0x3301fc2,0x302042,0x190fa0c0,0x190fa0bf,0x182fe042,0x1b2fdfc2,0x70603e,0xb705fbe,0x97020be,0x196fe0be,0x190fa0c1,0x930a040,0xb309fc0,0x8306042,0xb305fc2,0x93020c2,0x192fe0c2,0xa70a03f, + 15,0x10203f,0x101fbf,0x101fc0,0xfe040,0xfe03f,0xfdfbf,0xfdfc0,0x1020c0,0x1020bf,0x10603f,0x106040,0x105fc0,0x105fbf,0xfe0bf,0xfe0c0,0x302041,0x1060c0,0x1060bf,0x301fc1,0x2fe041,0x2fdfc1,0x70203e,0x701fbe,0x6fe03e,0x6fdfbe,0x3020c1,0x306041,0x305fc1,0x2fe0c1,0x7020be,0x70603e,0x705fbe,0x3101f3f,0x3101f40,0x180fa040,0x180fa03f,0x6fe0be,0x180f9fbf,0x180f9fc0,0x1b0fdf40,0x1b0fdf3f,0x93060c1,0x97060be,0x3105f3f,0x3105f40,0x180fa0c0,0x180fa0bf,0x192fa041,0x182f9fc1,0xb301f41,0x1b2fdf41,0xb701f3e,0x36fdf3e,0x196fa03e,0x1b6f9fbe,0x970213f,0x9302140,0x192fe140,0x196fe13f,0x970a03f,0x930a040,0xb309fc0,0xb709fbf, + 15,0x10203f,0x101fc0,0xfe040,0xfe03f,0x101fbf,0xfdfc0,0xfdfbf,0x1020c0,0x106040,0x10603f,0x1020bf,0xfe0c0,0xfe0bf,0x105fc0,0x105fbf,0x302041,0x301fc1,0x2fe041,0x2fdfc1,0x1060c0,0x1060bf,0x3020c1,0x306041,0x305fc1,0x2fe0c1,0x70203e,0x6fe03e,0x701fbe,0x6fdfbe,0x93060c1,0x3101f40,0x3101f3f,0x180fa040,0x186fa03f,0x180f9fc0,0x1b0fdf40,0x30fdf3f,0x1b6f9fbf,0x7020be,0x70603e,0x705fbe,0x6fe0be,0x186fa0bf,0x180fa0c0,0x3105f40,0x3105f3f,0x3301f41,0x32fdf41,0x182fa041,0x1b2f9fc1,0x97060be,0x970a03f,0x930a040,0xb309fc0,0xb305f41,0x9302140,0x970213f,0x192fe140,0x192fa0c1,0x196fe13f,0xb709fbf,0xb701f3e,0x1b6fdf3e, + 16,0x10203f,0x101fc0,0xfe040,0xfe03f,0x101fbf,0xfdfc0,0xfdfbf,0x102041,0x1020c0,0x106040,0x10603f,0x1020bf,0xfe0c0,0xfe041,0x101fc1,0x105fc0,0x105fbf,0xfe0bf,0xfdfc1,0x1020c1,0x106041,0x1060c0,0x1060bf,0xfe0c1,0x105fc1,0x93060c1,0x70203e,0x3101f40,0x180fa040,0x180fa03f,0x186fe03e,0x701fbe,0x3701f3f,0x30fdf40,0x1b0f9fc0,0x180f9fbf,0x186fdfbe,0x1b6fdf3f,0x3101f41,0x3105f40,0xb105f3f,0x70603e,0x7020be,0x6fe0be,0x180fa0c0,0x180fa041,0x182f9fc1,0x1b2fdf41,0xb705fbe,0x186fa0bf,0x192fa0c1,0x97060be,0xb305f41,0x9302042,0x192fe042,0x13301fc2,0x930a040,0x970a03f,0xb509fc0,0x9302140,0x970213f,0x192fe140,0x196fe13f, + 15,0x101fc0,0xfe040,0xfdfc0,0x10203f,0x101fbf,0xfe03f,0x102041,0x101fc1,0xfdfbf,0xfe041,0x1020c0,0x106040,0xfdfc1,0x105fc0,0xfe0c0,0x1020bf,0x10603f,0x105fbf,0xfe0bf,0x1020c1,0x106041,0x105fc1,0xfe0c1,0x1060c0,0x11060bf,0x91060c1,0x3101f40,0x180fa040,0x180f9fc0,0x1b0fdf40,0x3101f3f,0x30fdf3f,0x180fa03f,0x1b0f9fbf,0x180fa041,0x180f9fc1,0x3101f41,0x1b0fdf41,0x70203e,0x3701fbe,0x186fe03e,0x1b6fdfbe,0x3105f40,0xb105f3f,0x180fa0c0,0x190fa0bf,0x192fa0c1,0x302042,0x3301fc2,0xb305f41,0x182fe042,0x1b2fdfc2,0x17020be,0x170603e,0xb705fbe,0x196fe0be,0x9502140,0x194fe140,0x193020c2,0xa306042,0x930a040,0xb309fc0,0xa70a03f, + 15,0x10203f,0xfe03f,0xfe040,0x101fc0,0x101fbf,0xfdfbf,0xfdfc0,0x1020c0,0x1020bf,0xfe0bf,0xfe0c0,0x106040,0x10603f,0x105fbf,0x105fc0,0x1060c0,0x1060bf,0x302041,0x2fe041,0x301fc1,0x2fdfc1,0x70203e,0x6fe03e,0x3020c1,0x2fe0c1,0x306041,0x701fbe,0x6fdfbe,0x7020be,0x6fe0be,0x70603e,0x305fc1,0x83060c1,0x180fa040,0x180fa03f,0x180f9fbf,0x705fbe,0x87060be,0x180f9fc0,0x180fa0c0,0x180fa0bf,0x3701f3f,0x3101f40,0x1b0fdf40,0x1b6fdf3f,0x3705f3f,0x3105f40,0x1302140,0x170213f,0x196fe13f,0x192fe140,0x182fa041,0x1b2f9fc1,0x192fa0c1,0x196fa03e,0x1b6f9fbe,0x970a03f,0x930a040,0x9306140,0x970613f,0xb709fbf,0xb309fc0,0x13301f41, + 14,0x10203f,0xfe040,0xfe03f,0x101fc0,0x101fbf,0xfdfc0,0xfdfbf,0x1020c0,0x1020bf,0xfe0c0,0xfe0bf,0x106040,0x10603f,0x105fc0,0x302041,0x105fbf,0x2fe041,0x1060c0,0x1060bf,0x301fc1,0x2fdfc1,0x3020c1,0x2fe0c1,0x306041,0x305fc1,0x83060c1,0x70203e,0x6fe03e,0x701fbe,0x6fdfbe,0x7020be,0x6fe0be,0x186fa03f,0x180fa040,0x180f9fc0,0x186f9fbf,0x70603e,0x8705fbe,0x3701f3f,0x3101f40,0x1b0fdf40,0x180fa0c0,0x186fa0bf,0x1b6fdf3f,0x87060be,0x170213f,0x1102140,0x182fa041,0x182f9fc1,0x190fe140,0x196fe13f,0x3105f40,0xb705f3f,0xb301f41,0x1b2fdf41,0x182fa0c1,0x930a040,0x970a03f,0x9106140,0x970613f,0x9302141,0x192fe141,0xb509fc0, + 15,0x10203f,0xfe040,0xfe03f,0x101fc0,0x101fbf,0xfdfc0,0x1020c0,0x1020bf,0xfdfbf,0xfe0c0,0x102041,0x106040,0xfe0bf,0x10603f,0xfe041,0x101fc1,0x105fc0,0x105fbf,0xfdfc1,0x1020c1,0x1060c0,0x1060bf,0xfe0c1,0x106041,0x305fc1,0x83060c1,0x70203e,0x180fa040,0x180fa03f,0x186fe03e,0x701fbe,0x6fdfbe,0x180f9fc0,0x186f9fbf,0x180fa0c0,0x180fa0bf,0x7020be,0x186fe0be,0x3101f40,0x3701f3f,0x1b0fdf40,0x1b6fdf3f,0x70603e,0x8705fbe,0x180fa041,0x182f9fc1,0x192fa0c1,0x1102140,0x170213f,0x97060be,0x190fe140,0x196fe13f,0x3301f41,0x3305f40,0xb705f3f,0x1b2fdf41,0xa302042,0x1a2fe042,0x19302141,0x9506140,0x930a040,0x970a03f,0xb509fc0, + 17,0xfe040,0x10203f,0x101fc0,0xfdfc0,0xfe03f,0x1020c0,0x102041,0x101fbf,0xfe041,0xfe0c0,0x106040,0xfdfbf,0x1020bf,0x101fc1,0xfdfc1,0xfe0bf,0x1020c1,0x10603f,0x105fc0,0xfe0c1,0x1060c0,0x106041,0x8105fbf,0x81060bf,0x8105fc1,0x81060c1,0x180fa040,0x180f9fc0,0x180fa03f,0x180fa0c0,0x180fa041,0x180f9fbf,0x70203e,0x186fe03e,0x3101f40,0x1b0fdf40,0x180f9fc1,0x180fa0bf,0x701fbe,0x3701f3f,0x1b0fdf3f,0x1b6fdfbe,0x7020be,0x186fe0be,0x192fa0c1,0x9102140,0x190fe140,0x8302042,0x3101f41,0x1b0fdf41,0x182fe042,0xb301fc2,0xb305f40,0x870603e,0x970213f,0x196fe13f,0x11102141,0x113020c2,0x1b2fdfc2,0xb105f3f,0xb705fbe,0x97060be,0xa50a040, + 11,0x10203f,0x101fc0,0x101fbf,0xfdfbf,0xfe03f,0xfe040,0xfdfc0,0x105fc0,0x106040,0x10603f,0x105fbf,0x11020bf,0x11020c0,0x302041,0x301fc1,0x2fdfc1,0x2fe041,0x10fe0c0,0x10fe0bf,0x70203e,0x701fbe,0x3101f3f,0x3101f40,0x305fc1,0x306041,0x11060c0,0x11060bf,0x6fe03e,0x6fdfbe,0x30fdf3f,0x30fdf40,0x3105f40,0x3105f3f,0x705fbe,0x70603e,0x13020c1,0x12fe0c1,0x180fa040,0x180fa03f,0x180f9fbf,0x180f9fc0,0x3301f41,0x17020be,0x16fe0be,0x93060c1,0x32fdf41,0xb305f41,0x3701f3e,0x36fdf3e,0x97060be,0x970a03f,0x930a040,0xb309fc0,0xb709fbf,0xb705f3e,0x182f9fc1,0x182fa041,0x192fa0c0,0x190fa0bf,0x196fa03e,0x186f9fbe,0x1b6f9f3f,0x1b2f9f40, + 11,0x101fc0,0x10203f,0x101fbf,0xfdfc0,0xfe040,0xfe03f,0xfdfbf,0x105fc0,0x106040,0x10603f,0x105fbf,0x301fc1,0x302041,0x2fe041,0x2fdfc1,0x11020c0,0x11020bf,0x306041,0x305fc1,0x10fe0c0,0x10fe0bf,0x3101f40,0x3101f3f,0x11060c0,0x11060bf,0x70203e,0x30fdf40,0x30fdf3f,0x701fbe,0x3105f40,0x3105f3f,0x13020c1,0x6fe03e,0x6fdfbe,0x705fbe,0x70603e,0x12fe0c1,0x3301f41,0x13060c1,0x32fdf41,0x1b0f9fc0,0x180fa040,0x186fa03f,0x1b6f9fbf,0x3305f41,0xb109fc0,0x17020be,0x16fe0be,0x810a040,0x870a03f,0xb709fbf,0x3701f3e,0x1b6fdf3e,0x17060be,0x182fa041,0x1b2f9fc1,0x192fa0c0,0x196fa0bf,0xb705f3e,0xb309fc1,0x830a041,0x930a0c0,0x970a0bf, + 15,0x101fc0,0x101fbf,0x10203f,0xfe040,0xfdfc0,0xfdfbf,0xfe03f,0x106040,0x105fc0,0x105fbf,0x10603f,0x102041,0x101fc1,0xfdfc1,0xfe041,0x106041,0x105fc1,0x11020c0,0x11020bf,0x10fe0c0,0x10fe0bf,0x3101f40,0x3101f3f,0x11060c0,0x11060bf,0x11020c1,0x30fdf40,0x30fdf3f,0x3105f40,0x3105f3f,0x3101f41,0x10fe0c1,0x13060c1,0x70203e,0x701fbe,0x6fdfbe,0x30fdf41,0x3305f41,0x6fe03e,0x70603e,0x705fbe,0x1b0f9fc0,0x180fa040,0x186fa03f,0x1b6f9fbf,0x1b0f9fc1,0x180fa041,0x910a040,0xb109fc0,0xb709fbf,0x970a03f,0x17020be,0x196fe0be,0x97060be,0xb701f3e,0x1b6fdf3e,0xb301fc2,0x9302042,0x930a041,0xb309fc1,0x1b2fdfc2,0x192fe042,0x194fa0c0, + 17,0x101fc0,0x101fbf,0x10203f,0xfe040,0xfdfc0,0x101fc1,0x102041,0x106040,0x105fc0,0xfdfbf,0xfe03f,0x10603f,0x105fbf,0xfdfc1,0xfe041,0x106041,0x105fc1,0x11020c0,0x11020bf,0x10fe0c0,0x11020c1,0x11060c0,0x3101f40,0x3101f3f,0x30fdf40,0x10fe0bf,0x11060bf,0x10fe0c1,0x3101f41,0x3105f40,0x30fdf3f,0x11060c1,0x3105f3f,0x30fdf41,0x3105f41,0x3701fbe,0x70203e,0x180fa040,0x1b0f9fc0,0x1b0f9fbf,0x180fa03f,0x186fe03e,0x1b6fdfbe,0x3705fbe,0x70603e,0x910a040,0xb109fc0,0x3301fc2,0x1302042,0x180fa041,0x1b0f9fc1,0x1b2fdfc2,0x192fe042,0x1306042,0x3305fc2,0xb709fbf,0x970a03f,0x930a041,0xb309fc1,0x97020be,0x192fa0c0,0x190fa0bf,0x196fe0be, + 11,0x10203f,0x101fc0,0x101fbf,0xfe03f,0xfe040,0xfdfc0,0xfdfbf,0x10603f,0x106040,0x105fc0,0x105fbf,0x11020bf,0x11020c0,0x10fe0c0,0x10fe0bf,0x302041,0x301fc1,0x11060c0,0x11060bf,0x2fe041,0x2fdfc1,0x70203e,0x701fbe,0x306041,0x305fc1,0x3101f40,0x6fe03e,0x6fdfbe,0x3101f3f,0x70603e,0x705fbe,0x13020c1,0x30fdf40,0x30fdf3f,0x3105f3f,0x3105f40,0x12fe0c1,0x17020be,0x13060c1,0x16fe0be,0x186fa03f,0x180fa040,0x1b0f9fc0,0x1b6f9fbf,0x17060be,0x870a03f,0x3301f41,0x32fdf41,0x810a040,0xb109fc0,0xb709fbf,0x3701f3e,0x1b6fdf3e,0x3305f41,0x190fa0c0,0x196fa0bf,0x192fa041,0x1b2f9fc1,0xb705f3e,0x970a0bf,0x910a0c0,0x930a041,0xb309fc1, + 11,0x10203f,0x101fc0,0x101fbf,0xfe040,0xfe03f,0xfdfc0,0xfdfbf,0x106040,0x10603f,0x105fc0,0x105fbf,0x302041,0x11020c0,0x11020bf,0x301fc1,0x2fe041,0x10fe0c0,0x10fe0bf,0x2fdfc1,0x306041,0x11060c0,0x11060bf,0x305fc1,0x13020c1,0x12fe0c1,0x70203e,0x701fbe,0x3101f3f,0x3101f40,0x30fdf40,0x30fdf3f,0x6fdfbe,0x6fe03e,0x70603e,0x13060c1,0x3105f40,0x3105f3f,0x705fbe,0x17020be,0x180fa040,0x186fa03f,0x1b0f9fc0,0x1b6f9fbf,0x3301f41,0x32fdf41,0x3305f41,0x16fe0be,0x17060be,0x870a03f,0x810a040,0xb109fc0,0xb709fbf,0x3701f3e,0x182fa041,0x192fa0c0,0x196fa0bf,0x1b2f9fc1,0x1b6fdf3e,0xb705f3e,0x830a041,0x930a0c0,0x970a0bf,0xb309fc1, + 14,0x101fc0,0x10203f,0x101fbf,0xfe040,0xfdfc0,0xfe03f,0xfdfbf,0x106040,0x105fc0,0x10603f,0x105fbf,0x102041,0x101fc1,0xfe041,0x11020c0,0xfdfc1,0x11020bf,0x106041,0x105fc1,0x10fe0c0,0x10fe0bf,0x11060c0,0x11060bf,0x11020c1,0x10fe0c1,0x13060c1,0x3101f40,0x3101f3f,0x30fdf40,0x30fdf3f,0x3105f40,0x3105f3f,0x3701fbe,0x70203e,0x6fe03e,0x36fdfbe,0x3101f41,0x32fdf41,0x1b0f9fc0,0x180fa040,0x186fa03f,0x70603e,0x3705fbe,0x1b6f9fbf,0x3305f41,0xb109fc0,0x810a040,0x17020be,0x16fe0be,0x870a03f,0xb709fbf,0x180fa041,0x1b2f9fc1,0x192fa0c0,0x196fa0bf,0x17060be,0x9302042,0xb301fc2,0x830a041,0xb309fc1,0x930a0c0,0x970a0bf,0x1a2fe042, + 17,0x101fc0,0x10203f,0xfe040,0xfdfc0,0x101fbf,0x106040,0x102041,0x101fc1,0x105fc0,0xfe03f,0xfdfbf,0x10603f,0x105fbf,0xfe041,0xfdfc1,0x106041,0x105fc1,0x11020c0,0x11020bf,0x10fe0c0,0x11020c1,0x11060c0,0x10fe0bf,0x11060bf,0x10fe0c1,0x11060c1,0x3101f40,0x30fdf40,0x3101f3f,0x3105f40,0x3101f41,0x30fdf3f,0x3105f3f,0x30fdf41,0x3105f41,0x70203e,0x3701fbe,0x180fa040,0x1b0f9fc0,0x180fa03f,0x186fe03e,0x36fdfbe,0x1b6f9fbf,0x180fa041,0x1b0f9fc1,0x1302042,0x3301fc2,0x910a040,0x70603e,0x3705fbe,0xb109fc0,0x970a03f,0xb709fbf,0x910a041,0x192fe042,0x1b2fdfc2,0x9306042,0x3305fc2,0xb309fc1,0x97020be,0x192fa0c0,0x190fa0bf,0x196fe0be, + 15,0x10203f,0x101fbf,0x101fc0,0xfe040,0xfe03f,0xfdfbf,0xfdfc0,0x106040,0x10603f,0x105fbf,0x105fc0,0x1020c0,0x1020bf,0xfe0bf,0xfe0c0,0x1060c0,0x1060bf,0x302041,0x301fc1,0x2fe041,0x2fdfc1,0x70203e,0x701fbe,0x306041,0x305fc1,0x3020c1,0x6fe03e,0x6fdfbe,0x70603e,0x705fbe,0x7020be,0x2fe0c1,0x13060c1,0x3101f40,0x3101f3f,0x30fdf3f,0x6fe0be,0x17060be,0x30fdf40,0x3105f40,0x3105f3f,0x186fa03f,0x180fa040,0x1b0f9fc0,0x1b6f9fbf,0x186fa0bf,0x180fa0c0,0x830a040,0x870a03f,0xb709fbf,0xb309fc0,0x3301f41,0x1b2fdf41,0xb305f41,0xb701f3e,0x1b6fdf3e,0x970213f,0x9302140,0x930a0c0,0x970a0bf,0x196fe13f,0x192fe140,0x1a2fa041, + 14,0x10203f,0x101fc0,0x101fbf,0xfe040,0xfe03f,0xfdfc0,0xfdfbf,0x106040,0x10603f,0x105fc0,0x105fbf,0x1020c0,0x1020bf,0xfe0c0,0x302041,0xfe0bf,0x301fc1,0x1060c0,0x1060bf,0x2fe041,0x2fdfc1,0x306041,0x305fc1,0x3020c1,0x2fe0c1,0x13060c1,0x70203e,0x701fbe,0x6fe03e,0x6fdfbe,0x70603e,0x705fbe,0x3701f3f,0x3101f40,0x30fdf40,0x36fdf3f,0x7020be,0x16fe0be,0x186fa03f,0x180fa040,0x1b0f9fc0,0x3105f40,0x3705f3f,0x1b6f9fbf,0x17060be,0x870a03f,0x810a040,0x3301f41,0x32fdf41,0xb109fc0,0xb709fbf,0x180fa0c0,0x196fa0bf,0x192fa041,0x1b2f9fc1,0x3305f41,0x9302140,0x970213f,0x910a0c0,0x970a0bf,0x930a041,0xb309fc1,0x194fe140, + 15,0x10203f,0x101fc0,0x101fbf,0xfe040,0xfe03f,0xfdfc0,0x106040,0x10603f,0xfdfbf,0x105fc0,0x102041,0x1020c0,0x105fbf,0x1020bf,0x101fc1,0xfe041,0xfe0c0,0xfe0bf,0xfdfc1,0x106041,0x1060c0,0x1060bf,0x105fc1,0x1020c1,0x2fe0c1,0x13060c1,0x70203e,0x3101f40,0x3101f3f,0x3701fbe,0x6fe03e,0x6fdfbe,0x30fdf40,0x36fdf3f,0x3105f40,0x3105f3f,0x70603e,0x3705fbe,0x180fa040,0x186fa03f,0x1b0f9fc0,0x1b6f9fbf,0x7020be,0x16fe0be,0x3101f41,0x32fdf41,0xb305f41,0x810a040,0x870a03f,0x97060be,0xb109fc0,0xb709fbf,0x182fa041,0x182fa0c0,0x196fa0bf,0x1b2f9fc1,0x11302042,0x13301fc2,0xb30a041,0x950a0c0,0x9302140,0x970213f,0x194fe140, + 17,0x101fc0,0x10203f,0xfe040,0xfdfc0,0x101fbf,0x106040,0x102041,0xfe03f,0x101fc1,0x105fc0,0x1020c0,0xfdfbf,0x10603f,0xfe041,0xfdfc1,0x105fbf,0x106041,0x1020bf,0xfe0c0,0x105fc1,0x1060c0,0x1020c1,0x10fe0bf,0x11060bf,0x10fe0c1,0x11060c1,0x3101f40,0x30fdf40,0x3101f3f,0x3105f40,0x3101f41,0x30fdf3f,0x70203e,0x3701fbe,0x180fa040,0x1b0f9fc0,0x30fdf41,0x3105f3f,0x6fe03e,0x186fa03f,0x1b0f9fbf,0x1b6fdfbe,0x70603e,0x3705fbe,0xb305f41,0x910a040,0xb109fc0,0x1302042,0x180fa041,0x1b0f9fc1,0x3301fc2,0x192fe042,0x192fa0c0,0x17020be,0x970a03f,0xb709fbf,0xa10a041,0xa306042,0x1b2fdfc2,0x190fa0bf,0x196fe0be,0x97060be,0x11502140, + 17,0x10203f,0x101fbf,0x101fc0,0xfe040,0xfe03f,0x1020bf,0x1020c0,0x106040,0x10603f,0xfdfbf,0xfdfc0,0x105fc0,0x105fbf,0xfe0bf,0xfe0c0,0x1060c0,0x1060bf,0x302041,0x301fc1,0x2fe041,0x3020c1,0x306041,0x70203e,0x701fbe,0x6fe03e,0x2fdfc1,0x305fc1,0x2fe0c1,0x7020be,0x70603e,0x6fdfbe,0x3060c1,0x705fbe,0x6fe0be,0x7060be,0x3701f3f,0x3101f40,0x180fa040,0x186fa03f,0x186f9fbf,0x180f9fc0,0x1b0fdf40,0x1b6fdf3f,0x3705f3f,0x3105f40,0x830a040,0x870a03f,0x170213f,0x1302140,0x180fa0c0,0x186fa0bf,0x196fe13f,0x192fe140,0x1306140,0x170613f,0xb709fbf,0xb309fc0,0x930a0c0,0x970a0bf,0xb301f41,0x192fa041,0x182f9fc1,0x1b2fdf41, + 17,0x10203f,0x101fc0,0xfe040,0xfe03f,0x101fbf,0x106040,0x1020c0,0x1020bf,0x10603f,0xfdfc0,0xfdfbf,0x105fc0,0x105fbf,0xfe0c0,0xfe0bf,0x1060c0,0x1060bf,0x302041,0x301fc1,0x2fe041,0x3020c1,0x306041,0x2fdfc1,0x305fc1,0x2fe0c1,0x3060c1,0x70203e,0x6fe03e,0x701fbe,0x70603e,0x7020be,0x6fdfbe,0x705fbe,0x6fe0be,0x7060be,0x3101f40,0x3701f3f,0x180fa040,0x186fa03f,0x180f9fc0,0x1b0fdf40,0x36fdf3f,0x1b6f9fbf,0x180fa0c0,0x186fa0bf,0x1302140,0x170213f,0x830a040,0x3105f40,0x3705f3f,0x870a03f,0xb309fc0,0xb709fbf,0x830a0c0,0x192fe140,0x196fe13f,0x9306140,0x170613f,0x970a0bf,0xb301f41,0x192fa041,0x182f9fc1,0x1b2fdf41, + 17,0x10203f,0x101fc0,0xfe040,0xfe03f,0x101fbf,0x106040,0x1020c0,0xfdfc0,0x1020bf,0x10603f,0x102041,0xfdfbf,0x105fc0,0xfe0c0,0xfe0bf,0x105fbf,0x1060c0,0x101fc1,0xfe041,0x1060bf,0x106041,0x1020c1,0x2fdfc1,0x305fc1,0x2fe0c1,0x3060c1,0x70203e,0x6fe03e,0x701fbe,0x70603e,0x7020be,0x6fdfbe,0x3101f40,0x3701f3f,0x180fa040,0x186fa03f,0x6fe0be,0x705fbe,0x30fdf40,0x1b0f9fc0,0x186f9fbf,0x1b6fdf3f,0x3105f40,0x3705f3f,0x97060be,0x830a040,0x870a03f,0x1302140,0x180fa0c0,0x186fa0bf,0x170213f,0x192fe140,0x192fa041,0x3301f41,0xb309fc0,0xb709fbf,0x850a0c0,0x9506140,0x196fe13f,0x182f9fc1,0x1b2fdf41,0xb305f41,0x12302042, + 16,0x10203f,0x101fc0,0xfe040,0x102041,0x1020c0,0x106040,0x101fbf,0xfe03f,0xfdfc0,0x101fc1,0x105fc0,0x10603f,0x1020bf,0xfe0c0,0xfe041,0xfdfbf,0x1020c1,0x106041,0x1060c0,0x105fbf,0xfe0bf,0xfdfc1,0x105fc1,0x1060bf,0xfe0c1,0x83060c1,0x70203e,0x3101f40,0x180fa040,0x180fa03f,0x186fe03e,0x701fbe,0x3701f3f,0x30fdf40,0x1b0f9fc0,0x180fa041,0x180fa0c0,0x7020be,0x70603e,0x3105f40,0xb101f41,0x9302042,0x1102140,0x930a040,0x6fdfbe,0x36fdf3f,0x1b6f9fbf,0x190fa0bf,0x196fe0be,0x170213f,0x196fe140,0x182f9fc1,0x1b2fdf41,0xb301fc2,0x1a2fe042,0x192fa0c1,0x8705fbe,0xb705f3f,0xb309fc0,0xa70a03f,0x97060be,0x9706140,0x11302141 +}; diff --git a/contrib/voro++/src/v_compute.cc b/contrib/voro++/src/v_compute.cc new file mode 100644 index 0000000000000000000000000000000000000000..84991fd1ab3e419133c6b43e9e4d520d91ffb6c8 --- /dev/null +++ b/contrib/voro++/src/v_compute.cc @@ -0,0 +1,1006 @@ +// Voro++, a 3D cell-based Voronoi library +// +// Author : Chris H. Rycroft (LBL / UC Berkeley) +// Email : chr@alum.mit.edu +// Date : August 30th 2011 + +/** \file v_compute.cc + * \brief Function implementantions for the voro_compute template. */ + +#include "worklist.hh" +#include "v_compute.hh" +#include "rad_option.hh" +#include "container.hh" +#include "container_prd.hh" + +namespace voro { + +/** The class constructor initializes constants from the container class, and + * sets up the mask and queue used for Voronoi computations. + * \param[in] con_ a reference to the container class to use. + * \param[in] (hx_,hy_,hz_) the size of the mask to use. */ +template<class c_class> +voro_compute<c_class>::voro_compute(c_class &con_,int hx_,int hy_,int hz_) : + con(con_), boxx(con_.boxx), boxy(con_.boxy), boxz(con_.boxz), + xsp(con_.xsp), ysp(con_.ysp), zsp(con_.zsp), + hx(hx_), hy(hy_), hz(hz_), hxy(hx_*hy_), hxyz(hxy*hz_), ps(con_.ps), + id(con_.id), p(con_.p), co(con_.co), bxsq(boxx*boxx+boxy*boxy+boxz*boxz), + mv(0), qu_size(3*(3+hxy+hz*(hx+hy))), wl(con_.wl), mrad(con_.mrad), + mask(new unsigned int[hxyz]), qu(new int[qu_size]), qu_l(qu+qu_size) { + reset_mask(); +} + +/** Scans all of the particles within a block to see if any of them have a + * smaller distance to the given test vector. If one is found, the routine + * updates the minimum distance and store information about this particle. + * \param[in] ijk the index of the block. + * \param[in] (x,y,z) the test vector to consider (which may have already had a + * periodic displacement applied to it). + * \param[in] (di,dj,dk) the coordinates of the current block, to store if the + * particle record is updated. + * \param[in,out] w a reference to a particle record in which to store + * information about the particle whose Voronoi cell the + * vector is within. + * \param[in,out] mrs the current minimum distance, that may be updated if a + * closer particle is found. */ +template<class c_class> +inline void voro_compute<c_class>::scan_all(int ijk,double x,double y,double z,int di,int dj,int dk,particle_record &w,double &mrs) { + double x1,y1,z1,rs;bool in_block=false; + for(int l=0;l<co[ijk];l++) { + x1=p[ijk][ps*l]-x; + y1=p[ijk][ps*l+1]-y; + z1=p[ijk][ps*l+2]-z; + rs=con.r_current_sub(x1*x1+y1*y1+z1*z1,ijk,l); + if(rs<mrs) {mrs=rs;w.l=l;in_block=true;} + } + if(in_block) {w.ijk=ijk;w.di=di;w.dj=dj,w.dk=dk;} +} + +/** Finds the Voronoi cell that given vector is within. For containers that are + * not radially dependent, this corresponds to findig the particle that is + * closest to the vector; for the radical tessellation containers, this + * corresponds to a finding the minimum weighted distance. + * \param[in] (x,y,z) the vector to consider. + * \param[in] (ci,cj,ck) the coordinates of the block that the test particle is + * in relative to the container data structure. + * \param[in] ijk the index of the block that the test particle is in. + * \param[out] w a reference to a particle record in which to store information + * about the particle whose Voronoi cell the vector is within. + * \param[out] mrs the minimum computed distance. */ +template<class c_class> +void voro_compute<c_class>::find_voronoi_cell(double x,double y,double z,int ci,int cj,int ck,int ijk,particle_record &w,double &mrs) { + double qx=0,qy=0,qz=0,rs; + int i,j,k,di,dj,dk,ei,ej,ek,f,g,disp; + double fx,fy,fz,mxs,mys,mzs,*radp; + unsigned int q,*e,*mijk; + + // Init setup for parameters to return + w.ijk=-1;mrs=large_number; + + con.initialize_search(ci,cj,ck,ijk,i,j,k,disp); + + // Test all particles in the particle's local region first + scan_all(ijk,x,y,z,0,0,0,w,mrs); + + // Now compute the fractional position of the particle within its + // region and store it in (fx,fy,fz). We use this to compute an index + // (di,dj,dk) of which subregion the particle is within. + unsigned int m1,m2; + con.frac_pos(x,y,z,ci,cj,ck,fx,fy,fz); + di=int(fx*xsp*wl_fgrid);dj=int(fy*ysp*wl_fgrid);dk=int(fz*zsp*wl_fgrid); + + // The indices (di,dj,dk) tell us which worklist to use, to test the + // blocks in the optimal order. But we only store worklists for the + // eighth of the region where di, dj, and dk are all less than half the + // full grid. The rest of the cases are handled by symmetry. In this + // section, we detect for these cases, by reflecting high values of di, + // dj, and dk. For these cases, a mask is constructed in m1 and m2 + // which is used to flip the worklist information when it is loaded. + if(di>=wl_hgrid) { + mxs=boxx-fx; + m1=127+(3<<21);m2=1+(1<<21);di=wl_fgrid-1-di;if(di<0) di=0; + } else {m1=m2=0;mxs=fx;} + if(dj>=wl_hgrid) { + mys=boxy-fy; + m1|=(127<<7)+(3<<24);m2|=(1<<7)+(1<<24);dj=wl_fgrid-1-dj;if(dj<0) dj=0; + } else mys=fy; + if(dk>=wl_hgrid) { + mzs=boxz-fz; + m1|=(127<<14)+(3<<27);m2|=(1<<14)+(1<<27);dk=wl_fgrid-1-dk;if(dk<0) dk=0; + } else mzs=fz; + + // Do a quick test to account for the case when the minimum radius is + // small enought that no other blocks need to be considered + rs=con.r_max_add(mrs); + if(mxs*mxs>rs&&mys*mys>rs&&mzs*mzs>rs) return; + + // Now compute which worklist we are going to use, and set radp and e to + // point at the right offsets + ijk=di+wl_hgrid*(dj+wl_hgrid*dk); + radp=mrad+ijk*wl_seq_length; + e=(const_cast<unsigned int*> (wl))+ijk*wl_seq_length; + + // Read in how many items in the worklist can be tested without having to + // worry about writing to the mask + f=e[0];g=0; + do { + + // If mrs is less than the minimum distance to any untested + // block, then we are done + if(con.r_max_add(mrs)<radp[g]) return; + g++; + + // Load in a block off the worklist, permute it with the + // symmetry mask, and decode its position. These are all + // integer bit operations so they should run very fast. + q=e[g];q^=m1;q+=m2; + di=q&127;di-=64; + dj=(q>>7)&127;dj-=64; + dk=(q>>14)&127;dk-=64; + + // Check that the worklist position is in range + ei=di+i;if(ei<0||ei>=hx) continue; + ej=dj+j;if(ej<0||ej>=hy) continue; + ek=dk+k;if(ek<0||ek>=hz) continue; + + // Call the compute_min_max_radius() function. This returns + // true if the minimum distance to the block is bigger than the + // current mrs, in which case we skip this block and move on. + // Otherwise, it computes the maximum distance to the block and + // returns it in crs. + if(compute_min_radius(di,dj,dk,fx,fy,fz,mrs)) continue; + + // Now compute which region we are going to loop over, adding a + // displacement for the periodic cases + ijk=con.region_index(ci,cj,ck,ei,ej,ek,qx,qy,qz,disp); + + // If mrs is bigger than the maximum distance to the block, + // then we have to test all particles in the block for + // intersections. Otherwise, we do additional checks and skip + // those particles which can't possibly intersect the block. + scan_all(ijk,x-qx,y-qy,z-qz,di,dj,dk,w,mrs); + } while(g<f); + + // Update mask value and initialize queue + mv++; + if(mv==0) {reset_mask();mv=1;} + int *qu_s=qu,*qu_e=qu; + + while(g<wl_seq_length-1) { + + // If mrs is less than the minimum distance to any untested + // block, then we are done + if(con.r_max_add(mrs)<radp[g]) return; + g++; + + // Load in a block off the worklist, permute it with the + // symmetry mask, and decode its position. These are all + // integer bit operations so they should run very fast. + q=e[g];q^=m1;q+=m2; + di=q&127;di-=64; + dj=(q>>7)&127;dj-=64; + dk=(q>>14)&127;dk-=64; + + // Compute the position in the mask of the current block. If + // this lies outside the mask, then skip it. Otherwise, mark + // it. + ei=di+i;if(ei<0||ei>=hx) continue; + ej=dj+j;if(ej<0||ej>=hy) continue; + ek=dk+k;if(ek<0||ek>=hz) continue; + mijk=mask+ei+hx*(ej+hy*ek); + *mijk=mv; + + // Skip this block if it is further away than the current + // minimum radius + if(compute_min_radius(di,dj,dk,fx,fy,fz,mrs)) continue; + + // Now compute which region we are going to loop over, adding a + // displacement for the periodic cases + ijk=con.region_index(ci,cj,ck,ei,ej,ek,qx,qy,qz,disp); + scan_all(ijk,x-qx,y-qy,z-qz,di,dj,dk,w,mrs); + + if(qu_e>qu_l-18) add_list_memory(qu_s,qu_e); + scan_bits_mask_add(q,mijk,ei,ej,ek,qu_e); + } + + // Do a check to see if we've reached the radius cutoff + if(con.r_max_add(mrs)<radp[g]) return; + + // We were unable to completely compute the cell based on the blocks in + // the worklist, so now we have to go block by block, reading in items + // off the list + while(qu_s!=qu_e) { + + // Read the next entry of the queue + if(qu_s==qu_l) qu_s=qu; + ei=*(qu_s++);ej=*(qu_s++);ek=*(qu_s++); + di=ei-i;dj=ej-j;dk=ek-k; + if(compute_min_radius(di,dj,dk,fx,fy,fz,mrs)) continue; + + ijk=con.region_index(ci,cj,ck,ei,ej,ek,qx,qy,qz,disp); + scan_all(ijk,x-qx,y-qy,z-qz,di,dj,dk,w,mrs); + + // Test the neighbors of the current block, and add them to the + // block list if they haven't already been tested + if((qu_s<=qu_e?(qu_l-qu_e)+(qu_s-qu):qu_s-qu_e)<18) add_list_memory(qu_s,qu_e); + add_to_mask(ei,ej,ek,qu_e); + } +} + +/** Scans the six orthogonal neighbors of a given block and adds them to the + * queue if they haven't been considered already. It assumes that the queue + * will definitely have enough memory to add six entries at the end. + * \param[in] (ei,ej,ek) the block to consider. + * \param[in,out] qu_e a pointer to the end of the queue. */ +template<class c_class> +inline void voro_compute<c_class>::add_to_mask(int ei,int ej,int ek,int *&qu_e) { + unsigned int *mijk=mask+ei+hx*(ej+hy*ek); + if(ek>0) if(*(mijk-hxy)!=mv) {if(qu_e==qu_l) qu_e=qu;*(mijk-hxy)=mv;*(qu_e++)=ei;*(qu_e++)=ej;*(qu_e++)=ek-1;} + if(ej>0) if(*(mijk-hx)!=mv) {if(qu_e==qu_l) qu_e=qu;*(mijk-hx)=mv;*(qu_e++)=ei;*(qu_e++)=ej-1;*(qu_e++)=ek;} + if(ei>0) if(*(mijk-1)!=mv) {if(qu_e==qu_l) qu_e=qu;*(mijk-1)=mv;*(qu_e++)=ei-1;*(qu_e++)=ej;*(qu_e++)=ek;} + if(ei<hx-1) if(*(mijk+1)!=mv) {if(qu_e==qu_l) qu_e=qu;*(mijk+1)=mv;*(qu_e++)=ei+1;*(qu_e++)=ej;*(qu_e++)=ek;} + if(ej<hy-1) if(*(mijk+hx)!=mv) {if(qu_e==qu_l) qu_e=qu;*(mijk+hx)=mv;*(qu_e++)=ei;*(qu_e++)=ej+1;*(qu_e++)=ek;} + if(ek<hz-1) if(*(mijk+hxy)!=mv) {if(qu_e==qu_l) qu_e=qu;*(mijk+hxy)=mv;*(qu_e++)=ei;*(qu_e++)=ej;*(qu_e++)=ek+1;} +} + +/** Scans a worklist entry and adds any blocks to the queue + * \param[in] (ei,ej,ek) the block to consider. + * \param[in,out] qu_e a pointer to the end of the queue. */ +template<class c_class> +inline void voro_compute<c_class>::scan_bits_mask_add(unsigned int q,unsigned int *mijk,int ei,int ej,int ek,int *&qu_e) { + const unsigned int b1=1<<21,b2=1<<22,b3=1<<24,b4=1<<25,b5=1<<27,b6=1<<28; + if((q&b2)==b2) { + if(ei>0) {*(mijk-1)=mv;*(qu_e++)=ei-1;*(qu_e++)=ej;*(qu_e++)=ek;} + if((q&b1)==0&&ei<hx-1) {*(mijk+1)=mv;*(qu_e++)=ei+1;*(qu_e++)=ej;*(qu_e++)=ek;} + } else if((q&b1)==b1&&ei<hx-1) {*(mijk+1)=mv;*(qu_e++)=ei+1;*(qu_e++)=ej;*(qu_e++)=ek;} + if((q&b4)==b4) { + if(ej>0) {*(mijk-hx)=mv;*(qu_e++)=ei;*(qu_e++)=ej-1;*(qu_e++)=ek;} + if((q&b3)==0&&ej<hy-1) {*(mijk+hx)=mv;*(qu_e++)=ei;*(qu_e++)=ej+1;*(qu_e++)=ek;} + } else if((q&b3)==b3&&ej<hy-1) {*(mijk+hx)=mv;*(qu_e++)=ei;*(qu_e++)=ej+1;*(qu_e++)=ek;} + if((q&b6)==b6) { + if(ek>0) {*(mijk-hxy)=mv;*(qu_e++)=ei;*(qu_e++)=ej;*(qu_e++)=ek-1;} + if((q&b5)==0&&ek<hz-1) {*(mijk+hxy)=mv;*(qu_e++)=ei;*(qu_e++)=ej;*(qu_e++)=ek+1;} + } else if((q&b5)==b5&&ek<hz-1) {*(mijk+hxy)=mv;*(qu_e++)=ei;*(qu_e++)=ej;*(qu_e++)=ek+1;} +} + +/** This routine computes a Voronoi cell for a single particle in the + * container. It can be called by the user, but is also forms the core part of + * several of the main functions, such as store_cell_volumes(), print_all(), + * and the drawing routines. The algorithm constructs the cell by testing over + * the neighbors of the particle, working outwards until it reaches those + * particles which could not possibly intersect the cell. For maximum + * efficiency, this algorithm is divided into three parts. In the first + * section, the algorithm tests over the blocks which are in the immediate + * vicinity of the particle, by making use of one of the precomputed worklists. + * The code then continues to test blocks on the worklist, but also begins to + * construct a list of neighboring blocks outside the worklist which may need + * to be test. In the third section, the routine starts testing these + * neighboring blocks, evaluating whether or not a particle in them could + * possibly intersect the cell. For blocks that intersect the cell, it tests + * the particles in that block, and then adds the block neighbors to the list + * of potential places to consider. + * \param[in,out] c a reference to a voronoicell object. + * \param[in] ijk the index of the block that the test particle is in. + * \param[in] s the index of the particle within the test block. + * \param[in] (ci,cj,ck) the coordinates of the block that the test particle is + * in relative to the container data structure. + * \return False if the Voronoi cell was completely removed during the + * computation and has zero volume, true otherwise. */ +template<class c_class> +template<class v_cell> +bool voro_compute<c_class>::compute_cell(v_cell &c,int ijk,int s,int ci,int cj,int ck) { + static const int count_list[8]={7,11,15,19,26,35,45,59},*count_e=count_list+8; + double x,y,z,x1,y1,z1,qx=0,qy=0,qz=0; + double xlo,ylo,zlo,xhi,yhi,zhi,x2,y2,z2,rs; + int i,j,k,di,dj,dk,ei,ej,ek,f,g,l,disp; + double fx,fy,fz,gxs,gys,gzs,*radp; + unsigned int q,*e,*mijk; + + if(!con.initialize_voronoicell(c,ijk,s,ci,cj,ck,i,j,k,x,y,z,disp)) return false; + con.r_init(ijk,s); + + // Initialize the Voronoi cell to fill the entire container + double crs,mrs; + + int next_count=3,*count_p=(const_cast<int*> (count_list)); + + // Test all particles in the particle's local region first + for(l=0;l<s;l++) { + x1=p[ijk][ps*l]-x; + y1=p[ijk][ps*l+1]-y; + z1=p[ijk][ps*l+2]-z; + rs=con.r_scale(x1*x1+y1*y1+z1*z1,ijk,l); + if(!c.nplane(x1,y1,z1,rs,id[ijk][l])) return false; + } + l++; + while(l<co[ijk]) { + x1=p[ijk][ps*l]-x; + y1=p[ijk][ps*l+1]-y; + z1=p[ijk][ps*l+2]-z; + rs=con.r_scale(x1*x1+y1*y1+z1*z1,ijk,l); + if(!c.nplane(x1,y1,z1,rs,id[ijk][l])) return false; + l++; + } + + // Now compute the maximum distance squared from the cell center to a + // vertex. This is used to cut off the calculation since we only need + // to test out to twice this range. + mrs=c.max_radius_squared(); + + // Now compute the fractional position of the particle within its + // region and store it in (fx,fy,fz). We use this to compute an index + // (di,dj,dk) of which subregion the particle is within. + unsigned int m1,m2; + con.frac_pos(x,y,z,ci,cj,ck,fx,fy,fz); + di=int(fx*xsp*wl_fgrid);dj=int(fy*ysp*wl_fgrid);dk=int(fz*zsp*wl_fgrid); + + // The indices (di,dj,dk) tell us which worklist to use, to test the + // blocks in the optimal order. But we only store worklists for the + // eighth of the region where di, dj, and dk are all less than half the + // full grid. The rest of the cases are handled by symmetry. In this + // section, we detect for these cases, by reflecting high values of di, + // dj, and dk. For these cases, a mask is constructed in m1 and m2 + // which is used to flip the worklist information when it is loaded. + if(di>=wl_hgrid) { + gxs=fx; + m1=127+(3<<21);m2=1+(1<<21);di=wl_fgrid-1-di;if(di<0) di=0; + } else {m1=m2=0;gxs=boxx-fx;} + if(dj>=wl_hgrid) { + gys=fy; + m1|=(127<<7)+(3<<24);m2|=(1<<7)+(1<<24);dj=wl_fgrid-1-dj;if(dj<0) dj=0; + } else gys=boxy-fy; + if(dk>=wl_hgrid) { + gzs=fz; + m1|=(127<<14)+(3<<27);m2|=(1<<14)+(1<<27);dk=wl_fgrid-1-dk;if(dk<0) dk=0; + } else gzs=boxz-fz; + gxs*=gxs;gys*=gys;gzs*=gzs; + + // Now compute which worklist we are going to use, and set radp and e to + // point at the right offsets + ijk=di+wl_hgrid*(dj+wl_hgrid*dk); + radp=mrad+ijk*wl_seq_length; + e=(const_cast<unsigned int*> (wl))+ijk*wl_seq_length; + + // Read in how many items in the worklist can be tested without having to + // worry about writing to the mask + f=e[0];g=0; + do { + + // At the intervals specified by count_list, we recompute the + // maximum radius squared + if(g==next_count) { + mrs=c.max_radius_squared(); + if(count_p!=count_e) next_count=*(count_p++); + } + + // If mrs is less than the minimum distance to any untested + // block, then we are done + if(con.r_ctest(radp[g],mrs)) return true; + g++; + + // Load in a block off the worklist, permute it with the + // symmetry mask, and decode its position. These are all + // integer bit operations so they should run very fast. + q=e[g];q^=m1;q+=m2; + di=q&127;di-=64; + dj=(q>>7)&127;dj-=64; + dk=(q>>14)&127;dk-=64; + + // Check that the worklist position is in range + ei=di+i;if(ei<0||ei>=hx) continue; + ej=dj+j;if(ej<0||ej>=hy) continue; + ek=dk+k;if(ek<0||ek>=hz) continue; + + // Call the compute_min_max_radius() function. This returns + // true if the minimum distance to the block is bigger than the + // current mrs, in which case we skip this block and move on. + // Otherwise, it computes the maximum distance to the block and + // returns it in crs. + if(compute_min_max_radius(di,dj,dk,fx,fy,fz,gxs,gys,gzs,crs,mrs)) continue; + + // Now compute which region we are going to loop over, adding a + // displacement for the periodic cases + ijk=con.region_index(ci,cj,ck,ei,ej,ek,qx,qy,qz,disp); + + // If mrs is bigger than the maximum distance to the block, + // then we have to test all particles in the block for + // intersections. Otherwise, we do additional checks and skip + // those particles which can't possibly intersect the block. + if(co[ijk]>0) { + l=0;x2=x-qx;y2=y-qy;z2=z-qz; + if(!con.r_ctest(crs,mrs)) { + do { + x1=p[ijk][ps*l]-x2; + y1=p[ijk][ps*l+1]-y2; + z1=p[ijk][ps*l+2]-z2; + rs=con.r_scale(x1*x1+y1*y1+z1*z1,ijk,l); + if(!c.nplane(x1,y1,z1,rs,id[ijk][l])) return false; + l++; + } while (l<co[ijk]); + } else { + do { + x1=p[ijk][ps*l]-x2; + y1=p[ijk][ps*l+1]-y2; + z1=p[ijk][ps*l+2]-z2; + rs=x1*x1+y1*y1+z1*z1; + if(con.r_scale_check(rs,mrs,ijk,l)&&!c.nplane(x1,y1,z1,rs,id[ijk][l])) return false; + l++; + } while (l<co[ijk]); + } + } + } while(g<f); + + // If we reach here, we were unable to compute the entire cell using + // the first part of the worklist. This section of the algorithm + // continues the worklist, but it now starts preparing the mask that we + // need if we end up going block by block. We do the same as before, + // but we put a mark down on the mask for every block that's tested. + // The worklist also contains information about which neighbors of each + // block are not also on the worklist, and we start storing those + // points in a list in case we have to go block by block. Update the + // mask counter, and if it wraps around then reset the whole mask; that + // will only happen once every 2^32 tries. + mv++; + if(mv==0) {reset_mask();mv=1;} + + // Set the queue pointers + int *qu_s=qu,*qu_e=qu; + + while(g<wl_seq_length-1) { + + // At the intervals specified by count_list, we recompute the + // maximum radius squared + if(g==next_count) { + mrs=c.max_radius_squared(); + if(count_p!=count_e) next_count=*(count_p++); + } + + // If mrs is less than the minimum distance to any untested + // block, then we are done + if(con.r_ctest(radp[g],mrs)) return true; + g++; + + // Load in a block off the worklist, permute it with the + // symmetry mask, and decode its position. These are all + // integer bit operations so they should run very fast. + q=e[g];q^=m1;q+=m2; + di=q&127;di-=64; + dj=(q>>7)&127;dj-=64; + dk=(q>>14)&127;dk-=64; + + // Compute the position in the mask of the current block. If + // this lies outside the mask, then skip it. Otherwise, mark + // it. + ei=di+i;if(ei<0||ei>=hx) continue; + ej=dj+j;if(ej<0||ej>=hy) continue; + ek=dk+k;if(ek<0||ek>=hz) continue; + mijk=mask+ei+hx*(ej+hy*ek); + *mijk=mv; + + // Call the compute_min_max_radius() function. This returns + // true if the minimum distance to the block is bigger than the + // current mrs, in which case we skip this block and move on. + // Otherwise, it computes the maximum distance to the block and + // returns it in crs. + if(compute_min_max_radius(di,dj,dk,fx,fy,fz,gxs,gys,gzs,crs,mrs)) continue; + + // Now compute which region we are going to loop over, adding a + // displacement for the periodic cases + ijk=con.region_index(ci,cj,ck,ei,ej,ek,qx,qy,qz,disp); + + // If mrs is bigger than the maximum distance to the block, + // then we have to test all particles in the block for + // intersections. Otherwise, we do additional checks and skip + // those particles which can't possibly intersect the block. + if(co[ijk]>0) { + l=0;x2=x-qx;y2=y-qy;z2=z-qz; + if(!con.r_ctest(crs,mrs)) { + do { + x1=p[ijk][ps*l]-x2; + y1=p[ijk][ps*l+1]-y2; + z1=p[ijk][ps*l+2]-z2; + rs=con.r_scale(x1*x1+y1*y1+z1*z1,ijk,l); + if(!c.nplane(x1,y1,z1,rs,id[ijk][l])) return false; + l++; + } while (l<co[ijk]); + } else { + do { + x1=p[ijk][ps*l]-x2; + y1=p[ijk][ps*l+1]-y2; + z1=p[ijk][ps*l+2]-z2; + rs=x1*x1+y1*y1+z1*z1; + if(con.r_scale_check(rs,mrs,ijk,l)&&!c.nplane(x1,y1,z1,rs,id[ijk][l])) return false; + l++; + } while (l<co[ijk]); + } + } + + // If there might not be enough memory on the list for these + // additions, then add more + if(qu_e>qu_l-18) add_list_memory(qu_s,qu_e); + + // Test the parts of the worklist element which tell us what + // neighbors of this block are not on the worklist. Store them + // on the block list, and mark the mask. + scan_bits_mask_add(q,mijk,ei,ej,ek,qu_e); + } + + // Do a check to see if we've reached the radius cutoff + if(con.r_ctest(radp[g],mrs)) return true; + + // We were unable to completely compute the cell based on the blocks in + // the worklist, so now we have to go block by block, reading in items + // off the list + while(qu_s!=qu_e) { + + // If we reached the end of the list memory loop back to the + // start + if(qu_s==qu_l) qu_s=qu; + + // Read in a block off the list, and compute the upper and lower + // coordinates in each of the three dimensions + ei=*(qu_s++);ej=*(qu_s++);ek=*(qu_s++); + xlo=(ei-i)*boxx-fx;xhi=xlo+boxx; + ylo=(ej-j)*boxy-fy;yhi=ylo+boxy; + zlo=(ek-k)*boxz-fz;zhi=zlo+boxz; + + // Carry out plane tests to see if any particle in this block + // could possibly intersect the cell + if(ei>i) { + if(ej>j) { + if(ek>k) {if(corner_test(c,xlo,ylo,zlo,xhi,yhi,zhi)) continue;} + else if(ek<k) {if(corner_test(c,xlo,ylo,zhi,xhi,yhi,zlo)) continue;} + else {if(edge_z_test(c,xlo,ylo,zlo,xhi,yhi,zhi)) continue;} + } else if(ej<j) { + if(ek>k) {if(corner_test(c,xlo,yhi,zlo,xhi,ylo,zhi)) continue;} + else if(ek<k) {if(corner_test(c,xlo,yhi,zhi,xhi,ylo,zlo)) continue;} + else {if(edge_z_test(c,xlo,yhi,zlo,xhi,ylo,zhi)) continue;} + } else { + if(ek>k) {if(edge_y_test(c,xlo,ylo,zlo,xhi,yhi,zhi)) continue;} + else if(ek<k) {if(edge_y_test(c,xlo,ylo,zhi,xhi,yhi,zlo)) continue;} + else {if(face_x_test(c,xlo,ylo,zlo,yhi,zhi)) continue;} + } + } else if(ei<i) { + if(ej>j) { + if(ek>k) {if(corner_test(c,xhi,ylo,zlo,xlo,yhi,zhi)) continue;} + else if(ek<k) {if(corner_test(c,xhi,ylo,zhi,xlo,yhi,zlo)) continue;} + else {if(edge_z_test(c,xhi,ylo,zlo,xlo,yhi,zhi)) continue;} + } else if(ej<j) { + if(ek>k) {if(corner_test(c,xhi,yhi,zlo,xlo,ylo,zhi)) continue;} + else if(ek<k) {if(corner_test(c,xhi,yhi,zhi,xlo,ylo,zlo)) continue;} + else {if(edge_z_test(c,xhi,yhi,zlo,xlo,ylo,zhi)) continue;} + } else { + if(ek>k) {if(edge_y_test(c,xhi,ylo,zlo,xlo,yhi,zhi)) continue;} + else if(ek<k) {if(edge_y_test(c,xhi,ylo,zhi,xlo,yhi,zlo)) continue;} + else {if(face_x_test(c,xhi,ylo,zlo,yhi,zhi)) continue;} + } + } else { + if(ej>j) { + if(ek>k) {if(edge_x_test(c,xlo,ylo,zlo,xhi,yhi,zhi)) continue;} + else if(ek<k) {if(edge_x_test(c,xlo,ylo,zhi,xhi,yhi,zlo)) continue;} + else {if(face_y_test(c,xlo,ylo,zlo,xhi,zhi)) continue;} + } else if(ej<j) { + if(ek>k) {if(edge_x_test(c,xlo,yhi,zlo,xhi,ylo,zhi)) continue;} + else if(ek<k) {if(edge_x_test(c,xlo,yhi,zhi,xhi,ylo,zlo)) continue;} + else {if(face_y_test(c,xlo,yhi,zlo,xhi,zhi)) continue;} + } else { + if(ek>k) {if(face_z_test(c,xlo,ylo,zlo,xhi,yhi)) continue;} + else if(ek<k) {if(face_z_test(c,xlo,ylo,zhi,xhi,yhi)) continue;} + else voro_fatal_error("Compute cell routine revisiting central block, which should never\nhappen.",VOROPP_INTERNAL_ERROR); + } + } + + // Now compute the region that we are going to test over, and + // set a displacement vector for the periodic cases + ijk=con.region_index(ci,cj,ck,ei,ej,ek,qx,qy,qz,disp); + + // Loop over all the elements in the block to test for cuts. It + // would be possible to exclude some of these cases by testing + // against mrs, but this will probably not save time. + if(co[ijk]>0) { + l=0;x2=x-qx;y2=y-qy;z2=z-qz; + do { + x1=p[ijk][ps*l]-x2; + y1=p[ijk][ps*l+1]-y2; + z1=p[ijk][ps*l+2]-z2; + rs=con.r_scale(x1*x1+y1*y1+z1*z1,ijk,l); + if(!c.nplane(x1,y1,z1,rs,id[ijk][l])) return false; + l++; + } while (l<co[ijk]); + } + + // If there's not much memory on the block list then add more + if((qu_s<=qu_e?(qu_l-qu_e)+(qu_s-qu):qu_s-qu_e)<18) add_list_memory(qu_s,qu_e); + + // Test the neighbors of the current block, and add them to the + // block list if they haven't already been tested + add_to_mask(ei,ej,ek,qu_e); + } + + return true; +} + +/** This function checks to see whether a particular block can possibly have + * any intersection with a Voronoi cell, for the case when the closest point + * from the cell center to the block is at a corner. + * \param[in,out] c a reference to a Voronoi cell. + * \param[in] (xl,yl,zl) the relative coordinates of the corner of the block + * closest to the cell center. + * \param[in] (xh,yh,zh) the relative coordinates of the corner of the block + * furthest away from the cell center. + * \return False if the block may intersect, true if does not. */ +template<class c_class> +template<class v_cell> +bool voro_compute<c_class>::corner_test(v_cell &c,double xl,double yl,double zl,double xh,double yh,double zh) { + con.r_prime(xl*xl+yl*yl+zl*zl); + if(c.plane_intersects_guess(xh,yl,zl,con.r_cutoff(xl*xh+yl*yl+zl*zl))) return false; + if(c.plane_intersects(xh,yh,zl,con.r_cutoff(xl*xh+yl*yh+zl*zl))) return false; + if(c.plane_intersects(xl,yh,zl,con.r_cutoff(xl*xl+yl*yh+zl*zl))) return false; + if(c.plane_intersects(xl,yh,zh,con.r_cutoff(xl*xl+yl*yh+zl*zh))) return false; + if(c.plane_intersects(xl,yl,zh,con.r_cutoff(xl*xl+yl*yl+zl*zh))) return false; + if(c.plane_intersects(xh,yl,zh,con.r_cutoff(xl*xh+yl*yl+zl*zh))) return false; + return true; +} + +/** This function checks to see whether a particular block can possibly have + * any intersection with a Voronoi cell, for the case when the closest point + * from the cell center to the block is on an edge which points along the x + * direction. + * \param[in,out] c a reference to a Voronoi cell. + * \param[in] (x0,x1) the minimum and maximum relative x coordinates of the + * block. + * \param[in] (yl,zl) the relative y and z coordinates of the corner of the + * block closest to the cell center. + * \param[in] (yh,zh) the relative y and z coordinates of the corner of the + * block furthest away from the cell center. + * \return False if the block may intersect, true if does not. */ +template<class c_class> +template<class v_cell> +inline bool voro_compute<c_class>::edge_x_test(v_cell &c,double x0,double yl,double zl,double x1,double yh,double zh) { + con.r_prime(yl*yl+zl*zl); + if(c.plane_intersects_guess(x0,yl,zh,con.r_cutoff(yl*yl+zl*zh))) return false; + if(c.plane_intersects(x1,yl,zh,con.r_cutoff(yl*yl+zl*zh))) return false; + if(c.plane_intersects(x1,yl,zl,con.r_cutoff(yl*yl+zl*zl))) return false; + if(c.plane_intersects(x0,yl,zl,con.r_cutoff(yl*yl+zl*zl))) return false; + if(c.plane_intersects(x0,yh,zl,con.r_cutoff(yl*yh+zl*zl))) return false; + if(c.plane_intersects(x1,yh,zl,con.r_cutoff(yl*yh+zl*zl))) return false; + return true; +} + +/** This function checks to see whether a particular block can possibly have + * any intersection with a Voronoi cell, for the case when the closest point + * from the cell center to the block is on an edge which points along the y + * direction. + * \param[in,out] c a reference to a Voronoi cell. + * \param[in] (y0,y1) the minimum and maximum relative y coordinates of the + * block. + * \param[in] (xl,zl) the relative x and z coordinates of the corner of the + * block closest to the cell center. + * \param[in] (xh,zh) the relative x and z coordinates of the corner of the + * block furthest away from the cell center. + * \return False if the block may intersect, true if does not. */ +template<class c_class> +template<class v_cell> +inline bool voro_compute<c_class>::edge_y_test(v_cell &c,double xl,double y0,double zl,double xh,double y1,double zh) { + con.r_prime(xl*xl+zl*zl); + if(c.plane_intersects_guess(xl,y0,zh,con.r_cutoff(xl*xl+zl*zh))) return false; + if(c.plane_intersects(xl,y1,zh,con.r_cutoff(xl*xl+zl*zh))) return false; + if(c.plane_intersects(xl,y1,zl,con.r_cutoff(xl*xl+zl*zl))) return false; + if(c.plane_intersects(xl,y0,zl,con.r_cutoff(xl*xl+zl*zl))) return false; + if(c.plane_intersects(xh,y0,zl,con.r_cutoff(xl*xh+zl*zl))) return false; + if(c.plane_intersects(xh,y1,zl,con.r_cutoff(xl*xh+zl*zl))) return false; + return true; +} + +/** This function checks to see whether a particular block can possibly have + * any intersection with a Voronoi cell, for the case when the closest point + * from the cell center to the block is on an edge which points along the z + * direction. + * \param[in,out] c a reference to a Voronoi cell. + * \param[in] (z0,z1) the minimum and maximum relative z coordinates of the block. + * \param[in] (xl,yl) the relative x and y coordinates of the corner of the + * block closest to the cell center. + * \param[in] (xh,yh) the relative x and y coordinates of the corner of the + * block furthest away from the cell center. + * \return False if the block may intersect, true if does not. */ +template<class c_class> +template<class v_cell> +inline bool voro_compute<c_class>::edge_z_test(v_cell &c,double xl,double yl,double z0,double xh,double yh,double z1) { + con.r_prime(xl*xl+yl*yl); + if(c.plane_intersects_guess(xl,yh,z0,con.r_cutoff(xl*xl+yl*yh))) return false; + if(c.plane_intersects(xl,yh,z1,con.r_cutoff(xl*xl+yl*yh))) return false; + if(c.plane_intersects(xl,yl,z1,con.r_cutoff(xl*xl+yl*yl))) return false; + if(c.plane_intersects(xl,yl,z0,con.r_cutoff(xl*xl+yl*yl))) return false; + if(c.plane_intersects(xh,yl,z0,con.r_cutoff(xl*xh+yl*yl))) return false; + if(c.plane_intersects(xh,yl,z1,con.r_cutoff(xl*xh+yl*yl))) return false; + return true; +} + +/** This function checks to see whether a particular block can possibly have + * any intersection with a Voronoi cell, for the case when the closest point + * from the cell center to the block is on a face aligned with the x direction. + * \param[in,out] c a reference to a Voronoi cell. + * \param[in] xl the minimum distance from the cell center to the face. + * \param[in] (y0,y1) the minimum and maximum relative y coordinates of the + * block. + * \param[in] (z0,z1) the minimum and maximum relative z coordinates of the + * block. + * \return False if the block may intersect, true if does not. */ +template<class c_class> +template<class v_cell> +inline bool voro_compute<c_class>::face_x_test(v_cell &c,double xl,double y0,double z0,double y1,double z1) { + con.r_prime(xl*xl); + if(c.plane_intersects_guess(xl,y0,z0,con.r_cutoff(xl*xl))) return false; + if(c.plane_intersects(xl,y0,z1,con.r_cutoff(xl*xl))) return false; + if(c.plane_intersects(xl,y1,z1,con.r_cutoff(xl*xl))) return false; + if(c.plane_intersects(xl,y1,z0,con.r_cutoff(xl*xl))) return false; + return true; +} + +/** This function checks to see whether a particular block can possibly have + * any intersection with a Voronoi cell, for the case when the closest point + * from the cell center to the block is on a face aligned with the y direction. + * \param[in,out] c a reference to a Voronoi cell. + * \param[in] yl the minimum distance from the cell center to the face. + * \param[in] (x0,x1) the minimum and maximum relative x coordinates of the + * block. + * \param[in] (z0,z1) the minimum and maximum relative z coordinates of the + * block. + * \return False if the block may intersect, true if does not. */ +template<class c_class> +template<class v_cell> +inline bool voro_compute<c_class>::face_y_test(v_cell &c,double x0,double yl,double z0,double x1,double z1) { + con.r_prime(yl*yl); + if(c.plane_intersects_guess(x0,yl,z0,con.r_cutoff(yl*yl))) return false; + if(c.plane_intersects(x0,yl,z1,con.r_cutoff(yl*yl))) return false; + if(c.plane_intersects(x1,yl,z1,con.r_cutoff(yl*yl))) return false; + if(c.plane_intersects(x1,yl,z0,con.r_cutoff(yl*yl))) return false; + return true; +} + +/** This function checks to see whether a particular block can possibly have + * any intersection with a Voronoi cell, for the case when the closest point + * from the cell center to the block is on a face aligned with the z direction. + * \param[in,out] c a reference to a Voronoi cell. + * \param[in] zl the minimum distance from the cell center to the face. + * \param[in] (x0,x1) the minimum and maximum relative x coordinates of the + * block. + * \param[in] (y0,y1) the minimum and maximum relative y coordinates of the + * block. + * \return False if the block may intersect, true if does not. */ +template<class c_class> +template<class v_cell> +inline bool voro_compute<c_class>::face_z_test(v_cell &c,double x0,double y0,double zl,double x1,double y1) { + con.r_prime(zl*zl); + if(c.plane_intersects_guess(x0,y0,zl,con.r_cutoff(zl*zl))) return false; + if(c.plane_intersects(x0,y1,zl,con.r_cutoff(zl*zl))) return false; + if(c.plane_intersects(x1,y1,zl,con.r_cutoff(zl*zl))) return false; + if(c.plane_intersects(x1,y0,zl,con.r_cutoff(zl*zl))) return false; + return true; +} + + +/** This routine checks to see whether a point is within a particular distance + * of a nearby region. If the point is within the distance of the region, then + * the routine returns true, and computes the maximum distance from the point + * to the region. Otherwise, the routine returns false. + * \param[in] (di,dj,dk) the position of the nearby region to be tested, + * relative to the region that the point is in. + * \param[in] (fx,fy,fz) the displacement of the point within its region. + * \param[in] (gxs,gys,gzs) the maximum squared distances from the point to the + * sides of its region. + * \param[out] crs a reference in which to return the maximum distance to the + * region (only computed if the routine returns false). + * \param[in] mrs the distance to be tested. + * \return True if the region is further away than mrs, false if the region in + * within mrs. */ +template<class c_class> +bool voro_compute<c_class>::compute_min_max_radius(int di,int dj,int dk,double fx,double fy,double fz,double gxs,double gys,double gzs,double &crs,double mrs) { + double xlo,ylo,zlo; + if(di>0) { + xlo=di*boxx-fx; + crs=xlo*xlo; + if(dj>0) { + ylo=dj*boxy-fy; + crs+=ylo*ylo; + if(dk>0) { + zlo=dk*boxz-fz; + crs+=zlo*zlo;if(con.r_ctest(crs,mrs)) return true; + crs+=bxsq+2*(boxx*xlo+boxy*ylo+boxz*zlo); + } else if(dk<0) { + zlo=(dk+1)*boxz-fz; + crs+=zlo*zlo;if(con.r_ctest(crs,mrs)) return true; + crs+=bxsq+2*(boxx*xlo+boxy*ylo-boxz*zlo); + } else { + if(con.r_ctest(crs,mrs)) return true; + crs+=boxx*(2*xlo+boxx)+boxy*(2*ylo+boxy)+gzs; + } + } else if(dj<0) { + ylo=(dj+1)*boxy-fy; + crs+=ylo*ylo; + if(dk>0) { + zlo=dk*boxz-fz; + crs+=zlo*zlo;if(con.r_ctest(crs,mrs)) return true; + crs+=bxsq+2*(boxx*xlo-boxy*ylo+boxz*zlo); + } else if(dk<0) { + zlo=(dk+1)*boxz-fz; + crs+=zlo*zlo;if(con.r_ctest(crs,mrs)) return true; + crs+=bxsq+2*(boxx*xlo-boxy*ylo-boxz*zlo); + } else { + if(con.r_ctest(crs,mrs)) return true; + crs+=boxx*(2*xlo+boxx)+boxy*(-2*ylo+boxy)+gzs; + } + } else { + if(dk>0) { + zlo=dk*boxz-fz; + crs+=zlo*zlo;if(con.r_ctest(crs,mrs)) return true; + crs+=boxz*(2*zlo+boxz); + } else if(dk<0) { + zlo=(dk+1)*boxz-fz; + crs+=zlo*zlo;if(con.r_ctest(crs,mrs)) return true; + crs+=boxz*(-2*zlo+boxz); + } else { + if(con.r_ctest(crs,mrs)) return true; + crs+=gzs; + } + crs+=gys+boxx*(2*xlo+boxx); + } + } else if(di<0) { + xlo=(di+1)*boxx-fx; + crs=xlo*xlo; + if(dj>0) { + ylo=dj*boxy-fy; + crs+=ylo*ylo; + if(dk>0) { + zlo=dk*boxz-fz; + crs+=zlo*zlo;if(con.r_ctest(crs,mrs)) return true; + crs+=bxsq+2*(-boxx*xlo+boxy*ylo+boxz*zlo); + } else if(dk<0) { + zlo=(dk+1)*boxz-fz; + crs+=zlo*zlo;if(con.r_ctest(crs,mrs)) return true; + crs+=bxsq+2*(-boxx*xlo+boxy*ylo-boxz*zlo); + } else { + if(con.r_ctest(crs,mrs)) return true; + crs+=boxx*(-2*xlo+boxx)+boxy*(2*ylo+boxy)+gzs; + } + } else if(dj<0) { + ylo=(dj+1)*boxy-fy; + crs+=ylo*ylo; + if(dk>0) { + zlo=dk*boxz-fz; + crs+=zlo*zlo;if(con.r_ctest(crs,mrs)) return true; + crs+=bxsq+2*(-boxx*xlo-boxy*ylo+boxz*zlo); + } else if(dk<0) { + zlo=(dk+1)*boxz-fz; + crs+=zlo*zlo;if(con.r_ctest(crs,mrs)) return true; + crs+=bxsq+2*(-boxx*xlo-boxy*ylo-boxz*zlo); + } else { + if(con.r_ctest(crs,mrs)) return true; + crs+=boxx*(-2*xlo+boxx)+boxy*(-2*ylo+boxy)+gzs; + } + } else { + if(dk>0) { + zlo=dk*boxz-fz; + crs+=zlo*zlo;if(con.r_ctest(crs,mrs)) return true; + crs+=boxz*(2*zlo+boxz); + } else if(dk<0) { + zlo=(dk+1)*boxz-fz; + crs+=zlo*zlo;if(con.r_ctest(crs,mrs)) return true; + crs+=boxz*(-2*zlo+boxz); + } else { + if(con.r_ctest(crs,mrs)) return true; + crs+=gzs; + } + crs+=gys+boxx*(-2*xlo+boxx); + } + } else { + if(dj>0) { + ylo=dj*boxy-fy; + crs=ylo*ylo; + if(dk>0) { + zlo=dk*boxz-fz; + crs+=zlo*zlo;if(con.r_ctest(crs,mrs)) return true; + crs+=boxz*(2*zlo+boxz); + } else if(dk<0) { + zlo=(dk+1)*boxz-fz; + crs+=zlo*zlo;if(con.r_ctest(crs,mrs)) return true; + crs+=boxz*(-2*zlo+boxz); + } else { + if(con.r_ctest(crs,mrs)) return true; + crs+=gzs; + } + crs+=boxy*(2*ylo+boxy); + } else if(dj<0) { + ylo=(dj+1)*boxy-fy; + crs=ylo*ylo; + if(dk>0) { + zlo=dk*boxz-fz; + crs+=zlo*zlo;if(con.r_ctest(crs,mrs)) return true; + crs+=boxz*(2*zlo+boxz); + } else if(dk<0) { + zlo=(dk+1)*boxz-fz; + crs+=zlo*zlo;if(con.r_ctest(crs,mrs)) return true; + crs+=boxz*(-2*zlo+boxz); + } else { + if(con.r_ctest(crs,mrs)) return true; + crs+=gzs; + } + crs+=boxy*(-2*ylo+boxy); + } else { + if(dk>0) { + zlo=dk*boxz-fz;crs=zlo*zlo;if(con.r_ctest(crs,mrs)) return true; + crs+=boxz*(2*zlo+boxz); + } else if(dk<0) { + zlo=(dk+1)*boxz-fz;crs=zlo*zlo;if(con.r_ctest(crs,mrs)) return true; + crs+=boxz*(-2*zlo+boxz); + } else { + crs=0; + voro_fatal_error("Min/max radius function called for central block, which should never\nhappen.",VOROPP_INTERNAL_ERROR); + } + crs+=gys; + } + crs+=gxs; + } + return false; +} + +template<class c_class> +bool voro_compute<c_class>::compute_min_radius(int di,int dj,int dk,double fx,double fy,double fz,double mrs) { + double t,crs; + + if(di>0) {t=di*boxx-fx;crs=t*t;} + else if(di<0) {t=(di+1)*boxx-fx;crs=t*t;} + else crs=0; + + if(dj>0) {t=dj*boxy-fy;crs+=t*t;} + else if(dj<0) {t=(dj+1)*boxy-fy;crs+=t*t;} + + if(dk>0) {t=dk*boxz-fz;crs+=t*t;} + else if(dk<0) {t=(dk+1)*boxz-fz;crs+=t*t;} + + return crs>con.r_max_add(mrs); +} + +/** Adds memory to the queue. + * \param[in,out] qu_s a reference to the queue start pointer. + * \param[in,out] qu_e a reference to the queue end pointer. */ +template<class c_class> +inline void voro_compute<c_class>::add_list_memory(int*& qu_s,int*& qu_e) { + qu_size<<=1; + int *qu_n=new int[qu_size],*qu_c=qu_n; +#if VOROPP_VERBOSE >=2 + fprintf(stderr,"List memory scaled up to %d\n",qu_size); +#endif + if(qu_s<=qu_e) { + while(qu_s<qu_e) *(qu_c++)=*(qu_s++); + } else { + while(qu_s<qu_l) *(qu_c++)=*(qu_s++);qu_s=qu; + while(qu_s<qu_e) *(qu_c++)=*(qu_s++); + } + delete [] qu; + qu_s=qu=qu_n; + qu_l=qu+qu_size; + qu_e=qu_c; +} + +// Explicit template instantiation +template voro_compute<container>::voro_compute(container&,int,int,int); +template voro_compute<container_poly>::voro_compute(container_poly&,int,int,int); +template bool voro_compute<container>::compute_cell(voronoicell&,int,int,int,int,int); +template bool voro_compute<container>::compute_cell(voronoicell_neighbor&,int,int,int,int,int); +template void voro_compute<container>::find_voronoi_cell(double,double,double,int,int,int,int,particle_record&,double&); +template bool voro_compute<container_poly>::compute_cell(voronoicell&,int,int,int,int,int); +template bool voro_compute<container_poly>::compute_cell(voronoicell_neighbor&,int,int,int,int,int); +template void voro_compute<container_poly>::find_voronoi_cell(double,double,double,int,int,int,int,particle_record&,double&); + +// Explicit template instantiation +template voro_compute<container_periodic>::voro_compute(container_periodic&,int,int,int); +template voro_compute<container_periodic_poly>::voro_compute(container_periodic_poly&,int,int,int); +template bool voro_compute<container_periodic>::compute_cell(voronoicell&,int,int,int,int,int); +template bool voro_compute<container_periodic>::compute_cell(voronoicell_neighbor&,int,int,int,int,int); +template void voro_compute<container_periodic>::find_voronoi_cell(double,double,double,int,int,int,int,particle_record&,double&); +template bool voro_compute<container_periodic_poly>::compute_cell(voronoicell&,int,int,int,int,int); +template bool voro_compute<container_periodic_poly>::compute_cell(voronoicell_neighbor&,int,int,int,int,int); +template void voro_compute<container_periodic_poly>::find_voronoi_cell(double,double,double,int,int,int,int,particle_record&,double&); + +} diff --git a/contrib/voro++/src/v_compute.hh b/contrib/voro++/src/v_compute.hh new file mode 100644 index 0000000000000000000000000000000000000000..0ff17f9070cc27c1bb61da509876766dd61f655a --- /dev/null +++ b/contrib/voro++/src/v_compute.hh @@ -0,0 +1,155 @@ +// Voro++, a 3D cell-based Voronoi library +// +// Author : Chris H. Rycroft (LBL / UC Berkeley) +// Email : chr@alum.mit.edu +// Date : August 30th 2011 + +/** \file v_compute.hh + * \brief Header file for the voro_compute template and related classes. */ + +#ifndef VOROPP_V_COMPUTE_HH +#define VOROPP_V_COMPUTE_HH + +#include <cstdio> +#include <cstdlib> +#include <cmath> +#include <vector> +using namespace std; + +#include "config.hh" +#include "worklist.hh" +#include "cell.hh" + +namespace voro { + +/** \brief Structure for holding information about a particle. + * + * This small structure holds information about a single particle, and is used + * by several of the routines in the voro_compute template for passing + * information by reference between functions. */ +struct particle_record { + /** The index of the block that the particle is within. */ + int ijk; + /** The number of particle within its block. */ + int l; + /** The x-index of the block. */ + int di; + /** The y-index of the block. */ + int dj; + /** The z-index of the block. */ + int dk; +}; + +/** \brief Template for carrying out Voronoi cell computations. */ +template <class c_class> +class voro_compute { + public: + /** A reference to the container class on which to carry out*/ + c_class &con; + /** The size of an internal computational block in the x + * direction. */ + const double boxx; + /** The size of an internal computational block in the y + * direction. */ + const double boxy; + /** The size of an internal computational block in the z + * direction. */ + const double boxz; + /** The inverse box length in the x direction, set to + * nx/(bx-ax). */ + const double xsp; + /** The inverse box length in the y direction, set to + * ny/(by-ay). */ + const double ysp; + /** The inverse box length in the z direction, set to + * nz/(bz-az). */ + const double zsp; + /** The number of boxes in the x direction for the searching mask. */ + const int hx; + /** The number of boxes in the y direction for the searching mask. */ + const int hy; + /** The number of boxes in the z direction for the searching mask. */ + const int hz; + /** A constant, set to the value of hx multiplied by hy, which + * is used in the routines which step through mask boxes in + * sequence. */ + const int hxy; + /** A constant, set to the value of hx*hy*hz, which is used in + * the routines which step through mask boxes in sequence. */ + const int hxyz; + /** The number of floating point entries to store for each + * particle. */ + const int ps; + /** This array holds the numerical IDs of each particle in each + * computational box. */ + int **id; + /** A two dimensional array holding particle positions. For the + * derived container_poly class, this also holds particle + * radii. */ + double **p; + /** An array holding the number of particles within each + * computational box of the container. */ + int *co; + voro_compute(c_class &con_,int hx_,int hy_,int hz_); + /** The class destructor frees the dynamically allocated memory + * for the mask and queue. */ + ~voro_compute() { + delete [] qu; + delete [] mask; + } + template<class v_cell> + bool compute_cell(v_cell &c,int ijk,int s,int ci,int cj,int ck); + void find_voronoi_cell(double x,double y,double z,int ci,int cj,int ck,int ijk,particle_record &w,double &mrs); + private: + /** A constant set to boxx*boxx+boxy*boxy+boxz*boxz, which is + * frequently used in the computation. */ + const double bxsq; + /** This sets the current value being used to mark tested blocks + * in the mask. */ + unsigned int mv; + /** The current size of the search list. */ + int qu_size; + /** A pointer to the array of worklists. */ + const unsigned int *wl; + /** An pointer to the array holding the minimum distances + * associated with the worklists. */ + double *mrad; + /** This array is used during the cell computation to determine + * which blocks have been considered. */ + unsigned int *mask; + /** An array is used to store the queue of blocks to test + * during the Voronoi cell computation. */ + int *qu; + /** A pointer to the end of the queue array, used to determine + * when the queue is full. */ + int *qu_l; + template<class v_cell> + bool corner_test(v_cell &c,double xl,double yl,double zl,double xh,double yh,double zh); + template<class v_cell> + inline bool edge_x_test(v_cell &c,double x0,double yl,double zl,double x1,double yh,double zh); + template<class v_cell> + inline bool edge_y_test(v_cell &c,double xl,double y0,double zl,double xh,double y1,double zh); + template<class v_cell> + inline bool edge_z_test(v_cell &c,double xl,double yl,double z0,double xh,double yh,double z1); + template<class v_cell> + inline bool face_x_test(v_cell &c,double xl,double y0,double z0,double y1,double z1); + template<class v_cell> + inline bool face_y_test(v_cell &c,double x0,double yl,double z0,double x1,double z1); + template<class v_cell> + inline bool face_z_test(v_cell &c,double x0,double y0,double zl,double x1,double y1); + bool compute_min_max_radius(int di,int dj,int dk,double fx,double fy,double fz,double gx,double gy,double gz,double& crs,double mrs); + bool compute_min_radius(int di,int dj,int dk,double fx,double fy,double fz,double mrs); + inline void add_to_mask(int ei,int ej,int ek,int *&qu_e); + inline void scan_bits_mask_add(unsigned int q,unsigned int *mijk,int ei,int ej,int ek,int *&qu_e); + inline void scan_all(int ijk,double x,double y,double z,int di,int dj,int dk,particle_record &w,double &mrs); + void add_list_memory(int*& qu_s,int*& qu_e); + /** Resets the mask in cases where the mask counter wraps + * around. */ + inline void reset_mask() { + for(unsigned int *mp(mask);mp<mask+hxyz;mp++) *mp=0; + } +}; + +} + +#endif diff --git a/contrib/voro++/src/voro++.cc b/contrib/voro++/src/voro++.cc new file mode 100644 index 0000000000000000000000000000000000000000..0176105e1a7096b67d6f45e95061560010e3a7af --- /dev/null +++ b/contrib/voro++/src/voro++.cc @@ -0,0 +1,19 @@ +// Voro++, a 3D cell-based Voronoi library +// +// Author : Chris H. Rycroft (LBL / UC Berkeley) +// Email : chr@alum.mit.edu +// Date : August 30th 2011 + +/** \file voro++.cc + * \brief A file that loads all of the function implementation files. */ + +#include "cell.cc" +#include "common.cc" +#include "v_base.cc" +#include "container.cc" +#include "unitcell.cc" +#include "container_prd.cc" +#include "pre_container.cc" +#include "v_compute.cc" +#include "c_loops.cc" +#include "wall.cc" diff --git a/contrib/voro++/src/voro++.hh b/contrib/voro++/src/voro++.hh new file mode 100644 index 0000000000000000000000000000000000000000..444f53700bed378b20119650f6a564797975ea55 --- /dev/null +++ b/contrib/voro++/src/voro++.hh @@ -0,0 +1,333 @@ +// Voro++, a 3D cell-based Voronoi library +// +// Author : Chris H. Rycroft (LBL / UC Berkeley) +// Email : chr@alum.mit.edu +// Date : August 30th 2011 + +/** \file voro++.hh + * \brief A file that loads all of the Voro++ header files. */ + +/** \mainpage Voro++ class reference manual + * \section intro Introduction + * Voro++ is a software library for carrying out three-dimensional computations + * of the Voronoi tessellation. A distinguishing feature of the Voro++ library + * is that it carries out cell-based calculations, computing the Voronoi cell + * for each particle individually, rather than computing the Voronoi + * tessellation as a global network of vertices and edges. It is particularly + * well-suited for applications that rely on cell-based statistics, where + * features of Voronoi cells (eg. volume, centroid, number of faces) can be + * used to analyze a system of particles. + * + * Voro++ is written in C++ and can be built as a static library that can be + * linked to. This manual provides a reference for every function in the class + * structure. For a general overview of the program, see the Voro++ website at + * http://math.lbl.gov/voro++/ and in particular the example programs at + * http://math.lbl.gov/voro++/examples/ that demonstrate many of the library's + * features. + * + * \section class C++ class structure + * The code is structured around several C++ classes. The voronoicell_base + * class contains all of the routines for constructing a single Voronoi cell. + * It represents the cell as a collection of vertices that are connected by + * edges, and there are routines for initializing, making, and outputting the + * cell. The voronoicell_base class form the base of the voronoicell and + * voronoicell_neighbor classes, which add specialized routines depending on + * whether neighboring particle ID information for each face must be tracked or + * not. Collectively, these classes are referred to as "voronoicell classes" + * within the documentation. + * + * There is a hierarchy of classes that represent three-dimensional particle + * systems. All of these are derived from the voro_base class, which contains + * constants that divide a three-dimensional system into a rectangular grid of + * equally-sized rectangular blocks; this grid is used for computational + * efficiency during the Voronoi calculations. + * + * The container_base, container, and container_poly are then derived from the + * voro_base class to represent a particle system in a specific + * three-dimensional rectangular box using both periodic and non-periodic + * boundary conditions. In addition, the container_periodic_base, + * container_periodic, and container_periodic_poly classes represent + * a particle system in a three-dimensional non-orthogonal periodic domain, + * defined by three periodicity vectors that represent a parallelepiped. + * Collectively, these classes are referred to as "container classes" within + * the documentation. + * + * The voro_compute template encapsulates all of the routines for computing + * Voronoi cells. Each container class has a voro_compute template within + * it, that accesses the container's particle system, and computes the Voronoi + * cells. + * + * There are several wall classes that can be used to apply certain boundary + * conditions using additional plane cuts during the Voronoi cell compution. + * The code also contains a number of small loop classes, c_loop_all, + * c_loop_subset, c_loop_all_periodic, and c_loop_order that can be used to + * iterate over a certain subset of particles in a container. The latter class + * makes use of a special particle_order class that stores a specific order of + * particles within the container. The library also contains the classes + * pre_container_base, pre_container, and pre_container_poly, that can be used + * as temporary storage when importing data of unknown size. + * + * \section voronoicell The voronoicell classes + * The voronoicell class represents a single Voronoi cell as a convex + * polyhedron, with a set of vertices that are connected by edges. The class + * contains a variety of functions that can be used to compute and output the + * Voronoi cell corresponding to a particular particle. The command init() + * can be used to initialize a cell as a large rectangular box. The Voronoi cell + * can then be computed by repeatedly cutting it with planes that correspond to + * the perpendicular bisectors between that particle and its neighbors. + * + * This is achieved by using the plane() routine, which will recompute the + * cell's vertices and edges after cutting it with a single plane. This is the + * key routine in voronoicell class. It begins by exploiting the convexity + * of the underlying cell, tracing between edges to work out if the cell + * intersects the cutting plane. If it does not intersect, then the routine + * immediately exits. Otherwise, it finds an edge or vertex that intersects + * the plane, and from there, traces out a new face on the cell, recomputing + * the edge and vertex structure accordingly. + * + * Once the cell is computed, there are many routines for computing features of + * the the Voronoi cell, such as its volume, surface area, or centroid. There + * are also many routines for outputting features of the Voronoi cell, or + * writing its shape in formats that can be read by Gnuplot or POV-Ray. + * + * \subsection internal Internal data representation + * The voronoicell class has a public member p representing the + * number of vertices. The polyhedral structure of the cell is stored + * in the following arrays: + * + * - pts: a one-dimensional array of floating point numbers, that represent the + * position vectors x_0, x_1, ..., x_{p-1} of the polyhedron vertices. + * - nu: the order of each vertex n_0, n_1, ..., n_{p-1}, corresponding to + * the number of other vertices to which each is connected. + * - ed: a two-dimensional table of edges and relations. For the ith vertex, + * ed[i] has 2n_i+1 elements. The first n_i elements are the edges e(j,i), + * where e(j,i) is the jth neighbor of vertex i. The edges are ordered + * according to a right-hand rule with respect to an outward-pointing normal. + * The next n_i elements are the relations l(j,i) which satisfy the property + * e(l(j,i),e(j,i)) = i. The final element of the ed[i] list is a back + * pointer used in memory allocation. + * + * In a very large number of cases, the values of n_i will be 3. This is because + * the only way that a higher-order vertex can be created in the plane() + * routine is if the cutting plane perfectly intersects an existing vertex. For + * random particle arrangements with position vectors specified to double + * precision this should happen very rarely. A preliminary version of this code + * was quite successful with only making use of vertices of order 3. However, + * when calculating millions of cells, it was found that this approach is not + * robust, since a single floating point error can invalidate the computation. + * This can also be a problem for cases featuring crystalline arrangements of + * particles where the corresponding Voronoi cells may have high-order vertices + * by construction. + * + * Because of this, Voro++ takes the approach that it if an existing vertex is + * within a small numerical tolerance of the cutting plane, it is treated as + * being exactly on the plane, and the polyhedral topology is recomputed + * accordingly. However, while this improves robustness, it also adds the + * complexity that n_i may no longer always be 3. This causes memory management + * to be significantly more complicated, as different vertices require a + * different number of elements in the ed[][] array. To accommodate this, the + * voronoicell class allocated edge memory in a different array called mep[][], + * in such a way that all vertices of order k are held in mep[k]. If vertex + * i has order k, then ed[i] points to memory within mep[k]. The array ed[][] + * is never directly initialized as a two-dimensional array itself, but points + * at allocations within mep[][]. To the user, it appears as though each row of + * ed[][] has a different number of elements. When vertices are added or + * deleted, care must be taken to reorder and reassign elements in these + * arrays. + * + * During the plane() routine, the code traces around the vertices of the cell, + * and adds new vertices along edges which intersect the cutting plane to + * create a new face. The values of l(j,i) are used in this computation, as + * when the code is traversing from one vertex on the cell to another, this + * information allows the code to immediately work out which edge of a vertex + * points back to the one it came from. As new vertices are created, the l(j,i) + * are also updated to ensure consistency. To ensure robustness, the plane + * cutting algorithm should work with any possible combination of vertices + * which are inside, outside, or exactly on the cutting plane. + * + * Vertices exactly on the cutting plane create some additional computational + * difficulties. If there are two marginal vertices connected by an existing + * edge, then it would be possible for duplicate edges to be created between + * those two vertices, if the plane routine traces along both sides of this + * edge while constructing the new face. The code recognizes these cases and + * prevents the double edge from being formed. Another possibility is the + * formation of vertices of order two or one. At the end of the plane cutting + * routine, the code checks to see if any of these are present, removing the + * order one vertices by just deleting them, and removing the order two + * vertices by connecting the two neighbors of each vertex together. It is + * possible that the removal of a single low-order vertex could result in the + * creation of additional low-order vertices, so the process is applied + * recursively until no more are left. + * + * \section container The container classes + * There are four container classes available for general usage: container, + * container_poly, container_periodic, and container_periodic_poly. Each of + * these represent a system of particles in a specific three-dimensional + * geometry. They contain routines for importing particles from a text file, + * and adding particles individually. They also contain a large number of + * analyzing and outputting the particle system. Internally, the routines that + * compute Voronoi cells do so by making use of the voro_compute template. + * Each container class contains routines that tell the voro_compute template + * about the specific geometry of this container. + * + * \section voro_compute The voro_compute template + * The voro_compute template encapsulates the routines for carrying out the + * Voronoi cell computations. It contains data structures suchs as a mask and a + * queue that are used in the computations. The voro_compute template is + * associated with a specific container class, and during the computation, it + * calls routines in the container class to access the particle positions that + * are stored there. + * + * The key routine in this class is compute_cell(), which makes use of a + * voronoicell class to construct a Voronoi cell for a specific particle in the + * container. The basic approach that this function takes is to repeatedly cut + * the Voronoi cell by planes corresponding neighboring particles, and stop + * when it recognizes that all the remaining particles in the container are too + * far away to possibly influence cell's shape. The code makes use of two + * possible methods for working out when a cell computation is complete: + * + * - Radius test: if the maximum distance of a Voronoi cell + * vertex from the cell center is R, then no particles more than a distance + * 2R away can possibly influence the cell. This a very fast computation to + * do, but it has no directionality: if the cell extends a long way in one + * direction then particles a long distance in other directions will still + * need to be tested. + * - Region test: it is possible to test whether a specific region can + * possibly influence the cell by applying a series of plane tests at the + * point on the region which is closest to the Voronoi cell center. This is a + * slower computation to do, but it has directionality. + * + * Another useful observation is that the regions that need to be tested are + * simply connected, meaning that if a particular region does not need to be + * tested, then neighboring regions which are further away do not need to be + * tested. + * + * For maximum efficiency, it was found that a hybrid approach making use of + * both of the above tests worked well in practice. Radius tests work well for + * the first few blocks, but switching to region tests after then prevent the + * code from becoming extremely slow, due to testing over very large spherical + * shells of particles. The compute_cell() routine therefore takes the + * following approach: + * + * - Initialize the voronoicell class to fill the entire computational domain. + * - Cut the cell by any wall objects that have been added to the container. + * - Apply plane cuts to the cell corresponding to the other particles which + * are within the current particle's region. + * - Test over a pre-computed worklist of neighboring regions, that have been + * ordered according to the minimum distance away from the particle's + * position. Apply radius tests after every few regions to see if the + * calculation can terminate. + * - If the code reaches the end of the worklist, add all the neighboring + * regions to a new list. + * - Carry out a region test on the first item of the list. If the region needs + * to be tested, apply the plane() routine for all of its particles, and then + * add any neighboring regions to the end of the list that need to be tested. + * Continue until the list has no elements left. + * + * The compute_cell() routine forms the basis of many other routines, such as + * store_cell_volumes() and draw_cells_gnuplot() that can be used to calculate + * and draw the cells in a container. + * + * \section walls Wall computation + * Wall computations are handled by making use of a pure virtual wall class. + * Specific wall types are derived from this class, and require the + * specification of two routines: point_inside() that tests to see if a point + * is inside a wall or not, and cut_cell() that cuts a cell according to the + * wall's position. The walls can be added to the container using the + * add_wall() command, and these are called each time a compute_cell() command + * is carried out. At present, wall types for planes, spheres, cylinders, and + * cones are provided, although custom walls can be added by creating new + * classes derived from the pure virtual class. Currently all wall types + * approximate the wall surface with a single plane, which produces some small + * errors, but generally gives good results for dense particle packings in + * direct contact with a wall surface. It would be possible to create more + * accurate walls by making cut_cell() routines that approximate the curved + * surface with multiple plane cuts. + * + * The wall objects can used for periodic calculations, although to obtain + * valid results, the walls should also be periodic as well. For example, in a + * domain that is periodic in the x direction, a cylinder aligned along the x + * axis could be added. At present, the interior of all wall objects are convex + * domains, and consequently any superposition of them will be a convex domain + * also. Carrying out computations in non-convex domains poses some problems, + * since this could theoretically lead to non-convex Voronoi cells, which the + * internal data representation of the voronoicell class does not support. For + * non-convex cases where the wall surfaces feature just a small amount of + * negative curvature (eg. a torus) approximating the curved surface with a + * single plane cut may give an acceptable level of accuracy. For non-convex + * cases that feature internal angles, the best strategy may be to decompose + * the domain into several convex subdomains, carry out a calculation in each, + * and then add the results together. The voronoicell class cannot be easily + * modified to handle non-convex cells as this would fundamentally alter the + * algorithms that it uses, and cases could arise where a single plane cut + * could create several new faces as opposed to just one. + * + * \section loops Loop classes + * The container classes have a number of simple routines for calculating + * Voronoi cells for all particles within them. However, in some situations it + * is desirable to iterate over a specific subset of particles. This can be + * achieved with the c_loop classes that are all derived from the c_loop_base + * class. Each class can iterate over a specific subset of particles in a + * container. There are three loop classes for use with the container and + * container_poly classes: + * + * - c_loop_all will loop over all of the particles in a container. + * - c_loop_subset will loop over a subset of particles in a container that lie + * within some geometrical region. It can loop over particles in a + * rectangular box, particles in a sphere, or particles that lie within + * specific internal computational blocks. + * - c_loop_order will loop over a specific list of particles that were + * previously stored in a particle_order class. + * + * Several of the key routines within the container classes (such as + * draw_cells_gnuplot and print_custom) have versions where they can be passed + * a loop class to use. Loop classes can also be used directly and there are + * some examples on the library website that demonstrate this. It is also + * possible to write custom loop classes. + * + * In addition to the loop classes mentioned above, there is also a + * c_loop_all_periodic class, that is specifically for use with the + * container_periodic and container_periodic_poly classes. Since the data + * structures of these containers differ considerably, it requires a different + * loop class that is not interoperable with the others. + * + * \section pre_container The pre_container classes + * Voro++ makes use of internal computational grid of blocks that are used to + * configure the code for maximum efficiency. As discussed on the library + * website, the best performance is achieved for around 5 particles per block, + * with anything in the range from 3 to 12 giving good performance. Usually + * the size of the grid can be chosen by ensuring that the number of blocks is + * equal to the number of particles divided by 5. + * + * However, this can be difficult to choose in cases when the number of + * particles is not known a priori, and in thes cases the pre_container classes + * can be used. They can import an arbitrary number of particle positions from + * a file, dynamically allocating memory in chunks as necessary. Once particles + * are imported, they can guess an optimal block arrangement to use for the + * container class, and then transfer the particles to the container. By + * default, this procedure is used by the command-line utility to enable it to + * work well with arbitrary sizes of input data. + * + * The pre_container class can be used when no particle radius information is + * available, and the pre_container_poly class can be used when radius + * information is available. At present, the pre_container classes can only be + * used with the container and container_poly classes. They do not support + * the container_periodic and container_periodic_poly classes. */ + +#ifndef VOROPP_HH +#define VOROPP_HH + +#include "config.hh" +#include "common.hh" +#include "cell.hh" +#include "v_base.hh" +#include "rad_option.hh" +#include "container.hh" +#include "unitcell.hh" +#include "container_prd.hh" +#include "pre_container.hh" +#include "v_compute.hh" +#include "c_loops.hh" +#include "wall.hh" + +#endif diff --git a/contrib/voro++/src/wall.cc b/contrib/voro++/src/wall.cc new file mode 100644 index 0000000000000000000000000000000000000000..131d8132384fea6c37a09063f259a27de4ea814b --- /dev/null +++ b/contrib/voro++/src/wall.cc @@ -0,0 +1,122 @@ +// Voro++, a 3D cell-based Voronoi library +// +// Author : Chris H. Rycroft (LBL / UC Berkeley) +// Email : chr@alum.mit.edu +// Date : August 30th 2011 + +/** \file wall.cc + * \brief Function implementations for the derived wall classes. */ + +#include "wall.hh" + +namespace voro { + +/** Tests to see whether a point is inside the sphere wall object. + * \param[in,out] (x,y,z) the vector to test. + * \return True if the point is inside, false if the point is outside. */ +bool wall_sphere::point_inside(double x,double y,double z) { + return (x-xc)*(x-xc)+(y-yc)*(y-yc)+(z-zc)*(z-zc)<rc*rc; +} + +/** Cuts a cell by the sphere wall object. The spherical wall is approximated by + * a single plane applied at the point on the sphere which is closest to the center + * of the cell. This works well for particle arrangements that are packed against + * the wall, but loses accuracy for sparse particle distributions. + * \param[in,out] c the Voronoi cell to be cut. + * \param[in] (x,y,z) the location of the Voronoi cell. + * \return True if the cell still exists, false if the cell is deleted. */ +template<class v_cell> +bool wall_sphere::cut_cell_base(v_cell &c,double x,double y,double z) { + double xd=x-xc,yd=y-yc,zd=z-zc,dq=xd*xd+yd*yd+zd*zd; + if (dq>1e-5) { + dq=2*(sqrt(dq)*rc-dq); + return c.nplane(xd,yd,zd,dq,w_id); + } + return true; +} + +/** Tests to see whether a point is inside the plane wall object. + * \param[in] (x,y,z) the vector to test. + * \return True if the point is inside, false if the point is outside. */ +bool wall_plane::point_inside(double x,double y,double z) { + return x*xc+y*yc+z*zc<ac; +} + +/** Cuts a cell by the plane wall object. + * \param[in,out] c the Voronoi cell to be cut. + * \param[in] (x,y,z) the location of the Voronoi cell. + * \return True if the cell still exists, false if the cell is deleted. */ +template<class v_cell> +bool wall_plane::cut_cell_base(v_cell &c,double x,double y,double z) { + double dq=2*(ac-x*xc-y*yc-z*zc); + return c.nplane(xc,yc,zc,dq,w_id); +} + +/** Tests to see whether a point is inside the cylindrical wall object. + * \param[in] (x,y,z) the vector to test. + * \return True if the point is inside, false if the point is outside. */ +bool wall_cylinder::point_inside(double x,double y,double z) { + double xd=x-xc,yd=y-yc,zd=z-zc; + double pa=(xd*xa+yd*ya+zd*za)*asi; + xd-=xa*pa;yd-=ya*pa;zd-=za*pa; + return xd*xd+yd*yd+zd*zd<rc*rc; +} + +/** Cuts a cell by the cylindrical wall object. The cylindrical wall is + * approximated by a single plane applied at the point on the cylinder which is + * closest to the center of the cell. This works well for particle arrangements + * that are packed against the wall, but loses accuracy for sparse particle + * distributions. + * \param[in,out] c the Voronoi cell to be cut. + * \param[in] (x,y,z) the location of the Voronoi cell. + * \return True if the cell still exists, false if the cell is deleted. */ +template<class v_cell> +bool wall_cylinder::cut_cell_base(v_cell &c,double x,double y,double z) { + double xd=x-xc,yd=y-yc,zd=z-zc,pa=(xd*xa+yd*ya+zd*za)*asi; + xd-=xa*pa;yd-=ya*pa;zd-=za*pa; + pa=xd*xd+yd*yd+zd*zd; + if(pa>1e-5) { + pa=2*(sqrt(pa)*rc-pa); + return c.nplane(xd,yd,zd,pa,w_id); + } + return true; +} + +/** Tests to see whether a point is inside the cone wall object. + * \param[in] (x,y,z) the vector to test. + * \return True if the point is inside, false if the point is outside. */ +bool wall_cone::point_inside(double x,double y,double z) { + double xd=x-xc,yd=y-yc,zd=z-zc,pa=(xd*xa+yd*ya+zd*za)*asi; + xd-=xa*pa;yd-=ya*pa;zd-=za*pa; + pa*=gra; + if (pa<0) return false; + pa*=pa; + return xd*xd+yd*yd+zd*zd<pa; +} + +/** Cuts a cell by the cone wall object. The conical wall is + * approximated by a single plane applied at the point on the cone which is + * closest to the center of the cell. This works well for particle arrangements + * that are packed against the wall, but loses accuracy for sparse particle + * distributions. + * \param[in,out] c the Voronoi cell to be cut. + * \param[in] (x,y,z) the location of the Voronoi cell. + * \return True if the cell still exists, false if the cell is deleted. */ +template<class v_cell> +bool wall_cone::cut_cell_base(v_cell &c,double x,double y,double z) { + double xd=x-xc,yd=y-yc,zd=z-zc,xf,yf,zf,q,pa=(xd*xa+yd*ya+zd*za)*asi; + xd-=xa*pa;yd-=ya*pa;zd-=za*pa; + pa=xd*xd+yd*yd+zd*zd; + if(pa>1e-5) { + pa=1/sqrt(pa); + q=sqrt(asi); + xf=-sang*q*xa+cang*pa*xd; + yf=-sang*q*ya+cang*pa*yd; + zf=-sang*q*za+cang*pa*zd; + pa=2*(xf*(xc-x)+yf*(yc-y)+zf*(zc-z)); + return c.nplane(xf,yf,zf,pa,w_id); + } + return true; +} + +} diff --git a/contrib/voro++/src/wall.hh b/contrib/voro++/src/wall.hh new file mode 100644 index 0000000000000000000000000000000000000000..6db0c5a2e5f11af56ece61d40db6dfd5e8d7c4ab --- /dev/null +++ b/contrib/voro++/src/wall.hh @@ -0,0 +1,119 @@ +// Voro++, a 3D cell-based Voronoi library +// +// Author : Chris H. Rycroft (LBL / UC Berkeley) +// Email : chr@alum.mit.edu +// Date : August 30th 2011 + +/** \file wall.hh + * \brief Header file for the derived wall classes. */ + +#ifndef VOROPP_WALL_HH +#define VOROPP_WALL_HH + +#include "cell.hh" +#include "container.hh" + +namespace voro { + +/** \brief A class representing a spherical wall object. + * + * This class represents a spherical wall object. */ +struct wall_sphere : public wall { + public: + /** Constructs a spherical wall object. + * \param[in] w_id_ an ID number to associate with the wall for + * neighbor tracking. + * \param[in] (xc_,yc_,zc_) a position vector for the sphere's + * center. + * \param[in] rc_ the radius of the sphere. */ + wall_sphere(double xc_,double yc_,double zc_,double rc_,int w_id_=-99) + : w_id(w_id_), xc(xc_), yc(yc_), zc(zc_), rc(rc_) {} + bool point_inside(double x,double y,double z); + template<class v_cell> + bool cut_cell_base(v_cell &c,double x,double y,double z); + bool cut_cell(voronoicell &c,double x,double y,double z) {return cut_cell_base(c,x,y,z);} + bool cut_cell(voronoicell_neighbor &c,double x,double y,double z) {return cut_cell_base(c,x,y,z);} + private: + const int w_id; + const double xc,yc,zc,rc; +}; + +/** \brief A class representing a plane wall object. + * + * This class represents a single plane wall object. */ +struct wall_plane : public wall { + public: + /** Constructs a plane wall object. + * \param[in] (xc_,yc_,zc_) a normal vector to the plane. + * \param[in] ac_ a displacement along the normal vector. + * \param[in] w_id_ an ID number to associate with the wall for + * neighbor tracking. */ + wall_plane(double xc_,double yc_,double zc_,double ac_,int w_id_=-99) + : w_id(w_id_), xc(xc_), yc(yc_), zc(zc_), ac(ac_) {} + bool point_inside(double x,double y,double z); + template<class v_cell> + bool cut_cell_base(v_cell &c,double x,double y,double z); + bool cut_cell(voronoicell &c,double x,double y,double z) {return cut_cell_base(c,x,y,z);} + bool cut_cell(voronoicell_neighbor &c,double x,double y,double z) {return cut_cell_base(c,x,y,z);} + private: + const int w_id; + const double xc,yc,zc,ac; +}; + +/** \brief A class representing a cylindrical wall object. + * + * This class represents a open cylinder wall object. */ +struct wall_cylinder : public wall { + public: + /** Constructs a cylinder wall object. + * \param[in] (xc_,yc_,zc_) a point on the axis of the + * cylinder. + * \param[in] (xa_,ya_,za_) a vector pointing along the + * direction of the cylinder. + * \param[in] rc_ the radius of the cylinder + * \param[in] w_id_ an ID number to associate with the wall for + * neighbor tracking. */ + wall_cylinder(double xc_,double yc_,double zc_,double xa_,double ya_,double za_,double rc_,int w_id_=-99) + : w_id(w_id_), xc(xc_), yc(yc_), zc(zc_), xa(xa_), ya(ya_), za(za_), + asi(1/(xa_*xa_+ya_*ya_+za_*za_)), rc(rc_) {} + bool point_inside(double x,double y,double z); + template<class v_cell> + bool cut_cell_base(v_cell &c,double x,double y,double z); + bool cut_cell(voronoicell &c,double x,double y,double z) {return cut_cell_base(c,x,y,z);} + bool cut_cell(voronoicell_neighbor &c,double x,double y,double z) {return cut_cell_base(c,x,y,z);} + private: + const int w_id; + const double xc,yc,zc,xa,ya,za,asi,rc; +}; + + +/** \brief A class representing a conical wall object. + * + * This class represents a cone wall object. */ +struct wall_cone : public wall { + public: + /** Constructs a cone wall object. + * \param[in] (xc_,yc_,zc_) the apex of the cone. + * \param[in] (xa_,ya_,za_) a vector pointing along the axis of + * the cone. + * \param[in] ang the angle (in radians) of the cone, measured + * from the axis. + * \param[in] w_id_ an ID number to associate with the wall for + * neighbor tracking. */ + wall_cone(double xc_,double yc_,double zc_,double xa_,double ya_,double za_,double ang,int w_id_=-99) + : w_id(w_id_), xc(xc_), yc(yc_), zc(zc_), xa(xa_), ya(ya_), za(za_), + asi(1/(xa_*xa_+ya_*ya_+za_*za_)), + gra(tan(ang)), sang(sin(ang)), cang(cos(ang)) {} + bool point_inside(double x,double y,double z); + template<class v_cell> + bool cut_cell_base(v_cell &c,double x,double y,double z); + bool cut_cell(voronoicell &c,double x,double y,double z) {return cut_cell_base(c,x,y,z);} + bool cut_cell(voronoicell_neighbor &c,double x,double y,double z) {return cut_cell_base(c,x,y,z);} + private: + const int w_id; + const double xc,yc,zc,xa,ya,za,asi,gra,sang,cang; +}; + +} + +#endif diff --git a/contrib/voro++/src/worklist.hh b/contrib/voro++/src/worklist.hh new file mode 100644 index 0000000000000000000000000000000000000000..878cf2cfb122562d15797169c02bad2cb542cf92 --- /dev/null +++ b/contrib/voro++/src/worklist.hh @@ -0,0 +1,32 @@ +// Voro++, a 3D cell-based Voronoi library +// +// Author : Chris H. Rycroft (LBL / UC Berkeley) +// Email : chr@alum.mit.edu +// Date : August 30th 2011 + +/** \file worklist.hh + * \brief Header file for setting constants used in the block worklists that are + * used during cell computation. + * + * This file is automatically generated by worklist_gen.pl and it is not + * intended to be edited by hand. */ + +#ifndef VOROPP_WORKLIST_HH +#define VOROPP_WORKLIST_HH + +namespace voro { + +/** Each region is divided into a grid of subregions, and a worklist is +# constructed for each. This parameter sets is set to half the number of +# subregions that the block is divided into. */ +const int wl_hgrid=4; +/** The number of subregions that a block is subdivided into, which is twice +the value of hgrid. */ +const int wl_fgrid=8; +/** The total number of worklists, set to the cube of hgrid. */ +const int wl_hgridcu=64; +/** The number of elements in each worklist. */ +const int wl_seq_length=64; + +} +#endif diff --git a/contrib/voro++/src/worklist_gen.pl b/contrib/voro++/src/worklist_gen.pl new file mode 100755 index 0000000000000000000000000000000000000000..f6beb6619646720c8f9ba0bcbd081fa80b1d3474 --- /dev/null +++ b/contrib/voro++/src/worklist_gen.pl @@ -0,0 +1,236 @@ +#!/usr/bin/perl +# Voro++, a 3D cell-based Voronoi library +# +# Author : Chris H. Rycroft (LBL / UC Berkeley) +# Email : chr@alum.mit.edu +# Date : August 30th 2011 +# +# worklist_gen.pl - this perl script is used to automatically generate the +# worklists of blocks that are stored in worklist.cc, that are used by the +# compute_cell() routine to ensure maximum efficiency + +# Each region is divided into a grid of subregions, and a worklist is +# constructed for each. This parameter sets is set to half the number of +# subregions that the block is divided into. +$hr=4; + +# This parameter is automatically set to the the number of subregions that the +# block is divided into +$r=$hr*2; + +# This parameter sets the total number of block entries in each worklist +$ls=63; + +# When the worklists are being constructed, a mask array is made use of. To +# prevent the creation of array elements with negative indices, this parameter +# sets an arbitrary displacement. +$dis=8; + +# Constants used mask indexing +$d=2*$dis+1;$dd=$d*$d;$d0=(1+$d+$dd)*$dis; + +use Math::Trig; + +# Construct the worklist header file, based on the parameters above +open W,">worklist.hh"; +print W <<EOF; +// Voro++, a 3D cell-based Voronoi library +// +// Author : Chris H. Rycroft (LBL / UC Berkeley) +// Email : chr\@alum.mit.edu +// Date : August 30th 2011 + +/** \\file worklist.hh + * \\brief Header file for setting constants used in the block worklists that are + * used during cell computation. + * + * This file is automatically generated by worklist_gen.pl and it is not + * intended to be edited by hand. */ + +#ifndef VOROPP_WORKLIST_HH +#define VOROPP_WORKLIST_HH + +namespace voro { + +/** Each region is divided into a grid of subregions, and a worklist is +# constructed for each. This parameter sets is set to half the number of +# subregions that the block is divided into. */ +EOF +print W "const int wl_hgrid=$hr;\n"; +print W <<EOF; +/** The number of subregions that a block is subdivided into, which is twice +the value of hgrid. */ +EOF +print W "const int wl_fgrid=$r;\n"; +print W <<EOF; +/** The total number of worklists, set to the cube of hgrid. */ +EOF +printf W "const int wl_hgridcu=%d;\n",$hr*$hr*$hr; +print W <<EOF; +/** The number of elements in each worklist. */ +EOF +printf W "const int wl_seq_length=%d;\n",$ls+1; +print W <<EOF; + +} +#endif +EOF +close W; + +# Construct the preamble to the worklist.cc file +open W,">v_base_wl.cc"; +print W <<EOF; +// Voro++, a 3D cell-based Voronoi library +// +// Author : Chris H. Rycroft (LBL / UC Berkeley) +// Email : chr\@alum.mit.edu +// Date : August 30th 2011 + +/** \\file v_base_wl.cc + * \\brief The table of block worklists that are used during the cell + * computation, which is part of the voro_base class. + * + * This file is automatically generated by worklist_gen.pl and it is not + * intended to be edited by hand. */ + +EOF +printf W "const unsigned int voro_base::wl[wl_seq_length*wl_hgridcu]={\n"; + +# Now create a worklist for each subregion +for($kk=0;$kk<$hr;$kk++) { + for($jj=0;$jj<$hr;$jj++) { + for($ii=0;$ii<$hr;$ii++) { + worklist($ii,$jj,$kk); + } + } +} + +# Finish the file and close it +print W "};\n"; +close W; + +# A subroutine +sub worklist { +# print "@_[0] @_[1] @_[2]\n"; + $ind=@_[0]+$hr*(@_[1]+$hr*@_[2]); + $ac=0;$v+=2; + $xp=$yp=$zp=0; + $x=(@_[0]+0.5)/$r; + $y=(@_[1]+0.5)/$r; + $z=(@_[2]+0.5)/$r; + $m[$d0]=$v; + add(1,0,0);add(0,1,0);add(0,0,1); + add(-1,0,0);add(0,-1,0);add(0,0,-1); + foreach $l (1..$ls) { + $minwei=1e9; + foreach (0..$ac-1) { + $xt=@a[3*$_];$yt=@a[3*$_+1];$zt=@a[3*$_+2]; +# $wei=dis($x,$y,$z,$xt,$yt,$zt)+1*acos(($xt*$xp+$yt*$yp+$zt*$zp)/($xt*$xt+$yt*$yt+$zt*$zt)*($xp*$xp+$yp*$yp+$zp*$zp)); + $wei=adis($x,$y,$z,$xt,$yt,$zt)+0.02*sqrt(($xt-$xp)**2+($yt-$yp)**2+($zt-$zp)**2); + $nx=$_,$minwei=$wei if $wei<$minwei; + } + $xp=@a[3*$nx];$yp=@a[3*$nx+1];$zp=@a[3*$nx+2]; + add($xp+1,$yp,$zp);add($xp,$yp+1,$zp);add($xp,$yp,$zp+1); + add($xp-1,$yp,$zp);add($xp,$yp-1,$zp);add($xp,$yp,$zp-1); +# print "=> $l $xp $yp $zp\n" if $l<4; + push @b,(splice @a,3*$nx,3);$ac--; + } + + # Mark all blocks that are on this worklist entry + $m[$d0]=++$v; + for($i=0;$i<$#b;$i+=3) { + $xt=$b[$i];$yt=$b[$i+1];$zt=$b[$i+2]; + $m[$d0+$xt+$d*$yt+$dd*$zt]=$v; + } + + # Find which neighboring outside blocks need to be marked when + # considering this block, being as conservative as possible by + # overwriting the marks, so that the last possible entry that can reach + # a block is used + for($i=$j=0;$i<$#b;$i+=3,$j++) { + $xt=$b[$i];$yt=$b[$i+1];$zt=$b[$i+2]; + $k=$d0+$xt+$yt*$d+$zt*$dd; + $la[$k+1]=$j, $m[$k+1]=$v+1 if $xt>=0 && $m[$k+1]!=$v; + $la[$k+$d]=$j, $m[$k+$d]=$v+1 if $yt>=0 && $m[$k+$d]!=$v; + $la[$k+$dd]=$j, $m[$k+$dd]=$v+1 if $zt>=0 && $m[$k+$dd]!=$v; + $la[$k-1]=$j, $m[$k-1]=$v+1 if $xt<=0 && $m[$k-1]!=$v; + $la[$k-$d]=$j, $m[$k-$d]=$v+1 if $yt<=0 && $m[$k-$d]!=$v; + $la[$k-$dd]=$j, $m[$k-$dd]=$v+1 if $zt<=0 && $m[$k-$dd]!=$v; + } + + # Scan to ensure that no neighboring blocks have been missed by the + # outwards-looking logic in the above section + for($i=0;$i<$#b;$i+=3) { + wl_check($d0+$b[$i]+$b[$i+1]*$d+$b[$i+2]*$dd); + } + + # Compute the number of entries where outside blocks do not need to be + # consider + for($i=$j=0;$i<$#b;$i+=3,$j++) { + $k=$d0+$b[$i]+$b[$i+1]*$d+$b[$i+2]*$dd; + last if $m[$k+1]!=$v; + last if $m[$k+$d]!=$v; + last if $m[$k+$dd]!=$v; + last if $m[$k-1]!=$v; + last if $m[$k-$d]!=$v; + last if $m[$k-$dd]!=$v; + } + print W "\t$j"; + + # Create worklist entry and save to file + $j=0; + while ($#b>0) { + $xt=shift @b;$yt=shift @b;$zt=shift @b; + $k=$d0+$xt+$yt*$d+$zt*$dd; + $o=0; + $o|=1 if $m[$k+1]!=$v && $la[$k+1]==$j; + $o^=3 if $m[$k-1]!=$v && $la[$k-1]==$j; + $o|=8 if $m[$k+$d]!=$v && $la[$k+$d]==$j; + $o^=24 if $m[$k-$d]!=$v && $la[$k-$d]==$j; + $o|=64 if $m[$k+$dd]!=$v && $la[$k+$dd]==$j; + $o^=192 if $m[$k-$dd]!=$v && $la[$k-$dd]==$j; + printf W ",%#x",(($xt+64)|($yt+64)<<7|($zt+64)<<14|$o<<21); + $j++; + } + print W "," unless $ind==$hr*$hr*$hr-1; + print W "\n"; + + # Remove list memory + undef @a; + undef @b; +} + +sub add { + if ($m[$d0+@_[0]+$d*@_[1]+$dd*@_[2]]!=$v) { + $ac++; + push @a,@_[0],@_[1],@_[2]; + $m[$d0+@_[0]+$d*@_[1]+$dd*@_[2]]=$v; + } +} + +sub dis { + $xl=@_[3]+0.3-@_[0];$xh=@_[3]+0.7-@_[0]; + $yl=@_[4]+0.3-@_[1];$yh=@_[4]+0.7-@_[1]; + $zl=@_[5]+0.3-@_[2];$zh=@_[5]+0.7-@_[2]; + $dis=(abs($xl)<abs($xh)?$xl:$xh)**2 + +(abs($yl)<abs($yh)?$yl:$yh)**2 + +(abs($zl)<abs($zh)?$zl:$zh)**2; + return sqrt $dis; +} + +sub adis { + $xco=$yco=$zco=0; + $xco=@_[0]-@_[3] if @_[3]>0; + $xco=@_[0]-@_[3]-1 if @_[3]<0; + $yco=@_[1]-@_[4] if @_[4]>0; + $yco=@_[1]-@_[4]-1 if @_[4]<0; + $zco=@_[2]-@_[5] if @_[5]>0; + $zco=@_[2]-@_[5]-1 if @_[5]<0; + return sqrt $xco*$xco+$yco*$yco+$zco*$zco; +} + +sub wl_check { + die "Failure in worklist construction\n" if $m[@_[0]+1]<$v||$m[@_[0]-1]<$v + ||$m[@_[0]+$d]<$v||$m[@_[0]-$d]<$v + ||$m[@_[0]+$dd]<$v||$m[@_[0]-$dd]<$v; +} diff --git a/contrib/voro++/zeo/Makefile b/contrib/voro++/zeo/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..cffb935d59bc4319c8790a4eaf5f0e833a00f8b5 --- /dev/null +++ b/contrib/voro++/zeo/Makefile @@ -0,0 +1,35 @@ +# Voro++ makefile +# +# Author : Chris H. Rycroft (LBL / UC Berkeley) +# Email : chr@alum.mit.edu +# Date : August 30th 2011 + +# Load the common configuration file +include ../config.mk + +# List of executables +EXECUTABLES=network images cp_test + +# Makefile rules +all: $(EXECUTABLES) + +# List of the common source files +objs=v_network.o +src=$(patsubst %.o,%.cc,$(objs)) + +%.o: %.cc + $(CXX) $(CFLAGS) -I../src -c $< + +network: network.cc v_network.o v_network.hh r_table.cc + $(CXX) $(CFLAGS) -I../src -L../src -o network network.cc v_network.o -lvoro++ + +images: images.cc + $(CXX) $(CFLAGS) -I../src -L../src -o images images.cc -lvoro++ + +cp_test: cp_test.cc + $(CXX) $(CFLAGS) -I../src -L../src -o cp_test cp_test.cc -lvoro++ + +clean: + rm -f $(EXECUTABLES) + +.PHONY: all clean diff --git a/contrib/voro++/zeo/cp_test.cc b/contrib/voro++/zeo/cp_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..a5e2176d0677b1796a4f6cf5e94203deff4b72c8 --- /dev/null +++ b/contrib/voro++/zeo/cp_test.cc @@ -0,0 +1,47 @@ +// Parallelepiped calculation example code +// +// Author : Chris H. Rycroft (LBL / UC Berkeley) +// Email : chr@alum.mit.edu +// Date : August 30th 2011 + +#include "voro++.hh" +using namespace voro; + +// Set up +const double bx=4; +const double bxy=0,by=2; +const double bxz=1,byz=0,bz=3; + +// Set up the number of blocks that the container is divided into +const int nx=5,ny=5,nz=5; + +// Set the number of particles that are going to be randomly introduced +const int particles=20; + +// This function returns a random double between 0 and 1 +double rnd() {return double(rand())/RAND_MAX;} + +int main() { + int i; + double x,y,z; + + // Create a parallelepiped with + container_periodic con(bx,bxy,by,bxz,byz,bz,nx,ny,nz,8); + + // Randomly add particles into the container + for(i=0;i<particles;i++) { + x=rnd()*bx; + y=rnd()*by; + z=rnd()*bz; + con.put(i,x,y,z); + } + + // Output the particle positions in gnuplot format + con.draw_particles("cp_test_p.gnu"); + + // Output the Voronoi cells in gnuplot format + con.draw_cells_gnuplot("cp_test_v.gnu"); + + // Output the domain outline + con.draw_domain_gnuplot("cp_test_d.gnu"); +} diff --git a/contrib/voro++/zeo/cp_test.gnuplot b/contrib/voro++/zeo/cp_test.gnuplot new file mode 100644 index 0000000000000000000000000000000000000000..6ed39ca7e79885dc133374adab0e65532830b800 --- /dev/null +++ b/contrib/voro++/zeo/cp_test.gnuplot @@ -0,0 +1,11 @@ +set term pdf +set xlabel 'x' +set ylabel 'y' +set zlabel 'z' +set view 60,60 +set size square +set xtics offset -0.2,-0.2 +set ytics offset 0.2,-0.2 +set output 'cp_test.pdf' +splot 'cp_test_v.gnu' w l t 'Voronoi cells', 'cp_test_p.gnu' u 2:3:4 w p lt 4 t 'Particles', 'cp_test_d.gnu' w l t 'Domain' +set output diff --git a/contrib/voro++/zeo/examples/AFX.v1 b/contrib/voro++/zeo/examples/AFX.v1 new file mode 100644 index 0000000000000000000000000000000000000000..a778da2a2cd90452159707a3c8d75d963de6196e --- /dev/null +++ b/contrib/voro++/zeo/examples/AFX.v1 @@ -0,0 +1,150 @@ +Unit cell vectors: +va= 13.67400000 0.00000000 0.00000000 +vb= -6.83700000 11.84203137 0.00000000 +vc= 0.00000000 0.00000000 19.69500000 +144 +O 0.00000000 2.32103815 1.81194000 +O 11.66392200 1.16051908 11.65944000 +O 2.01007800 1.16051908 11.65944000 +O 4.82692200 10.68151230 1.81194000 +O -4.82692200 10.68151230 1.81194000 +O 6.83700000 9.52099322 17.88306000 +O 11.66392200 1.16051908 17.88306000 +O 6.83700000 9.52099322 11.65944000 +O 2.01007800 1.16051908 17.88306000 +O 4.82692200 10.68151230 8.03556000 +O 0.00000000 2.32103815 8.03556000 +O -4.82692200 10.68151230 8.03556000 +O 11.20652670 1.42459637 1.94192700 +O 4.36952670 10.41743500 11.78942700 +O 0.00000000 2.84919275 11.78942700 +O 6.83700000 8.99283862 1.94192700 +O 2.46747330 1.42459637 1.94192700 +O 4.36952670 10.41743500 17.75307300 +O 0.00000000 2.84919275 17.75307300 +O -4.36952670 10.41743500 11.78942700 +O -4.36952670 10.41743500 17.75307300 +O 11.20652670 1.42459637 7.90557300 +O 2.46747330 1.42459637 7.90557300 +O 6.83700000 8.99283862 7.90557300 +O -1.76189490 3.05169148 0.00000000 +O 10.15021020 0.00000000 9.84750000 +O 1.76189490 3.05169149 9.84750000 +O 5.07510510 8.79033989 0.00000000 +O 3.52378980 0.00000000 0.00000000 +O -5.07510510 8.79033989 9.84750000 +O -5.07510510 8.79033989 0.00000000 +O 3.52378980 0.00000000 9.84750000 +O 5.07510510 8.79033989 9.84750000 +O 1.76189490 3.05169148 0.00000000 +O 10.15021020 0.00000000 0.00000000 +O -1.76189490 3.05169149 9.84750000 +O -1.96221900 3.94813326 2.46187500 +O 9.27370680 0.27473513 12.30937500 +O 2.43807420 3.67339813 12.30937500 +O 4.39892580 8.16863324 2.46187500 +O -2.43670680 11.56729624 2.46187500 +O 4.87478100 7.89389811 17.23312500 +O 11.23592580 3.67339813 17.23312500 +O 8.79921900 7.89389811 12.30937500 +O 4.40029320 0.27473513 17.23312500 +O 2.43670680 11.56729624 7.38562500 +O 1.96221900 3.94813326 7.38562500 +O -4.39892580 8.16863324 7.38562500 +O 8.79921900 7.89389811 17.23312500 +O -2.43670680 11.56729624 7.38562500 +O 4.39892580 8.16863324 7.38562500 +O 2.43807420 3.67339813 17.23312500 +O 9.27370680 0.27473513 17.23312500 +O 1.96221900 3.94813326 2.46187500 +O -4.39892580 8.16863324 2.46187500 +O -1.96221900 3.94813326 7.38562500 +O 2.43670680 11.56729624 2.46187500 +O 4.40029320 0.27473513 12.30937500 +O 4.87478100 7.89389811 12.30937500 +O 11.23592580 3.67339813 12.30937500 +O 0.00000000 5.57641257 3.10590150 +O 8.84468505 2.78820629 12.95340150 +O 4.82931495 2.78820629 12.95340150 +O 2.00768505 9.05382509 3.10590150 +O -2.00768505 9.05382509 3.10590150 +O 6.83700000 6.26561880 16.58909850 +O 8.84468505 2.78820629 16.58909850 +O 6.83700000 6.26561880 12.95340150 +O 4.82931495 2.78820629 16.58909850 +O 2.00768505 9.05382509 6.74159850 +O 0.00000000 5.57641257 6.74159850 +O -2.00768505 9.05382509 6.74159850 +O 1.75369050 4.83746982 4.92375000 +O 10.36147350 3.93747543 14.77125000 +O 5.06621700 0.89999439 14.77125000 +O 1.77078300 10.94203699 4.92375000 +O -3.52447350 7.90455594 4.92375000 +O 8.59069050 7.00456156 14.77125000 +O 8.60778300 0.89999439 14.77125000 +O 5.08330950 7.00456156 14.77125000 +O 3.31252650 3.93747543 14.77125000 +O 3.52447350 7.90455594 4.92375000 +O -1.75369050 4.83746982 4.92375000 +O -1.77078300 10.94203699 4.92375000 +O 2.46884070 6.46930174 2.98970100 +O 9.30584070 5.37272963 12.83720100 +O 6.83700000 1.09657211 12.83720100 +O 0.00000000 10.74545927 2.98970100 +O -2.46884070 6.46930174 2.98970100 +O 9.30584070 5.37272963 16.70529900 +O 6.83700000 1.09657211 16.70529900 +O 4.36815930 5.37272963 12.83720100 +O 4.36815930 5.37272963 16.70529900 +O 2.46884070 6.46930174 6.85779900 +O -2.46884070 6.46930174 6.85779900 +O 0.00000000 10.74545927 6.85779900 +Si -1.54652940 2.68577272 1.55196600 +Si 10.57478790 0.00355261 11.39946600 +Si 1.55268270 2.68222011 11.39946600 +Si 5.28431730 9.15981127 1.55196600 +Si -3.73778790 11.83847876 1.55196600 +Si 5.29047060 9.15625866 18.14303400 +Si 12.12131730 2.68222011 18.14303400 +Si 8.38352940 9.15625866 11.39946600 +Si 3.09921210 0.00355261 18.14303400 +Si 3.73778790 11.83847876 8.29553400 +Si 1.54652940 2.68577272 8.29553400 +Si -5.28431730 9.15981127 8.29553400 +Si 8.38352940 9.15625866 18.14303400 +Si -3.73778790 11.83847876 8.29553400 +Si 5.28431730 9.15981127 8.29553400 +Si 1.55268270 2.68222011 18.14303400 +Si 10.57478790 0.00355261 18.14303400 +Si 1.54652940 2.68577272 1.55196600 +Si -5.28431730 9.15981127 1.55196600 +Si -1.54652940 2.68577272 8.29553400 +Si 3.73778790 11.83847876 1.55196600 +Si 3.09921210 0.00355261 11.39946600 +Si 5.29047060 9.15625866 11.39946600 +Si 12.12131730 2.68222011 11.39946600 +Si 1.54516200 5.20812540 3.37178400 +Si 9.93621210 3.94221224 13.21928400 +Si 5.28294990 1.26591315 13.21928400 +Si 1.55405010 10.57611822 3.37178400 +Si -3.09921210 7.89981913 3.37178400 +Si 8.38216200 6.63390598 16.32321600 +Si 8.39105010 1.26591315 16.32321600 +Si 5.29183800 6.63390598 13.21928400 +Si 3.73778790 3.94221224 16.32321600 +Si 3.09921210 7.89981913 6.47571600 +Si -1.54516200 5.20812540 6.47571600 +Si -1.55405010 10.57611822 6.47571600 +Si 5.29183800 6.63390598 16.32321600 +Si -3.09921210 7.89981913 6.47571600 +Si 1.55405010 10.57611822 6.47571600 +Si 5.28294990 1.26591315 16.32321600 +Si 9.93621210 3.94221224 16.32321600 +Si -1.54516200 5.20812540 3.37178400 +Si -1.55405010 10.57611822 3.37178400 +Si 1.54516200 5.20812540 6.47571600 +Si 3.09921210 7.89981913 3.37178400 +Si 3.73778790 3.94221224 13.21928400 +Si 8.38216200 6.63390598 13.21928400 +Si 8.39105010 1.26591315 13.21928400 + diff --git a/contrib/voro++/zeo/examples/BIK.v1 b/contrib/voro++/zeo/examples/BIK.v1 new file mode 100644 index 0000000000000000000000000000000000000000..cfb81f4fce79afd93eaa3a31195165ff519fdd87 --- /dev/null +++ b/contrib/voro++/zeo/examples/BIK.v1 @@ -0,0 +1,42 @@ +Unit cell vectors: +va= 7.54000000 0.00000000 0.00000000 +vb= 0.00000000 16.22200000 0.00000000 +vc= 0.00000000 0.00000000 5.25600000 +36 +O 1.88500000 4.05550000 2.62800000 +O 1.88500000 12.16650000 2.62800000 +O 5.65500000 4.05550000 0.00000000 +O 5.65500000 12.16650000 0.00000000 +O 5.65500000 12.16650000 2.62800000 +O 5.65500000 4.05550000 2.62800000 +O 1.88500000 12.16650000 0.00000000 +O 1.88500000 4.05550000 0.00000000 +O 2.45502400 1.85417460 1.31400000 +O 2.45502400 14.36782540 3.94200000 +O 5.08497600 1.85417460 1.31400000 +O 5.08497600 14.36782540 3.94200000 +O 6.22502400 9.96517460 1.31400000 +O 6.22502400 6.25682540 3.94200000 +O 1.31497600 9.96517460 1.31400000 +O 1.31497600 6.25682540 3.94200000 +O 0.00000000 2.78045080 1.31400000 +O 0.00000000 13.44154920 3.94200000 +O 3.77000000 10.89145080 1.31400000 +O 3.77000000 5.33054920 3.94200000 +O 3.77000000 0.00000000 0.00000000 +O 3.77000000 0.00000000 2.62800000 +O 0.00000000 8.11100000 0.00000000 +O 0.00000000 8.11100000 2.62800000 +Si 1.55701000 3.18924520 1.31400000 +Si 1.55701000 13.03275480 3.94200000 +Si 5.98299000 3.18924520 1.31400000 +Si 5.98299000 13.03275480 3.94200000 +Si 5.32701000 11.30024520 1.31400000 +Si 5.32701000 4.92175480 3.94200000 +Si 2.21299000 11.30024520 1.31400000 +Si 2.21299000 4.92175480 3.94200000 +Si 3.77000000 0.92627620 1.31400000 +Si 3.77000000 15.29572380 3.94200000 +Si 0.00000000 9.03727620 1.31400000 +Si 0.00000000 7.18472380 3.94200000 + diff --git a/contrib/voro++/zeo/examples/EDI.v1 b/contrib/voro++/zeo/examples/EDI.v1 new file mode 100644 index 0000000000000000000000000000000000000000..9b44265dee72b2a2a98852b8ce45fc9d2ac4c99c --- /dev/null +++ b/contrib/voro++/zeo/examples/EDI.v1 @@ -0,0 +1,20 @@ +Unit cell vectors: +va= 6.926 0.0 0.0 +vb= 3.10954e-10 6.926 0.0 +vc= 2.87787e-10 2.87787e-10 6.41 +15 +O 1.31455 1.02164e-10 2.27555 +O 4.37557e-10 5.61145 4.13445 +O 2.44642e-10 1.31455 4.13445 +O 5.61145 1.02164e-10 2.27555 +O 1.31386 1.31386 0.0 +O 1.31386 5.61214 0.0 +O 5.61214 1.31386 0.0 +O 5.61214 5.61214 0.0 +O 3.463 3.40452e-11 0.758303 +O 4.09219e-10 3.463 5.6517 +Si 1.85548 3.4074e-11 0.758944 +Si 4.81362e-10 5.07052 5.65106 +Si 3.37018e-10 1.85548 5.65106 +Si 5.07052 3.4074e-11 0.758944 +Si 1.43894e-10 1.43894e-10 3.205 diff --git a/contrib/voro++/zeo/examples/EMT.v1 b/contrib/voro++/zeo/examples/EMT.v1 new file mode 100644 index 0000000000000000000000000000000000000000..2211c1adc875234066a6b3f32672e7088a575403 --- /dev/null +++ b/contrib/voro++/zeo/examples/EMT.v1 @@ -0,0 +1,294 @@ +Unit cell vectors: +va= 17.21500000 0.00000000 0.00000000 +vb= -8.60750000 14.90862733 0.00000000 +vc= 0.00000000 0.00000000 28.08200000 +288 +0 -3.56264425 7.88219127 2.61443420 +1 8.60750000 0.85575521 16.65543420 +2 5.04485575 7.02643606 16.65543420 +3 3.56264425 7.88219127 2.61443420 +4 0.00000000 14.05287212 2.61443420 +5 5.04485575 7.02643606 25.46756580 +6 12.17014425 7.02643606 25.46756580 +7 12.17014425 7.02643606 16.65543420 +8 8.60750000 0.85575521 25.46756580 +9 0.00000000 14.05287212 11.42656580 +10 3.56264425 7.88219127 11.42656580 +11 -3.56264425 7.88219127 11.42656580 +12 -2.49445350 6.42561838 4.52401020 +13 10.40302450 1.05254909 18.56501020 +14 4.31752200 5.37306929 18.56501020 +15 4.28997800 9.53555804 4.52401020 +16 -1.79552450 13.85607824 4.52401020 +17 6.11304650 8.48300895 23.55798980 +18 12.89747800 5.37306929 23.55798980 +19 11.10195350 8.48300895 18.56501020 +20 6.81197550 1.05254909 23.55798980 +21 1.79552450 13.85607824 9.51698980 +22 2.49445350 6.42561838 9.51698980 +23 -4.28997800 9.53555804 9.51698980 +24 11.10195350 8.48300895 23.55798980 +25 -1.79552450 13.85607824 9.51698980 +26 4.28997800 9.53555804 9.51698980 +27 4.31752200 5.37306929 23.55798980 +28 10.40302450 1.05254909 23.55798980 +29 2.49445350 6.42561838 4.52401020 +30 -4.28997800 9.53555804 4.52401020 +31 -2.49445350 6.42561838 9.51698980 +32 1.79552450 13.85607824 4.52401020 +33 6.81197550 1.05254909 18.56501020 +34 6.11304650 8.48300895 18.56501020 +35 12.89747800 5.37306929 18.56501020 +36 12.90780700 5.38201447 2.93176080 +37 1.79294225 13.86949600 16.97276080 +38 2.50736475 6.42114579 16.97276080 +39 6.10013525 8.48748154 2.93176080 +40 6.81455775 1.03913132 2.93176080 +41 4.30030700 9.52661286 25.15023920 +42 -2.50736475 6.42114579 25.15023920 +43 -4.30030700 9.52661286 16.97276080 +44 -1.79294225 13.86949600 25.15023920 +45 10.40044225 1.03913133 11.10923920 +46 4.30719300 5.38201447 11.10923920 +47 11.11486475 8.48748154 11.10923920 +48 -4.30030700 9.52661286 25.15023920 +49 6.81455775 1.03913133 11.10923920 +50 6.10013525 8.48748154 11.10923920 +51 2.50736475 6.42114579 25.15023920 +52 1.79294225 13.86949600 25.15023920 +53 4.30719300 5.38201447 2.93176080 +54 11.11486475 8.48748154 2.93176080 +55 12.90780700 5.38201447 11.10923920 +56 10.40044225 1.03913132 2.93176080 +57 -1.79294225 13.86949600 16.97276080 +58 4.30030700 9.52661286 16.97276080 +59 -2.50736475 6.42114579 16.97276080 +60 -1.90570050 5.93065195 2.01067120 +61 11.12605450 1.31494093 16.05167120 +62 4.18324500 4.61571102 16.05167120 +63 4.42425500 10.29291631 2.01067120 +64 -2.51855450 13.59368640 2.01067120 +65 6.70179950 8.97797538 26.07132880 +66 13.03175500 4.61571102 26.07132880 +67 10.51320050 8.97797538 16.05167120 +68 6.08894550 1.31494093 26.07132880 +69 2.51855450 13.59368640 12.03032880 +70 1.90570050 5.93065195 12.03032880 +71 -4.42425500 10.29291631 12.03032880 +72 10.51320050 8.97797538 26.07132880 +73 -2.51855450 13.59368640 12.03032880 +74 4.42425500 10.29291631 12.03032880 +75 4.18324500 4.61571102 26.07132880 +76 11.12605450 1.31494093 26.07132880 +77 1.90570050 5.93065195 2.01067120 +78 -4.42425500 10.29291631 2.01067120 +79 -1.90570050 5.93065195 12.03032880 +80 2.51855450 13.59368640 2.01067120 +81 6.08894550 1.31494093 16.05167120 +82 6.70179950 8.97797538 16.05167120 +83 13.03175500 4.61571102 16.05167120 +84 -2.50822550 4.34437400 0.00000000 +85 12.19854900 0.00000000 14.04100000 +86 2.50822550 4.34437400 14.04100000 +87 6.09927450 10.56425332 0.00000000 +88 5.01645100 0.00000000 0.00000000 +89 -6.09927450 10.56425332 14.04100000 +90 -6.09927450 10.56425332 0.00000000 +91 5.01645100 0.00000000 14.04100000 +92 6.09927450 10.56425332 14.04100000 +93 2.50822550 4.34437400 0.00000000 +94 12.19854900 0.00000000 0.00000000 +95 -2.50822550 4.34437400 14.04100000 +96 -1.68707000 6.79833406 27.62145520 +97 10.48393500 1.93812155 13.58045520 +98 5.04399500 4.86021251 13.58045520 +99 3.56350500 10.04841482 27.62145520 +100 -1.87643500 12.97050578 27.62145520 +101 6.92043000 8.11029327 0.46054480 +102 12.17100500 4.86021251 0.46054480 +103 10.29457000 8.11029327 13.58045520 +104 6.73106500 1.93812155 0.46054480 +105 1.87643500 12.97050578 14.50154480 +106 1.68707000 6.79833406 14.50154480 +107 -3.56350500 10.04841482 14.50154480 +108 10.29457000 8.11029327 0.46054480 +109 -1.87643500 12.97050578 14.50154480 +110 3.56350500 10.04841482 14.50154480 +111 5.04399500 4.86021251 0.46054480 +112 10.48393500 1.93812155 0.46054480 +113 1.68707000 6.79833406 27.62145520 +114 -3.56350500 10.04841482 27.62145520 +115 -1.68707000 6.79833406 14.50154480 +116 1.87643500 12.97050578 27.62145520 +117 6.73106500 1.93812155 13.58045520 +118 6.92043000 8.11029327 13.58045520 +119 12.17100500 4.86021251 13.58045520 +120 0.00000000 5.00333533 0.45492840 +121 12.88198450 2.50166767 14.49592840 +122 4.33301550 2.50166767 14.49592840 +123 4.27448450 12.40695966 0.45492840 +124 -4.27448450 12.40695966 0.45492840 +125 8.60750000 9.90529200 27.62707160 +126 12.88198450 2.50166767 27.62707160 +127 8.60750000 9.90529200 14.49592840 +128 4.33301550 2.50166767 27.62707160 +129 4.27448450 12.40695966 13.58607160 +130 0.00000000 5.00333533 13.58607160 +131 -4.27448450 12.40695966 13.58607160 +132 0.00000000 7.06072590 25.62201680 +133 11.10023200 3.53036295 11.58101680 +134 6.11476800 3.53036295 11.58101680 +135 2.49273200 11.37826438 25.62201680 +136 -2.49273200 11.37826438 25.62201680 +137 8.60750000 7.84790142 2.45998320 +138 11.10023200 3.53036295 2.45998320 +139 8.60750000 7.84790143 11.58101680 +140 6.11476800 3.53036295 2.45998320 +141 2.49273200 11.37826438 16.50098320 +142 0.00000000 7.06072590 16.50098320 +143 -2.49273200 11.37826438 16.50098320 +144 -1.90096637 8.84156144 25.97865820 +145 8.60750000 2.77449555 11.93765820 +146 6.70653363 6.06706589 11.93765820 +147 1.90096638 8.84156144 25.97865820 +148 0.00000000 12.13413178 25.97865820 +149 6.70653363 6.06706589 2.10334180 +150 10.50846638 6.06706589 2.10334180 +151 10.50846638 6.06706589 11.93765820 +152 8.60750000 2.77449555 2.10334180 +153 0.00000000 12.13413178 16.14434180 +154 1.90096638 8.84156144 16.14434180 +155 -1.90096637 8.84156144 16.14434180 +156 -1.89192850 8.84677946 5.34962100 +157 8.60750000 2.78493159 19.39062100 +158 6.71557150 6.06184787 19.39062100 +159 1.89192850 8.84677946 5.34962100 +160 0.00000000 12.12369574 5.34962100 +161 6.71557150 6.06184787 22.73237900 +162 10.49942850 6.06184787 22.73237900 +163 10.49942850 6.06184787 19.39062100 +164 8.60750000 2.78493159 22.73237900 +165 0.00000000 12.12369574 8.69137900 +166 1.89192850 8.84677946 8.69137900 +167 -1.89192850 8.84677946 8.69137900 +168 0.00000000 7.04134469 5.08284200 +169 11.11701663 3.52067234 19.12384200 +170 6.09798338 3.52067234 19.12384200 +171 2.50951663 11.38795498 5.08284200 +172 -2.50951662 11.38795498 5.08284200 +173 8.60750000 7.86728264 22.99915800 +174 11.11701663 3.52067234 22.99915800 +175 8.60750000 7.86728264 19.12384200 +176 6.09798338 3.52067234 22.99915800 +177 2.50951663 11.38795498 8.95815800 +178 0.00000000 7.04134469 8.95815800 +179 -2.50951662 11.38795498 8.95815800 +180 -1.76281600 6.82218787 7.02050000 +181 10.42540400 1.88445050 21.06150000 +182 5.02678000 4.93773737 21.06150000 +183 3.58072000 9.97088996 7.02050000 +184 -1.81790400 13.02417683 7.02050000 +185 6.84468400 8.08643946 21.06150000 +186 12.18822000 4.93773737 21.06150000 +187 10.37031600 8.08643946 21.06150000 +188 6.78959600 1.88445050 21.06150000 +189 1.81790400 13.02417683 7.02050000 +190 1.76281600 6.82218787 7.02050000 +191 -3.58072000 9.97088996 7.02050000 +192 -3.06771300 6.40474630 3.01881500 +193 10.13447050 0.54565576 17.05981500 +194 4.01281650 5.85909054 17.05981500 +195 4.59468350 9.04953679 3.01881500 +196 -1.52697050 14.36297157 3.01881500 +197 5.53978700 8.50388103 25.06318500 +198 13.20218350 5.85909054 25.06318500 +199 11.67521300 8.50388103 17.05981500 +200 7.08052950 0.54565576 25.06318500 +201 1.52697050 14.36297157 11.02218500 +202 3.06771300 6.40474630 11.02218500 +203 -4.59468350 9.04953679 11.02218500 +204 11.67521300 8.50388103 25.06318500 +205 -1.52697050 14.36297157 11.02218500 +206 4.59468350 9.04953679 11.02218500 +207 4.01281650 5.85909054 25.06318500 +208 10.13447050 0.54565576 25.06318500 +209 3.06771300 6.40474630 3.01881500 +210 -4.59468350 9.04953679 3.01881500 +211 -3.06771300 6.40474630 11.02218500 +212 1.52697050 14.36297157 3.01881500 +213 7.08052950 0.54565576 17.05981500 +214 5.53978700 8.50388103 17.05981500 +215 13.20218350 5.85909054 17.05981500 +216 -1.52610975 5.51768297 0.50266780 +217 11.67349150 1.43719168 14.54366780 +218 4.01539875 4.08049130 14.54366780 +219 4.59210125 10.82813603 0.50266780 +220 -3.06599150 13.47143565 0.50266780 +221 7.08139025 9.39094436 27.57933220 +222 13.19960125 4.08049130 27.57933220 +223 10.13360975 9.39094435 14.54366780 +224 5.54150850 1.43719168 27.57933220 +225 3.06599150 13.47143565 13.53833220 +226 1.52610975 5.51768297 13.53833220 +227 -4.59210125 10.82813603 13.53833220 +228 10.13360975 9.39094436 27.57933220 +229 -3.06599150 13.47143565 13.53833220 +230 4.59210125 10.82813603 13.53833220 +231 4.01539875 4.08049130 27.57933220 +232 11.67349150 1.43719168 27.57933220 +233 1.52610975 5.51768297 0.50266780 +234 -4.59210125 10.82813603 0.50266780 +235 -1.52610975 5.51768297 13.53833220 +236 3.06599150 13.47143565 0.50266780 +237 5.54150850 1.43719168 14.54366780 +238 7.08139025 9.39094435 14.54366780 +239 13.19960125 4.08049130 14.54366780 +240 -1.52524900 7.28137359 26.09379440 +241 10.14652100 2.31978241 12.05279440 +242 5.54323000 4.96159118 12.05279440 +243 3.06427000 9.94703615 26.09379440 +244 -1.53902100 12.58884492 26.09379440 +245 7.08225100 7.62725374 1.98820560 +246 11.67177000 4.96159117 1.98820560 +247 10.13274900 7.62725374 12.05279440 +248 7.06847900 2.31978241 1.98820560 +249 1.53902100 12.58884492 16.02920560 +250 1.52524900 7.28137359 16.02920560 +251 -3.06427000 9.94703615 16.02920560 +252 10.13274900 7.62725374 1.98820560 +253 -1.53902100 12.58884492 16.02920560 +254 3.06427000 9.94703615 16.02920560 +255 5.54323000 4.96159117 1.98820560 +256 10.14652100 2.31978241 1.98820560 +257 1.52524900 7.28137359 26.09379440 +258 -3.06427000 9.94703615 26.09379440 +259 -1.52524900 7.28137359 16.02920560 +260 1.53902100 12.58884492 26.09379440 +261 7.06847900 2.31978241 12.05279440 +262 7.08225100 7.62725374 12.05279440 +263 11.67177000 4.96159118 12.05279440 +264 -1.53643875 7.28286445 5.49564740 +265 10.13963500 2.31083724 19.53664740 +266 5.53892625 4.97202721 19.53664740 +267 3.06857375 9.93660011 5.49564740 +268 -1.53213500 12.59779009 5.49564740 +269 7.07106125 7.62576288 22.58635260 +270 11.67607375 4.97202722 22.58635260 +271 10.14393875 7.62576288 19.53664740 +272 7.07536500 2.31083724 22.58635260 +273 1.53213500 12.59779009 8.54535260 +274 1.53643875 7.28286445 8.54535260 +275 -3.06857375 9.93660011 8.54535260 +276 10.14393875 7.62576288 22.58635260 +277 -1.53213500 12.59779009 8.54535260 +278 3.06857375 9.93660011 8.54535260 +279 5.53892625 4.97202722 22.58635260 +280 10.13963500 2.31083724 22.58635260 +281 1.53643875 7.28286445 5.49564740 +282 -3.06857375 9.93660011 5.49564740 +283 -1.53643875 7.28286445 8.54535260 +284 1.53213500 12.59779009 5.49564740 +285 7.07536500 2.31083724 19.53664740 +286 7.07106125 7.62576288 19.53664740 +287 11.67607375 4.97202721 19.53664740 + diff --git a/contrib/voro++/zeo/examples/HEU.v1 b/contrib/voro++/zeo/examples/HEU.v1 new file mode 100644 index 0000000000000000000000000000000000000000..8966af903823ad9852fb9fd3941ed7d993544bf4 --- /dev/null +++ b/contrib/voro++/zeo/examples/HEU.v1 @@ -0,0 +1,114 @@ +Unit cell vectors: +va= 17.52300000 0.00000000 0.00000000 +vb= 0.00000000 17.64400000 0.00000000 +vc= -3.25645379 0.00000000 6.64607476 +108 +0 1.24241386 2.86715000 0.43265947 +1 13.02413235 2.86715000 6.21341529 +2 13.02413236 14.77685000 6.21341529 +3 1.24241386 14.77685000 0.43265947 +4 10.00391386 11.68915000 0.43265947 +5 4.26263235 11.68915000 6.21341529 +6 4.26263235 5.95485000 6.21341529 +7 10.00391386 5.95485000 0.43265947 +8 3.26976944 1.83321160 1.74525923 +9 10.99677678 1.83321160 4.90081553 +10 10.99677678 15.81078840 4.90081553 +11 3.26976944 15.81078840 1.74525923 +12 12.03126944 10.65521160 1.74525923 +13 2.23527678 10.65521160 4.90081553 +14 2.23527678 6.98878840 4.90081553 +15 12.03126944 6.98878840 1.74525923 +16 0.36517474 2.77363680 5.96019985 +17 13.90137147 2.77363680 0.68587492 +18 13.90137147 14.87036320 0.68587492 +19 0.36517474 14.87036320 5.96019985 +20 9.12667474 11.59563680 5.96019985 +21 5.13987147 11.59563680 0.68587492 +22 5.13987147 6.04836320 0.68587492 +23 9.12667474 6.04836320 5.96019985 +24 3.17018082 4.42335080 1.31193516 +25 11.09636539 4.42335080 5.33413960 +26 11.09636539 13.22064920 5.33413960 +27 3.17018082 13.22064920 1.31193516 +28 11.93168082 13.24535080 1.31193516 +29 2.33486539 13.24535080 5.33413960 +30 2.33486539 4.39864920 5.33413960 +31 11.93168082 4.39864920 1.31193516 +32 0.84223406 6.46652600 2.73353055 +33 13.42431216 6.46652600 3.91254421 +34 13.42431216 11.17747400 3.91254421 +35 0.84223406 11.17747400 2.73353055 +36 9.60373406 15.28852600 2.73353055 +37 4.66281216 15.28852600 3.91254421 +38 4.66281216 2.35547400 3.91254421 +39 9.60373406 2.35547400 2.73353055 +40 1.96533577 8.82200000 3.03061009 +41 12.30121044 8.82200000 3.61546467 +42 10.72683577 0.00000000 3.03061009 +43 3.53971044 0.00000000 3.61546467 +44 3.45658741 6.70295560 2.59063994 +45 10.80995880 6.70295560 4.05543482 +46 10.80995880 10.94104440 4.05543482 +47 3.45658741 10.94104440 2.59063994 +48 12.21808741 15.52495560 2.59063994 +49 2.04845880 15.52495560 4.05543482 +50 2.04845880 2.11904440 4.05543482 +51 12.21808741 2.11904440 2.59063994 +52 0.32589946 4.06341320 3.66929788 +53 13.94064675 4.06341320 2.97677689 +54 13.94064675 13.58058680 2.97677689 +55 0.32589946 13.58058680 3.66929788 +56 9.08739946 12.88541320 3.66929788 +57 5.17914675 12.88541320 2.97677689 +58 5.17914675 4.75858680 2.97677689 +59 9.08739946 4.75858680 3.66929788 +60 -1.62822689 5.78723200 3.32303738 +61 -1.62822689 11.85676800 3.32303738 +62 7.13327311 14.60923200 3.32303738 +63 7.13327311 3.03476800 3.32303738 +64 -0.43417658 4.72506320 1.24015755 +65 14.70072279 4.72506320 5.40591721 +66 14.70072279 12.91893680 5.40591721 +67 -0.43417658 12.91893680 1.24015755 +68 8.32732342 13.54706320 1.24015755 +69 5.93922279 13.54706320 5.40591721 +70 5.93922279 4.09693680 5.40591721 +71 8.32732342 4.09693680 1.24015755 +72 2.82668047 2.97477840 0.70049628 +73 11.43986574 2.97477840 5.94557848 +74 11.43986574 14.66922160 5.94557848 +75 2.82668047 14.66922160 0.70049628 +76 11.58818047 11.79677840 0.70049628 +77 2.67836574 11.79677840 5.94557848 +78 2.67836574 5.84722160 5.94557848 +79 11.58818047 5.84722160 0.70049628 +80 2.12560285 7.24639080 3.31506209 +81 12.14094336 7.24639080 3.33101267 +82 12.14094336 10.39760920 3.33101267 +83 2.12560285 10.39760920 3.31506209 +84 10.88710285 16.06839080 3.31506209 +85 3.37944336 16.06839080 3.33101267 +86 3.37944336 1.57560920 3.33101267 +87 10.88710285 1.57560920 3.31506209 +88 1.26747922 3.34000920 4.75526649 +89 12.99906700 3.34000920 1.89080827 +90 12.99906700 14.30399080 1.89080827 +91 1.26747922 14.30399080 4.75526649 +92 10.02897922 12.16200920 4.75526649 +93 4.23756700 12.16200920 1.89080827 +94 4.23756700 5.48199080 1.89080827 +95 10.02897922 5.48199080 4.75526649 +96 -0.22103982 5.25967640 2.74349966 +97 14.48758604 5.25967640 3.90257510 +98 14.48758604 12.38432360 3.90257510 +99 -0.22103982 12.38432360 2.74349966 +100 8.54046018 14.08167640 2.74349966 +101 5.72608604 14.08167640 3.90257510 +102 5.72608604 3.56232360 3.90257510 +103 8.54046018 3.56232360 2.74349966 +104 0.00000000 3.79522440 0.00000000 +105 0.00000000 13.84877560 0.00000000 +106 8.76150000 12.61722440 0.00000000 +107 8.76150000 5.02677560 0.00000000 + diff --git a/contrib/voro++/zeo/examples/HV.v1 b/contrib/voro++/zeo/examples/HV.v1 new file mode 100644 index 0000000000000000000000000000000000000000..13f622820e69e0c383824a61f4467b8c04737391 --- /dev/null +++ b/contrib/voro++/zeo/examples/HV.v1 @@ -0,0 +1,114 @@ +Unit cell vectors: +va= 17.52300000 0.00000000 0.00000000 +vb= 0.00000000 17.64400000 0.00000000 +vc= 0.00000000 0.00000000 6.64607476 +108 +0 1.24241386 2.86715000 0.43265947 +1 13.02413235 2.86715000 6.21341529 +2 13.02413236 14.77685000 6.21341529 +3 1.24241386 14.77685000 0.43265947 +4 10.00391386 11.68915000 0.43265947 +5 4.26263235 11.68915000 6.21341529 +6 4.26263235 5.95485000 6.21341529 +7 10.00391386 5.95485000 0.43265947 +8 3.26976944 1.83321160 1.74525923 +9 10.99677678 1.83321160 4.90081553 +10 10.99677678 15.81078840 4.90081553 +11 3.26976944 15.81078840 1.74525923 +12 12.03126944 10.65521160 1.74525923 +13 2.23527678 10.65521160 4.90081553 +14 2.23527678 6.98878840 4.90081553 +15 12.03126944 6.98878840 1.74525923 +16 0.36517474 2.77363680 5.96019985 +17 13.90137147 2.77363680 0.68587492 +18 13.90137147 14.87036320 0.68587492 +19 0.36517474 14.87036320 5.96019985 +20 9.12667474 11.59563680 5.96019985 +21 5.13987147 11.59563680 0.68587492 +22 5.13987147 6.04836320 0.68587492 +23 9.12667474 6.04836320 5.96019985 +24 3.17018082 4.42335080 1.31193516 +25 11.09636539 4.42335080 5.33413960 +26 11.09636539 13.22064920 5.33413960 +27 3.17018082 13.22064920 1.31193516 +28 11.93168082 13.24535080 1.31193516 +29 2.33486539 13.24535080 5.33413960 +30 2.33486539 4.39864920 5.33413960 +31 11.93168082 4.39864920 1.31193516 +32 0.84223406 6.46652600 2.73353055 +33 13.42431216 6.46652600 3.91254421 +34 13.42431216 11.17747400 3.91254421 +35 0.84223406 11.17747400 2.73353055 +36 9.60373406 15.28852600 2.73353055 +37 4.66281216 15.28852600 3.91254421 +38 4.66281216 2.35547400 3.91254421 +39 9.60373406 2.35547400 2.73353055 +40 1.96533577 8.82200000 3.03061009 +41 12.30121044 8.82200000 3.61546467 +42 10.72683577 0.00000000 3.03061009 +43 3.53971044 0.00000000 3.61546467 +44 3.45658741 6.70295560 2.59063994 +45 10.80995880 6.70295560 4.05543482 +46 10.80995880 10.94104440 4.05543482 +47 3.45658741 10.94104440 2.59063994 +48 12.21808741 15.52495560 2.59063994 +49 2.04845880 15.52495560 4.05543482 +50 2.04845880 2.11904440 4.05543482 +51 12.21808741 2.11904440 2.59063994 +52 0.32589946 4.06341320 3.66929788 +53 13.94064675 4.06341320 2.97677689 +54 13.94064675 13.58058680 2.97677689 +55 0.32589946 13.58058680 3.66929788 +56 9.08739946 12.88541320 3.66929788 +57 5.17914675 12.88541320 2.97677689 +58 5.17914675 4.75858680 2.97677689 +59 9.08739946 4.75858680 3.66929788 +60 -1.62822689 5.78723200 3.32303738 +61 -1.62822689 11.85676800 3.32303738 +62 7.13327311 14.60923200 3.32303738 +63 7.13327311 3.03476800 3.32303738 +64 -0.43417658 4.72506320 1.24015755 +65 14.70072279 4.72506320 5.40591721 +66 14.70072279 12.91893680 5.40591721 +67 -0.43417658 12.91893680 1.24015755 +68 8.32732342 13.54706320 1.24015755 +69 5.93922279 13.54706320 5.40591721 +70 5.93922279 4.09693680 5.40591721 +71 8.32732342 4.09693680 1.24015755 +72 2.82668047 2.97477840 0.70049628 +73 11.43986574 2.97477840 5.94557848 +74 11.43986574 14.66922160 5.94557848 +75 2.82668047 14.66922160 0.70049628 +76 11.58818047 11.79677840 0.70049628 +77 2.67836574 11.79677840 5.94557848 +78 2.67836574 5.84722160 5.94557848 +79 11.58818047 5.84722160 0.70049628 +80 2.12560285 7.24639080 3.31506209 +81 12.14094336 7.24639080 3.33101267 +82 12.14094336 10.39760920 3.33101267 +83 2.12560285 10.39760920 3.31506209 +84 10.88710285 16.06839080 3.31506209 +85 3.37944336 16.06839080 3.33101267 +86 3.37944336 1.57560920 3.33101267 +87 10.88710285 1.57560920 3.31506209 +88 1.26747922 3.34000920 4.75526649 +89 12.99906700 3.34000920 1.89080827 +90 12.99906700 14.30399080 1.89080827 +91 1.26747922 14.30399080 4.75526649 +92 10.02897922 12.16200920 4.75526649 +93 4.23756700 12.16200920 1.89080827 +94 4.23756700 5.48199080 1.89080827 +95 10.02897922 5.48199080 4.75526649 +96 -0.22103982 5.25967640 2.74349966 +97 14.48758604 5.25967640 3.90257510 +98 14.48758604 12.38432360 3.90257510 +99 -0.22103982 12.38432360 2.74349966 +100 8.54046018 14.08167640 2.74349966 +101 5.72608604 14.08167640 3.90257510 +102 5.72608604 3.56232360 3.90257510 +103 8.54046018 3.56232360 2.74349966 +104 0.00000000 3.79522440 0.00000000 +105 0.00000000 13.84877560 0.00000000 +106 8.76150000 12.61722440 0.00000000 +107 8.76150000 5.02677560 0.00000000 + diff --git a/contrib/voro++/zeo/examples/IFR.v1 b/contrib/voro++/zeo/examples/IFR.v1 new file mode 100644 index 0000000000000000000000000000000000000000..9ed59bbabaf39f5fe77892528ebec02e2c8a5fca --- /dev/null +++ b/contrib/voro++/zeo/examples/IFR.v1 @@ -0,0 +1,102 @@ +Unit cell vectors: +va= 18.62800000 0.00000000 0.00000000 +vb= 0.00000000 13.43600000 0.00000000 +vc= -1.62807078 0.00000000 7.45325610 +96 +0 -0.23606478 8.40690520 6.27415099 +1 17.23599400 8.40690520 1.17910512 +2 17.23599400 5.02909480 1.17910512 +3 -0.23606478 5.02909480 6.27415099 +4 9.07793522 1.68890520 6.27415099 +5 7.92199400 1.68890520 1.17910512 +6 7.92199400 11.74709480 1.17910512 +7 9.07793522 11.74709480 6.27415099 +8 16.75104912 6.71800000 5.10473510 +9 0.24888010 6.71800000 2.34852100 +10 7.43704912 0.00000000 5.10473510 +11 9.56288010 0.00000000 2.34852100 +12 15.99458490 9.20097280 5.54894917 +13 1.00534432 9.20097280 1.90430693 +14 1.00534432 4.23502720 1.90430693 +15 15.99458490 4.23502720 5.54894917 +16 6.68058490 2.48297280 5.54894917 +17 10.31934432 2.48297280 1.90430693 +18 10.31934432 10.95302720 1.90430693 +19 6.68058490 10.95302720 5.54894917 +20 -0.81403539 8.69040480 3.72662805 +21 -0.81403539 4.74559520 3.72662805 +22 8.49996461 1.97240480 3.72662805 +23 8.49996461 11.46359520 3.72662805 +24 3.23907505 9.18216240 0.52172793 +25 13.76085417 9.18216240 6.93152818 +26 13.76085417 4.25383760 6.93152818 +27 3.23907505 4.25383760 0.52172793 +28 12.55307505 2.46416240 0.52172793 +29 4.44685417 2.46416240 6.93152818 +30 4.44685417 10.97183760 6.93152818 +31 12.55307505 10.97183760 0.52172793 +32 1.61273244 6.71800000 7.07164939 +33 15.38719678 6.71800000 0.38160671 +34 10.92673244 0.00000000 7.07164939 +35 6.07319678 0.00000000 0.38160671 +36 2.25215289 8.69577920 5.46621803 +37 14.74777633 8.69577920 1.98703808 +38 14.74777633 4.74022080 1.98703808 +39 2.25215289 4.74022080 5.46621803 +40 11.56615289 1.97777920 5.46621803 +41 5.43377633 1.97777920 1.98703808 +42 5.43377633 11.45822080 1.98703808 +43 11.56615289 11.45822080 5.46621803 +44 12.20465218 9.19156760 2.42379888 +45 4.79527704 9.19156760 5.02945722 +46 4.79527704 4.24443240 5.02945722 +47 12.20465218 4.24443240 2.42379888 +48 2.89065218 2.47356760 2.42379888 +49 14.10927704 2.47356760 5.02945722 +50 14.10927704 10.96243240 5.02945722 +51 2.89065218 10.96243240 2.42379888 +52 13.75327894 8.43377720 4.40785566 +53 3.24665028 8.43377720 3.04540044 +54 3.24665028 5.00222280 3.04540044 +55 13.75327894 5.00222280 4.40785566 +56 4.43927894 1.71577720 4.40785566 +57 12.56065028 1.71577720 3.04540044 +58 12.56065028 11.72022280 3.04540044 +59 4.43927894 11.72022280 4.40785566 +60 13.09900802 6.71800000 2.52516317 +61 3.90092120 6.71800000 4.92809294 +62 3.78500802 0.00000000 2.52516317 +63 13.21492120 0.00000000 4.92809294 +64 14.40415517 9.44550800 5.47888856 +65 2.59577405 9.44550800 1.97436754 +66 2.59577405 3.99049200 1.97436754 +67 14.40415517 3.99049200 5.47888856 +68 5.09015517 2.72750800 5.47888856 +69 11.90977405 2.72750800 1.97436754 +70 11.90977405 10.70849200 1.97436754 +71 5.09015517 10.70849200 5.47888856 +72 17.23741776 8.25104760 5.16361583 +73 -0.23748854 8.25104760 2.28964027 +74 -0.23748854 5.18495240 2.28964027 +75 17.23741776 5.18495240 5.16361583 +76 7.92341776 1.53304760 5.16361583 +77 9.07651146 1.53304760 2.28964027 +78 9.07651146 11.90295240 2.28964027 +79 7.92341776 11.90295240 5.16361583 +80 1.30967603 8.25373480 6.69376931 +81 15.69025319 8.25373480 0.75948680 +82 15.69025319 5.18226520 0.75948680 +83 1.30967603 5.18226520 6.69376931 +84 10.62367603 1.53573480 6.69376931 +85 6.37625319 1.53573480 0.75948680 +86 6.37625319 11.90026520 0.75948680 +87 10.62367603 11.90026520 6.69376931 +88 13.45024747 8.25776560 2.83596395 +89 3.54968175 8.25776560 4.61729216 +90 3.54968175 5.17823440 4.61729216 +91 13.45024747 5.17823440 2.83596395 +92 4.13624747 1.53976560 2.83596395 +93 12.86368175 1.53976560 4.61729216 +94 12.86368175 11.89623440 4.61729216 +95 4.13624747 11.89623440 2.83596395 + diff --git a/contrib/voro++/zeo/examples/JBW.v1 b/contrib/voro++/zeo/examples/JBW.v1 new file mode 100644 index 0000000000000000000000000000000000000000..82f69692dd38e14c276057551ea2bda473d9467e --- /dev/null +++ b/contrib/voro++/zeo/examples/JBW.v1 @@ -0,0 +1,24 @@ +Unit cell vectors: +va= 5.25600000 0.00000000 0.00000000 +vb= 0.00000000 7.45000000 0.00000000 +vc= 0.00000000 0.00000000 8.15900000 +18 +O 0.00000000 1.94594000 0.00000000 +O 2.62800000 5.50406000 0.00000000 +O 0.00000000 5.50406000 0.00000000 +O 2.62800000 1.94594000 0.00000000 +O 1.31400000 0.00000000 1.18713450 +O 3.94200000 0.00000000 6.97186550 +O 1.31400000 2.41007500 2.22577520 +O 3.94200000 5.03992500 5.93322480 +O 3.94200000 2.41007500 5.93322480 +O 1.31400000 5.03992500 2.22577520 +O 2.62800000 3.72500000 4.07950000 +O 0.00000000 3.72500000 4.07950000 +Si 1.31400000 1.57269500 0.85016780 +Si 3.94200000 5.87730500 7.30883220 +Si 3.94200000 1.57269500 7.30883220 +Si 1.31400000 5.87730500 0.85016780 +Si 1.31400000 3.72500000 3.15345350 +Si 3.94200000 3.72500000 5.00554650 + diff --git a/contrib/voro++/zeo/examples/P1.v1 b/contrib/voro++/zeo/examples/P1.v1 new file mode 100644 index 0000000000000000000000000000000000000000..e69aa093bcb5d4b519020e674bac77ccaf641837 --- /dev/null +++ b/contrib/voro++/zeo/examples/P1.v1 @@ -0,0 +1,89 @@ +Unit cell vectors: +va= 13.05700000 0.00000000 0.00000000 +vb= -6.52850000 11.30769370 0.00000000 +vc= 0.00000000 0.00000000 12.96900000 +84 +0 4.01111040 2.50578492 3.98537370 +1 6.69301820 6.58107773 8.98362630 +2 8.88137140 2.22083104 8.98362630 +3 8.88137140 2.22083104 3.98537370 +4 6.69301820 6.58107773 3.98537370 +5 -2.51738960 8.80190877 8.98362630 +6 2.35287140 9.08686266 8.98362630 +7 0.16451820 4.72661597 8.98362630 +8 4.01111040 2.50578492 8.98362630 +9 0.16451820 4.72661597 3.98537370 +10 -2.51738960 8.80190877 3.98537370 +11 2.35287140 9.08686266 3.98537370 +12 2.62184560 4.54116979 3.06587160 +13 -3.90665440 6.76652391 9.90312840 +14 7.81330880 0.00000000 9.90312840 +15 7.81330880 0.00000000 3.06587160 +16 -3.90665440 6.76652391 3.06587160 +17 2.62184560 4.54116979 9.90312840 +18 5.04196055 4.07642358 2.14636950 +19 7.53780610 4.90301599 10.82263050 +20 7.00573335 2.32825413 10.82263050 +21 7.00573335 2.32825413 2.14636950 +22 7.53780610 4.90301599 2.14636950 +23 -1.48653945 7.23127012 10.82263050 +24 0.47723335 8.97943957 10.82263050 +25 1.00930610 6.40467771 10.82263050 +26 5.04196055 4.07642358 10.82263050 +27 1.00930610 6.40467771 2.14636950 +28 -1.48653945 7.23127012 2.14636950 +29 0.47723335 8.97943957 2.14636950 +30 4.71553555 4.96068523 4.60140120 +31 8.46681165 4.74357751 8.36759880 +32 6.40315280 1.60343097 8.36759880 +33 6.40315280 1.60343097 4.60140120 +34 8.46681165 4.74357751 4.60140120 +35 -1.81296445 6.34700847 8.36759880 +36 -0.12534720 9.70426273 8.36759880 +37 1.93831165 6.56411619 8.36759880 +38 4.71553555 4.96068523 8.36759880 +39 1.93831165 6.56411619 4.60140120 +40 -1.81296445 6.34700847 4.60140120 +41 -0.12534720 9.70426273 4.60140120 +42 4.36495510 7.56032401 4.72979430 +43 -2.16354490 3.74736969 8.23920570 +44 4.32708980 0.00000000 8.23920570 +45 4.32708980 0.00000000 4.72979430 +46 -2.16354490 3.74736969 4.72979430 +47 4.36495510 7.56032401 8.23920570 +48 2.54937925 8.29419333 6.48450000 +49 -0.62020750 4.95276984 6.48450000 +50 -1.92917175 9.36842423 6.48450000 +51 9.07787925 3.01350037 6.48450000 +52 4.59932825 1.93926947 6.48450000 +53 5.90829250 6.35492386 6.48450000 +54 0.00000000 7.53846247 0.00000000 +55 6.52850000 3.76923123 0.00000000 +56 4.09663375 4.02214665 3.44845710 +57 7.96346430 5.74883148 9.52054290 +58 7.52540195 1.53671557 9.52054290 +59 7.52540195 1.53671557 3.44845710 +60 7.96346430 5.74883148 3.44845710 +61 -2.43186625 7.28554705 9.52054290 +62 0.99690195 9.77097812 9.52054290 +63 1.43496430 5.55886222 9.52054290 +64 4.09663375 4.02214665 9.52054290 +65 1.43496430 5.55886222 3.44845710 +66 -2.43186625 7.28554705 3.44845710 +67 0.99690195 9.77097812 3.44845710 +68 2.80137935 7.87807020 4.95026730 +69 -1.10658075 4.94259292 8.01873270 +70 -1.69479860 9.79472428 8.01873270 +71 -1.69479860 9.79472428 4.95026730 +72 -1.10658075 4.94259292 4.95026730 +73 9.32987935 3.42962350 8.01873270 +74 4.83370140 1.51296942 8.01873270 +75 5.42191925 6.36510078 8.01873270 +76 2.80137935 7.87807020 8.01873270 +77 5.42191925 6.36510078 4.95026730 +78 9.32987935 3.42962350 4.95026730 +79 4.83370140 1.51296942 4.95026730 +80 0.00000000 7.53846247 1.60685910 +81 0.00000000 7.53846247 11.36214090 +82 6.52850000 3.76923123 11.36214090 +83 6.52850000 3.76923123 1.60685910 diff --git a/contrib/voro++/zeo/examples/P2.v1 b/contrib/voro++/zeo/examples/P2.v1 new file mode 100644 index 0000000000000000000000000000000000000000..a0fe4b52c69ae3049290a79509a8d3af00c49f4d --- /dev/null +++ b/contrib/voro++/zeo/examples/P2.v1 @@ -0,0 +1,293 @@ +Unit cell vectors: +va= 12.55900000 0.00000000 0.00000000 +vb= -6.27950000 10.87641305 0.00000000 +vc= 0.00000000 0.00000000 41.02600000 +288 +0 8.54765540 0.44593294 39.79522000 +1 3.88763845 7.62545319 19.28222000 +2 -1.61948305 3.69689280 19.28222000 +3 7.89898305 7.17952026 39.79522000 +4 2.39186155 3.25095986 39.79522000 +5 2.26815540 10.43048011 1.23078000 +6 1.61948305 3.69689279 1.23078000 +7 -2.26815540 10.43048011 19.28222000 +8 -3.88763845 7.62545319 1.23078000 +9 10.16713845 3.25095986 21.74378000 +10 4.01134460 0.44593294 21.74378000 +11 4.66001695 7.17952025 21.74378000 +12 -2.26815540 10.43048011 1.23078000 +13 2.39186155 3.25095986 21.74378000 +14 7.89898305 7.17952025 21.74378000 +15 -1.61948305 3.69689279 1.23078000 +16 3.88763845 7.62545319 1.23078000 +17 4.01134460 0.44593294 39.79522000 +18 4.66001695 7.17952026 39.79522000 +19 8.54765540 0.44593294 21.74378000 +20 10.16713845 3.25095986 39.79522000 +21 -3.88763845 7.62545319 19.28222000 +22 2.26815540 10.43048011 19.28222000 +23 1.61948305 3.69689280 19.28222000 +24 4.13191100 9.63650196 40.58702180 +25 6.27950000 8.39659087 20.07402180 +26 10.41141100 1.23991109 20.07402180 +27 -4.13191100 9.63650196 40.58702180 +28 0.00000000 2.47982218 40.58702180 +29 10.41141100 1.23991109 0.43897820 +30 2.14758900 1.23991109 0.43897820 +31 2.14758900 1.23991109 20.07402180 +32 6.27950000 8.39659087 0.43897820 +33 0.00000000 2.47982218 20.95197820 +34 -4.13191100 9.63650196 20.95197820 +35 4.13191100 9.63650196 20.95197820 +36 0.00000000 9.36132871 30.76950000 +37 4.45185153 4.68066436 10.25650000 +38 8.10714848 4.68066436 10.25650000 +39 -1.82764847 6.19574869 30.76950000 +40 1.82764848 6.19574869 30.76950000 +41 6.27950000 1.51508434 10.25650000 +42 1.73188610 10.83073211 32.08643460 +43 4.04525390 6.91522342 11.57343460 +44 10.24563220 3.91550870 11.57343460 +45 -3.96613220 6.96090435 32.08643460 +46 2.23424610 3.96118963 32.08643460 +47 8.01138610 0.04568094 8.93956540 +48 2.31336780 3.91550870 8.93956540 +49 4.54761390 0.04568094 11.57343460 +50 8.51374610 6.91522342 8.93956540 +51 -2.23424610 3.96118963 29.45256540 +52 -1.73188610 10.83073211 29.45256540 +53 3.96613220 6.96090435 29.45256540 +54 4.54761390 0.04568094 8.93956540 +55 2.23424610 3.96118963 29.45256540 +56 -3.96613220 6.96090435 29.45256540 +57 10.24563220 3.91550870 8.93956540 +58 4.04525390 6.91522342 8.93956540 +59 -1.73188610 10.83073211 32.08643460 +60 3.96613220 6.96090435 32.08643460 +61 1.73188610 10.83073211 29.45256540 +62 -2.23424610 3.96118963 32.08643460 +63 8.51374610 6.91522342 11.57343460 +64 8.01138610 0.04568094 11.57343460 +65 2.31336780 3.91550870 11.57343460 +66 2.56925743 8.73430350 30.76950000 +67 6.27950000 6.59219395 10.25650000 +68 8.84875743 2.14210955 10.25650000 +69 -2.56925742 8.73430350 30.76950000 +70 0.00000000 4.28421910 30.76950000 +71 3.71024258 2.14210955 10.25650000 +72 4.15326130 6.83038739 3.70875040 +73 -3.83865835 7.01202349 24.22175040 +74 1.71241965 10.69477695 24.22175040 +75 4.56708035 0.18163610 3.70875040 +76 10.11815835 3.86438956 3.70875040 +77 -2.12623870 4.04602566 37.31724960 +78 -1.71241965 10.69477695 37.31724960 +79 2.12623870 4.04602566 24.22175040 +80 3.83865835 7.01202349 37.31724960 +81 2.44084165 3.86438956 16.80424960 +82 8.40573870 6.83038739 16.80424960 +83 7.99191965 0.18163610 16.80424960 +84 2.12623870 4.04602566 37.31724960 +85 10.11815835 3.86438956 16.80424960 +86 4.56708035 0.18163610 16.80424960 +87 1.71241965 10.69477695 37.31724960 +88 -3.83865835 7.01202349 37.31724960 +89 8.40573870 6.83038739 3.70875040 +90 7.99191965 0.18163610 3.70875040 +91 4.15326130 6.83038739 16.80424960 +92 2.44084165 3.86438956 3.70875040 +93 3.83865835 7.01202349 24.22175040 +94 -2.12623870 4.04602566 24.22175040 +95 -1.71241965 10.69477695 24.22175040 +96 2.27255105 8.56299999 3.07695000 +97 6.27950000 6.24958694 23.58995000 +98 8.55205105 2.31341306 23.58995000 +99 -2.27255105 8.56299999 3.07695000 +100 0.00000000 4.62682611 3.07695000 +101 8.55205105 2.31341306 37.94905000 +102 4.00694895 2.31341306 37.94905000 +103 4.00694895 2.31341306 23.58995000 +104 6.27950000 6.24958694 37.94905000 +105 0.00000000 4.62682611 17.43605000 +106 -2.27255105 8.56299999 17.43605000 +107 2.27255105 8.56299999 17.43605000 +108 2.06595550 6.05816207 2.30155860 +109 8.34545550 4.81825098 22.81455860 +110 6.27950000 1.23991109 22.81455860 +111 0.00000000 9.63650196 2.30155860 +112 -2.06595550 6.05816207 2.30155860 +113 8.34545550 4.81825098 38.72444140 +114 6.27950000 1.23991109 38.72444140 +115 4.21354450 4.81825098 22.81455860 +116 4.21354450 4.81825098 38.72444140 +117 2.06595550 6.05816207 18.21144140 +118 -2.06595550 6.05816207 18.21144140 +119 0.00000000 9.63650196 18.21144140 +120 0.00000000 9.44942766 35.75826160 +121 4.37555560 4.72471383 15.24526160 +122 8.18344440 4.72471383 15.24526160 +123 -1.90394440 6.15169922 35.75826160 +124 1.90394440 6.15169922 35.75826160 +125 6.27950000 1.42698539 5.26773840 +126 4.37555560 4.72471383 5.26773840 +127 6.27950000 1.42698539 15.24526160 +128 8.18344440 4.72471383 5.26773840 +129 -1.90394440 6.15169922 25.78073840 +130 0.00000000 9.44942766 25.78073840 +131 1.90394440 6.15169922 25.78073840 +132 8.12944070 0.12181583 34.71209860 +133 3.95922475 7.10121008 14.19909860 +134 -2.10928405 3.89701880 14.19909860 +135 8.38878405 6.97939425 34.71209860 +136 2.32027525 3.77520297 34.71209860 +137 1.84994070 10.75459722 6.31390140 +138 2.10928405 3.89701880 6.31390140 +139 -1.84994070 10.75459722 14.19909860 +140 -3.95922475 7.10121008 6.31390140 +141 10.23872475 3.77520297 26.82690140 +142 4.42955930 0.12181583 26.82690140 +143 4.17021595 6.97939425 26.82690140 +144 -1.84994070 10.75459722 6.31390140 +145 2.32027525 3.77520297 26.82690140 +146 8.38878405 6.97939425 26.82690140 +147 -2.10928405 3.89701880 6.31390140 +148 3.95922475 7.10121008 6.31390140 +149 4.42955930 0.12181583 34.71209860 +150 4.17021595 6.97939425 34.71209860 +151 8.12944070 0.12181583 26.82690140 +152 10.23872475 3.77520297 34.71209860 +153 -3.95922475 7.10121008 14.19909860 +154 1.84994070 10.75459722 14.19909860 +155 2.10928405 3.89701880 14.19909860 +156 2.53346428 8.71363831 35.79518500 +157 6.27950000 6.55086358 15.28218500 +158 8.81296428 2.16277474 15.28218500 +159 -2.53346427 8.71363831 35.79518500 +160 0.00000000 4.32554947 35.79518500 +161 8.81296428 2.16277473 5.23081500 +162 3.74603573 2.16277473 5.23081500 +163 3.74603573 2.16277474 15.28218500 +164 6.27950000 6.55086358 5.23081500 +165 0.00000000 4.32554947 25.74381500 +166 -2.53346427 8.71363831 25.74381500 +167 2.53346428 8.71363831 25.74381500 +168 1.88698975 6.16148799 7.63493860 +169 8.16648975 4.71492506 28.14793860 +170 6.27950000 1.44656294 28.14793860 +171 0.00000000 9.42985011 7.63493860 +172 -1.88698975 6.16148799 7.63493860 +173 8.16648975 4.71492506 33.39106140 +174 6.27950000 1.44656294 33.39106140 +175 4.39251025 4.71492506 28.14793860 +176 4.39251025 4.71492506 33.39106140 +177 1.88698975 6.16148799 12.87806140 +178 -1.88698975 6.16148799 12.87806140 +179 0.00000000 9.42985011 12.87806140 +180 2.53063850 8.71200685 7.80724780 +181 6.27950000 6.54760066 28.32024780 +182 8.81013850 2.16440620 28.32024780 +183 -2.53063850 8.71200685 7.80724780 +184 0.00000000 4.32881239 7.80724780 +185 8.81013850 2.16440620 33.21875220 +186 3.74886150 2.16440620 33.21875220 +187 3.74886150 2.16440620 28.32024780 +188 6.27950000 6.54760066 33.21875220 +189 0.00000000 4.32881239 12.70575220 +190 -2.53063850 8.71200685 12.70575220 +191 2.53063850 8.71200685 12.70575220 +192 3.09139785 7.26653156 2.58463800 +193 7.81169800 6.31049485 23.09763800 +194 7.83869985 0.95603671 23.09763800 +195 -1.55919985 9.92037634 2.58463800 +196 -1.53219800 4.56591820 2.58463800 +197 9.37089785 3.60988149 38.44136200 +198 4.72030015 0.95603671 38.44136200 +199 3.18810215 3.60988149 23.09763800 +200 4.74730200 6.31049485 38.44136200 +201 1.53219800 4.56591820 17.92836200 +202 -3.09139785 7.26653156 17.92836200 +203 1.55919985 9.92037634 17.92836200 +204 3.18810215 3.60988149 38.44136200 +205 -1.53219800 4.56591820 17.92836200 +206 -1.55919985 9.92037634 17.92836200 +207 7.83869985 0.95603671 38.44136200 +208 7.81169800 6.31049485 38.44136200 +209 -3.09139785 7.26653156 2.58463800 +210 1.55919985 9.92037634 2.58463800 +211 3.09139785 7.26653156 17.92836200 +212 1.53219800 4.56591820 2.58463800 +213 4.74730200 6.31049485 23.09763800 +214 9.37089785 3.60988149 23.09763800 +215 4.72030015 0.95603671 23.09763800 +216 1.52215080 9.95844379 35.89775000 +217 4.69581010 6.29744316 15.38475000 +218 9.38534070 3.66100063 15.38475000 +219 -3.10584070 7.21541242 35.89775000 +220 1.58368990 4.57896990 35.89775000 +221 7.80165080 0.91796926 5.12825000 +222 3.17365930 3.66100063 5.12825000 +223 4.75734920 0.91796926 15.38475000 +224 7.86318990 6.29744315 5.12825000 +225 -1.58368990 4.57896989 25.64125000 +226 -1.52215080 9.95844379 25.64125000 +227 3.10584070 7.21541242 25.64125000 +228 4.75734920 0.91796926 5.12825000 +229 1.58368990 4.57896989 25.64125000 +230 -3.10584070 7.21541242 25.64125000 +231 9.38534070 3.66100063 5.12825000 +232 4.69581010 6.29744315 5.12825000 +233 -1.52215080 9.95844379 35.89775000 +234 3.10584070 7.21541242 35.89775000 +235 1.52215080 9.95844379 25.64125000 +236 -1.58368990 4.57896990 35.89775000 +237 7.86318990 6.29744316 15.38475000 +238 7.80165080 0.91796926 15.38475000 +239 3.17365930 3.66100063 15.38475000 +240 3.10270095 7.21650006 7.67186200 +241 7.86067810 6.29526787 28.18486200 +242 7.80102285 0.92123219 28.18486200 +243 -1.52152285 9.95518086 7.67186200 +244 -1.58117810 4.58114518 7.67186200 +245 9.38220095 3.65991299 33.35413800 +246 4.75797715 0.92123219 33.35413800 +247 3.17679905 3.65991299 28.18486200 +248 4.69832190 6.29526787 33.35413800 +249 1.58117810 4.58114518 12.84113800 +250 -3.10270095 7.21650006 12.84113800 +251 1.52152285 9.95518086 12.84113800 +252 3.17679905 3.65991299 33.35413800 +253 -1.58117810 4.58114518 12.84113800 +254 -1.52152285 9.95518086 12.84113800 +255 7.80102285 0.92123219 33.35413800 +256 7.86067810 6.29526787 33.35413800 +257 -3.10270095 7.21650006 7.67186200 +258 1.52152285 9.95518086 7.67186200 +259 3.10270095 7.21650006 12.84113800 +260 1.58117810 4.58114518 7.67186200 +261 4.69832190 6.29526787 28.18486200 +262 9.38220095 3.65991299 28.18486200 +263 4.75797715 0.92123219 28.18486200 +264 1.50394025 9.93777860 30.76950000 +265 4.70460140 6.27133976 10.25650000 +266 9.35833885 3.66643884 10.25650000 +267 -3.07883885 7.20997421 30.76950000 +268 1.57489860 4.60507329 30.76950000 +269 7.78344025 0.93863445 10.25650000 +270 3.20066115 3.66643884 10.25650000 +271 4.77555975 0.93863445 10.25650000 +272 7.85439860 6.27133976 10.25650000 +273 -1.57489860 4.60507329 30.76950000 +274 -1.50394025 9.93777860 30.76950000 +275 3.07883885 7.20997421 30.76950000 +276 9.48204500 0.00000000 0.00000000 +277 4.74102250 8.21169185 20.51300000 +278 -1.53847750 2.66472120 20.51300000 +279 -4.74102250 8.21169185 0.00000000 +280 1.53847750 2.66472120 0.00000000 +281 3.07695500 0.00000000 20.51300000 +282 3.07695500 0.00000000 0.00000000 +283 1.53847750 2.66472120 20.51300000 +284 -4.74102250 8.21169185 20.51300000 +285 -1.53847750 2.66472120 0.00000000 +286 4.74102250 8.21169185 0.00000000 +287 9.48204500 0.00000000 20.51300000 diff --git a/contrib/voro++/zeo/examples/P3.v1 b/contrib/voro++/zeo/examples/P3.v1 new file mode 100644 index 0000000000000000000000000000000000000000..8444546a842e7c2791291fe85fa317b767a8cc51 --- /dev/null +++ b/contrib/voro++/zeo/examples/P3.v1 @@ -0,0 +1,329 @@ +Unit cell vectors: +va= 31.20200000 0.00000000 0.00000000 +vb= -15.60100000 27.02172465 0.00000000 +vc= 0.00000000 0.00000000 7.55100000 +324 +0 2.54452310 4.40724329 3.77550000 +1 -2.54452310 4.40724329 3.77550000 +2 5.08904620 0.00000000 3.77550000 +3 26.11295380 0.00000000 3.77550000 +4 -13.05647690 22.61448136 3.77550000 +5 13.05647690 22.61448136 3.77550000 +6 4.43692440 2.56165950 3.77550000 +7 0.00000000 5.12331899 3.77550000 +8 -11.16407560 24.46006515 3.77550000 +9 26.76507560 2.56165950 3.77550000 +10 15.60100000 21.89840566 3.77550000 +11 11.16407560 24.46006515 3.77550000 +12 4.77234590 4.81797351 2.46087090 +13 -1.78631450 6.54195954 2.46087090 +14 -9.04233960 25.29773862 2.46087090 +15 24.64333960 1.72398603 2.46087090 +16 17.38731450 20.47976511 2.46087090 +17 -10.82865410 22.20375115 5.09012910 +18 9.04233960 25.29773862 5.09012910 +19 10.82865410 22.20375114 2.46087090 +20 1.78631450 6.54195954 5.09012910 +21 13.81468550 20.47976511 5.09012910 +22 26.42965410 4.81797351 5.09012910 +23 6.55866040 1.72398603 5.09012910 +24 10.82865410 22.20375115 5.09012910 +25 17.38731450 20.47976511 5.09012910 +26 24.64333960 1.72398603 5.09012910 +27 -9.04233960 25.29773862 5.09012910 +28 -1.78631450 6.54195954 5.09012910 +29 26.42965410 4.81797351 2.46087090 +30 6.55866040 1.72398603 2.46087090 +31 4.77234590 4.81797351 5.09012910 +32 13.81468550 20.47976511 2.46087090 +33 1.78631450 6.54195954 2.46087090 +34 -10.82865410 22.20375114 2.46087090 +35 9.04233960 25.29773862 2.46087090 +36 7.19596125 4.15459017 1.69217910 +37 0.00000000 8.30918033 1.69217910 +38 -8.40503875 22.86713449 1.69217910 +39 24.00603875 4.15459017 1.69217910 +40 15.60100000 18.71254432 1.69217910 +41 -8.40503875 22.86713449 5.85882090 +42 8.40503875 22.86713449 5.85882090 +43 8.40503875 22.86713449 1.69217910 +44 0.00000000 8.30918033 5.85882090 +45 15.60100000 18.71254432 5.85882090 +46 24.00603875 4.15459017 5.85882090 +47 7.19596125 4.15459017 5.85882090 +48 5.54927570 5.30976889 0.00000000 +49 -1.82375690 7.46069818 0.00000000 +50 -8.22796740 24.87079537 0.00000000 +51 23.82896740 2.15092928 0.00000000 +52 17.42475690 19.56102647 0.00000000 +53 -10.05172430 21.71195576 0.00000000 +54 8.22796740 24.87079537 0.00000000 +55 10.05172430 21.71195576 0.00000000 +56 1.82375690 7.46069818 0.00000000 +57 13.77724310 19.56102647 0.00000000 +58 25.65272430 5.30976889 0.00000000 +59 7.37303260 2.15092928 0.00000000 +60 6.56178060 6.69057902 1.99270890 +61 -2.51332110 9.02795821 1.99270890 +62 -6.52589830 24.68434547 1.99270890 +63 22.12689830 2.33737918 1.99270890 +64 18.11432110 17.99376644 1.99270890 +65 -9.03921940 20.33114563 5.55829110 +66 6.52589830 24.68434547 5.55829110 +67 9.03921940 20.33114563 1.99270890 +68 2.51332110 9.02795821 5.55829110 +69 13.08767890 17.99376644 5.55829110 +70 24.64021940 6.69057902 5.55829110 +71 9.07510170 2.33737918 5.55829110 +72 9.03921940 20.33114563 5.55829110 +73 18.11432110 17.99376644 5.55829110 +74 22.12689830 2.33737918 5.55829110 +75 -6.52589830 24.68434547 5.55829110 +76 -2.51332110 9.02795821 5.55829110 +77 24.64021940 6.69057902 1.99270890 +78 9.07510170 2.33737918 1.99270890 +79 6.56178060 6.69057902 5.55829110 +80 13.08767890 17.99376644 1.99270890 +81 2.51332110 9.02795821 1.99270890 +82 -9.03921940 20.33114563 1.99270890 +83 6.52589830 24.68434547 1.99270890 +84 7.25914530 8.25513688 0.00000000 +85 -3.51958560 10.41417268 0.00000000 +86 -4.82226910 24.86268885 0.00000000 +87 20.42326910 2.15903580 0.00000000 +88 19.12058560 16.60755197 0.00000000 +89 -8.34185470 18.76658777 0.00000000 +90 4.82226910 24.86268885 0.00000000 +91 8.34185470 18.76658777 0.00000000 +92 3.51958560 10.41417268 0.00000000 +93 12.08141440 16.60755197 0.00000000 +94 23.94285470 8.25513688 0.00000000 +95 10.77873090 2.15903580 0.00000000 +96 7.29970790 9.17387552 2.46087090 +97 -4.29495530 10.90867024 2.46087090 +98 -4.00633680 25.28692993 2.46087090 +99 19.60733680 1.73479472 2.46087090 +100 19.89595530 16.11305441 2.46087090 +101 -8.30129210 17.84784913 5.09012910 +102 4.00633680 25.28692993 5.09012910 +103 8.30129210 17.84784913 2.46087090 +104 4.29495530 10.90867024 5.09012910 +105 11.30604470 16.11305441 5.09012910 +106 23.90229210 9.17387552 5.09012910 +107 11.59466320 1.73479472 5.09012910 +108 8.30129210 17.84784913 5.09012910 +109 19.89595530 16.11305441 5.09012910 +110 19.60733680 1.73479472 5.09012910 +111 -4.00633680 25.28692993 5.09012910 +112 -4.29495530 10.90867024 5.09012910 +113 23.90229210 9.17387552 2.46087090 +114 11.59466320 1.73479472 2.46087090 +115 7.29970790 9.17387552 5.09012910 +116 11.30604470 16.11305441 2.46087090 +117 4.29495530 10.90867024 2.46087090 +118 -8.30129210 17.84784913 2.46087090 +119 4.00633680 25.28692993 2.46087090 +120 9.07822190 7.39584604 1.69444440 +121 -1.86587960 11.55989381 1.69444440 +122 -4.65689850 22.85767688 1.69444440 +123 20.25789850 4.16404777 1.69444440 +124 17.46687960 15.46183084 1.69444440 +125 -6.52277810 19.62587861 5.85655560 +126 4.65689850 22.85767688 5.85655560 +127 6.52277810 19.62587861 1.69444440 +128 1.86587960 11.55989381 5.85655560 +129 13.73512040 15.46183085 5.85655560 +130 22.12377810 7.39584604 5.85655560 +131 10.94410150 4.16404777 5.85655560 +132 6.52277810 19.62587861 5.85655560 +133 17.46687960 15.46183085 5.85655560 +134 20.25789850 4.16404777 5.85655560 +135 -4.65689850 22.85767688 5.85655560 +136 -1.86587960 11.55989381 5.85655560 +137 22.12377810 7.39584604 1.69444440 +138 10.94410150 4.16404777 1.69444440 +139 9.07822190 7.39584604 5.85655560 +140 13.73512040 15.46183084 1.69444440 +141 1.86587960 11.55989381 1.69444440 +142 -6.52277810 19.62587861 1.69444440 +143 4.65689850 22.85767688 1.69444440 +144 6.52589830 11.30318742 3.77550000 +145 -6.52589830 11.30318742 3.77550000 +146 13.05179660 0.00000000 3.77550000 +147 18.15020340 0.00000000 3.77550000 +148 -9.07510170 15.71853723 3.77550000 +149 9.07510170 15.71853723 3.77550000 +150 9.07354160 10.60872910 3.77550000 +151 -4.65065810 13.16228208 3.77550000 +152 -1.87680030 24.46817167 3.77550000 +153 17.47780030 2.55355298 3.77550000 +154 20.25165810 13.85944257 3.77550000 +155 -6.52745840 16.41299555 3.77550000 +156 1.87680030 24.46817167 3.77550000 +157 6.52745840 16.41299555 3.77550000 +158 4.65065810 13.16228208 3.77550000 +159 10.95034190 13.85944257 3.77550000 +160 22.12845840 10.60872910 3.77550000 +161 13.72419970 2.55355298 3.77550000 +162 11.61962480 11.30588959 3.77550000 +163 -3.98137520 15.71583506 3.77550000 +164 0.00000000 22.61177919 3.77550000 +165 15.60100000 4.40994546 3.77550000 +166 19.58237520 11.30588959 3.77550000 +167 3.98137520 15.71583506 3.77550000 +168 10.85205560 9.17657769 2.46162600 +169 -2.52112160 13.98644468 2.46162600 +170 -2.22782280 22.21185766 2.46162600 +171 17.82882280 4.80986699 2.46162600 +172 18.12212160 13.03527997 2.46162600 +173 -4.74894440 17.84514696 5.08937400 +174 2.22782280 22.21185766 5.08937400 +175 4.74894440 17.84514696 2.46162600 +176 2.52112160 13.98644468 5.08937400 +177 13.07987840 13.03527997 5.08937400 +178 20.34994440 9.17657769 5.08937400 +179 13.37317720 4.80986699 5.08937400 +180 4.74894440 17.84514696 5.08937400 +181 18.12212160 13.03527997 5.08937400 +182 17.82882280 4.80986699 5.08937400 +183 -2.22782280 22.21185766 5.08937400 +184 -2.52112160 13.98644468 5.08937400 +185 20.34994440 9.17657769 2.46162600 +186 13.37317720 4.80986699 2.46162600 +187 10.85205560 9.17657769 5.08937400 +188 13.07987840 13.03527997 2.46162600 +189 2.52112160 13.98644468 2.46162600 +190 -4.74894440 17.84514696 2.46162600 +191 2.22782280 22.21185766 2.46162600 +192 11.59310310 6.69328120 1.98364770 +193 0.00000000 13.38656239 1.98364770 +194 -4.00789690 20.32844345 1.98364770 +195 19.60889690 6.69328120 1.98364770 +196 15.60100000 13.63516226 1.98364770 +197 -4.00789690 20.32844345 5.56735230 +198 4.00789690 20.32844345 5.56735230 +199 4.00789690 20.32844345 1.98364770 +200 0.00000000 13.38656239 5.56735230 +201 15.60100000 13.63516226 5.56735230 +202 19.60889690 6.69328120 5.56735230 +203 11.59310310 6.69328120 5.56735230 +204 10.88793790 8.26594557 0.00000000 +205 -1.71454990 13.56220360 0.00000000 +206 -2.99851220 21.72546662 0.00000000 +207 18.59951220 5.29625803 0.00000000 +208 17.31554990 13.45952105 0.00000000 +209 -4.71306210 18.75577908 0.00000000 +210 2.99851220 21.72546662 0.00000000 +211 4.71306210 18.75577908 0.00000000 +212 1.71454990 13.56220360 0.00000000 +213 13.88645010 13.45952105 0.00000000 +214 20.31406210 8.26594557 0.00000000 +215 12.60248780 5.29625803 0.00000000 +216 6.02198600 5.24221458 1.53813870 +217 -1.52889800 7.83630015 1.53813870 +218 -8.05011600 24.42763908 1.53813870 +219 23.65111600 2.59408557 1.53813870 +220 17.12989800 19.18542450 1.53813870 +221 -9.57901400 21.77951007 6.01286130 +222 8.05011600 24.42763908 6.01286130 +223 9.57901400 21.77951007 1.53813870 +224 1.52889800 7.83630015 6.01286130 +225 14.07210200 19.18542450 6.01286130 +226 25.18001400 5.24221458 6.01286130 +227 7.55088400 2.59408557 6.01286130 +228 9.57901400 21.77951007 6.01286130 +229 17.12989800 19.18542450 6.01286130 +230 23.65111600 2.59408557 6.01286130 +231 -8.05011600 24.42763908 6.01286130 +232 -1.52889800 7.83630015 6.01286130 +233 25.18001400 5.24221458 1.53813870 +234 7.55088400 2.59408557 1.53813870 +235 6.02198600 5.24221458 6.01286130 +236 14.07210200 19.18542450 1.53813870 +237 1.52889800 7.83630015 1.53813870 +238 -9.57901400 21.77951007 1.53813870 +239 8.05011600 24.42763908 1.53813870 +240 7.54776380 7.87953491 1.53889380 +241 -3.04999550 10.47632265 1.53889380 +242 -5.00324070 24.42493691 1.53889380 +243 20.60424070 2.59678774 1.53889380 +244 18.65099550 16.54540200 1.53889380 +245 -8.05323620 19.14218974 6.01210620 +246 5.00324070 24.42493691 6.01210620 +247 8.05323620 19.14218974 1.53889380 +248 3.04999550 10.47632265 6.01210620 +249 12.55100450 16.54540200 6.01210620 +250 23.65423620 7.87953491 6.01210620 +251 10.59775930 2.59678774 6.01210620 +252 8.05323620 19.14218974 6.01210620 +253 18.65099550 16.54540200 6.01210620 +254 20.60424070 2.59678774 6.01210620 +255 -5.00324070 24.42493691 6.01210620 +256 -3.04999550 10.47632265 6.01210620 +257 23.65423620 7.87953491 1.53889380 +258 10.59775930 2.59678774 1.53889380 +259 7.54776380 7.87953491 6.01210620 +260 12.55100450 16.54540200 1.53889380 +261 3.04999550 10.47632265 1.53889380 +262 -8.05323620 19.14218974 1.53889380 +263 5.00324070 24.42493691 1.53889380 +264 10.60399970 7.88223708 1.53813870 +265 -1.52421770 13.12445166 1.53813870 +266 -3.47278260 21.77951007 1.53813870 +267 19.07378260 5.24221458 1.53813870 +268 17.12521770 13.89727299 1.53813870 +269 -4.99700030 19.13948757 6.01286130 +270 3.47278260 21.77951007 6.01286130 +271 4.99700030 19.13948757 1.53813870 +272 1.52421770 13.12445166 6.01286130 +273 14.07678230 13.89727299 6.01286130 +274 20.59800030 7.88223708 6.01286130 +275 12.12821740 5.24221458 6.01286130 +276 4.99700030 19.13948757 6.01286130 +277 17.12521770 13.89727299 6.01286130 +278 19.07378260 5.24221458 6.01286130 +279 -3.47278260 21.77951007 6.01286130 +280 -1.52421770 13.12445166 6.01286130 +281 20.59800030 7.88223708 1.53813870 +282 12.12821740 5.24221458 1.53813870 +283 10.60399970 7.88223708 6.01286130 +284 14.07678230 13.89727299 1.53813870 +285 1.52421770 13.12445166 1.53813870 +286 -4.99700030 19.13948757 1.53813870 +287 3.47278260 21.77951007 1.53813870 +288 4.13582510 4.14243039 3.77550000 +289 -1.51953740 5.65294480 3.77550000 +290 -9.94563750 25.51121024 3.77550000 +291 25.54663750 1.51051441 3.77550000 +292 17.12053740 21.36877985 3.77550000 +293 -11.46517490 22.87929426 3.77550000 +294 9.94563750 25.51121024 3.77550000 +295 11.46517490 22.87929426 3.77550000 +296 1.51953740 5.65294480 3.77550000 +297 14.08146260 21.36877985 3.77550000 +298 27.06617490 4.14243039 3.77550000 +299 5.65536250 1.51051441 3.77550000 +300 7.55868450 10.06559243 3.77550000 +301 -4.93771650 11.57880901 3.77550000 +302 -3.10459900 25.50850807 3.77550000 +303 18.70559900 1.51321658 3.77550000 +304 20.53871650 15.44291564 3.77550000 +305 -8.04231550 16.95613222 3.77550000 +306 3.10459900 25.50850807 3.77550000 +307 8.04231550 16.95613222 3.77550000 +308 4.93771650 11.57880901 3.77550000 +309 10.66328350 15.44291564 3.77550000 +310 23.64331550 10.06559243 3.77550000 +311 12.49640100 1.51321658 3.77550000 +312 10.59151890 10.07099678 3.77550000 +313 -3.42597960 14.20802282 3.77550000 +314 -1.58350150 22.88469861 3.77550000 +315 17.18450150 4.13702604 3.77550000 +316 19.02697960 12.81370183 3.77550000 +317 -5.00948110 16.95072787 3.77550000 +318 1.58350150 22.88469861 3.77550000 +319 5.00948110 16.95072787 3.77550000 +320 3.42597960 14.20802282 3.77550000 +321 12.17502040 12.81370183 3.77550000 +322 20.61048110 10.07099678 3.77550000 +323 14.01749850 4.13702604 3.77550000 diff --git a/contrib/voro++/zeo/examples/P4.v1 b/contrib/voro++/zeo/examples/P4.v1 new file mode 100644 index 0000000000000000000000000000000000000000..acb384ca5fb4436ac6b77161791de07419aca5f7 --- /dev/null +++ b/contrib/voro++/zeo/examples/P4.v1 @@ -0,0 +1,293 @@ +Unit cell vectors: +va= 17.19300000 0.00000000 0.00000000 +vb= -8.59650000 14.88957477 0.00000000 +vc= 0.00000000 0.00000000 27.33300000 +288 +0 -2.42593230 4.28819753 16.18113600 +1 12.26634585 0.04317977 2.51463600 +2 2.50072185 4.24501777 2.51463600 +3 6.09577815 10.64455700 16.18113600 +4 -3.66984585 14.84639500 16.18113600 +5 6.17056770 10.60137724 11.15186400 +6 14.69227815 4.24501777 11.15186400 +7 11.02243230 10.60137723 2.51463600 +8 4.92665415 0.04317977 11.15186400 +9 3.66984585 14.84639500 24.81836400 +10 2.42593230 4.28819754 24.81836400 +11 -6.09577815 10.64455700 24.81836400 +12 11.02243230 10.60137724 11.15186400 +13 -3.66984585 14.84639500 24.81836400 +14 6.09577815 10.64455700 24.81836400 +15 2.50072185 4.24501777 11.15186400 +16 12.26634585 0.04317977 11.15186400 +17 2.42593230 4.28819753 16.18113600 +18 -6.09577815 10.64455700 16.18113600 +19 -2.42593230 4.28819754 24.81836400 +20 3.66984585 14.84639500 16.18113600 +21 4.92665415 0.04317977 2.51463600 +22 6.17056770 10.60137723 2.51463600 +23 14.69227815 4.24501777 2.51463600 +24 -2.08894950 3.61816667 13.66650000 +25 13.01510100 0.00000000 0.00000000 +26 2.08894950 3.61816667 0.00000000 +27 6.50755050 11.27140810 13.66650000 +28 4.17789900 0.00000000 13.66650000 +29 -6.50755050 11.27140810 0.00000000 +30 -6.50755050 11.27140810 13.66650000 +31 4.17789900 0.00000000 0.00000000 +32 6.50755050 11.27140810 0.00000000 +33 2.08894950 3.61816667 13.66650000 +34 13.01510100 0.00000000 13.66650000 +35 -2.08894950 3.61816667 0.00000000 +36 0.00000000 4.19737113 15.16161510 +37 13.55796998 2.09868556 1.49511510 +38 3.63503003 2.09868556 1.49511510 +39 4.96146998 12.79088921 15.16161510 +40 -4.96146997 12.79088921 15.16161510 +41 8.59650000 10.69220364 12.17138490 +42 13.55796998 2.09868556 12.17138490 +43 8.59650000 10.69220364 1.49511510 +44 3.63503003 2.09868556 12.17138490 +45 4.96146998 12.79088921 25.83788490 +46 0.00000000 4.19737113 25.83788490 +47 -4.96146997 12.79088921 25.83788490 +48 -1.66858065 6.09728087 14.42909070 +49 11.07830955 1.60360720 0.76259070 +50 4.44610980 4.49367366 0.76259070 +51 4.15039020 10.39590110 14.42909070 +52 -2.48180955 13.28596757 14.42909070 +53 6.92791935 8.79229390 12.90390930 +54 12.74689020 4.49367367 12.90390930 +55 10.26508065 8.79229390 0.76259070 +56 6.11469045 1.60360720 12.90390930 +57 2.48180955 13.28596757 26.57040930 +58 1.66858065 6.09728087 26.57040930 +59 -4.15039020 10.39590110 26.57040930 +60 10.26508065 8.79229390 12.90390930 +61 -2.48180955 13.28596757 26.57040930 +62 4.15039020 10.39590110 26.57040930 +63 4.44610980 4.49367367 12.90390930 +64 11.07830955 1.60360720 12.90390930 +65 1.66858065 6.09728087 14.42909070 +66 -4.15039020 10.39590110 14.42909070 +67 -1.66858065 6.09728087 26.57040930 +68 2.48180955 13.28596757 14.42909070 +69 6.11469045 1.60360720 0.76259070 +70 6.92791935 8.79229390 0.76259070 +71 12.74689020 4.49367366 0.76259070 +72 11.08776570 1.44428875 18.00424710 +73 4.29309210 10.32443114 4.33774710 +74 -1.80182640 6.00943238 4.33774710 +75 10.39832640 8.88014239 18.00424710 +76 4.30340790 4.56514363 18.00424710 +77 2.49126570 13.44528602 9.32875290 +78 1.80182640 6.00943238 9.32875290 +79 -2.49126570 13.44528602 4.33774710 +80 -4.29309210 10.32443114 9.32875290 +81 12.88959210 4.56514363 22.99525290 +82 6.10523430 1.44428875 22.99525290 +83 6.79467360 8.88014239 22.99525290 +84 -2.49126570 13.44528602 9.32875290 +85 4.30340790 4.56514363 22.99525290 +86 10.39832640 8.88014239 22.99525290 +87 -1.80182640 6.00943238 9.32875290 +88 4.29309210 10.32443114 9.32875290 +89 6.10523430 1.44428875 18.00424710 +90 6.79467360 8.88014239 18.00424710 +91 11.08776570 1.44428875 22.99525290 +92 12.88959210 4.56514363 18.00424710 +93 -4.29309210 10.32443114 4.33774710 +94 2.49126570 13.44528602 4.33774710 +95 1.80182640 6.00943238 4.33774710 +96 10.48085280 1.74208025 15.46227810 +97 3.73174065 9.94772490 1.79577810 +98 -1.84738785 6.68393011 1.79577810 +99 10.44388785 8.20564466 15.46227810 +100 4.86475935 4.94184987 15.46227810 +101 1.88435280 13.14749452 11.87072190 +102 1.84738785 6.68393011 11.87072190 +103 -1.88435280 13.14749452 1.79577810 +104 -3.73174065 9.94772490 11.87072190 +105 12.32824065 4.94184987 25.53722190 +106 6.71214720 1.74208025 25.53722190 +107 6.74911215 8.20564466 25.53722190 +108 -1.88435280 13.14749452 11.87072190 +109 4.86475935 4.94184987 25.53722190 +110 10.44388785 8.20564466 25.53722190 +111 -1.84738785 6.68393011 11.87072190 +112 3.73174065 9.94772490 11.87072190 +113 6.71214720 1.74208025 15.46227810 +114 6.74911215 8.20564466 15.46227810 +115 10.48085280 1.74208025 25.53722190 +116 12.32824065 4.94184987 15.46227810 +117 -3.73174065 9.94772490 1.79577810 +118 1.88435280 13.14749452 1.79577810 +119 1.84738785 6.68393011 1.79577810 +120 12.82941660 2.51931605 16.35333390 +121 4.23291660 12.37025872 2.68683390 +122 0.00000000 5.03863210 2.68683390 +123 8.59650000 9.85094267 16.35333390 +124 4.36358340 2.51931605 16.35333390 +125 4.23291660 12.37025872 10.97966610 +126 0.00000000 5.03863210 10.97966610 +127 -4.23291660 12.37025872 2.68683390 +128 -4.23291660 12.37025872 10.97966610 +129 12.82941660 2.51931605 24.64616610 +130 4.36358340 2.51931605 24.64616610 +131 8.59650000 9.85094267 24.64616610 +132 2.52909030 8.46621221 13.68289980 +133 11.12559030 6.42336255 0.01639980 +134 8.59650000 2.04284966 0.01639980 +135 0.00000000 12.84672511 13.68289980 +136 -2.52909030 8.46621221 13.68289980 +137 11.12559030 6.42336256 13.65010020 +138 8.59650000 2.04284966 13.65010020 +139 6.06740970 6.42336255 0.01639980 +140 6.06740970 6.42336256 13.65010020 +141 2.52909030 8.46621222 27.31660020 +142 -2.52909030 8.46621222 27.31660020 +143 0.00000000 12.84672511 27.31660020 +144 0.00000000 7.81553780 13.35490380 +145 10.42454573 3.90776890 27.02140380 +146 6.76845428 3.90776890 27.02140380 +147 1.82804573 10.98180587 13.35490380 +148 -1.82804572 10.98180587 13.35490380 +149 8.59650000 7.07403697 13.97809620 +150 10.42454573 3.90776890 13.97809620 +151 8.59650000 7.07403697 27.02140380 +152 6.76845428 3.90776890 13.97809620 +153 1.82804573 10.98180587 0.31159620 +154 0.00000000 7.81553780 0.31159620 +155 -1.82804572 10.98180587 0.31159620 +156 11.10495870 6.41145090 18.56184030 +157 0.00000000 12.82290179 4.89534030 +158 2.50845870 8.47812387 4.89534030 +159 6.08804130 6.41145090 18.56184030 +160 8.59650000 2.06667298 18.56184030 +161 2.50845870 8.47812387 8.77115970 +162 -2.50845870 8.47812387 8.77115970 +163 -2.50845870 8.47812387 4.89534030 +164 0.00000000 12.82290179 8.77115970 +165 8.59650000 2.06667298 22.43765970 +166 6.08804130 6.41145090 22.43765970 +167 11.10495870 6.41145090 22.43765970 +168 12.17608260 4.99396338 20.49975000 +169 1.76314215 13.04177854 6.83325000 +170 1.81644045 6.84175961 6.83325000 +171 6.78005955 8.04781516 20.49975000 +172 6.83335785 1.84779623 20.49975000 +173 3.57958260 9.89561139 6.83325000 +174 -1.81644045 6.84175961 6.83325000 +175 -3.57958260 9.89561139 6.83325000 +176 -1.76314215 13.04177854 6.83325000 +177 10.35964215 1.84779623 20.49975000 +178 5.01691740 4.99396338 20.49975000 +179 10.41294045 8.04781516 20.49975000 +180 10.49288790 3.86831153 18.82423710 +181 1.89638790 11.02126324 5.15773710 +182 0.00000000 7.73662305 5.15773710 +183 8.59650000 7.15295172 18.82423710 +184 6.70011210 3.86831153 18.82423710 +185 1.89638790 11.02126324 8.50876290 +186 0.00000000 7.73662305 8.50876290 +187 -1.89638790 11.02126324 5.15773710 +188 -1.89638790 11.02126324 8.50876290 +189 10.49288790 3.86831153 22.17526290 +190 6.70011210 3.86831153 22.17526290 +191 8.59650000 7.15295172 22.17526290 +192 -1.54135245 4.55174301 14.85821880 +193 12.48039870 0.94102113 1.19171880 +194 3.17124885 3.61072188 1.19171880 +195 5.42525115 11.27885289 14.85821880 +196 -3.88389870 13.94855364 14.85821880 +197 7.05514755 10.33783176 12.47478120 +198 14.02175115 3.61072188 12.47478120 +199 10.13785245 10.33783176 1.19171880 +200 4.71260130 0.94102113 12.47478120 +201 3.88389870 13.94855364 26.14128120 +202 1.54135245 4.55174301 26.14128120 +203 -5.42525115 11.27885289 26.14128120 +204 10.13785245 10.33783176 12.47478120 +205 -3.88389870 13.94855364 26.14128120 +206 5.42525115 11.27885289 26.14128120 +207 3.17124885 3.61072188 12.47478120 +208 12.48039870 0.94102113 12.47478120 +209 1.54135245 4.55174301 14.85821880 +210 -5.42525115 11.27885289 14.85821880 +211 -1.54135245 4.55174301 26.14128120 +212 3.88389870 13.94855364 14.85821880 +213 4.71260130 0.94102113 1.19171880 +214 7.05514755 10.33783176 1.19171880 +215 14.02175115 3.61072188 1.19171880 +216 11.66631015 1.41599856 16.50093210 +217 4.60686435 10.81132024 2.83443210 +218 -1.53705420 5.49425309 2.83443210 +219 10.13355420 9.39532168 16.50093210 +220 3.98963565 4.07825453 16.50093210 +221 3.06981015 13.47357621 10.83206790 +222 1.53705420 5.49425309 10.83206790 +223 -3.06981015 13.47357621 2.83443210 +224 -4.60686435 10.81132024 10.83206790 +225 13.20336435 4.07825453 24.49856790 +226 5.52668985 1.41599856 24.49856790 +227 7.05944580 9.39532168 24.49856790 +228 -3.06981015 13.47357621 10.83206790 +229 3.98963565 4.07825453 24.49856790 +230 10.13355420 9.39532168 24.49856790 +231 -1.53705420 5.49425309 10.83206790 +232 4.60686435 10.81132024 10.83206790 +233 5.52668985 1.41599856 16.50093210 +234 7.05944580 9.39532168 16.50093210 +235 11.66631015 1.41599856 24.49856790 +236 13.20336435 4.07825453 16.50093210 +237 -4.60686435 10.81132024 2.83443210 +238 3.06981015 13.47357621 2.83443210 +239 1.53705420 5.49425309 2.83443210 +240 11.66631015 4.95971736 18.97183530 +241 1.53791385 12.58317964 5.30533530 +242 1.53189630 7.26611249 5.30533530 +243 7.06460370 7.62346228 18.97183530 +244 7.05858615 2.30639513 18.97183530 +245 3.06981015 9.92985741 8.36116470 +246 -1.53189630 7.26611249 8.36116470 +247 -3.06981015 9.92985741 5.30533530 +248 -1.53791385 12.58317964 8.36116470 +249 10.13441385 2.30639513 22.02766470 +250 5.52668985 4.95971736 22.02766470 +251 10.12839630 7.62346228 22.02766470 +252 -3.06981015 9.92985741 8.36116470 +253 7.05858615 2.30639513 22.02766470 +254 7.06460370 7.62346228 22.02766470 +255 1.53189630 7.26611249 8.36116470 +256 1.53791385 12.58317964 8.36116470 +257 5.52668985 4.95971736 18.97183530 +258 10.12839630 7.62346228 18.97183530 +259 11.66631015 4.95971736 22.02766470 +260 10.13441385 2.30639513 18.97183530 +261 -1.53791385 12.58317964 5.30533530 +262 3.06981015 9.92985741 5.30533530 +263 -1.53189630 7.26611249 5.30533530 +264 1.51470330 7.26611249 13.33577070 +265 11.65771365 4.94482778 27.00227070 +266 7.04998965 2.32128471 27.00227070 +267 1.54651035 12.56829006 13.33577070 +268 -3.06121365 9.94474699 13.33577070 +269 10.11120330 7.62346228 13.99722930 +270 10.14301035 2.32128471 13.99722930 +271 7.08179670 7.62346228 27.00227070 +272 5.53528635 4.94482778 13.99722930 +273 3.06121365 9.94474699 0.33072930 +274 -1.51470330 7.26611249 0.33072930 +275 -1.54651035 12.56829006 0.33072930 +276 7.08179670 7.62346228 13.99722930 +277 -3.06121365 9.94474699 0.33072930 +278 1.54651035 12.56829006 0.33072930 +279 7.04998965 2.32128471 13.99722930 +280 11.65771365 4.94482778 13.99722930 +281 -1.51470330 7.26611249 13.33577070 +282 -1.54651035 12.56829006 13.33577070 +283 1.51470330 7.26611249 0.33072930 +284 3.06121365 9.94474699 13.33577070 +285 5.53528635 4.94482778 27.00227070 +286 10.11120330 7.62346228 27.00227070 +287 10.14301035 2.32128471 27.00227070 diff --git a/contrib/voro++/zeo/examples/YUG.v1 b/contrib/voro++/zeo/examples/YUG.v1 new file mode 100644 index 0000000000000000000000000000000000000000..5d982d3683f2d03e3b46cfaa10a6ec83b591c91e --- /dev/null +++ b/contrib/voro++/zeo/examples/YUG.v1 @@ -0,0 +1,53 @@ +Unit cell vectors: +va= 10.248 0.0 0.0 +vb= 6.19034e-10 13.788 0.0 +vc= -2.49057 4.16307e-10 6.30814 +48 +O 1.31672 3.447 3.15407 +O 6.44072 3.447 3.15407 +O 6.44072 10.341 3.15407 +O 1.31672 10.341 3.15407 +O 2.92616 2.32328 1.41113 +O 4.83128 2.32328 4.89701 +O 4.83128 11.4647 4.89701 +O 2.92616 11.4647 1.41113 +O 8.05016 9.21728 1.41113 +O -0.292722 9.21728 4.89701 + O -0.292722 4.57072 4.89701 + O 8.05016 4.57072 1.41113 + O 2.33729 4.87406 1.19728 + O 5.42014 4.87406 5.11085 + O 5.42014 8.91394 5.11085 + O 2.33729 8.91394 1.19728 + O 7.46129 11.7681 1.19728 + O 0.296141 11.7681 5.11085 + O 0.296141 2.01994 5.11085 + O 7.46129 2.01994 1.19728 + O 3.87872 4.04678 3.15407 + O 3.87872 9.74122 3.15407 + O -1.24528 10.9408 3.15407 + O -1.24528 2.84722 3.15407 + O 3.49909 2.18561e-11 0.331177 + O 4.25835 3.94451e-10 5.97696 + O 8.62309 6.894 0.331177 + O -0.865653 6.894 5.97696 + O 5.124 2.042 0.0 + O 5.124 11.746 0.0 + O 4.01196e-10 8.936 0.0 + O 2.17838e-10 4.852 0.0 + Si 2.61443 3.67174 2.23182 + Si 5.143 3.67174 4.07632 + Si 5.143 10.1163 4.07632 + Si 2.61443 10.1163 2.23182 + Si 7.73843 10.5657 2.23182 + Si 0.0190031 10.5657 4.07632 + Si 0.0190031 3.22226 4.07632 + Si 7.73843 3.22226 2.23182 + Si 3.58372 1.59389 0.134994 + Si 4.17372 1.59389 6.17314 + Si 4.17372 12.1941 6.17314 + Si 3.58372 12.1941 0.134994 + Si 8.70772 8.48789 0.134994 + Si -0.950284 8.48789 6.17314 + Si -0.950284 5.30011 6.17314 + Si 8.70772 5.30011 0.134994 diff --git a/contrib/voro++/zeo/examples/test.v1 b/contrib/voro++/zeo/examples/test.v1 new file mode 100644 index 0000000000000000000000000000000000000000..255e93d1931ed9b5a7a0e1672903ed7863217ab6 --- /dev/null +++ b/contrib/voro++/zeo/examples/test.v1 @@ -0,0 +1,7 @@ +Unit cell vectors: +va= 1.0 0.0 0.0 +vb= 0.0 1.0 0.0 +vc= 1.0 0.0 1.0 +2 +O 0.375 0.6 0.6 +O 0.875 0.6 0.6 diff --git a/contrib/voro++/zeo/images.cc b/contrib/voro++/zeo/images.cc new file mode 100644 index 0000000000000000000000000000000000000000..ce5565d24aefd92cc0686e423a86c86c47c6ee81 --- /dev/null +++ b/contrib/voro++/zeo/images.cc @@ -0,0 +1,28 @@ +#include <cstdio> +#include <cstdlib> +#include <cmath> +using namespace std; + +#include "unitcell.hh" +using namespace voro; + +int main(int argc,char **argv) { + unsigned int i,j; + vector<int> vi; + vector<double> vd; + + // Check the command line syntax + if(argc!=7) { + fprintf(stderr,"Syntax: ./images bx bxy by bxz byz bz\n"); + return VOROPP_CMD_LINE_ERROR; + } + + // Create the unit cell + unitcell uc(atof(argv[1]),atof(argv[2]),atof(argv[3]),atof(argv[4]),atof(argv[5]),atof(argv[6])); + + // Calculate the images + uc.images(vi,vd); + + // Print the output + for(i=j=0;i<vd.size();i++,j+=3) printf("%d %d %d %g\n",vi[j],vi[j+1],vi[j+2],vd[i]); +} diff --git a/contrib/voro++/zeo/network.cc b/contrib/voro++/zeo/network.cc new file mode 100644 index 0000000000000000000000000000000000000000..0c1ff6046772d9479f1647a982b2163a0368484d --- /dev/null +++ b/contrib/voro++/zeo/network.cc @@ -0,0 +1,190 @@ +// Voronoi calculation example code +// +// Author : Chris H. Rycroft (LBL / UC Berkeley) +// Email : chr@alum.mit.edu +// Date : August 30th 2011 + +#include <cstring> + +#include "voro++.hh" +using namespace voro; + +#include "v_network.hh" +#include "r_table.cc" + +// A guess for the memory allocation per region +const int memory=16; + +// A maximum allowed number of regions, to prevent enormous amounts of memory +// being allocated +const int max_regions=16777216; + +// A buffer size +const int bsize=2048; + +// Output routine +template<class c_class> +void compute(c_class &con,char *buffer,int bp,double vol); + +// Commonly used error message +void file_import_error() { + voro_fatal_error("File import error",VOROPP_FILE_ERROR); +} + +int main(int argc,char **argv) { + char *farg,buffer[bsize]; + bool radial;int i,n,bp; + double bx,bxy,by,bxz,byz,bz,x,y,z,vol; + + // Check the command line syntax + if(argc==2) { + radial=false;farg=argv[1]; + } else if(argc==3&&strcmp(argv[1],"-r")==0) { + radial=true;farg=argv[2]; + } else { + fputs("Syntax: ./network [-r] <filename.v1>\n",stderr); + return VOROPP_CMD_LINE_ERROR; + } + + // Check that the file has a ".v1" extension + bp=strlen(farg); + if(bp+2>bsize) { + fputs("Filename too long\n",stderr); + return VOROPP_CMD_LINE_ERROR; + } + if(bp<3||farg[bp-3]!='.'||farg[bp-2]!='v'||farg[bp-1]!='1') { + fputs("Filename must end in '.v1'\n",stderr); + return VOROPP_CMD_LINE_ERROR; + } + + // Try opening the file + FILE *fp(fopen(farg,"r")); + if(fp==NULL) voro_fatal_error("Unable to open file for import",VOROPP_FILE_ERROR); + + // Read header line + if(fgets(buffer,bsize,fp)!=buffer) file_import_error(); + if(strcmp(buffer,"Unit cell vectors:\n")!=0) + voro_fatal_error("Invalid header line",VOROPP_FILE_ERROR); + + // Read in the box dimensions and the number of particles + if(fscanf(fp,"%s %lg %lg %lg",buffer,&bx,&x,&x)!=4) file_import_error(); + if(strcmp(buffer,"va=")!=0) voro_fatal_error("Invalid first vector",VOROPP_FILE_ERROR); + if(fscanf(fp,"%s %lg %lg %lg",buffer,&bxy,&by,&x)!=4) file_import_error(); + if(strcmp(buffer,"vb=")!=0) voro_fatal_error("Invalid second vector",VOROPP_FILE_ERROR); + if(fscanf(fp,"%s %lg %lg %lg",buffer,&bxz,&byz,&bz)!=4) file_import_error(); + if(strcmp(buffer,"vc=")!=0) voro_fatal_error("Invalid third vector",VOROPP_FILE_ERROR); + if(fscanf(fp,"%d",&n)!=1) file_import_error(); + + // Print the box dimensions + printf("Box dimensions:\n" + " va=(%f 0 0)\n" + " vb=(%f %f 0)\n" + " vc=(%f %f %f)\n\n",bx,bxy,by,bxz,byz,bz); + + // Check that the input parameters make sense + if(n<1) voro_fatal_error("Invalid number of particles",VOROPP_FILE_ERROR); + if(bx<tolerance||by<tolerance||bz<tolerance) + voro_fatal_error("Invalid box dimensions",VOROPP_FILE_ERROR); + + // Compute the internal grid size, aiming to make + // the grid blocks square with around 6 particles + // in each + double ls=1.8*pow(bx*by*bz,-1.0/3.0); + double nxf=bx*ls+1.5; + double nyf=by*ls+1.5; + double nzf=bz*ls+1.5; + + // Check the grid is not too huge, using floating point numbers to avoid + // integer wrap-arounds + if (nxf*nyf*nzf>max_regions) { + fprintf(stderr,"voro++: Number of computational blocks exceeds the maximum allowed of %d\n" + "Either increase the particle length scale, or recompile with an increased\nmaximum.\n", + max_regions); + return VOROPP_MEMORY_ERROR; + } + + // Now that we are confident that the number of regions is reasonable, + // create integer versions of them + int nx=int(nxf); + int ny=int(nyf); + int nz=int(nzf); + printf("Total particles = %d\n\nInternal grid size = (%d %d %d)\n\n",n,nx,ny,nz); + + vol=bx*by*bz; + if(radial) { + + // Create a container with the geometry given above + container_periodic_poly con(bx,bxy,by,bxz,byz,bz,nx,ny,nz,memory); + + // Read in the particles from the file + for(i=0;i<n;i++) { + if(fscanf(fp,"%s %lg %lg %lg",buffer,&x,&y,&z)!=4) file_import_error(); + con.put(i,x,y,z,radial_lookup(buffer)); + } + fclose(fp); + + // Copy the output filename + for(i=0;i<bp-2;i++) buffer[i]=farg[i]; + compute(con,buffer,bp,vol); + } else { + + // Create a container with the geometry given above + container_periodic con(bx,bxy,by,bxz,byz,bz,nx,ny,nz,memory); + + // Read in the particles from the file + for(i=0;i<n;i++) { + if(fscanf(fp,"%s %lg %lg %lg",buffer,&x,&y,&z)!=4) + voro_fatal_error("File import error",VOROPP_FILE_ERROR); + con.put(i,x,y,z); + } + fclose(fp); + + // Copy the output filename + for(i=0;i<bp-2;i++) buffer[i]=farg[i]; + compute(con,buffer,bp,vol); + } +} + +inline void extension(const char *ext,char *bu) { + char *ep((char*) ext); + while(*ep!=0) *(bu++)=*(ep++);*bu=*ep; +} + +template<class c_class> +void compute(c_class &con,char *buffer,int bp,double vol) { + char *bu(buffer+bp-2); + int id; + double vvol(0),x,y,z,r; + voronoicell c; + voronoi_network vn(con,1e-5),vn2(con,1e-5); + + // Compute Voronoi cells and + c_loop_all_periodic vl(con); + if(vl.start()) do if(con.compute_cell(c,vl)) { + vvol+=c.volume(); + vl.pos(id,x,y,z,r); + vn.add_to_network(c,id,x,y,z,r); + vn2.add_to_network_rectangular(c,id,x,y,z,r); + } while(vl.inc()); + + // Carry out the volume check + printf("Volume check:\n Total domain volume = %f\n" + " Total Voronoi volume = %f\n",vol,vvol); + + // Print non-rectangular cell network + extension("nd2",bu);vn.draw_network(buffer); + extension("nt2",bu);vn.print_network(buffer); + + // Print rectangular cell network + extension("ntd",bu);vn2.draw_network(buffer); + extension("net",bu);vn2.print_network(buffer); + + // Output the particles and any constructed periodic images + extension("par",bu);con.draw_particles(buffer); + + // Output the Voronoi cells in gnuplot format + extension("out",bu);con.draw_cells_gnuplot(buffer); + + // Output the unit cell in gnuplot format + extension("dom",bu);con.draw_domain_gnuplot(buffer); +} diff --git a/contrib/voro++/zeo/r_table.cc b/contrib/voro++/zeo/r_table.cc new file mode 100644 index 0000000000000000000000000000000000000000..bcfce3b0d01b36731990972df7194dd9411ed08f --- /dev/null +++ b/contrib/voro++/zeo/r_table.cc @@ -0,0 +1,25 @@ +// Voro++, a 3D cell-based Voronoi library +// +// Author : Chris H. Rycroft (LBL / UC Berkeley) +// Email : chr@alum.mit.edu +// Date : July 1st 2008 + +#include <cstdlib> + +const int n_table=2; + +const char rad_ctable[][4]={ + "O", + "Si" +}; + +const double rad_table[]={ + 0.8, + 0.5 +}; + +double radial_lookup(char *buffer) { + for(int i=0;i<n_table;i++) if(strcmp(rad_ctable[i],buffer)==0) return rad_table[i]; + fprintf(stderr,"Entry \"%s\" not found in table\n",buffer); + exit(VOROPP_FILE_ERROR); +} diff --git a/contrib/voro++/zeo/v_network.cc b/contrib/voro++/zeo/v_network.cc new file mode 100644 index 0000000000000000000000000000000000000000..805c517e4792efbc6f10ad7f07da0f17f234c5dd --- /dev/null +++ b/contrib/voro++/zeo/v_network.cc @@ -0,0 +1,538 @@ +#include "v_network.hh" + +/** Initializes the Voronoi network object. The geometry is set up to match a + * corresponding container class, and memory is allocated for the network. + * \param[in] c a reference to a container or container_poly class. */ +template<class c_class> +voronoi_network::voronoi_network(c_class &c,double net_tol_) : + bx(c.bx), bxy(c.bxy), by(c.by), bxz(c.bxz), byz(c.byz), bz(c.bz), + nx(c.nx), ny(c.ny), nz(c.nz), nxyz(nx*ny*nz), + xsp(nx/bx), ysp(ny/by), zsp(nz/bz), net_tol(net_tol_) { + int l; + + // Allocate memory for vertex structure + pts=new double*[nxyz]; + idmem=new int*[nxyz]; + ptsc=new int[nxyz]; + ptsmem=new int[nxyz]; + for(l=0;l<nxyz;l++) { + pts[l]=new double[4*init_network_vertex_memory]; + idmem[l]=new int[init_network_vertex_memory]; + ptsc[l]=0;ptsmem[l]=init_network_vertex_memory; + } + + // Allocate memory for network edges and related statistics + edc=0;edmem=init_network_vertex_memory*nxyz; + ed=new int*[edmem]; + ne=new int*[edmem]; + pered=new unsigned int*[edmem]; + raded=new block*[edmem]; + nu=new int[edmem]; + nec=new int[edmem]; + numem=new int[edmem]; + + // Allocate memory for back pointers + reg=new int[edmem]; + regp=new int[edmem]; + + // Allocate edge memory + for(l=0;l<edmem;l++) { + ed[l]=new int[2*init_network_edge_memory]; + ne[l]=ed[l]+init_network_edge_memory; + } + for(l=0;l<edmem;l++) raded[l]=new block[init_network_edge_memory]; + for(l=0;l<edmem;l++) pered[l]=new unsigned int[init_network_edge_memory]; + for(l=0;l<edmem;l++) {nu[l]=nec[l]=0;numem[l]=init_network_edge_memory;} + + // vertices + vmap=new int[4*init_vertices]; + map_mem=init_vertices; +} + +/** The voronoi_network destructor removes the dynamically allocated memory. */ +voronoi_network::~voronoi_network() { + int l; + + // Remove Voronoi mapping array + delete [] vmap; + + // Remove individual edge arrays + for(l=0;l<edmem;l++) delete [] pered[l]; + for(l=0;l<edmem;l++) delete [] raded[l]; + for(l=0;l<edmem;l++) delete [] ed[l]; + + // Remove back pointers + delete [] regp;delete [] reg; + + // Remove memory for edges and related statistics + delete [] numem;delete [] nec;delete [] nu; + delete [] raded;delete [] pered; + delete [] ne;delete [] ed; + + // Remove vertex structure arrays + for(l=0;l<nxyz;l++) { + delete [] idmem[l]; + delete [] pts[l]; + } + delete [] ptsmem;delete [] ptsc; + delete [] idmem;delete [] pts; +} + +/** Increase network memory for a particular region. */ +void voronoi_network::add_network_memory(int l) { + ptsmem[l]<<=1; + + // Check to see that an absolute maximum in memory allocation + // has not been reached, to prevent runaway allocation + if(ptsmem[l]>max_network_vertex_memory) + voro_fatal_error("Container vertex maximum memory allocation exceeded",VOROPP_MEMORY_ERROR); + + // Allocate new arrays + double *npts(new double[4*ptsmem[l]]); + int *nidmem(new int[ptsmem[l]]); + + // Copy the contents of the old arrays into the new ones + for(int i=0;i<4*ptsc[l];i++) npts[i]=pts[l][i]; + for(int i=0;i<ptsc[l];i++) nidmem[i]=idmem[l][i]; + + // Delete old arrays and update pointers to the new ones + delete [] pts[l];delete [] idmem[l]; + pts[l]=npts;idmem[l]=nidmem; +} + +/** Increase edge network memory. */ +void voronoi_network::add_edge_network_memory() { + int i; + edmem<<=1; + + // Allocate new arrays + int **ned(new int*[edmem]); + int **nne(new int*[edmem]); + block **nraded(new block*[edmem]); + unsigned int **npered(new unsigned int*[edmem]); + int *nnu(new int[edmem]); + int *nnec(new int[edmem]); + int *nnumem(new int[edmem]); + int *nreg(new int[edmem]); + int *nregp(new int[edmem]); + + // Copy the contents of the old arrays into the new ones + for(i=0;i<edc;i++) { + ned[i]=ed[i]; + nne[i]=ne[i]; + nraded[i]=raded[i]; + npered[i]=pered[i]; + nnu[i]=nu[i]; + nnec[i]=nec[i]; + nnumem[i]=numem[i]; + nreg[i]=reg[i]; + nregp[i]=regp[i]; + } + + // Carry out new allocation + while(i<edmem) { + ned[i]=new int[2*init_network_edge_memory]; + nne[i]=ned[i]+init_network_edge_memory; + nnu[i]=nnec[i]=0;nnumem[i]=init_network_edge_memory; + nraded[i]=new block[init_network_edge_memory]; + npered[i++]=new unsigned int[init_network_edge_memory]; + } + + // Delete old arrays and update pointers to the new ones + delete [] ed;ed=ned; + delete [] ne;ne=nne; + delete [] raded;raded=nraded; + delete [] pered;pered=npered; + delete [] nu;nu=nnu; + delete [] nec;nec=nnec; + delete [] numem;numem=nnumem; + delete [] reg;reg=nreg; + delete [] regp;regp=nregp; +} + +/** Increase a particular vertex memory. */ +void voronoi_network::add_particular_vertex_memory(int l) { + numem[l]<<=1; + + // Check that the vertex allocation does not exceed a maximum safe + // limit + if(numem[l]>max_vertex_order) + voro_fatal_error("Particular vertex maximum memory allocation exceeded",VOROPP_MEMORY_ERROR); + + // Allocate new arrays + int *ned(new int[2*numem[l]]); + int *nne(ned+numem[l]); + block *nraded(new block[numem[l]]); + unsigned int *npered(new unsigned int[numem[l]]); + + // Copy the contents of the old arrays into the new ones + for(int i=0;i<nu[l];i++) { + ned[i]=ed[l][i]; + nraded[i]=raded[l][i]; + npered[i]=pered[l][i]; + } + for(int i=0;i<nec[l];i++) nne[i]=ne[l][i]; + + // Delete old arrays and update pointers to the new ones + delete [] ed[l];ed[l]=ned;ne[l]=nne; + delete [] raded[l];raded[l]=nraded; + delete [] pered[l];pered[l]=npered; +} + + +/** Increases the memory for the vertex mapping. + * \param[in] pmem the amount of memory needed. */ +void voronoi_network::add_mapping_memory(int pmem) { + do {map_mem<<=1;} while(map_mem<pmem); + delete [] vmap; + vmap=new int[4*map_mem]; +} + +/** Clears the class of all vertices and edges. */ +void voronoi_network::clear_network() { + int l; + edc=0; + for(l=0;l<nxyz;l++) ptsc[l]=0; + for(l=0;l<edmem;l++) nu[l]=0; +} + +/** Outputs the network in a format that can be read by gnuplot. + * \param[in] fp a file handle to write to. */ +void voronoi_network::draw_network(FILE *fp) { + voronoicell c; + int l,q,ai,aj,ak; + double x,y,z,*ptsp; + for(l=0;l<edc;l++) { + ptsp=pts[reg[l]]+4*regp[l]; + x=*(ptsp++);y=*(ptsp++);z=*ptsp; + for(q=0;q<nu[l];q++) { + unpack_periodicity(pered[l][q],ai,aj,ak); + if(ed[l][q]<l&&ai==0&&aj==0&&ak==0) continue; + ptsp=pts[reg[ed[l][q]]]+4*regp[ed[l][q]]; + fprintf(fp,"%g %g %g\n%g %g %g\n\n\n",x,y,z, + *ptsp+bx*ai+bxy*aj+bxz*ak, + ptsp[1]+by*aj+byz*ak,ptsp[2]+bz*ak); + } + } +} + +/** Prints out the network. + * \param[in] fp a file handle to write to. + * \param[in] reverse_remove a boolean value, setting whether or not to remove + * reverse edges. */ +void voronoi_network::print_network(FILE *fp,bool reverse_remove) { + int ai,aj,ak,j,l,ll,q; + double x,y,z,x2,y2,z2,*ptsp; + + // Print the vertex table + fprintf(fp,"Vertex table:\n%d\n",edc); + //os << edc << "\n"; + for(l=0;l<edc;l++) { + ptsp=pts[reg[l]];j=4*regp[l]; + fprintf(fp,"%d %g %g %g %g",l,ptsp[j],ptsp[j+1],ptsp[j+2],ptsp[j+3]); + for(ll=0;ll<nec[l];ll++) fprintf(fp," %d",ne[l][ll]); + fputs("\n",fp); + } + + // Print out the edge table, loop over vertices + fputs("\nEdge table:\n",fp); + for(l=0;l<edc;l++) { + + // Store the position of this vertex + ptsp=pts[reg[l]];j=4*regp[l]; + x=ptsp[j];y=ptsp[j+1];z=ptsp[j+2]; + + // Loop over edges of this vertex + for(q=0;q<nu[l];q++) { + + unpack_periodicity(pered[l][q],ai,aj,ak); + + // If this option is enabled, then the code will not + // print edges from i to j for j<i. + if(reverse_remove) if(ed[l][q]<l&&ai==0&&aj==0&&ak==0) continue; + + fprintf(fp,"%d -> %d",l,ed[l][q]); + raded[l][q].print(fp); + + // Compute and print the length of the edge + ptsp=pts[reg[ed[l][q]]];j=4*regp[ed[l][q]]; + x2=ptsp[j]+ai*bx+aj*bxy+ak*bxz-x; + y2=ptsp[j+1]+aj*by+ak*byz-y; + z2=ptsp[j+2]+ak*bz-z; + fprintf(fp," %d %d %d %g\n",ai,aj,ak,sqrt(x2*x2+y2*y2+z2*z2)); + } + } +} + +// Converts three periodic image displacements into a single unsigned integer. +// \param[in] i the periodic image in the x direction. +// \param[in] j the periodic image in the y direction. +// \param[in] k the periodic image in the z direction. +// \return The packed integer. */ +inline unsigned int voronoi_network::pack_periodicity(int i,int j,int k) { + unsigned int pa=((unsigned int) (127+i)); + pa<<=8;pa+=((unsigned int) (127+j)); + pa<<=8;pa+=((unsigned int) (127+k)); + return pa; +} + +/** Unpacks an unsigned integer into three periodic image displacements. + * \param[in] pa the packed integer. +// \param[out] i the periodic image in the x direction. +// \param[out] j the periodic image in the y direction. +// \param[out] k the periodic image in the z direction. */ +inline void voronoi_network::unpack_periodicity(unsigned int pa,int &i,int &j,int &k) { + i=((signed int) (pa>>16))-127; + j=((signed int) ((pa>>8)&255))-127; + k=((signed int) (pa&255))-127; +} + +/** Adds a Voronoi cell to the network structure. The routine first checks all + * of the Voronoi cell vertices and merges them with existing ones where + * possible. Edges are then added to the structure. + * \param[in] c a reference to a Voronoi cell. + * \param[in] (x,y,z) the position of the Voronoi cell. + * \param[in] idn the ID number of the particle associated with the cell. */ +template<class v_cell> +void voronoi_network::add_to_network_internal(v_cell &c,int idn,double x,double y,double z,double rad,int *cmap) { + int i,j,k,ijk,l,q,ai,aj,ak,*vmp(cmap); + double gx,gy,vx,vy,vz,crad,*cp(c.pts); + + // Loop over the vertices of the Voronoi cell + for(l=0;l<c.p;l++,vmp+=4) { + + // Compute the real position of this vertex, and evaluate its + // position along the non-rectangular axes + vx=x+cp[3*l]*0.5;vy=y+cp[3*l+1]*0.5;vz=z+cp[3*l+2]*0.5; + gx=vx-vy*(bxy/by)+vz*(bxy*byz-by*bxz)/(by*bz); + gy=vy-vz*(byz/bz); + + // Compute the adjusted radius, which will be needed either way + crad=0.5*sqrt(cp[3*l]*cp[3*l]+cp[3*l+1]*cp[3*l+1]+cp[3*l+2]*cp[3*l+2])-rad; + + // Check to see if a vertex very close to this one already + // exists in the network + if(search_previous(gx,gy,vx,vy,vz,ijk,q,vmp[1],vmp[2],vmp[3])) { + + // If it does, then just map the Voronoi cell + // vertex to it + *vmp=idmem[ijk][q]; + + // Store this radius if it smaller than the current + // value + if(pts[ijk][4*q+3]>crad) pts[ijk][4*q+3]=crad; + } else { + k=step_int(vz*zsp);if(k<0||k>=nz) {ak=step_div(k,nz);vx-=bxz*ak;vy-=byz*ak;vz-=bz*ak;k-=ak*nz;} else ak=0; + j=step_int(gy*ysp);if(j<0||j>=ny) {aj=step_div(j,ny);vx-=bxy*aj;vy-=by*aj;j-=aj*ny;} else aj=0; + i=step_int(gx*xsp);if(i<0||i>=nx) {ai=step_div(i,nx);vx-=bx*ai;i-=ai*nx;} else ai=0; + + vmp[1]=ai;vmp[2]=aj;vmp[3]=ak; + ijk=i+nx*(j+ny*k); + + if(edc==edmem) add_edge_network_memory(); + if(ptsc[ijk]==ptsmem[ijk]) add_network_memory(ijk); + + reg[edc]=ijk;regp[edc]=ptsc[ijk]; + pts[ijk][4*ptsc[ijk]]=vx; + pts[ijk][4*ptsc[ijk]+1]=vy; + pts[ijk][4*ptsc[ijk]+2]=vz; + pts[ijk][4*ptsc[ijk]+3]=crad; + idmem[ijk][ptsc[ijk]++]=edc; + *vmp=edc++; + } + + // Add the neighbor information to this vertex + add_neighbor(*vmp,idn); + } + + add_edges_to_network(c,x,y,z,rad,cmap); +} + +/** Adds a neighboring particle ID to a vertex in the Voronoi network, first + * checking that the ID is not already recorded. + * \param[in] k the Voronoi vertex. + * \param[in] idn the particle ID number. */ +inline void voronoi_network::add_neighbor(int k,int idn) { + for(int i=0;i<nec[k];i++) if(ne[k][i]==idn) return; + if(nec[k]==numem[k]) add_particular_vertex_memory(k); + ne[k][nec[k]++]=idn; +} + +/** Adds edges to the network structure, after the vertices have been + * considered. This routine assumes that the cmap array has a mapping between + * Voronoi cell vertices and Voronoi network vertices. */ +template<class v_cell> +void voronoi_network::add_edges_to_network(v_cell &c,double x,double y,double z,double rad,int *cmap) { + int i,j,ai,aj,ak,bi,bj,bk,k,l,q,*vmp;unsigned int cper; + double vx,vy,vz,wx,wy,wz,dx,dy,dz,dis;double *pp; + for(l=0;l<c.p;l++) { + vmp=cmap+4*l;k=*(vmp++);ai=*(vmp++);aj=*(vmp++);ak=*vmp; + pp=pts[reg[k]]+4*regp[k]; + vx=pp[0]+ai*bx+aj*bxy+ak*bxz; + vy=pp[1]+aj*by+ak*byz; + vz=pp[2]+ak*bz; + for(q=0;q<c.nu[l];q++) { + i=c.ed[l][q]; + vmp=cmap+4*i; + j=*(vmp++);bi=*(vmp++);bj=*(vmp++);bk=*vmp; + + // Skip if this is a self-connecting edge + if(j==k&&bi==ai&&bj==aj&&bk==ak) continue; + cper=pack_periodicity(bi-ai,bj-aj,bk-ak); + pp=pts[reg[j]]+(4*regp[j]); + wx=pp[0]+bi*bx+bj*bxy+bk*bxz; + wy=pp[1]+bj*by+bk*byz; + wz=pp[2]+bk*bz; + dx=wx-vx;dy=wy-vy;dz=wz-vz; + dis=(x-vx)*dx+(y-vy)*dy+(z-vz)*dz; + dis/=dx*dx+dy*dy+dz*dz; + if(dis<0) dis=0;if(dis>1) dis=1; + wx=vx-x+dis*dx;wy=vy-y+dis*dy;wz=vz-z+dis*dz; + int nat=not_already_there(k,j,cper); + if(nat==nu[k]) { + if(nu[k]==numem[k]) add_particular_vertex_memory(k); + ed[k][nu[k]]=j; + raded[k][nu[k]].first(sqrt(wx*wx+wy*wy+wz*wz)-rad,dis); + pered[k][nu[k]++]=cper; + } else { + raded[k][nat].add(sqrt(wx*wx+wy*wy+wz*wz)-rad,dis); + } + } + } +} + +template<class v_cell> +void voronoi_network::add_to_network_rectangular_internal(v_cell &c,int idn,double x,double y,double z,double rad,int *cmap) { + int i,j,k,ijk,l,q,ai,aj,ak,*vmp(cmap); + double vx,vy,vz,crad,*cp(c.pts); + + for(l=0;l<c.p;l++,vmp+=4) { + vx=x+cp[3*l]*0.5;vy=y+cp[3*l+1]*0.5;vz=z+cp[3*l+2]*0.5; + crad=0.5*sqrt(cp[3*l]*cp[3*l]+cp[3*l+1]*cp[3*l+1]+cp[3*l+2]*cp[3*l+2])-rad; + if(safe_search_previous_rect(vx,vy,vz,ijk,q,vmp[1],vmp[2],vmp[3])) { + *vmp=idmem[ijk][q]; + + // Store this radius if it smaller than the current + // value + if(pts[ijk][4*q+3]>crad) pts[ijk][4*q+3]=crad; + } else { + k=step_int(vz*zsp); + if(k<0||k>=nz) { + ak=step_div(k,nz); + vz-=ak*bz;vy-=ak*byz;vx-=ak*bxz;k-=ak*nz; + } else ak=0; + j=step_int(vy*ysp); + if(j<0||j>=ny) { + aj=step_div(j,ny); + vy-=aj*by;vx-=aj*bxy;j-=aj*ny; + } else aj=0; + i=step_int(vx*xsp); + if(i<0||i>=nx) { + ai=step_div(i,nx); + vx-=ai*bx;i-=ai*nx; + } else ai=0; + vmp[1]=ai; + vmp[2]=aj; + vmp[3]=ak; + ijk=i+nx*(j+ny*k); + if(edc==edmem) add_edge_network_memory(); + if(ptsc[ijk]==ptsmem[ijk]) add_network_memory(ijk); + reg[edc]=ijk;regp[edc]=ptsc[ijk]; + pts[ijk][4*ptsc[ijk]]=vx; + pts[ijk][4*ptsc[ijk]+1]=vy; + pts[ijk][4*ptsc[ijk]+2]=vz; + pts[ijk][4*ptsc[ijk]+3]=crad; + idmem[ijk][ptsc[ijk]++]=edc; + *vmp=edc++; + } + + add_neighbor(*vmp,idn); + } + + add_edges_to_network(c,x,y,z,rad,cmap); +} + +int voronoi_network::not_already_there(int k,int j,unsigned int cper) { + for(int i=0;i<nu[k];i++) if(ed[k][i]==j&&pered[k][i]==cper) return i; + return nu[k]; +} + +bool voronoi_network::search_previous(double gx,double gy,double x,double y,double z,int &ijk,int &q,int &pi,int &pj,int &pk) { + int ai=step_int((gx-net_tol)*xsp),bi=step_int((gx+net_tol)*xsp); + int aj=step_int((gy-net_tol)*ysp),bj=step_int((gy+net_tol)*ysp); + int ak=step_int((z-net_tol)*zsp),bk=step_int((z+net_tol)*zsp); + int i,j,k,mi,mj,mk; + double px,py,pz,px2,py2,px3,*pp; + + for(k=ak;k<=bk;k++) { + pk=step_div(k,nz);px=pk*bxz;py=pk*byz;pz=pk*bz;mk=k-nz*pk; + for(j=aj;j<=bj;j++) { + pj=step_div(j,ny);px2=px+pj*bxy;py2=py+pj*by;mj=j-ny*pj; + for(i=ai;i<=bi;i++) { + pi=step_div(i,nx);px3=px2+pi*bx;mi=i-nx*pi; + ijk=mi+nx*(mj+ny*mk); + pp=pts[ijk]; + for(q=0;q<ptsc[ijk];q++,pp+=4) if(abs(*pp+px3-x)<net_tol&&abs(pp[1]+py2-y)<net_tol&&abs(pp[2]+pz-z)<net_tol) return true; + } + } + } + return false; +} + +bool voronoi_network::safe_search_previous_rect(double x,double y,double z,int &ijk,int &q,int &ci,int &cj,int &ck) { + const double tol(0.5*net_tol); + if(search_previous_rect(x+tol,y+tol,z+tol,ijk,q,ci,cj,ck)) return true; + if(search_previous_rect(x-tol,y+tol,z+tol,ijk,q,ci,cj,ck)) return true; + if(search_previous_rect(x+tol,y-tol,z+tol,ijk,q,ci,cj,ck)) return true; + if(search_previous_rect(x-tol,y-tol,z+tol,ijk,q,ci,cj,ck)) return true; + if(search_previous_rect(x+tol,y+tol,z-tol,ijk,q,ci,cj,ck)) return true; + if(search_previous_rect(x-tol,y+tol,z-tol,ijk,q,ci,cj,ck)) return true; + if(search_previous_rect(x+tol,y-tol,z-tol,ijk,q,ci,cj,ck)) return true; + return search_previous_rect(x-tol,y-tol,z-tol,ijk,q,ci,cj,ck); +} + +bool voronoi_network::search_previous_rect(double x,double y,double z,int &ijk,int &q,int &ci,int &cj,int &ck) { + int k=step_int(z*zsp); + if(k<0||k>=nz) { + ck=step_div(k,nz); + z-=ck*bz;y-=ck*byz;x-=ck*bxz;k-=ck*nz; + } else ck=0; + + int j=step_int(y*ysp); + if(j<0||j>=ny) { + cj=step_div(j,ny); + y-=cj*by;x-=cj*bxy;j-=cj*ny; + } else cj=0; + + ijk=step_int(x*xsp); + if(ijk<0||ijk>=nx) { + ci=step_div(ijk,nx); + x-=ci*bx;ijk-=ci*nx; + } else ci=0; + + ijk+=nx*(j+ny*k);double *pp(pts[ijk]); + for(q=0;q<ptsc[ijk];q++,pp+=4) + if(abs(*pp-x)<net_tol&&abs(pp[1]-y)<net_tol&&abs(pp[2]-z)<net_tol) return true; + return false; +} + +/** Custom int function, that gives consistent stepping for negative numbers. + * With normal int, we have (-1.5,-0.5,0.5,1.5) -> (-1,0,0,1). + * With this routine, we have (-1.5,-0.5,0.5,1.5) -> (-2,-1,0,1). */ +inline int voronoi_network::step_int(double a) { + return a<0?int(a)-1:int(a); +} + +/** Custom integer division function, that gives consistent stepping for + * negative numbers. */ +inline int voronoi_network::step_div(int a,int b) { + return a>=0?a/b:-1+(a+1)/b; +} + +// Explicit instantiation +template voronoi_network::voronoi_network(container_periodic&, double); +template voronoi_network::voronoi_network(container_periodic_poly&, double); +template void voronoi_network::add_to_network<voronoicell>(voronoicell&, int, double, double, double, double); +template void voronoi_network::add_to_network<voronoicell_neighbor>(voronoicell_neighbor&, int, double, double, double, double); +template void voronoi_network::add_to_network_rectangular<voronoicell>(voronoicell&, int, double, double, double, double); +template void voronoi_network::add_to_network_rectangular<voronoicell_neighbor>(voronoicell_neighbor&, int, double, double, double, double); diff --git a/contrib/voro++/zeo/v_network.hh b/contrib/voro++/zeo/v_network.hh new file mode 100644 index 0000000000000000000000000000000000000000..d099d16ada027716da5daf295b51cdac67f714e6 --- /dev/null +++ b/contrib/voro++/zeo/v_network.hh @@ -0,0 +1,113 @@ +#ifndef ZEOPP_V_NETWORK_HH +#define ZEOPP_V_NETWORK_HH + +#include <vector> + +#include "voro++.hh" +using namespace voro; + +const int init_network_edge_memory=4; +const int init_network_vertex_memory=64; +const int max_network_vertex_memory=65536; + +struct block { + double dis; + double e; + inline void first(double v,double d) {e=v>0?v:0;dis=d;} + inline void add(double v,double d) { + if(v<0) e=0; + else if(v<e) {e=v;dis=d;} + } + inline void print(FILE *fp) {fprintf(fp," %g %g",e,dis);} +}; + +class voronoi_network { + public: + const double bx; + const double bxy; + const double by; + const double bxz; + const double byz; + const double bz; + const int nx; + const int ny; + const int nz; + const int nxyz; + const double xsp,ysp,zsp; + const double net_tol; + double **pts; + int **idmem; + int *ptsc; + int *ptsmem; + int **ed; + int **ne; + block **raded; + unsigned int **pered; + int edc,edmem; + int *nu; + int *nec; + int *numem; + int *reg; + int *regp; + int *vmap; + int map_mem; + template<class c_class> + voronoi_network(c_class &c,double net_tol_=tolerance); + ~voronoi_network(); + void print_network(FILE *fp=stdout,bool reverse_remove=false); + inline void print_network(const char* filename,bool reverse_remove=false) { + FILE *fp(safe_fopen(filename,"w")); + print_network(fp); + fclose(fp); + } + void draw_network(FILE *fp=stdout); + inline void draw_network(const char* filename) { + FILE *fp(safe_fopen(filename,"w")); + draw_network(fp); + fclose(fp); + } + template<class v_cell> + inline void add_to_network(v_cell &c,int idn,double x,double y,double z,double rad,int *&cmap) { + cmap=new int[4*c.p]; + add_to_network_internal(c,idn,x,y,z,rad,cmap); + } + template<class v_cell> + inline void add_to_network_rectangular(v_cell &c,int idn,double x,double y,double z,double rad,int *&cmap) { + cmap=new int[4*c.p]; + add_to_network_rectangular_internal(c,idn,x,y,z,rad,cmap); + } + template<class v_cell> + inline void add_to_network(v_cell &c,int idn,double x,double y,double z,double rad) { + if(c.p>map_mem) add_mapping_memory(c.p); + add_to_network_internal(c,idn,x,y,z,rad,vmap); + } + template<class v_cell> + inline void add_to_network_rectangular(v_cell &c,int idn,double x,double y,double z,double rad) { + if(c.p>map_mem) add_mapping_memory(c.p); + add_to_network_rectangular_internal(c,idn,x,y,z,rad,vmap); + } + + void clear_network(); + private: + inline int step_div(int a,int b); + inline int step_int(double a); + inline void add_neighbor(int k,int idn); + void add_particular_vertex_memory(int l); + void add_edge_network_memory(); + void add_network_memory(int l); + void add_mapping_memory(int pmem); + inline unsigned int pack_periodicity(int i,int j,int k); + inline void unpack_periodicity(unsigned int pa,int &i,int &j,int &k); + template<class v_cell> + void add_edges_to_network(v_cell &c,double x,double y,double z,double rad,int *cmap); + int not_already_there(int k,int j,unsigned int cper); + bool search_previous(double gx,double gy,double x,double y,double z,int &ijk,int &q,int &ci,int &cj,int &ck); + bool safe_search_previous_rect(double x,double y,double z,int &ijk,int &q,int &ci,int &cj,int &ck); + bool search_previous_rect(double x,double y,double z,int &ijk,int &q,int &ci,int &cj,int &ck); + template<class v_cell> + void add_to_network_internal(v_cell &c,int idn,double x,double y,double z,double rad,int *cmap); + template<class v_cell> + void add_to_network_rectangular_internal(v_cell &c,int idn,double x,double y,double z,double rad,int *cmap); +}; + +#endif diff --git a/wrappers/gmshpy/gmshMesh.i b/wrappers/gmshpy/gmshMesh.i index 9fafb67a5dcf101a845d2a02ee2483d8b82bd356..f140aa275c03e38691d1e9296399e768d2048228 100644 --- a/wrappers/gmshpy/gmshMesh.i +++ b/wrappers/gmshpy/gmshMesh.i @@ -10,13 +10,16 @@ #include "meshGFaceLloyd.h" #include "meshGFaceOptimize.h" #include "meshPartitionOptions.h" - #include "Levy3D.h" #if defined(HAVE_METIS) || defined(HAVE_CHACO) #include "meshPartition.h" #endif #include "meshMetric.h" #include "Field.h" #include "CenterlineField.h" + #include "simple3D.h" + #include "Voronoi3D.h" + #include "Levy3D.h" + #include "periodical.h" #endif %} @@ -32,11 +35,14 @@ namespace std { %include "meshGFaceLloyd.h" %include "meshGFaceOptimize.h" %include "meshPartitionOptions.h" -%include "Levy3D.h" #if defined(HAVE_METIS) || defined(HAVE_CHACO) %include "meshPartition.h" #endif %include "meshMetric.h" %include "Field.h" %include "CenterlineField.h" +%include "simple3D.h" +%include "Voronoi3D.h" +%include "Levy3D.h" +%include "periodical.h" #endif