You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何复用已有casadi::Function成本函数实现CasADI优化?

复用CasADI成本/梯度函数实现CasADI优化的两种方案

方案一:用casadi::Callback封装现有函数

你可以自定义一个Callback类,把已有的final_result_fun包装进去,适配nlpsol对目标函数(含梯度)的输入输出要求:

  1. 定义Callback子类
class CostGradientCallback : public casadi::Callback {
public:
  // 构造函数传入已有的成本梯度计算函数
  CostGradientCallback(casadi::Function fun) : fun_(std::move(fun)) {}

  // 重写eval方法,处理输入输出转换
  void eval(const std::vector<casadi::DM>& arg, std::vector<casadi::DM>& res) override {
    // 构造final_result_fun的完整输入:优化变量u + 提前准备好的固定参数
    std::vector<casadi::DM> fun_input = {
      arg[0],          // 优化变量u
      init_x_val,      // 预存的init_x数值
      obj_list_1_val,  // 预存的obj_list_1数值
      obj_list_2_val,  // 预存的obj_list_2数值
      dt_val,          // 预存的dt数值
      cost_val         // 预存的cost数值
    };

    // 调用现有函数计算成本和梯度
    auto fun_output = fun_(fun_input);

    // 输出结果:成本+梯度
    res.resize(2);
    res[0] = fun_output[0];
    res[1] = fun_output[1];
  }

  // 声明输入输出数量
  casadi::casadi_int n_in() override { return 1; }  // 仅输入优化变量u
  casadi::casadi_int n_out() override { return 2; } // 输出成本和梯度

private:
  casadi::Function fun_;
  // 预存固定参数的DM值(需从业务逻辑中获取实际值)
  casadi::DM init_x_val;
  casadi::DM obj_list_1_val;
  casadi::DM obj_list_2_val;
  casadi::DM dt_val;
  casadi::DM cost_val;
};
  1. 实例化Callback并构建求解器
// 准备固定参数的实际数值
casadi::DM init_x_val = ...;
casadi::DM obj_list_1_val = ...;
casadi::DM obj_list_2_val = ...;
casadi::DM dt_val = ...;
casadi::DM cost_val = ...;

// 创建Callback实例并绑定参数
CostGradientCallback cost_grad_cb(final_result_fun);
cost_grad_cb.init_x_val = init_x_val;
cost_grad_cb.obj_list_1_val = obj_list_1_val;
cost_grad_cb.obj_list_2_val = obj_list_2_val;
cost_grad_cb.dt_val = dt_val;
cost_grad_cb.cost_val = cost_val;

// 定义优化变量符号
casadi::MX u = casadi::MX::sym("u", u_sym.size1(), u_sym.size2());

// 用Callback构建目标函数(含梯度)
casadi::MX f = cost_grad_cb(u)[0];
casadi::MX grad_f = cost_grad_cb(u)[1];

// 构建NLP问题(无约束示例,有约束可添加"g"和"h"字段)
casadi::MXDict nlp = {{"x", u}, {"f", f}, {"grad_f", grad_f}};

// 创建nlpsol求解器(以IPOPT为例,可替换为sqpmethod等)
casadi::Function solver = casadi::nlpsol("solver", "ipopt", nlp, {
  {"ipopt.print_level", 0},
  {"print_time", false}
});

// 设置初始猜测值
casadi::DM u0 = ...;

// 求解优化问题
casadi::DMDict sol = solver({{"x0", u0}});

// 获取最优解
casadi::DM u_opt = sol["x"];
casadi::DM f_opt = sol["f"];

方案二:直接用nlpsol整合符号化成本与梯度

如果final_result_fun基于符号变量构建,可直接将符号化的成本和梯度整合到NLP定义中,无需Callback:

  1. 提取符号化的成本与梯度
// 定义优化变量和固定参数的符号
casadi::MX u = u_sym;
casadi::MX init_x = init_x_sym;
casadi::MX obj_list_1 = obj_list_1_sym;
casadi::MX obj_list_2 = obj_list_2_sym;
casadi::MX dt = dt_sym;
casadi::MX cost = cost_sym;

// 调用函数获取符号化的成本和梯度
casadi::MXArray output = final_result_fun({u, init_x, obj_list_1, obj_list_2, dt, cost});
casadi::MX f = output[0];
casadi::MX grad_f = output[1];

// 将固定参数替换为实际数值(可选,也可作为NLP参数传入)
// init_x = casadi::DM(...);
  1. 构建NLP并求解
// 构建NLP字典
casadi::MXDict nlp = {
  {"x", u},
  {"f", f},
  {"grad_f", grad_f} // 手动提供梯度,避免自动微分
};

// 创建求解器
casadi::Function solver = casadi::nlpsol("solver", "ipopt", nlp, {
  {"ipopt.max_iter", 100},
  {"print_time", true}
});

// 求解
casadi::DMDict sol = solver({{"x0", u0}});
casadi::DM u_opt = sol["x"];

关键注意事项

  • 固定参数需提前转为casadi::DM类型,可直接替换符号变量,或通过NLP的"p"字段作为参数传入求解器。
  • 选择求解器时,根据问题类型(凸/非凸)选合适后端(如IPOPT适合非凸,OSQP适合凸二次规划)。
  • 手动提供梯度可保证和NLopt逻辑一致,确保性能对比的公平性。

内容的提问来源于stack exchange,提问作者Rémi.T

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 07:53:34