您的问题是线性最小二乘法:
minimize_x norm2(x-s)
such that G x <= h
x >= 0
1^T x = R
它符合 qpsolvers 中 solve_ls 函数的要求。
鉴于您指定的内容,这是我想象您的问题矩阵想要的一个实例。由于它是稀疏的,我们应该确保使用 SciPy CSC 矩阵(以及用于向量的常规 NumPy 数组):
import numpy as np
import scipy.sparse as spa
n = 150_000
# minimize || x - s ||^2
R = spa.eye(n, format="csc")
s = np.array(range(n), dtype=float)
# such that G * x <= h
G = spa.diags(
diagonals=[
[1.0 if i % 2 == 0 else 0.0 for i in range(n)],
[1.0 if i % 3 == 0 else 0.0 for i in range(n - 1)],
[1.0 if i % 5 == 0 else 0.0 for i in range(n - 1)],
],
offsets=[0, 1, -1],
)
a_dozen_rows = np.linspace(0, n - 1, 12, dtype=int)
G = G[a_dozen_rows]
h = np.ones(12)
# such that sum(x) == 42
A = spa.csc_matrix(np.ones((1, n)))
b = np.array([42.0]).reshape((1,))
# such that x >= 0
lb = np.zeros(n)
接下来,我们可以解决这个问题:
from qpsolvers import solve_ls
x = solve_ls(R, s, G, h, A, b, lb, solver="cvxopt", verbose=True)
在这里,我选择了 CVXOPT,但您还可以安装其他开源求解器,例如 ProxQP、OSQP 或 SCS。您可以通过以下方式安装一组开源求解器:pip install qpsolvers[open_source_solvers]。安装一些求解器后,您可以通过以下方式列出稀疏矩阵的求解器:
print(qpsolvers.sparse_solvers)
最后,这里有一些代码来检查求解器返回的解决方案是否满足我们的约束:
tol = 1e-8 # tolerance for checks
print(f"- Objective: {np.linalg.norm(x - s):.1f}")
print(f"- G * x <= h: {(G.dot(x) <= h + tol).all()}")
print(f"- x >= 0: {(x + tol >= 0.0).all()}")
print(f"- sum(x) = {x.sum():.1f}")
希望这会有所帮助。快乐解决!