我正在寻找一种在Python中求解线性方程组的方法。 特别是,我正在寻找大于全零的最小整数向量并解决给定的方程。 例如,我有以下等式:
但是,如何自动确定此解决方案?
如果我使用scipy.optimize.nnls
,例如
A = np.array([[1,-1,0],[0,2,-1],[2,0,-1]])
b = np.array([0,0,0])
nnls(A,b)
结果是(array([ 0., 0., 0.]), 0.0)
。
这也是正确的,但不是理想的解决方案...
编辑:我为在某些方面不精确而道歉。 如果有人对细节感兴趣,问题来自论文 “用于数字信号处理的同步数据流程序的静态调度”,Edward A. Lee和David G. Messerschmitt, IEEE Transactions on Computers,Vol。 C-36,第1号,第24-35页,1987年1月。
定理2说
对于具有s个节点和拓扑矩阵A且秩(A)= s-2的连通SDF图,我们可以找到正整数向量b!= 0,使得Ab = 0,其中0是零向量。 / p>
直接在定理证明2之后他们说
可能需要求解零空间中最小的正整数向量。为此,减少u'中的每个有理条目,使其分子和分母相对为素数。欧几里德的算法将适用于此。
答案 0 :(得分:3)
要找到您想要的确切解决方案,numpy和scipy可能不是最好的工具。他们的算法通常以浮点工作,并且不能保证给出完全答案。
您可以使用sympy
来获得此问题的确切答案。 Matrix
中的sympy
类提供方法nullspace()
,该方法返回nullspace的基础向量列表。这是一个例子:
In [20]: from sympy import Matrix, lcm
In [21]: A = Matrix([[1, -1, 0], [0, 2, -1], [2, 0, -1]])
在nullspace中获取向量。 nullspace()
返回一个列表;此代码假定A的等级为2,因此列表的长度为1:
In [22]: v = A.nullspace()[0]
In [23]: v
Out[23]:
Matrix([
[1/2],
[1/2],
[ 1]])
在v
中找到值的分母的最小公倍数,以便我们可以将结果缩放到最小的整数:
In [24]: m = lcm([val.q for val in v])
In [25]: m
Out[25]: 2
x
包含整数答案:
In [26]: x = m*v
In [27]: x
Out[27]:
Matrix([
[1],
[1],
[2]])
要将该结果转换为numpy整数数组,您可以执行以下操作:
In [52]: np.array([int(val) for val in x])
Out[52]: array([1, 1, 2])
答案 1 :(得分:3)
实际上,它只是基本的线性代数。
>>> A = np.array([[1,-1,0], [0,2,-1],[2,0,-1]])
让我们计算这个矩阵的特征值和特征向量。
>>> e = np.linalg.eig(A)
>>> e
(array([ -4.14213562e-01, -1.05471187e-15, 2.41421356e+00]), array([[-0.26120387, -0.40824829, 0.54691816],
[-0.36939806, -0.40824829, -0.77345908],
[-0.89180581, -0.81649658, 0.32037724]]))
>>>> np.round(e[0], 10)
array([-0.41421356, -0. , 2.41421356])
舍入后,我们看到0是矩阵A的特征值。因此,0-特征值的特征向量是方程组的一个很好的候选者。
>>> s = e[1][:,1]
>>> s
array([-0.40824829, -0.40824829, -0.81649658])
将特征向量与相关矩阵相乘得到特征向量本身,由相关特征值缩放。因此,在上面的例子中我们看到:As = 0s = 0
>>> np.round(A.dot(s), 10)
array([ 0., 0., 0.])
由于我们对整数解决方案感兴趣,因此我们必须缩放解决方案向量。
>>> x = s / s[1]
>>> x
array([ 1., 1., 2.])
希望这个答案能解决你的问题。
答案 2 :(得分:0)
这或许是一个疯狂的想法,但听起来你正在寻找建立一个约束求解器。
minizinc是一个通用约束求解器。也许有可能以minizinc可以解决它的方式表达你的约束?
然后看来有一个Python库可以与它进行交互:https://pypi.python.org/pypi/pymzn/
答案 3 :(得分:0)
这个问题非常非正式,如评论中所示。如果不知道你对最小的定义(例子:l1-norm,l2-norm),很难回答你的具体问题。
一般问题与解决丢番图方程组有关,但这些问题很难解决(在一般情况下)并且软件不多。
一种自然的方法是使用整数编程,这是NP难的,但商业和一些开源解算器非常强大。
numpy / scipy中没有内置方法可以在没有大量修改的情况下解决您的问题(例如:基于numpy / scipy实现一些自己的算法)。可悲的是,在numpy / scipy中也没有IP解算器。
我们假设:
x is nonnegative
这是使用纸浆和numpy的一些简单的基于IP的实现。我不喜欢纸浆,但很容易在所有类型的流行系统上安装(pip install pulp
)。
from pulp import *
import numpy as np
EPS = 1e-3
""" Input """
A = np.array([[1,-1,0],[0,2,-1],[2,0,-1]])
b = np.array([0,0,0])
""" MIP """
# Variables
x = np.empty(b.shape[0], dtype=object)
for i in range(b.shape[0]):
x[i] = LpVariable("x" + str(i), lowBound=0, upBound=None, cat='Integer')
# Problem
prob = LpProblem("prob", LpMinimize)
# Objective
prob += np.sum(x)
# Constraints
for row in range(A.shape[0]):
prob += np.dot(A[row], x) == b[row]
prob += np.sum(x) >= EPS # forbid zero-vector
# Solve
status = prob.solve()
print(LpStatus[status])
print([value(x_) for x_ in x])
Optimal
[1.0, 1.0, 2.0]
答案 4 :(得分:-1)
pypi处有这种等式的求解器。它显然可以计算矩阵的Hermite normal form,而矩阵又可以用来解决你的问题。
该软件包的版本为0.1。
Sage似乎也是support Hermite正常形态。
同构系统的特殊情况,即b = 0稍微容易一些,这里是一个求解器,用于矩阵的最简单可能情况,其等级为n-1
import sympy
import numpy as np
def create_rd(n, defect=1, range=10):
while True:
res = sympy.Matrix((np.random.randint(-range+1,range,(n, n-defect))
@np.random.randint(0,2,(n-defect, n)))
.astype(object))
if res.rank() == n-defect:
break
return res
def solve(M):
ns = M.nullspace()
ns = [n / sympy.gcd(list(n)) for n in ns]
nsnp = np.array([[int(k) for k in n] for n in ns])
if len(ns) == 1:
return ns[0], nsnp[0]
else:
raise NotImplementedError
示例输出:
>>> M = create_rd(4) # creates a rank-deficient matirx
>>> ns, nn = solve(M) # finds the 1d nullspace and a minimal integer basis vector
>>> M
Matrix([
[-7, -7, -7, -12],
[ 0, 6, 0, 6],
[ 4, 1, 4, -3],
[-4, -7, -4, -9]])
>>> ns
Matrix([
[-1],
[ 0],
[ 1],
[ 0]])
>>> M*ns
Matrix([
[0],
[0],
[0],
[0]])
>>> M = create_rd(40) # we can go to higher dimensions
>>> ns, nn = solve(M) # but solutions quickly become unwieldy
>>> ns
Matrix([
[ 8620150337],
[-48574455644],
[ -6216916999],
[-14703127270],
< - snip - >