我有一个线性方程组Ax=b,A-矩阵(m×n),x-(n×1),b-(m×1).矩阵A几乎全为0,只包含~n*m^(1/2)个非零元素.M和n可以相当大,例如n=28680,m=22500或n=28680,m=62500.显然,该系统的高概率精确解根本不存在.因此,我需要找到这样一个向量X0,在该向量处实现和((Ax-b)^2)函数的最小值.同时,非常希望向量X0只由0和1组成.因此,我需要解决这个问题 Sum((ax-b)^2)->min,x from{0,1}

你是怎么试着解决这个问题的? 首先,我解决了一个简化的问题. Sum((Ax-b)^2)->min,x来自实数 这个问题很快就用十种方法解决了.我四舍五入得到的解决方案,但这导致了非常差的质量.

然后我试着解决完全的问题.有人向我推荐了CVXPY图书馆.通过研究CVXPY官方网站发现,对于混合整数二次类,它适合我使用求解器.我用SCIP解算器编写了一个程序.由于等待最优解的时间太长,我将求解时间限制在200秒.该程序有效,但仅适用于小的m和n,例如n=4950,m=1600.如果进一步增加m和n,则SCIP会给出一个简单的零向量作为解决方案,尽管实际上任何只有一个1的向量都更接近最优.以下是程序代码:

import cvxpy as cp
import numpy as np

#I tried to simulate my inputs for you. 
#Here the problem manifests itself already at m, n = 1600, 4950.
np.random.seed(0)
m, n= 1600, 4950
A = np.round(np.random.rand(m, n)/(1-1/m**(1/2))/2)*255*(m**(1/2)/1800)**1.1
b = 255*(np.random.randn(m))

x = cp.Variable(n, integer=True)
objective = cp.Minimize(cp.sum_squares(A @ x - b))
constraints = []
constraints.extend([x >= 0.0, x <= 1])
prob = cp.Problem(objective,constraints)
prob.solve(solver=cp.SCIP,verbose=True,scip_params={"limits/time": 50})
print("Status: ", prob.status)
print("The optimal value is", prob.value)
print("A solution x is")
print(x.value)
print("Non-zero ",sum([i for i in x.value]))

我的问题如下:

  1. 有没有更好的办法来解决我的问题?
  2. 也许我应该用其他的解算器?我找不到另一个免费的解决方案来解决我的问题.
  3. 如果SCIP是最好的 Select ,我如何才能使其适用于大的m和n?我不明白为什么它停止工作了...

最新情况: 我认为避免使用导数不连续的函数会更好,但至少在我的例子中,"绝对误差和"似乎比平方和更有效. 至于矩阵A,它是可以的.不幸的是,我的问题没有确切的解决方案.然而,矩阵A仍然不是像例子中那样的噪声,我希望它能提供一个足够接近精确解的解.同时,我100%确定零向量离最优解非常远,因为我判断了一些由0和1组成的向量,其中约80%更接近最优解. AirSquid CVXPY代码对我来说很有效,即使是27000x23000的矩阵,也没有确切的解决方案!此外,我的内存也快用完了. 在我的实际数据中,使用绝对误差和的选项不再返回零矢量.但还有另一个问题--太多了.现在sum(abs(Ax-b))在0向量的情况下比求解器给出的解更小!我不明白为什么会发生这种事.

推荐答案

我假设"绝对误差和"足以代替SSE作为解决方案的质量衡量标准.通过这样做,模型可以很容易地线性化,我认为使用MIP解算器比使用二次求解器更容易处理.请注意,assume以下的两个示例都有一个good(在本例中实际上是精确的)解.如果矩阵基本上是"噪声"的,而您正在寻找最佳匹配,那么几乎可以肯定的是,解算器将更加费力,因为问题可能更退化.

在看解决方案之前,我认为你的A以上的建造有问题.做一个小的m x n矩阵,看看它是不是你想要的.我得到了很多重复的值,都是正值,所以完全有可能,对于一个b向量,x向量is the optimal solution的"全零"应该是~0的平均值.我改变了一些关于位置/负值和 struct 的东西,以获得你想要的密度.

如果你把我的cvxpyshell 换回SSE,我很好奇你会得到什么样的性能与线性相比.我找不到合适的解算器来解决这个问题,因为我不经常使用cvxpy.

对于这种可以很容易地用矩阵格式表示的问题,cvxpy是很自然的.为了在解题之前达到相同的点,我在pyomo中跳过了几个圈,但它工作得很好.在我8岁的时候.旧机器,pyomo需要大约200秒来构建最大规模的问题(如您在结果中所见)

我下面的cvxpy解决方案对于较小的实例很好,但对于20k x 20k左右的矩阵来说是"不可行的",所以可能有一些内在的东西我不明白,因为它显然是可行的.也许更了解cvxpy的人可以修修补补,看看发生了什么.

小型矩阵的CVXPY:

import cvxpy as cp
import numpy as np
from time import time

#I tried to simulate my inputs for you. 
#Here the problem manifests itself already at m, n = 1600, 4950.
np.random.seed(0)
m, n= 5_000, 5_000  # 20_000, 20_000  <--- barfs
A_base = (np.random.randint(-1000, 1000, (m, n)))
marks = np.random.binomial(n=1, p=(n*m)**0.5/(m*n), size=(m, n))
A = np.where(marks, A_base, 0)
true_x = np.random.binomial(n=1, p=0.6, size=n)
b = A @ true_x

