program.hpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. #ifndef INCLUDE_PROGRAM
  2. #define INCLUDE_PROGRAM
  3. #include "IpTNLP.hpp"
  4. #include <armadillo>
  5. #include "GPM.h"
  6. using namespace arma;
  7. using namespace Ipopt;
  8. /*
  9. MyNLP实现了一个C ++示例,该示例显示了如何通过TNLP接口与IPOPT接口。
  10. 本示例旨在与教程文档一起使用(请参阅示例/ CppTutorial /)。
  11. 此类实现以下NLP。
  12. min_x f(x) = -(x2-2)^2
  13. s.t.
  14. 0 = x1^2 + x2 - 1
  15. -1 <= x1 <= 1
  16. */
  17. class Program : public TNLP
  18. {
  19. public:
  20. /* 默认构造函数 */
  21. Program();
  22. /* 默认析构函数 */
  23. virtual ~Program();
  24. /* 从TNLP重载 */
  25. /*
  26. 返回有关nlp的一些信息的方法
  27. n :(输出),问题中变量的数量(x的维)。
  28. m :(输出),问题中约束的数量(g(x)的维)。
  29. nnz_jac_g : (输出),雅可比行列中非零条目的数量。
  30. nnz_h_lag : (输出),Hessian中非零条目的数量。
  31. IndexStyleEnum:(输出),用于稀疏矩阵格式的行/列条目的编号样式(C样式:基于0; FORTRAN样式:基于1;另请参见附录A)。
  32. Ipopt在分配数组时会使用此信息,稍后它将要求您填充值。 请谨慎使用此方法,因为不正确的值将导致可能很难找到的内存错误。
  33. */
  34. virtual bool get_nlp_info(Index& n, Index& m, Index& nnz_jac_g,
  35. Index& nnz_h_lag, IndexStyleEnum& index_style);
  36. /*
  37. 返回问题界限的方法
  38. n : (输入),问题中的变量数(x的维数)。
  39. x_l :(输出),x的下限xL。
  40. x_u :(输出),x的上限xU。
  41. m : (输入),问题中的约束个数(g(x)的维)。
  42. g_l :(输出),g(x)的下限gL。
  43. g_u :(输出),g(x)的上限gU。
  44. 您在get nlp info中指定的n和m值将传递给您进行调试检查。
  45. 将下界设置为小于或等于选项nlp_lower_bound_inf将导致Ipopt假定没有下界。
  46. 同样,指定大于或等于选项nlp_upper_bound_inf将使Ipopt假定没有上限。
  47. 默认情况下,这些选项(nlp_lower_bound_inf 和 nlp_upper_bound_inf)分别设置为-10^19和10*19,但可以通过更改选项进行修改。
  48. */
  49. virtual bool get_bounds_info(Index n, Number* x_l, Number* x_u,
  50. Index m, Number* g_l, Number* g_u);
  51. /*
  52. 返回算法起点的方法
  53. n : (输入),问题中的变量数(x的维数)。
  54. init_x : (输入),如果为true,则此方法必须为x提供初始值。
  55. x : (输出),原始变量x的初始值。
  56. init_z : (输入),如果为true,则此方法必须为边界乘数zL和zU提供一个初始值。
  57. z_L : (输出),边界乘数zL的初始值。
  58. z_U : (输出),边界乘数zU的初始值。
  59. m : (输入),问题中的约束个数(g(x)的维)。
  60. init_lambda:(输入),如果为true,则此方法必须为约束乘数λ提供初始值。
  61. lambda : (输出),约束乘数的初始值λ
  62. 为方便起见,传递了变量n和m。
  63. 这些变量将具有您在get nlp info中指定的相同值。
  64. 根据已设置的选项,Ipopt可能会或可能不需要原始变量x,边界乘数zL和zU以及约束乘数λ的边界。
  65. 布尔标志init_x,init_z和init_lambda告诉您是否应分别为x,zL,zU或λ提供初始值。
  66. 默认选项只需要初始变量x的初始值。
  67. 请注意,“无穷大”边界(x(Li)=-∞或x(Ui)=∞)的边界乘数分量的初始值将被忽略
  68. */
  69. virtual bool get_starting_point(Index n, bool init_x, Number* x,
  70. bool init_z, Number* z_L, Number* z_U,
  71. Index m, bool init_lambda,
  72. Number* lambda);
  73. /*
  74. 返回目标值的方法
  75. n : (输入),问题中的变量数(x的维数)。
  76. x : (输入),原始变量x的值,将在此求f(x)。
  77. new_x : (输入),如果先前使用x中相同的值调用了任何评估方法,则为false,否则为true。
  78. obj_value: (输出), 目标函数的值(f(x))。
  79. 如果最后一次对任何评估方法(eval *)的调用使用相同的x值,则布尔变量new_x将为false。
  80. 当用户具有可以一次计算多个输出的高效实现时,这将很有帮助。
  81. Ipopt在内部缓存TNLP的结果,通常可以忽略此标志。
  82. 为方便起见,传入了变量n。 此变量将具有您在get_nlp_info中指定的相同值。
  83. */
  84. virtual bool eval_f(Index n, const Number* x, bool new_x, Number& obj_value);
  85. /*
  86. 返回指标梯度的方法
  87. n : (输入),问题中的变量数(x的维数)。
  88. x : (输入),原始变量x的值,应在其中求出梯度。
  89. new_x :(输入),如果先前使用x中相同的值调用了任何评估方法,则为false,否则为true。
  90. grad_f: (输出),目标函数梯度的值。
  91. 梯度数组与x变量的顺序相同(即,性能指标相对于x[2]的梯度应放在grad_f[2]中)。
  92. 如果最后一次对任何评估方法(eval *)的调用使用相同的x值,则布尔变量new x将为false。
  93. 当用户具有可以一次计算多个输出的高效实现时,这将很有帮助。
  94. Ipopt在内部缓存TNLP的结果,通常可以忽略此标志。
  95. 为方便起见,传入了变量n。 此变量将具有您在get_nlp_info中指定的相同值。
  96. */
  97. virtual bool eval_grad_f(Index n, const Number* x, bool new_x, Number* grad_f);
  98. /*
  99. 返回约束残差的方法
  100. n : (输入),问题中的变量数(x的维数)。
  101. x : (输入),原始变量x的值,将以此计算约束函数g(x)。
  102. new_x :(输入),如果先前使用x中相同的值调用了任何评估方法,则为false,否则为true。
  103. m : (输入),问题中的约束个数(g(x)的维)。
  104. g : (输出),约束函数值的数组,g(x)
  105. g中返回的值应仅为g(x)值,请勿加或减边界值gL或gU。
  106. 如果最后一次对任何评估方法(eval *)的调用使用相同的x值,则布尔变量new x将为false。
  107. 当用户具有可以一次计算多个输出的高效实现时,这将很有帮助。
  108. Ipopt在内部缓存TNLP的结果,通常,此标志可以忽略
  109. 为方便起见,传递了变量n和m。 这些变量将具有您在get nlp info中指定的相同值。
  110. */
  111. virtual bool eval_g(Index n, const Number* x, bool new_x, Index m, Number* g);
  112. /* 该方法返回如下值:
  113. 1) 雅可比矩阵的结构 ( 如果 "values" 为 NULL)
  114. 2) 雅可比的值 ( 如果 "values" 不为 NULL)
  115. n : (输入),问题中的变量数(x的维数)。
  116. x: (输入),原始变量x的值,在该变量上求约束Jacobian。
  117. new_x : (输入),如果先前使用x中相同的值调用了任何评估方法,则为false,否则为true。
  118. m : (输入),问题中的约束个数(g(x)的维)。
  119. n_ele_jac :(输入),雅可比行列中非零元素的数量(iRow,jCol和值的维)。
  120. iRow : (输出),约束的雅可比行中条目的行索引。
  121. jCol : (输出),约束的雅可比行中条目的列索引。
  122. values : (输出),约束的雅可比行列中的条目的值。
  123. 雅可比行列式是导数矩阵,其中约束g(i)相对于变量x(j)的导数位于第i行和第j列。
  124. 有关此方法中使用的稀疏矩阵格式的讨论,请参见附录A。
  125. 如果iRow和jCol参数不为NULL,则Ipopt希望您填写Jacobian的稀疏结构(仅行和列索引)。此时,x参数和values参数将为NULL。
  126. 如果x参数和values参数不为NULL,则Ipopt希望您填写从数组x计算得出的Jacobian值(使用与指定稀疏结构时相同的顺序)。
  127. 此时,iRow和jCol参数将为NULL;如果最后一次对任何评估方法(eval *)的调用使用相同的x值,则布尔变量new x将为false。
  128. 当用户具有可以一次计算多个输出的高效实现时,这将很有帮助。
  129. Ipopt在内部缓存TNLP的结果,通常可以忽略此标志。
  130. 为方便起见,传递了变量n,m和nele jac。这些参数将具有您在获取nlp信息中指定的值。
  131. */
  132. virtual bool eval_jac_g(Index n, const Number* x, bool new_x,
  133. Index m, Index nele_jac, Index* iRow, Index *jCol,
  134. Number* values);
  135. /* 该方法返回如下值:
  136. 1) 拉格朗日海森矩阵的结果 (如果 "values" 为 NULL)
  137. 2) 拉格朗日海森矩阵的值 (如果 "values" 不为 NULL)
  138. n : (输入),问题中的变量数(x的维数)。
  139. x : (输入),原始变量x的值,将在该变量上评估Hessian。
  140. new x : (输入),如果先前使用x中相同的值调用了任何评估方法,则为false,否则为true。
  141. obj factor: (输入),在黑森州,sigmaf中,位于客观术语前面的因子。
  142. m : (输入),问题中的约束个数(g(x)的维)。
  143. lambda : (输入),用于在其上评估Hessian的约束乘数λ的值。
  144. new lambda: (输入),如果先前使用lambda中的相同值调用了任何评估方法,则为false,否则为true。
  145. nele hess :(输入),黑森矩阵非零元素的数量(iRow,jCol和值的维)
  146. iRow : (输出),黑森矩阵条目的行索引。
  147. jCol : (输出),黑森矩阵条目的列索引。
  148. values : (输出),黑森矩阵中条目的值。
  149. Ipopt使用的Hessian矩阵在等式中 9.有关此方法中使用的稀疏对称矩阵格式的讨论,请参见附录A。
  150. 如果iRow和jCol参数不为NULL,则Ipopt希望您填写Hessian的稀疏结构(仅下部三角形或上部三角形的行和列索引)。
  151. 在这种情况下,x,lambda和values数组将为NULL。
  152. 如果x,lambda和values数组不为NULL,则Ipopt希望您填写使用x和lambda计算的Hessian值(使用与指定稀疏结构时相同的顺序)。
  153. 在这种情况下,iRow和jCol参数将为NULL。
  154. 如果对任何评估方法(eval *)的最后一次调用使用相同的值,则布尔变量new x和new lambda都将为false。
  155. 当用户有足够的执行能力可以一次计算多个输出时,这将很有帮助。
  156. Ipopt在内部缓存TNLP的结果,通常可以忽略此标志。
  157. 为方便起见,传递了变量n,m和nele hess。这些参数将具有您在get nlp info中指定的相同值。
  158. */
  159. virtual bool eval_h(Index n, const Number* x, bool new_x,
  160. Number obj_factor, Index m, const Number* lambda,
  161. bool new_lambda, Index nele_hess, Index* iRow,
  162. Index* jCol, Number* values);
  163. /*
  164. 解决方法
  165. 算法完成后将调用此方法,以便TNLP可以存储/写入解决方案
  166. status :(输入),给出IpAlgTypes.hpp中指定的算法状态,
  167. –SUCCESS: 算法在局部最优点成功终止,满足收敛容限(可以通过选项指定)。
  168. –MAXITER EXCEEDED: 超过最大迭代次数(可以通过选项指定)。
  169. –STOP AT TINY STEP: 算法进展甚微。
  170. –STOP AT ACCEPTABLE POINT:算法在收敛点停止,而不是收敛到“期望的”公差,而是达到“可接受的”公差(请参阅accept -...选项)。
  171. –LOCAL INFEASIBILITY: 算法收敛到局部不可行点。问题可能不可行。
  172. –USER REQUESTED STOP: 用户回调函数中间回调(请参阅第3.3.4节)返回false,即用户代码请求过早终止优化。
  173. –DIVERGING ITERATES: 迭代似乎是发散的。
  174. –RESTORATION FAILURE: 恢复阶段失败,算法不知道如何继续。
  175. –ERROR IN STEP COMPUTATION:Ipopt尝试计算搜索方向时发生不可恢复的错误。
  176. –INVALID NUMBER DETECTED: 算法从NLP接收到无效数字(例如NaN或Inf);另请参阅naninf的选项检查派生工具。
  177. –INTERNAL ERROR: 发生未知的内部错误。 请通过邮件列表联系Ipopt作者。
  178. n : (输入),问题中的变量数(x的维数)。
  179. x : (输入),原始变量x ∗的最终值。
  180. z L : (输入),下界乘数的最终值zL。
  181. z U : (输入),上限乘数zU的最终值。
  182. m : (输入),问题中的约束个数(g(x)的维)。
  183. g : (输入),约束函数值的最终值g(x ∗)。
  184. lambda : (输入),约束乘数的最终值λ。
  185. obj_value: (输入),目标的最终值f(x)。
  186. 为专业用户提供了ip_data和ip_cq。
  187. */
  188. virtual void finalize_solution(SolverReturn status,
  189. Index n, const Number* x, const Number* z_L, const Number* z_U,
  190. Index m, const Number* g, const Number* lambda,
  191. Number obj_value,
  192. const IpoptData* ip_data,
  193. IpoptCalculatedQuantities* ip_cq);
  194. public:
  195. static vec x; // 当前点的值
  196. static vec z_L; // 变量乘子下限
  197. static vec z_U; // 变量乘子上限
  198. static vec lambda; // 约束乘子
  199. private:
  200. /* 阻止默认编译器方法的方法。
  201. 编译器自动生成以下三种方法。
  202. 由于默认编译器实现通常不是您想要的(对于所有类,而是最简单的类),因此我们通常将这些方法的声明放在private节中,而不用实现它们。
  203. 这可以防止编译器在我们不知道的情况下实现错误的“默认”行为。 (请参阅Scott Meyers的书“有效的C ++”) */
  204. Program(const Program&);
  205. Program& operator=(const Program&);
  206. };
  207. #endif