如何求解非线性方程组

时间:2013-12-25 20:11:13

标签: python math numpy scipy sympy

我有一组可以表示为矩阵的方程式,我还要求解决方案中的所有变量x i ,(x i 3 - x i = 0.例如,

A = [0 1 0 0]
    [0 0 1 0]
    [1 0 0 1]

我也不是所有变量都是=。

这意味着

x 2 = 0
x 3 = 0
x 1 + x 4 = 0
(x 1 3 - x 1 = 0
(x 2 3 - x 2 = 0
(x 3 3 - x 3 = 0
(x 4 3 - x 4 = 0

一个简单的解决方案是x 1 = 1且x 4 = -1。

如何解决像这样的方程组的小实例?我想要一个至少可以从python中调用的解决方案。

我目前解决问题的方法是尝试所有3个 n 不同的向量,其值为-1,0,1。

for v in itertools.product([-1,0,1], repeat = n):
    vector = np.asarray(v)
    if (not np.dot(M,v).any()):
        print "Solution found!"
        break

修改

这应该是对@ alko答案的评论,但它太长了。让我通过一个例子来研究这个方法。

A = np.matrix([[0, 1, 1, 1, 1, 0, 1], [1, 0, 1, 1, 1, 1, 0], [0, 1, 0, 1, 1, 1, 1], [1, 0, 1, 0, 1, 1, 1], [0, 1, 0, 1, 0, 1, 1]])
p,l,u=scipy.linalg.lu(A)
print u
[[ 1.  0.  1.  1.  1.  1.  0.]
 [ 0.  1.  1.  1.  1.  0.  1.]
 [ 0.  0. -1.  0.  0.  1.  0.]
 [ 0.  0.  0. -1.  0.  0.  1.]
 [ 0.  0.  0.  0. -1.  0.  0.]]

我不清楚下一步会是什么......?

3 个答案:

答案 0 :(得分:2)

这种问题叫做约束编程。有一些python库可以解决这个问题。例如,以下代码使用or-tools

from constraint_solver import pywrapcp as cs
import numpy as np

A = np.array(
    [[0, 1, 0, 0],
     [0, 0, 1, 0],
     [1, 0, 0, 1]], np.bool)

#A = np.array( [[0, 1, 1, 1, 1, 0, 1],
#               [1, 0, 1, 1, 1, 1, 0], 
#               [0, 1, 0, 1, 1, 1, 1], 
#               [1, 0, 1, 0, 1, 1, 1], 
#               [0, 1, 0, 1, 0, 1, 1]], np.bool)

values = [-1, 0, 1]
solver = cs.Solver("name")
X = np.array([solver.IntVar(values) for i in range(A.shape[1])])
Xl = X.tolist()

for row in A:
    x = X[row].tolist()
    solver.Add(solver.Sum(x) == 0)

db = solver.Phase(Xl, 
                  solver.INT_VAR_DEFAULT, 
                  solver.INT_VALUE_DEFAULT)

solver.NewSearch(db)
while solver.NextSolution():
    solution = [x.Value() for x in Xl]
    print solution

输出:

[-1, 0, 0, 1]
[0, 0, 0, 0]
[1, 0, 0, -1]

答案 1 :(得分:2)

既然你放了SymPy标签,我会指出SymPy可以很容易地象征性地解决这个问题

In [6]: x1, x2, x3, x4 = symbols('x1:5')

In [7]: solve([x2, x3, x1 + x4, x1**3 - x1, x2**3 - x2, x3**3 - x3, x4**3 - x4], [x1, x2, x3, x4], dict=True)
Out[7]: [{x₁: -1, x₂: 0, x₃: 0, x₄: 1}, {x₁: 0, x₂: 0, x₃: 0, x₄: 0}, {x₁: 1, x₂: 0, x₃: 0, x₄: -1}]

如果你的解决方案不是整数,那么事情会变得更加毛茸茸,因为激进分子的解决方案可能不存在,或者至少SymPy可能无法找到它们。如果是这种情况并且您只对数字解决方案感兴趣,那么您应该使用像numpy或scipy这样的数字库,但由于您的解决方案都是-1,0或1,因此这不是问题。

修改

如果您有Matrix,请说:

A = Matrix([[0, 1, 0, 0],
            [0, 0, 1, 0],
            [1, 0, 0, 1]])

然后将其转换为系统很容易。只需将它乘以包含符号的向量(为方便起见,我在此处切换到基于0的索引):

In [13]: syms = symbols("x:4")

In [14]: s = Matrix(syms)

In [15]: constraints = [xi**3 - xi for xi in syms]

In [16]: A*s
Out[16]:
⎡  x₁   ⎤
⎢       ⎥
⎢  x₂   ⎥
⎢       ⎥
⎣x₀ + x₃⎦

In [17]: solve(list(A*s) + constraints, syms, dict=True)
Out[17]: [{x₀: -1, x₁: 0, x₂: 0, x₃: 1}, {x₀: 0, x₁: 0, x₂: 0, x₃: 0}, {x₀: 1, x₁: 0, x₂: 0, x₃: -1}]

以下是您的大型系统的解决方案:

In [35]: A = np.matrix([[0, 1, 1, 1, 1, 0, 1], [1, 0, 1, 1, 1, 1, 0], [0, 1, 0, 1, 1, 1, 1], [1, 0, 1, 0, 1, 1, 1], [0, 1, 0, 1, 0, 1, 1]])

In [36]: A = Matrix(A).applyfunc(int)

In [37]: syms = symbols("x:7")

In [38]: s = Matrix(syms)

In [39]: constraints = [xi**3 - xi for xi in syms]

In [40]: solve(list(A*s) + constraints, syms, dict=True)
Out[40]:
[{x₀: -1, x₁: 1, x₂: 1, x₃: -1, x₄: 0, x₅: 1, x₆: -1}, {x₀: 0, x₁: 0, x₂: 0, x₃: 0, x₄: 0, x₅: 0, x₆: 0}, {x₀: 1, x₁: -1, x₂: -1, x₃: 1, x₄: 0, x₅: -1, x₆:
1}]

两个注释:

  • 您无需在LU中获取它。 SymPy的解决方案将为您解决(如果您的计算时间过长,您可以开始担心这些事情)。

  • In [36]将Matrix条目转换为int(默认情况下为浮点数)。没有必要,但一般来说,当你知道它们是准确的时候,SymPy会用确切的数字做得更好,特别是因为你知道你的解决方案无论如何都是整数。如果您从一开始就使用SymPy Matrix,则无需担心这一点。

答案 2 :(得分:0)

您可以将A分解为lu decomposition

import numpy as np
import scipy.linalg
A = np.matrix([[0, 1, 1, 1, 1, 0, 1],
               [1, 0, 1, 1, 1, 1, 0], 
               [0, 1, 0, 1, 1, 1, 1], 
               [1, 0, 1, 0, 1, 1, 1], 
               [0, 1, 0, 1, 0, 1, 1]])
p, l, u = scipy.linalg.lu(A)

为简单起见,我们假设A具有最大等级,即其中一些适当的未成年人是可逆的。如果不是这样,你可以将矩阵A减少到一个较小的A',其具有与下面相同的LU分解,其中A'满足该属性并且在等式方面是等价的(u的最后一行将为零,删除他们继续)。您的等式Ax=0等于(plu)x=0,而pl是可逆矩阵ux=0u,反过来是上三角

print u
# [[ 1.  0.  1.  1.  1.  1.  0.]
#  [ 0.  1.  1.  1.  1.  0.  1.]
#  [ 0.  0. -1.  0.  0.  1.  0.]
#  [ 0.  0.  0. -1.  0.  0.  1.]
#  [ 0.  0.  0.  0. -1.  0.  0.]]

您只对最后(两列)列感兴趣,这两列定义了最后一个变量值的所有变量。探测所有x4可能的非零值,1-1,您可以检查您的方程组是否有解:

from itertools import product
idx = u.shape[0] - u.shape[1] 
m, v = u[:, :idx], u[:,idx:]
for spare in product({1, 0, -1}, repeat=-idx):
    if any(spare): # to exclude all zeros
        sol = scipy.linalg.solve(m, -np.dot(v, spare))
        if not set(sol).difference({0,1,-1}):
            print 'solution: ', sol, spare
# solution:  [-1.  1.  1. -1. -0.] (1, -1)
# solution:  [ 1. -1. -1.  1. -0.] (-1, 1)