代码生成与部署
当完成问题定义后, 需通过OPTIMake的代码生成函数生成问题定义与求解器的C/C++代码. 该章节主要介绍了如何配置代码生成以及调用生成的代码或库.
OPTIMake的代码生成流程如下:

其中, 代码生成分为问题生成与求解器生成两个步骤:
- 问题生成:生成问题相关的函数, 如约束的函数值及其梯度. 该过程在用户本地进行.
- 求解器生成:生成问题对应的求解器. 该过程在OPTIMake服务器进行 (该过程需要联网). 当调用生成的求解器时, 不需要联网.
在本地完成问题生成后, 客户端会将问题脱敏后发送至OPTIMake服务器进行求解器生成, 即用户的具体问题定义及数据不会被发送至OPTIMake服务器. 所有上传的数据均对用户透明 (客户端上传部分的代码开源) . 以下为具体发送至服务器的数据:
- 脱敏后的问题 (masked_multi_stage_problem):
- 维度
- 稀疏性: 为0/1的矩阵, 用于稀疏求解加速运算
- 性质 (如是否线性): 用于选择更好的求解策略
- 用户信息 (user_info), 用于license check:
- mac地址
- 计算机名
- OS
- CPU
- 代码生成option (codegen_option): 定义了需要生成的求解器类型, 硬件平台等信息
代码生成
下面首先介绍代码生成的option, 主要可被分类为生成配置相关, 求解算法相关与性能相关.
生成配置相关
codegen_path: 代码生成路径
overwrite: 是否overwrite已生成的代码
verbose: 是否打印代码生成相关的信息 (默认False)
enable_printing: 是否开启打印功能
- True: 生成代码中包含printf函数, 在求解器print_level设置为非0时, 求解器可打印求解状态 (默认)
- False: 生成代码中不包含printf函数, 即使在求解器print_level设置为非0时, 求解器亦不可以可打印求解状态
enable_timing: 是否在生成代码中包含计时功能 (默认True)
enable_serialization: 是否开启序列化功能 (可将求解设定存储为二进制文件并读取复现, 默认False). 详见Tools > 序列化工具
platform
- 'linux-x86_64-gcc' (默认)
- 'windows-x86_64-mingw'
- 'linux-arm64-gcc'
- 'linux-armv7-gcc'
lib_type
- 'static': 生成求解器的静态链接库 (默认)
- 'shared': 生成求解器的动态链接库
求解算法相关
solver
- 'pdipm': primal-dual interior-point method (默认)
- 'sqp': sequential quadratic programming method (当前暂未支持)
hessian_approximation
- 'exact' (默认)
- 'gauss-newton'
- 'bfgs'
Note
- 当objective为least square类型且残差较小, 或问题的非线性较低时, 选择'gauss-newton'. 当非上述情况, 需要计算Hessian才能收敛时, 选择'exact'或'bfgs'.
- 当Hessian很容易得到 (比如问题通过符号定义, OPTIMake会自动生成exact Hessian), 选择'exact'一般比'bfgs'更高效且鲁棒
- 如下的情况OPTIMake不能自动生成exact Hessian:
- 外部函数, 此时Hessian需要用户自己提供. (见建模接口 > 外部C/C++函数支持了解OPTIMake中的外部函数)
- differential_equation且discretization_method为'irk2'或'irk4'
bfgs_init_hessian: bfgs的Hessian初始值, 可以为常数或关于参数p的维度为[nv, nv]的对称矩阵 (通过list传入, list的元素为nv维的list);其默认值单位矩阵
Note
求解过程中计算的Hessian值被存储在workspace中, 可以求解优化问题后访问该值来优化bfgs_init_hessian的选取.
性能相关
optimization_level: 编译优化等级
- 0,1,2,3 (默认3)
common_subexpression_elimination: 提取公共表达式, 减少运算量
- 'on'
- 'off'
- 'auto' (默认)
会导致计算顺序变化, 当问题对数值敏感时, 可以尝试不同的选项求解.
simplify_expression: 简化表达式, 可能会导致本地问题时间过长
- True
- False (默认)
default_tolerance_level: 默认的求解精度 (设置后求解精度亦可手动调整)
- 'low'
- 'medium' (默认)
- 'high'
下面为代码生成的例子:
option = codegen_option()
option.solver = 'pdipm' # primal-dual interior-point method
option.enable_printing = True
option.optimization_level = 3
# 'windows-x86_64-mingw', 'linux-x86_64-gcc', 'linux-arm64-gcc', 'linux-armv7-gcc'
option.platform = 'linux-x86_64-gcc'
codegen = code_generator()
codegen.codegen(prob, option)
假设问题的名称为 'vehicle', 生成platform为 'linux-x86_64-gcc', OPTIMake会生成以下文件:
- vehicle_prob.h:问题的头文件, 定义了维度, 优化变量与参数index的enum值等
- vehicle_prob.c:问题的源码文件, 定义了各函数, 如objective及其梯度的实现
- vehicle_prob_ext.c.template:只当问题定义中出现外部函数时会生成该文件, 包含了外部函数的模板. 用户完成外部函数的实现后需要去掉.template后缀编译
- vehicle_solver.h:求解代码的接口头文件
- libvehicle_solver_shared.so:求解代码的动态链接库 (platform为windows时后缀为.dll)
- libvehicle_solver_static.a:求解代码的静态链接库 (platform为windows时后缀为.dll.a)
Note
每一次代码生成都会有唯一的session uuid. 当前代码生成失败时, 请提供该id以及返回状态至OPTIMake以获取技术支持.
代码部署
包含生成的源码文件以及链接动态库或静态库即可调用生成代码. 调用生成代码时需注意:
- 调用平台及编译器需与代码生成中的option.platform保持一致
- 当调用的平台为Linux/Mac时, 需要链接math库 (-lm) , 以使用sin, cos, tan, sqrt等函数.
- 当调用平台为Windows时, 需要iphlpapi链接 (-liphlpapi) , 以获取mac地址.
以下为使用静态链接库编译一个demo (vehicle_demo.cpp)的CMake示例:
# ${VEHICLE_CODEGEN_DIR} is the dir of the generated code
set(VEHICLE_CODEGEN_DIR ${CMAKE_CURRENT_SOURCE_DIR}/vehicle)
# ${LIBS} is the required libs (math or iphlpapi)
set(LIBS m)
add_executable(vehicle_demo vehicle_demo.cpp ${VEHICLE_CODEGEN_DIR}/vehicle_prob.c)
target_include_directories(vehicle_demo PRIVATE ${VEHICLE_CODEGEN_DIR})
target_link_libraries(vehicle_demo ${VEHICLE_CODEGEN_DIR}/libvehicle_solver_shared.a ${LIBS})