9

对于一个固定整数n,我有一组联2(n-1)立方程如下。

M(p) = 1+((n-p-1)/n)*M(n-1) + (2/n)*N(p-1) + ((p-1)/n)*M(p-1)

N(p) = 1+((n-p-1)/n)*M(n-1) + (p/n)*N(p-1)

M(1) = 1+((n-2)/n)*M(n-1) + (2/n)*N(0)

N(0) = 1+((n-1)/n)*M(n-1)

M(p)被定义为1 <= p <= n-1N(p)被定义为0 <= p <= n-2。另请注意,这p只是每个方程中的一个常数整数,因此整个系统是线性的。

我一直在使用 Maple,但我想现在设置这些并在 python 中解决它们,也许使用numpy.linalg.solve(或任何其他更好的方法)。我实际上只想要M(n-1). 例如,当n=2答案应该是M(1) = 4,我相信。这是因为方程变为

M(1) = 1+(2/2)*N(0)
N(0) = 1 + (1/2)*M(1)

所以

M(1)/2 = 1+1

所以

M(1) = 4. 

如果我想插入n=50,比如说,你如何在 python 中设置这个联立方程组,以便 numpy.linalg.solve 可以解决它们?

更新 答案很好,但他们使用方程组稀疏的密集求解器。发布后续使用 scipy 稀疏矩阵求解方程组

4

3 回答 3

7

更新:使用 scipy.sparse 添加了实现


这按顺序给出了解决方案N_max,...,N_0,M_max,...,M_1

要求解的线性系统是形状A dot x == const 1-vectorx是寻求的解决方案向量。
在这里,我对方程进行了排序,xN_max,...,N_0,M_max,...,M_1。然后我从 4 个块矩阵
构建- 系数矩阵。A

这是示例案例的快照,n=50展示了如何导出系数矩阵并理解块结构。系数矩阵A为浅蓝色,常数右侧为橙色。寻求的解决方案向量x在这里是浅绿色的,用于标记列。第一列显示了上述给定方程中的哪一个。行 (= eq.) 已导出: 在此处输入图像描述

正如 Jaime 所建议的,乘以n改进代码。这没有反映在上面的电子表格中,但已在下面的代码中实现:

使用 numpy 实现:

import numpy as np
import numpy.linalg as linalg


def solve(n):
    # upper left block
    n_to_M = -2. * np.eye(n-1) 

    # lower left block
    n_to_N = (n * np.eye(n-1)) - np.diag(np.arange(n-2, 0, -1), 1)

    # upper right block
    m_to_M = n_to_N.copy()
    m_to_M[1:, 0] = -np.arange(1, n-1)

    # lower right block
    m_to_N = np.zeros((n-1, n-1))
    m_to_N[:,0] = -np.arange(1,n)

    # build A, combine all blocks
    coeff_mat = np.hstack(
                          (np.vstack((n_to_M, n_to_N)),
                           np.vstack((m_to_M, m_to_N))))

    # const vector, right side of eq.
    const = n * np.ones((2 * (n-1),1))

    return linalg.solve(coeff_mat, const)

使用 scipy.sparse 的解决方案:

from scipy.sparse import spdiags, lil_matrix, vstack, hstack
from scipy.sparse.linalg import spsolve
import numpy as np


def solve(n):
    nrange = np.arange(n)
    diag = np.ones(n-1)

    # upper left block
    n_to_M = spdiags(-2. * diag, 0, n-1, n-1)

    # lower left block
    n_to_N = spdiags([n * diag, -nrange[-1:0:-1]], [0, 1], n-1, n-1)

    # upper right block
    m_to_M = lil_matrix(n_to_N)
    m_to_M[1:, 0] = -nrange[1:-1].reshape((n-2, 1))

    # lower right block
    m_to_N = lil_matrix((n-1, n-1))
    m_to_N[:, 0] = -nrange[1:].reshape((n-1, 1))

    # build A, combine all blocks
    coeff_mat = hstack(
                       (vstack((n_to_M, n_to_N)),
                        vstack((m_to_M, m_to_N))))

    # const vector, right side of eq.
    const = n * np.ones((2 * (n-1),1))

    return spsolve(coeff_mat.tocsr(), const).reshape((-1,1))

示例n=4

[[ 7.25      ]
 [ 7.76315789]
 [ 8.10526316]
 [ 9.47368421]   # <<< your result
 [ 9.69736842]
 [ 9.78947368]]

示例n=10

[[ 24.778976  ]
 [ 25.85117842]
 [ 26.65015984]
 [ 27.26010007]
 [ 27.73593401]
 [ 28.11441922]
 [ 28.42073207]
 [ 28.67249606]
 [ 28.88229939]
 [ 30.98033266]  # <<< your result
 [ 31.28067182]
 [ 31.44628982]
 [ 31.53365219]
 [ 31.57506477]
 [ 31.58936225]
 [ 31.58770694]
 [ 31.57680467]
 [ 31.560726  ]]
于 2013-01-16T22:43:23.460 回答
4

这是一种完全不同的方法,使用sympy. 它不是很快,但它允许我准确地复制你的方程的 RHS,限制我需要做的思考(总是一个加号),并给出分数的答案。

from sympy import Integer, Symbol, Eq, solve

