如何求解非负整数上的线性方程组?

时间:2017-10-20 00:52:45

标签: python matrix linear-algebra sympy integer-programming

给定线性系统Ax = b,其中矩阵A和向量b具有整数值,我想找到所有非负整数向量{{1}解决这个等式。

到目前为止,我已经找到了一些技术,例如矩阵的Smith normal formHermite normal form来找到整数解,我想我可以使用线性求解器来找到非负解。是否有一个可以让这更容易的图书馆?

Python解决方案是理想的,但如果一个库存在于另一种语言中,我想知道它。

4 个答案:

答案 0 :(得分:6)

您可以使用整数编程来执行此操作,为您拥有的每个x值定义一个非负整数决策变量。然后你可以用约束Ax = b和objective 0来解决这个问题,它会为你的方程组搜索任何可行的整数解。

这可以使用python中的纸浆包轻松实现。例如,考虑解决以下系统:

x+2y+z = 5
3x+y-z = 5

你可以用纸浆解决这个问题:

import pulp
A = [[1, 2, 1], [3, 1, -1]]
b = [5, 5]
mod = pulp.LpProblem('prob')
vars = pulp.LpVariable.dicts('x', range(len(A[0])), lowBound=0, cat='Integer')
for row, rhs in zip(A, b):
    mod += sum([row[i]*vars[i] for i in range(len(row))]) == rhs
mod.solve()
[vars[i].value() for i in range(len(A[0]))]
# [1.0, 2.0, 0.0]

这标识了一个可行的整数解,x = 1,y = 2,z = 0。

答案 1 :(得分:3)

如果存在Ax=b的至少一个非负整数解,那么整数编程应该能够找到它。所有非负整数解的集合可以通过A的零空间找到。

实施例

在Erwin的回答中使用Ab

>>> from sympy import *
>>> A = Matrix([[ 1, 2, 1],
                [ 3, 1,-1]])
>>> b = Matrix([20,12])

计算零空间:

>>> A.nullspace()
[Matrix([
[ 3/5],
[-4/5],
[   1]])]

零空间是1维的,其基础向量是有理的 - 值。使用Erwin找到的特定解决方案(2,8,2),所有真实解决方案的集合都是参数化为(2,8,2) + t (3,-4,5)。由于我们只对非负整数解决方案感兴趣,我们将线与非负八分圆相交,然后与整数晶格相交,产生t ∈ {0,1,2}。因此,如果:

  • t=1,我们获得解决方案(5,4,7)
  • t=2,我们获得解决方案(8,0,12)

请注意,这些是Erwin使用Z3找到的3种解决方案。

但是,当零空间的维度大于1时,要困难得多。看看:

答案 2 :(得分:2)

这是Z3型号。 Z3是微软的定理证明。该模型与之前提出的MIP模型非常相似。

在MIP中枚举整数解决方案并非完全无关紧要(可以通过一些努力[link]或在高级MIP求解器中使用“解决方案池”技术来完成。使用Z3这会更容易一些。更简单的方法是使用约束编程(CP)解算器:它们可以自动枚举解决方案。

我们走了:

from z3 import *
A = [[1, 2, 1], [3, 1, -1]]
b = [20, 12]
n = len(A[0]) # number of variables
m = len(b)    # number of constraints

X = [ Int('x%d' % i) for i in range(n) ]
s = Solver()
s.add(And([ X[i] >= 0 for i in range(n) ]))
for i in range(m):
    s.add( Sum([ A[i][j]*X[j] for j in range(n) ]) == b[i])

while s.check() == sat:
    print(s.model())
    sol = [s.model().evaluate(X[i]) for i in range(n)]
    forbid = Or([X[i] != sol[i] for i in range(n)])
    s.add(forbid)  

它解决了

x0+2x1+x2 = 20
3x0+x1-x2 = 12

解决方案如下:

[x2 = 2, x0 = 2, x1 = 8]
[x2 = 7, x1 = 4, x0 = 5]
[x2 = 12, x1 = 0, x0 = 8]

我们可以打印最终模型,以便我们可以看到如何添加“禁止”约束:

[And(x0 >= 0, x1 >= 0, x2 >= 0),
 1*x0 + 2*x1 + 1*x2 == 20,
 3*x0 + 1*x1 + -1*x2 == 12,
 Or(x0 != 2, x1 != 8, x2 != 2),
 Or(x0 != 5, x1 != 4, x2 != 7),
 Or(x0 != 8, x1 != 0, x2 != 12)]

答案 3 :(得分:0)

参见herezsolve包的4ti2方法。