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

带等式约束与上下界的二次规划求解问题:Python求解返回None但Matlab可正常运行

带等式约束与上下界的凸二次规划求解:Python问题排查与解决方案

首先,你的问题是典型的**凸二次规划(QP)**问题(因为Q是对角半正定矩阵),Matlab的fmincon能解但Python中solve_qp返回None,大概率是参数格式不匹配、求解器调用错误,或者代码中的小bug导致的。下面一步步拆解问题:

一、先排查代码中的基础错误

你的代码里有几个明显的问题,先修正这些才能让求解器正常工作:

  1. random.randint用法错误:Python标准库的random.randint只能生成单个整数,要生成数组得用numpy.random.randint。比如:
    M = np.random.randint(200, 300, size=(24,1))
    ppp = np.random.randint(150, 200, size=(24,))
    
  2. 上下界构造的维度隐患:你用np.bmat拼接上下界时,第三块的[0.1],0.1*np.ones(22),[0.9]是行方向拼接,转置后虽然能得到列向量,但这种写法容易出错。建议改用np.concatenate更清晰:
    # 构造lb的第三部分:1个0.1 + 22个0.1 + 1个0.9,共24个元素的列向量
    lb_part3 = np.concatenate([[0.1], 0.1*np.ones((22,1)), [0.9]])
    lb = np.concatenate([np.zeros((24,1)), np.zeros((24,1)), lb_part3, np.zeros((24,1))])
    # ub同理
    ub_part3 = np.concatenate([[0.9], 0.9*np.ones((22,1)), [0.9]])
    ub = np.concatenate([max_pch*np.ones((24,1)), max_pdch*np.ones((24,1)), ub_part3, 500*np.ones((24,1))])
    
  3. solve_qp的参数格式问题:如果你的solve_qp来自cvxopt,它要求所有输入必须是cvxopt.matrix类型,且向量维度要严格匹配(比如q必须是列向量,而非一维数组)。直接传numpy数组会导致求解器无法解析,返回None。

二、适合你场景的求解器推荐

针对你的凸QP问题(带等式约束+上下界,Q稀疏对角),推荐以下几种Python求解器,按易用性和效率排序:

1. CVXPY(最易用,推荐快速验证)

CVXPY是高层优化建模语言,不需要关心底层求解器的参数格式,只需像写数学公式一样定义问题,它会自动调用合适的求解器(比如OSQP、ECOS等)。

示例代码:

import numpy as np
import cvxpy as cp

# 初始化参数(先修正基础错误)
n = 24
I = np.eye(n)
Z = np.zeros((n,n))
a = 0.012
b = 1.1
gamma1 = 0.9/80
gamma2 = 1.1/80
MM = np.eye(n)
for i in range(n-2):
    MM[i+1,i] = -1
MM[0, n-1] = -1
M = np.random.randint(200, 300, size=(n,1))
max_pch = 30.0
max_pdch = 30.0
ppp = np.random.randint(150, 200, size=(n,))

# 构造Q、C、Aeq、beq、lb、ub
Q = np.block([[a*I, Z, Z, Z],
              [Z, a*I, Z, Z],
              [Z, Z, 1e-5*I, Z],
              [Z, Z, Z, 1e-5*I]])
C = np.concatenate([b*np.ones(n), b*np.ones(n), np.zeros(n), ppp]).reshape(-1,1)
Aeq = np.block([[-I, I, Z, I],
                [-gamma1*I, gamma2*I, MM, Z],
                [Z, Z, Z, Z],
                [Z, Z, Z, Z]])
beq = np.concatenate([M, np.zeros((3*n,1))])

lb_part3 = np.concatenate([[0.1], 0.1*np.ones((n-2,1)), [0.9]])
lb = np.concatenate([np.zeros((n,1)), np.zeros((n,1)), lb_part3, np.zeros((n,1))])
ub_part3 = np.concatenate([[0.9], 0.9*np.ones((n-2,1)), [0.9]])
ub = np.concatenate([max_pch*np.ones((n,1)), max_pdch*np.ones((n,1)), ub_part3, 500*np.ones((n,1))])

# 定义CVXPY变量和问题
x = cp.Variable((4*n, 1))
objective = cp.quad_form(x, Q) + cp.sum(cp.multiply(C, x))
constraints = [
    Aeq @ x == beq,
    lb <= x,
    x <= ub
]
prob = cp.Problem(cp.Minimize(objective), constraints)

# 求解(默认用OSQP,适合稀疏QP)
prob.solve(solver=cp.OSQP)

print("QP solution status:", prob.status)
print("QP solution: x = {}".format(x.value))

2. OSQP(高效,适合大规模稀疏QP)

OSQP是专门针对稀疏二次规划的求解器,你的Q是对角矩阵(极端稀疏),Aeq也有大量零元素,用OSQP效率会很高。如果不想用CVXPY的高层接口,可以直接调用OSQP:

import numpy as np
import osqp

# (参数构造部分同CVXPY示例,略)

# 转换为OSQP需要的稀疏矩阵格式
Q_sparse = osqp.utils.dense_to_sparse(Q)
Aeq_sparse = osqp.utils.dense_to_sparse(Aeq)

# 创建OSQP求解器实例
solver = osqp.OSQP()
solver.setup(
    P=Q_sparse,
    q=C.flatten(),
    A=Aeq_sparse,
    l=beq.flatten(),  # 等式约束的上下界都是beq
    u=beq.flatten(),
    lb=lb.flatten(),
    ub=ub.flatten(),
    verbose=True  # 可以看求解过程
)

# 求解
res = solver.solve()

print("QP solution status:", res.info.status)
print("QP solution: x = {}".format(res.x))

3. SciPy的minimize(兼容类似fmincon的SQP方法)

如果你习惯Matlabfmincon的思路,可以用SciPy的scipy.optimize.minimize,选择SLSQP方法(和fmincon的核心算法类似):

import numpy as np
from scipy.optimize import minimize

# (参数构造部分同CVXPY示例,略)

# 定义目标函数(二次型)
def objective(x):
    return 0.5 * x.T @ Q @ x + C.T @ x  # 注意QP的标准形式通常带0.5,有些求解器需要这个

# 定义等式约束
def eq_constraint(x):
    return Aeq @ x - beq.flatten()

constraints = [{
    'type': 'eq',
    'fun': eq_constraint
}]

# 初始值(随便给一个可行的初始值,或者全零)
x0 = np.zeros(4*n)

# 求解
res = minimize(
    objective,
    x0,
    method='SLSQP',
    bounds=list(zip(lb.flatten(), ub.flatten())),
    constraints=constraints,
    options={'disp': True}
)

print("QP solution status:", res.message)
print("QP solution: x = {}".format(res.x))

三、为什么你的原代码返回None?

大概率是以下两个原因:

  1. 参数类型不匹配:如果用的是cvxopt.solvers.qp,你直接传入numpy数组而不是cvxopt.matrix,求解器无法正确解析输入,导致求解失败返回None。
  2. 初始代码中的random.randint错误:这个错误会直接导致数组生成失败,程序报错,但你说返回None,可能是你实际运行时修改了,但参数维度或类型仍有问题。

用上面推荐的任何一种方法,只要参数构造正确,都能得到和Matlabfmincon类似的结果。

内容的提问来源于stack exchange,提问作者sajad parvizi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 13:59:03