Трехдиагональный матричный алгоритм (TDMA), также известный как алгоритм Томаса, использующий Python с массивами NumPy - PullRequest
2 голосов
/ 04 января 2012

Я нашел реализацию алгоритма Томаса или TDMA в MATLAB.

function x = TDMAsolver(a,b,c,d)
    %a, b, c are the column vectors for the compressed tridiagonal matrix, d is the right vector
    n = length(b); % n is the number of rows

    % Modify the first-row coefficients
    c(1) = c(1) / b(1);    % Division by zero risk.
    d(1) = d(1) / b(1);    % Division by zero would imply a singular matrix.

    for i = 2:n-1
        temp = b(i) - a(i) * c(i-1);
        c(i) = c(i) / temp;
        d(i) = (d(i) - a(i) * d(i-1))/temp;
    end

    d(n) = (d(n) - a(n) * d(n-1))/( b(n) - a(n) * c(n-1));

    % Now back substitute.
    x(n) = d(n);
    for i = n-1:-1:1
        x(i) = d(i) - c(i) * x(i + 1);
    end
end

Мне нужно это в python, используя массивы numpy, вот моя первая попытка алгоритма в python.

import numpy

aa = (0.,8.,9.,3.,4.)
bb = (4.,5.,9.,4.,7.)
cc = (9.,4.,5.,7.,0.)
dd = (8.,4.,5.,9.,6.)

ary = numpy.array

a = ary(aa)
b = ary(bb)
c = ary(cc)
d = ary(dd)

n = len(b)## n is the number of rows

## Modify the first-row coefficients
c[0] = c[0]/ b[0]    ## risk of Division by zero.
d[0] = d[0]/ b[0]

for i in range(1,n,1):
    temp = b[i] - a[i] * c[i-1]
    c[i] = c[i]/temp
    d[i] = (d[i] - a[i] * d[i-1])/temp

d[-1] = (d[-1] - a[-1] * d[-2])/( b[-1] - a[-1] * c[-2])

## Now back substitute.
x = numpy.zeros(5)
x[-1] = d[-1]
for i in range(-2, -n-1, -1):
    x[i] = d[i] - c[i] * x[i + 1]

Они дают разные результаты, так что я делаю не так?

Ответы [ 3 ]

1 голос
/ 04 апреля 2017

Я сделал это, поскольку ни одна из онлайн-реализаций для python на самом деле не работает. Я проверил его на соответствие встроенной матричной инверсии и совпадение результатов.

Здесь a = нижний диагональ, b = основной диагональ, c = верхний диагональ, d = вектор решения

import numpy as np

def TDMA(a,b,c,d):
    n = len(d)
    w= np.zeros(n-1,float)
    g= np.zeros(n, float)
    p = np.zeros(n,float)

    w[0] = c[0]/b[0]
    g[0] = d[0]/b[0]

    for i in range(1,n-1):
        w[i] = c[i]/(b[i] - a[i-1]*w[i-1])
    for i in range(1,n):
        g[i] = (d[i] - a[i-1]*g[i-1])/(b[i] - a[i-1]*w[i-1])
    p[n-1] = g[n-1]
    for i in range(n-1,0,-1):
        p[i-1] = g[i-1] - w[i-1]*p[i]
    return p

Для повышения производительности больших матриц используйте numba! Этот код превосходит np.linalg.inv () в моих тестах:

import numpy as np
from numba import jit    

@jit
def TDMA(a,b,c,d):
    n = len(d)
    w= np.zeros(n-1,float)
    g= np.zeros(n, float)
    p = np.zeros(n,float)

    w[0] = c[0]/b[0]
    g[0] = d[0]/b[0]

    for i in range(1,n-1):
        w[i] = c[i]/(b[i] - a[i-1]*w[i-1])
    for i in range(1,n):
        g[i] = (d[i] - a[i-1]*g[i-1])/(b[i] - a[i-1]*w[i-1])
    p[n-1] = g[n-1]
    for i in range(n-1,0,-1):
        p[i-1] = g[i-1] - w[i-1]*p[i]
    return p
1 голос
/ 04 января 2012

Существует как минимум одно различие между ними:

for i in range(1,n,1):

в Python выполняет итерацию от индекса 1 до последнего индекса n-1, в то время как

for i = 2:n-1

- итерацию от индекса 1 (от нуля) до индекса (last-1), так как Matlab имеет индексирование по одному.

0 голосов
/ 05 января 2012

В вашем цикле версия Matlab перебирает элементы со второго по второй.Чтобы сделать то же самое в Python, вы хотите:

for i in range(1,n-1):

(Как отмечалось в комментарии Войтоса, это потому, что функция диапазона исключает последний индекс, поэтому вам нужно исправить это в дополнение к изменению0 индексация).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...