求解接口
该章节介绍OPTIMake的求解接口. 求解接口接收problem, option, workspace作为输入, 返回solve_status与output. 下面为求解接口solve的伪代码:
[solve_status, output] = solve(problem, option, workspace)
Warning
在第一次求解时, 需要调用初始化函数将problem, option以及workspace初始化. 在连续求解时, 也只需要在第一次求解前进行初始化. 该初始化函数会完成以下工作:
- 将problem中用户定义的数据初始化, 如插值表
- 将option设置为默认值
- 将workspace中需要清零的部分清零
problem设置
在模型中定义的stage-independent parameter与stage-dependent parameter (详见建模接口 > parameter定义) 可通过problem结构体设置.
下面为设置parameter的示例代码:
/* mass */
problem.param[VEHICLE_PARAM_MASS] = 2500.0;
/* length */
problem.param[VEHICLE_PARAM_LENGTH] = 2.2;
for (i = 0; i < VEHICLE_DIM_N; i++) {
/* xLowerBound */
problem.param_stage[i][VEHICLE_PARAM_STAGE_XLOWERBOUND] = i;
}
Note
VEHICLE_PARAM_MASS, VEHICLE_PARAM_LENGTH等enum变量会在代码生成时自动生成在prob.h的头文件中. 使用时需要包含该头文件 (比如vehicle模型需要包含vehicle_prob.h). 同时, 各优化变量index的enum值及各种维度信息也会被包含在该头文件中.
option设置
求解器参数, 可分为通用option与求解算法相关option.
通用option
print_level:打印信息的等级, int类型
- 0:不打印
- 1:打印错误信息与最终求解状态
- 2:在1的基础上, 打印迭代过程
- 3:在2的基础上, 打印更多求解信息
max_num_iter:最大迭代次数, int类型, 非负
max_stepsize:最大迭代步长, double类型, 0~1
auto scaling
obj_scaling_method:objective的scaling方法, int类型
- 0:无scaling
- 1:用户指定scaling factor, 其值通过option中的obj_scaling_factor输入
- 2:自动根据Hessian值进行scaling
obj_scaling_factor:objective的scaling factor, double类型, 非负
regularization
reg_hessian:hessian的regularization, double类型, 非负
reg_eq:等式约束拉格朗日乘子的regularization, double类型, 非负
reg_ineq:不等式约束拉格朗日乘子的regularization, double类型, 非负
line search
line_search_method: 线搜索策略
- 0: 无线搜索, 即每次迭代都全步长接收
- 1: filter策略
line_search_max_num_iter: 最大线搜索次数, int类型, 非负
infeasibility_relaxation_weight: 在线搜索打开且达到最大线搜索次数时, OPTIMake会将所有的等式硬约束与不等式硬约束 (不包含variable的hard bound约束)进行l1松弛, 该值为松弛的权重, double类型, 非负, 默认值为1e4
tolerance
tol_eq:等式约束的tolerance, double类型, 非负
tol_ineq:不等式约束的tolerance, double类型, 非负
tol_stat:stationarity condition的tolerance, double类型, 非负
tol_comp:complementarity condition的tolerance, double类型, 非负
tol_step:优化变量的变化的tolerance, double类型, 非负
其他option
bfgs_max_num_skipping: bfgs更新的最大skip次数, 当大于该次数时, Hessian会被初始化. int类型, 非负, 默认值为2
pdipm option
barrier
barrier_strategy: barrier策略
- 0: monotone策略
- 1: loqo adaptive策略
- 2: 结合monotone策略与loqo adaptive策略
barrier_init:barrier parameter的初始值, double类型, 非负
barrier_target:barrier parameter的最终值, double类型, 非负且不大于mu_start
try_warm_start_barrier:是否尝试从barrier_target开始warm start求解 (当hessian approximation设置为'bfgs'时, hessian也会被设置为上一次求解的hessian值), 如果warm start成功, 将有效降低迭代次数, 适合需要连续求解且barrier_target不至于过小的优化问题.
- 0:否 (默认)
- 1:是
如果warm start尝试失败, barrier parameter会被设置为barrier_init开始迭代, 且对偶变量, slack变量, hessian均会被初始化. 此时相对于try_warm_start_barrier=0的设置会多一次迭代.
workspace设置
优化问题的初始解通过workspace设定.
下面为设置初始解的示例代码:
for (i = 0; i < VEHICLE_DIM_N; i++) {
/* initial guess */
workspace.primal.var[i][VEHICLE_VAR_X] = 2.0; /* x */
workspace.primal.var[i][VEHICLE_VAR_Y] = 5.0; /* y */
workspace.primal.var[i][VEHICLE_VAR_PHI] = 1.57; /* phi */
}
solve_status
solve_status为求解状态.
- 1:求解成功:找到tol_eq、tol_ineq、tol_stat、tol_comp均满足的解
- 2:找到可行解:找到满足tol_eq与tol_ineq, 但tol_stat或tol_comp不满足的解
- 3:问题不可行, 即问题进行l1松弛后求解成功, 但该解对原问题不可行
- 4:达到最大迭代次数, 未找到可行解
- 5:优化变量的变化小于设定的tolerance (tol_step), 未找到可行解
- 6:迭代过程中产生inf/nan非法值, 未找到可行解
- 7:求解前未初始化
- 8: 求解问题无效
- 100:license检查失败
- 101:初始解检查失败 (包含inf/nan非法值)
- 102:参数检查失败 (包含inf/nan非法值)
output
output中包含了耗时 (代码生成中enable_timing为True时打开), 优化变量, 迭代次数, objective, residual信息.
以下为一个介绍了如何设置problem, option, initial guess的完整的demo:
#include "vehicle_solver.h"
#include "vehicle_prob.h"
#include <stdio.h>
int main(void)
{
size_t i = 0;
size_t j = 0;
int status;
Vehicle_Problem prob;
Vehicle_Option option;
Vehicle_WorkSpace ws;
Vehicle_Output output;
/* must be initialized before the very first solve */
vehicle_init(&prob, &option, ws);
/* prob */
prob.param[VEHICLE_PARAM_X0] = 0; /* x */
prob.param[VEHICLE_PARAM_Y0] = 0; /* y */
prob.param[VEHICLE_PARAM_PHI0] = 0; /* phi */
prob.param[VEHICLE_PARAM_LENGTH] = 1.0; /* L */
for (i = 0; i < VEHICLE_DIM_N; i++) {
prob.param_stage[i][VEHICLE_PARAM_STAGE_XREF] = i;
prob.param_stage[i][VEHICLE_PARAM_STAGE_YREF] = i;
}
/* option */
option.print_level = 2;
/* workspace, initial guess */
for (i = 0; i < VEHICLE_DIM_N; i++) {
ws.primal.var[i][VEHICLE_VAR_X] = i;
ws.primal.var[i][VEHICLE_VAR_Y] = i;
}
status = vehicle_solve(&prob, &option, &ws, &output);
for (i = 0; i < VEHICLE_DIM_N; i++) {
for (j = 0; j < VEHICLE_DIM_VAR; j++) {
printf("%f\t", output.primal.var[i][j]);
}
printf("\n");
}
printf("\n");
return 0;
}