def build_equations(n):
    ni = n
    n = Integer(n)
    Ms = {p: Symbol("M{}".format(p)) for p in range(ni)}
    Ns = {p: Symbol("N{}".format(p)) for p in range(ni-1)}
    M = lambda i: Ms[int(i)] if i >= 1 else 0
    N = lambda i: Ns[int(i)]

    M_eqs = {}
    M_eqs[1] = Eq(M(1), 1+((n-2)/n)*M(n-1) + (2/n)*N(0))
    for p in range(2, ni):
        M_eqs[p] = Eq(M(p), 1+((n-p-1)/n)*M(n-1) + (2/n)*N(p-1) + ((p-1)/n)*M(p-1))

    N_eqs = {}
    N_eqs[0] = Eq(N(0), 1+((n-1)/n)*M(n-1))
    for p in range(1, ni-1):
        N_eqs[p] = Eq(N(p), 1+((n-p-1)/n)*M(n-1) + (p/n)*N(p-1))

    return M_eqs.values() + N_eqs.values()

def solve_system(n, show=False):

    eqs = build_equations(n)
    sol = solve(eqs)

    if show:
        print 'equations:'
        for eq in sorted(eqs):
            print eq
        print 'solution:'
        for var, val in sorted(sol.items()):
            print var, val, float(val)

    return sol

这使

>>> solve_system(2, True)
equations:
M1 == N0 + 1
N0 == M1/2 + 1
solution:
M1 4 4.0
N0 3 3.0
{M1: 4, N0: 3}
>>> solve_system(3, True)
equations:
M1 == M2/3 + 2*N0/3 + 1
M2 == M1/3 + 2*N1/3 + 1
N0 == 2*M2/3 + 1
N1 == M2/3 + N0/3 + 1
solution:
M1 34/5 6.8
M2 33/5 6.6
N0 27/5 5.4
N1 5 5.0
{M2: 33/5, M1: 34/5, N1: 5, N0: 27/5}        

>>> solve_system(4, True)
equations:
M1 == M3/2 + N0/2 + 1
M2 == M1/4 + M3/4 + N1/2 + 1
M3 == M2/2 + N2/2 + 1
N0 == 3*M3/4 + 1
N1 == M3/2 + N0/4 + 1
N2 == M3/4 + N1/2 + 1
solution:
M1 186/19 9.78947368421
M2 737/76 9.69736842105
M3 180/19 9.47368421053
N0 154/19 8.10526315789
N1 295/38 7.76315789474
N2 29/4 7.25
{N2: 29/4, N1: 295/38, M1: 186/19, M3: 180/19, N0: 154/19, M2: 737/76}

这似乎与其他答案相匹配。

于 2013-01-17T14:01:21.883 回答
3

这很麻烦,但可以解决您的问题,除非在转录系数时出现非常可能的错误:

from __future__ import division
import numpy as np    
n = 2
# Solution vector is [N[0], N[1], ..., N[n - 2], M[1], M[2], ..., M[n - 1]]
n_pos = lambda p : p
m_pos = lambda p : p + n - 2
A = np.zeros((2 * (n - 1), 2 * (n - 1)))
# p = 0
# N[0] + (1 - n) / n * M[n-1] = 1
A[n_pos(0), n_pos(0)] = 1 # N[0]
A[n_pos(0), m_pos(n - 1)] = (1 - n) / n #M[n - 1]
for p in xrange(1, n - 1) :
    # M[p] + (1 + p - n) /n * M[n - 1] - 2 / n * N[p - 1] +
    #  (1 - p) / n * M[p - 1] = 1
    A[m_pos(p), m_pos(p)] = 1 # M[p]
    A[m_pos(p), m_pos(n - 1)] =  (1 + p - n) / n # M[n - 1]
    A[m_pos(p), n_pos(p - 1)] = -2 / n # N[p - 1]
    if p > 1 :
        A[m_pos(p), m_pos(p - 1)] = (1 - p) / n # M[p - 1]
    # N[p] + (1 + p -n) / n * M[n - 1] - p / n * N[p - 1] = 1
    A[n_pos(p), n_pos(p)] = 1 # N[p]
    A[n_pos(p), m_pos(n - 1)] = (1 + p - n) / n # M[n - 1]
    A[n_pos(p), n_pos(p - 1)] = -p / n # N[p - 1]
if n > 2 :
    # p = n - 1
    # M[n - 1] - 2 / n * N[n - 2] + (2 - n) / n * M[n - 2] = 1
    A[m_pos(n - 1), m_pos(n - 1)] = 1 # M[n - 1]
    A[m_pos(n - 1), n_pos(n - 2)] = -2 / n # N[n - 2]
    A[m_pos(n - 1), m_pos(n - 2)] = (2 - n) / n # M[n - 2]
else :
    # p = 1 
    #M[1] - 2 / n * N[0] = 1
    A[m_pos(n - 1), m_pos(n - 1)] = 1
    A[m_pos(n - 1), n_pos(n - 2)] = -2 / n

X = np.linalg.solve(A, np.ones((2 * (n - 1),)))

但它提供了一个解决方案

>>> X[-1]
6.5999999999999979

for M(2)when n=3,这不是你想出的。

于 2013-01-16T22:08:04.230 回答