#ifndef INCLUDE_PROGRAM #define INCLUDE_PROGRAM #include "IpTNLP.hpp" #include #include "GPM.h" using namespace arma; using namespace Ipopt; /* MyNLP实现了一个C ++示例,该示例显示了如何通过TNLP接口与IPOPT接口。 本示例旨在与教程文档一起使用(请参阅示例/ CppTutorial /)。 此类实现以下NLP。 min_x f(x) = -(x2-2)^2 s.t. 0 = x1^2 + x2 - 1 -1 <= x1 <= 1 */ class Program : public TNLP { public: /* 默认构造函数 */ Program(); /* 默认析构函数 */ virtual ~Program(); /* 从TNLP重载 */ /* 返回有关nlp的一些信息的方法 n :(输出),问题中变量的数量(x的维)。 m :(输出),问题中约束的数量(g(x)的维)。 nnz_jac_g : (输出),雅可比行列中非零条目的数量。 nnz_h_lag : (输出),Hessian中非零条目的数量。 IndexStyleEnum:(输出),用于稀疏矩阵格式的行/列条目的编号样式(C样式:基于0; FORTRAN样式:基于1;另请参见附录A)。 Ipopt在分配数组时会使用此信息,稍后它将要求您填充值。 请谨慎使用此方法,因为不正确的值将导致可能很难找到的内存错误。 */ virtual bool get_nlp_info(Index& n, Index& m, Index& nnz_jac_g, Index& nnz_h_lag, IndexStyleEnum& index_style); /* 返回问题界限的方法 n : (输入),问题中的变量数(x的维数)。 x_l :(输出),x的下限xL。 x_u :(输出),x的上限xU。 m : (输入),问题中的约束个数(g(x)的维)。 g_l :(输出),g(x)的下限gL。 g_u :(输出),g(x)的上限gU。 您在get nlp info中指定的n和m值将传递给您进行调试检查。 将下界设置为小于或等于选项nlp_lower_bound_inf将导致Ipopt假定没有下界。 同样,指定大于或等于选项nlp_upper_bound_inf将使Ipopt假定没有上限。 默认情况下,这些选项(nlp_lower_bound_inf 和 nlp_upper_bound_inf)分别设置为-10^19和10*19,但可以通过更改选项进行修改。 */ virtual bool get_bounds_info(Index n, Number* x_l, Number* x_u, Index m, Number* g_l, Number* g_u); /* 返回算法起点的方法 n : (输入),问题中的变量数(x的维数)。 init_x : (输入),如果为true,则此方法必须为x提供初始值。 x : (输出),原始变量x的初始值。 init_z : (输入),如果为true,则此方法必须为边界乘数zL和zU提供一个初始值。 z_L : (输出),边界乘数zL的初始值。 z_U : (输出),边界乘数zU的初始值。 m : (输入),问题中的约束个数(g(x)的维)。 init_lambda:(输入),如果为true,则此方法必须为约束乘数λ提供初始值。 lambda : (输出),约束乘数的初始值λ 为方便起见,传递了变量n和m。 这些变量将具有您在get nlp info中指定的相同值。 根据已设置的选项,Ipopt可能会或可能不需要原始变量x,边界乘数zL和zU以及约束乘数λ的边界。 布尔标志init_x,init_z和init_lambda告诉您是否应分别为x,zL,zU或λ提供初始值。 默认选项只需要初始变量x的初始值。 请注意,“无穷大”边界(x(Li)=-∞或x(Ui)=∞)的边界乘数分量的初始值将被忽略 */ virtual bool get_starting_point(Index n, bool init_x, Number* x, bool init_z, Number* z_L, Number* z_U, Index m, bool init_lambda, Number* lambda); /* 返回目标值的方法 n : (输入),问题中的变量数(x的维数)。 x : (输入),原始变量x的值,将在此求f(x)。 new_x : (输入),如果先前使用x中相同的值调用了任何评估方法,则为false,否则为true。 obj_value: (输出), 目标函数的值(f(x))。 如果最后一次对任何评估方法(eval *)的调用使用相同的x值,则布尔变量new_x将为false。 当用户具有可以一次计算多个输出的高效实现时,这将很有帮助。 Ipopt在内部缓存TNLP的结果,通常可以忽略此标志。 为方便起见,传入了变量n。 此变量将具有您在get_nlp_info中指定的相同值。 */ virtual bool eval_f(Index n, const Number* x, bool new_x, Number& obj_value); /* 返回指标梯度的方法 n : (输入),问题中的变量数(x的维数)。 x : (输入),原始变量x的值,应在其中求出梯度。 new_x :(输入),如果先前使用x中相同的值调用了任何评估方法,则为false,否则为true。 grad_f: (输出),目标函数梯度的值。 梯度数组与x变量的顺序相同(即,性能指标相对于x[2]的梯度应放在grad_f[2]中)。 如果最后一次对任何评估方法(eval *)的调用使用相同的x值,则布尔变量new x将为false。 当用户具有可以一次计算多个输出的高效实现时,这将很有帮助。 Ipopt在内部缓存TNLP的结果,通常可以忽略此标志。 为方便起见,传入了变量n。 此变量将具有您在get_nlp_info中指定的相同值。 */ virtual bool eval_grad_f(Index n, const Number* x, bool new_x, Number* grad_f); /* 返回约束残差的方法 n : (输入),问题中的变量数(x的维数)。 x : (输入),原始变量x的值,将以此计算约束函数g(x)。 new_x :(输入),如果先前使用x中相同的值调用了任何评估方法,则为false,否则为true。 m : (输入),问题中的约束个数(g(x)的维)。 g : (输出),约束函数值的数组,g(x) g中返回的值应仅为g(x)值,请勿加或减边界值gL或gU。 如果最后一次对任何评估方法(eval *)的调用使用相同的x值,则布尔变量new x将为false。 当用户具有可以一次计算多个输出的高效实现时,这将很有帮助。 Ipopt在内部缓存TNLP的结果,通常,此标志可以忽略 为方便起见,传递了变量n和m。 这些变量将具有您在get nlp info中指定的相同值。 */ virtual bool eval_g(Index n, const Number* x, bool new_x, Index m, Number* g); /* 该方法返回如下值: 1) 雅可比矩阵的结构 ( 如果 "values" 为 NULL) 2) 雅可比的值 ( 如果 "values" 不为 NULL) n : (输入),问题中的变量数(x的维数)。 x: (输入),原始变量x的值,在该变量上求约束Jacobian。 new_x : (输入),如果先前使用x中相同的值调用了任何评估方法,则为false,否则为true。 m : (输入),问题中的约束个数(g(x)的维)。 n_ele_jac :(输入),雅可比行列中非零元素的数量(iRow,jCol和值的维)。 iRow : (输出),约束的雅可比行中条目的行索引。 jCol : (输出),约束的雅可比行中条目的列索引。 values : (输出),约束的雅可比行列中的条目的值。 雅可比行列式是导数矩阵,其中约束g(i)相对于变量x(j)的导数位于第i行和第j列。 有关此方法中使用的稀疏矩阵格式的讨论,请参见附录A。 如果iRow和jCol参数不为NULL,则Ipopt希望您填写Jacobian的稀疏结构(仅行和列索引)。此时,x参数和values参数将为NULL。 如果x参数和values参数不为NULL,则Ipopt希望您填写从数组x计算得出的Jacobian值(使用与指定稀疏结构时相同的顺序)。 此时,iRow和jCol参数将为NULL;如果最后一次对任何评估方法(eval *)的调用使用相同的x值,则布尔变量new x将为false。 当用户具有可以一次计算多个输出的高效实现时,这将很有帮助。 Ipopt在内部缓存TNLP的结果,通常可以忽略此标志。 为方便起见,传递了变量n,m和nele jac。这些参数将具有您在获取nlp信息中指定的值。 */ virtual bool eval_jac_g(Index n, const Number* x, bool new_x, Index m, Index nele_jac, Index* iRow, Index *jCol, Number* values); /* 该方法返回如下值: 1) 拉格朗日海森矩阵的结果 (如果 "values" 为 NULL) 2) 拉格朗日海森矩阵的值 (如果 "values" 不为 NULL) n : (输入),问题中的变量数(x的维数)。 x : (输入),原始变量x的值,将在该变量上评估Hessian。 new x : (输入),如果先前使用x中相同的值调用了任何评估方法,则为false,否则为true。 obj factor: (输入),在黑森州,sigmaf中,位于客观术语前面的因子。 m : (输入),问题中的约束个数(g(x)的维)。 lambda : (输入),用于在其上评估Hessian的约束乘数λ的值。 new lambda: (输入),如果先前使用lambda中的相同值调用了任何评估方法,则为false,否则为true。 nele hess :(输入),黑森矩阵非零元素的数量(iRow,jCol和值的维) iRow : (输出),黑森矩阵条目的行索引。 jCol : (输出),黑森矩阵条目的列索引。 values : (输出),黑森矩阵中条目的值。 Ipopt使用的Hessian矩阵在等式中 9.有关此方法中使用的稀疏对称矩阵格式的讨论,请参见附录A。 如果iRow和jCol参数不为NULL,则Ipopt希望您填写Hessian的稀疏结构(仅下部三角形或上部三角形的行和列索引)。 在这种情况下,x,lambda和values数组将为NULL。 如果x,lambda和values数组不为NULL,则Ipopt希望您填写使用x和lambda计算的Hessian值(使用与指定稀疏结构时相同的顺序)。 在这种情况下,iRow和jCol参数将为NULL。 如果对任何评估方法(eval *)的最后一次调用使用相同的值,则布尔变量new x和new lambda都将为false。 当用户有足够的执行能力可以一次计算多个输出时,这将很有帮助。 Ipopt在内部缓存TNLP的结果,通常可以忽略此标志。 为方便起见,传递了变量n,m和nele hess。这些参数将具有您在get nlp info中指定的相同值。 */ virtual bool eval_h(Index n, const Number* x, bool new_x, Number obj_factor, Index m, const Number* lambda, bool new_lambda, Index nele_hess, Index* iRow, Index* jCol, Number* values); /* 解决方法 算法完成后将调用此方法,以便TNLP可以存储/写入解决方案 status :(输入),给出IpAlgTypes.hpp中指定的算法状态, –SUCCESS: 算法在局部最优点成功终止,满足收敛容限(可以通过选项指定)。 –MAXITER EXCEEDED: 超过最大迭代次数(可以通过选项指定)。 –STOP AT TINY STEP: 算法进展甚微。 –STOP AT ACCEPTABLE POINT:算法在收敛点停止,而不是收敛到“期望的”公差,而是达到“可接受的”公差(请参阅accept -...选项)。 –LOCAL INFEASIBILITY: 算法收敛到局部不可行点。问题可能不可行。 –USER REQUESTED STOP: 用户回调函数中间回调(请参阅第3.3.4节)返回false,即用户代码请求过早终止优化。 –DIVERGING ITERATES: 迭代似乎是发散的。 –RESTORATION FAILURE: 恢复阶段失败,算法不知道如何继续。 –ERROR IN STEP COMPUTATION:Ipopt尝试计算搜索方向时发生不可恢复的错误。 –INVALID NUMBER DETECTED: 算法从NLP接收到无效数字(例如NaN或Inf);另请参阅naninf的选项检查派生工具。 –INTERNAL ERROR: 发生未知的内部错误。 请通过邮件列表联系Ipopt作者。 n : (输入),问题中的变量数(x的维数)。 x : (输入),原始变量x ∗的最终值。 z L : (输入),下界乘数的最终值zL。 z U : (输入),上限乘数zU的最终值。 m : (输入),问题中的约束个数(g(x)的维)。 g : (输入),约束函数值的最终值g(x ∗)。 lambda : (输入),约束乘数的最终值λ。 obj_value: (输入),目标的最终值f(x)。 为专业用户提供了ip_data和ip_cq。 */ virtual void finalize_solution(SolverReturn status, Index n, const Number* x, const Number* z_L, const Number* z_U, Index m, const Number* g, const Number* lambda, Number obj_value, const IpoptData* ip_data, IpoptCalculatedQuantities* ip_cq); public: static vec x; // 当前点的值 static vec z_L; // 变量乘子下限 static vec z_U; // 变量乘子上限 static vec lambda; // 约束乘子 private: /* 阻止默认编译器方法的方法。 编译器自动生成以下三种方法。 由于默认编译器实现通常不是您想要的(对于所有类,而是最简单的类),因此我们通常将这些方法的声明放在private节中,而不用实现它们。 这可以防止编译器在我们不知道的情况下实现错误的“默认”行为。 (请参阅Scott Meyers的书“有效的C ++”) */ Program(const Program&); Program& operator=(const Program&); }; #endif