tic = time()
x = cp.Variable(n, integer=True)
objective = cp.Minimize(cp.sum(cp.abs(A @ x - b)))
constraints = []
constraints.extend([x >= 0.0, x <= 1])
prob = cp.Problem(objective,constraints)
res=prob.solve() #solver=cp.SCIP,verbose=True,scip_params={"limits/time": 50})
toc = time()
print("Status: ", prob.status)
print("The optimal value is", prob.value)
print("A solution x is")
print(x.value)
print("Non-zero ",sum([i for i in x.value if i is not None ]))
print(f'solver time:  {toc-tic : 0.1f} sec.')

CVXPY output:

Status:  optimal
The optimal value is 0.0
A solution x is
[ 1.  1.  1. ... -0.  1. -0.]
Non-zero  1907.0
solver time:   3.5 sec.
[Finished in 5.5s]

全尺寸矩阵的PYOMO

import numpy as np
import pyomo.environ as pyo
from time import time
import sys

np.random.seed(0)
m, n = 28_680, 62_500
A_base = (np.random.randint(-1000, 1000, (m, n)))
marks = np.random.binomial(n=1, p=(n*m)**0.5/(m*n), size=(m, n))
A = np.where(marks, A_base, 0)
true_x = np.random.binomial(n=1, p=0.6, size=n)
b = A @ true_x
# b = np.random.randint(-100, 100, n)
# print(b)

tic = time()
model = pyo.ConcreteModel()

model.N = pyo.Set(initialize=range(n))
model.M = pyo.Set(initialize=range(m))

# initializing x only because some values of x[n] may end up unconstrained and this prevents "None" in result
model.x           = pyo.Var(model.N, within=pyo.Binary, initialize=0)
model.row_err     = pyo.Var(model.M)
model.row_abs_err = pyo.Var(model.M)

# constrain the rowsum/error appropriately
@model.Constraint(model.M)
def rowsum(model, m):
    return model.row_err[m] == sum(A[m,n] * model.x[n] for n in model.N if A[m,n]) - b[m]


# constrain the abs error
@model.Constraint(model.M)
def abs_1(model, m):
    return model.row_abs_err[m] >= model.row_err[m]

@model.Constraint(model.M)
def abs_2(model, m):
    return model.row_abs_err[m] >= -model.row_err[m]

# minimize sum of absolute row errors
model.obj = pyo.Objective(expr=sum(model.row_abs_err[m] for m in model.M))
toc = time()
print(f'starting solver...  at time: {toc-tic: 0.1f} sec.')
solver = pyo.SolverFactory('cbc')
res = solver.solve(model)
toc = time()

print(f'total solve time:  {toc-tic: 0.1f} sec')
print(res)
# model.x.display()

x = np.array([pyo.value(model.x[n]) for n in model.N], dtype=int)

print(f'verifying solution:  {np.sum(A@x - b)}')

PYOMO output:

starting solver...  at time:  228.2 sec.
solver time:   384.8 sec

Problem: 
- Name: unknown
  Lower bound: 0.0
  Upper bound: 0.0
  Number of objectives: 1
  Number of constraints: 40941
  Number of variables: 50488
  Number of binary variables: 30839
  Number of integer variables: 30839
  Number of nonzeros: 20949
  Sense: minimize
Solver: 
- Status: ok
  User time: -1.0
  System time: 123.18
  Wallclock time: 152.91
  Termination condition: optimal
  Termination message: Model was solved to optimality (subject to tolerances), and an optimal solution is available.
  Statistics: 
    Branch and bound: 
      Number of bounded subproblems: 21
      Number of created subproblems: 21
    Black box: 
      Number of iterations: 2668
  Error rc: 0
  Time: 153.19930219650269
Solution: 
- number of solutions: 0
  number of solutions displayed: 0

verifying solution:  0

Python相关问答推荐

重命名变量并使用载体中的字符串存储 Select 该变量

如何修复fpdf中的线路出血

Django文件上传不起作用:文件未出现在媒体目录或数据库中

Tkinter -控制调色板的位置

将行从一个DF添加到另一个DF

无法使用equals_html从网址获取全文

如何才能知道Python中2列表中的巧合.顺序很重要,但当1个失败时,其余的不应该失败或是0巧合

返回nxon矩阵的diag元素,而不使用for循环

更改matplotlib彩色条的字体并勾选标签?

有症状地 destruct 了Python中的regex?

按顺序合并2个词典列表

为什么sys.exit()不能与subproccess.run()或subprocess.call()一起使用

Polars:用氨纶的其他部分替换氨纶的部分

cv2.matchTemplate函数匹配失败

如何根据一列的值有条件地 Select 前N个组,然后按两列分组?

不能使用Gekko方程'

通过ManyToMany字段与Through在Django Admin中过滤

旋转多边形而不改变内部空间关系

如何使用使用来自其他列的值的公式更新一个rabrame列?

如何将数据帧中的timedelta转换为datetime