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

带整数约束的曲线线性组合拟合及CPLEX求解报错咨询

带整数约束的最小二乘曲线拟合解决方案

问题本质梳理

你遇到的是**混合整数二次规划(MIQP)**问题:最小二乘的目标函数是二次的,而你需要的「限制拟合曲线数量」「要求所选曲线连续相邻」这类约束,都需要引入0-1整数变量来实现——普通的lsqlin只能处理连续变量的约束(比如你已经实现的非负限制),没法直接搞定整数约束,所以得换用支持MIQP的求解器,比如CPLEX、Gurobi,或者开源的SCIP。

先解决你当前CPLEX示例的报错

你用cplexlsqnonneglin时碰到的CPLEX Error 5002: %s is not convex,原因很明确:这个函数专门处理非负连续变量的凸最小二乘问题,要求C'*C是半正定矩阵。如果你的C存在线性相关的列(列不满秩),就会导致矩阵不满足凸性要求。

不过更重要的是:cplexlsqnonneglin根本不支持整数约束!如果你的最终目标是加整数约束,别在这个函数上浪费时间,直接把问题建模成MIQP才是正确方向。

正确建模思路(带整数约束)

假设我们要拟合d ≈ C*x,其中x是曲线的系数向量。要实现你要的约束,需要引入0-1整数变量z_j:z_j=1表示选中第j条曲线,z_j=0表示不选。

1. 限制拟合曲线数量

比如最多选k条曲线,需要添加两个约束:

  • x_j ≤ M * z_j:M是一个足够大的正数,确保当z_j=0时,x_j被强制为0(相当于不选这条曲线)
  • sum(z_j) ≤ k:限制选中的曲线总数不超过k
  • 保留你之前的非负约束:x_j ≥ 0

2. 要求所选曲线连续相邻

如果曲线是按顺序排列的,连续相邻的约束可以转化为线性约束:对于所有j,z_j - z_{j+1} + z_{j+2} ≤ 1。这个约束的逻辑是:如果第j和j+2条曲线都被选中,那么中间的j+1条必须也被选中,避免出现“跳选”的情况。

最终的目标函数是最小化0.5*(C*x - d)'*(C*x - d),这是一个二次目标,加上上面的线性约束和整数变量,就构成了标准的MIQP问题,可以用CPLEX的cplexmiqp函数求解。

针对你的场景的代码示例

下面是一个可参考的MIQP建模代码框架,适配你的需求:

function [] = miqp_curve_fit_example()
    load('C_n_d_2.mat');
    n = size(C,2); % 曲线的总数量
    max_selected = 5; % 你想要限制的最多选中曲线数,按需调整
    % 设定M值:要足够大,确保能约束x_j为0,但也别太大避免数值不稳定
    M = max(max(abs(C))) * norm(d); 
    
    % 构建MIQP的目标函数:0.5*x'*Q*x + f'*x
    Q = C' * C;
    f = -C' * d;
    
    % 构建约束条件 Ax ≤ b
    % 约束1:x_j ≤ M*z_j → x_j - M*z_j ≤ 0
    A1 = [eye(n), -M*eye(n)];
    b1 = zeros(n, 1);
    % 约束2:选中的曲线总数不超过max_selected
    A2 = [zeros(1, n), ones(1, n)];
    b2 = max_selected;
    % 如果需要连续相邻约束,添加下面的代码块
    % A3 = sparse(n-2, 2*n);
    % for j = 1:n-2
    %     A3(j, j) = 1;
    %     A3(j, j+1) = -1;
    %     A3(j, j+2) = 1;
    %     A3(j, n+j) = -1;
    %     A3(j, n+j+1) = 1;
    %     A3(j, n+j+2) = -1;
    % end
    % b3 = ones(n-2, 1);
    % 合并约束(如果加连续约束,修改下面两行的参数)
    A = [A1; A2];
    b = [b1; b2];
    
    % 变量上下界:x≥0,z是0-1变量
    lb = [zeros(n, 1); zeros(n, 1)];
    ub = [inf(n, 1); ones(n, 1)];
    
    % 变量类型:前n个是连续变量('C'),后n个是0-1整数变量('B')
    ctype = [repmat('C', 1, n), repmat('B', 1, n)];
    
    % CPLEX求解设置
    options = cplexoptimset('Display', 'on');
    [x_z, fval, exitflag, output] = cplexmiqp(Q, f, A, b, [], [], lb, ub, ctype, [], options);
    
    % 提取结果
    x_opt = x_z(1:n); % 拟合系数
    z_opt = x_z(n+1:end); % 选中曲线的0-1标记
    disp('选中的曲线索引:');
    disp(find(z_opt == 1));
    disp('拟合得到的系数:');
    disp(x_opt);
end

额外小贴士

  • 如果你用开源工具,可以试试SCIP,它对MIQP的支持也很好,不需要商业授权。
  • M值的选择很关键:可以用max(max(abs(C))) * norm(d)来估算,既能保证约束有效,又不会引入数值问题。
  • 连续相邻约束的逻辑可以根据你的具体需求调整,比如如果允许多个连续区间,上面的约束也能适用。

内容的提问来源于stack exchange,提问作者Jesse RJ

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 03:32:24