Skip to content

求解接口

该章节介绍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_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;
}