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

如何将Eigen库objective仿函数改造为支持scalar入参的p_objective用于线搜索

实现方案

核心思路

你需要的p_objective本质是对原目标函数、初始点、搜索方向的轻量封装,所有入参为alpha的方法,内部先计算x = x0 + alpha * p,再转发调用原目标函数的对应方法即可。我们可以用泛型实现,不仅支持你当前的objective结构体,也可兼容其他符合接口规范的目标函数。

完整实现代码

#ifndef P_OBJECTIVE_HPP
#define P_OBJECTIVE_HPP
#include "EigenDataTypes.hpp"

// 泛型版本,适配Eigen多维度目标函数
template <int Nx, typename ObjectiveT = objective<Nx>>
struct p_objective
{
private:
    const ObjectiveT& m_f;    // 原目标函数引用,避免拷贝大稀疏矩阵
    const Vec<Nx>& m_x0;      // 初始点引用
    const Vec<Nx>& m_p;       // 搜索方向引用

public:
    // 构造函数,传入原目标函数、初始点、搜索方向
    p_objective(const ObjectiveT& f, const Vec<Nx>& x0, const Vec<Nx>& p)
        : m_f(f), m_x0(x0), m_p(p) {}

    // 计算目标值,等价于 f(x0 + alpha*p)
    inline scalar operator()(double alpha) const
    {
        Vec<Nx> x = m_x0 + alpha * m_p;
        return m_f(x);
    }

    // 计算梯度,按需求等价于 f.Eval_grad(x0 + alpha*p)
    // 注:如果需要标准线搜索的一维phi导数,这里改为返回 m_p.dot(m_f.Eval_grad(x)) 即可
    inline Vec<Nx> Eval_grad(double alpha) const
    {
        Vec<Nx> x = m_x0 + alpha * m_p;
        return m_f.Eval_grad(x);
    }

    // 计算海森矩阵,等价于 f.Eval_hessian(x0 + alpha*p)
    inline Mat<Nx, Nx> Eval_hessian(double alpha) const
    {
        Vec<Nx> x = m_x0 + alpha * m_p;
        return m_f.Eval_hessian(x);
    }
};

// 1D无Eigen版本特化适配
template <>
struct p_objective<1, objective_1D>
{
private:
    const objective_1D& m_f;
    const double& m_x0;
    const double& m_p;

public:
    p_objective(const objective_1D& f, const double& x0, const double& p)
        : m_f(f), m_x0(x0), m_p(p) {}

    double operator()(double alpha) const
    {
        double x = m_x0 + alpha * m_p;
        return m_f(x);
    }

    double Eval_grad(double alpha) const
    {
        double x = m_x0 + alpha * m_p;
        return m_f.Eval_grad(x);
    }

    double Eval_hessian(double alpha) const
    {
        double x = m_x0 + alpha * m_p;
        return m_f.Eval_hessian(x);
    }
};
#endif

使用示例

完全符合你要求的调用形式:

// 2D Eigen版本调用示例
objective<2> f(Q, c);
Vec<2> x0{0, 1};
Vec<2> p{1, 0}; // 自定义搜索方向
p_objective<2> Phi(f, x0, p);
double alpha = 0.9;

// 调用方式和你要求完全一致
scalar obj_val = Phi(alpha);
Vec<2> grad = Phi.Eval_grad(alpha);
Mat<2,2> hess = Phi.Eval_hessian(alpha);

// 1D版本调用示例
objective_1D f1d(2.0, 1.0);
double x0_1d = 0.0;
double p_1d = 1.0;
p_objective<1, objective_1D> Phi_1d(f1d, x0_1d, p_1d);
double val_1d = Phi_1d(0.9);

可选优化点

如果担心每次调用都构造x向量的开销,可以把x作为缓存成员变量,用Eigen的noalias避免临时变量开销:

// 优化版本示例
template <int Nx, typename ObjectiveT = objective<Nx>>
struct p_objective
{
private:
    const ObjectiveT& m_f;
    const Vec<Nx>& m_x0;
    const Vec<Nx>& m_p;
    mutable Vec<Nx> m_x_cache; // mutable允许const方法修改缓存

public:
    p_objective(const ObjectiveT& f, const Vec<Nx>& x0, const Vec<Nx>& p)
        : m_f(f), m_x0(x0), m_p(p), m_x_cache(x0) {}

    inline scalar operator()(double alpha) const
    {
        m_x_cache.noalias() = m_x0 + alpha * m_p;
        return m_f(m_x_cache);
    }
    // 其余方法同理复用m_x_cache即可
};

注意:上述实现默认用引用存储外部对象,需要保证f、x0、p的生命周期长于p_objective实例,如果无法保证可以把成员变量改为值存储,牺牲少量拷贝成本保证安全。

内容的提问来源于stack exchange,提问作者Jonas Hjulstad

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 01:57:03