Я хотел бы создать трехдиагональную матрицу блока, начиная с трех numpy.ndarray. Есть ли какой-либо (прямой) способ сделать это в python?
Заранее благодарю вас!
Приветствия
Я хотел бы создать трехдиагональную матрицу блока, начиная с трех numpy.ndarray. Есть ли какой-либо (прямой) способ сделать это в python?
Заранее благодарю вас!
Приветствия
С "регулярными" массивами numpy, используя numpy.diag:
def tridiag(a, b, c, k1=-1, k2=0, k3=1):
return np.diag(a, k1) + np.diag(b, k2) + np.diag(c, k3)
a = [1, 1]; b = [2, 2, 2]; c = [3, 3]
A = tridiag(a, b, c)
Вы также можете сделать это с помощью "регулярных" массивов numpy посредством фантастической индексации:
import numpy as np
data = np.zeros((10,10))
data[np.arange(5), np.arange(5)+2] = [5, 6, 7, 8, 9]
data[np.arange(3)+4, np.arange(3)] = [1, 2, 3]
print data
(Вы можете заменить эти вызовы на np.arange
на np.r_
, если хотите сделать более кратким. Например, вместо data[np.arange(3)+4, np.arange(3)]
используйте data[np.r_[:3]+4, np.r_[:3]]
)
Это дает:
[[0 0 5 0 0 0 0 0 0 0]
[0 0 0 6 0 0 0 0 0 0]
[0 0 0 0 7 0 0 0 0 0]
[0 0 0 0 0 8 0 0 0 0]
[1 0 0 0 0 0 9 0 0 0]
[0 2 0 0 0 0 0 0 0 0]
[0 0 3 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 0]]
Однако, если вы все равно собираетесь использовать разреженные матрицы, посмотрите scipy.sparse.spdiags
. (Обратите внимание, что вам нужно будет добавить поддельные данные в свои значения строк, если вы помещаете данные в диагональное положение с положительным значением (например, 3 в позиции 4 в примере))
В качестве быстрого примера:
import numpy as np
import scipy as sp
import scipy.sparse
diag_rows = np.array([[1, 1, 1, 1, 1, 1, 1],
[2, 2, 2, 2, 2, 2, 2],
[0, 0, 0, 0, 3, 3, 3]])
positions = [-3, 0, 4]
print sp.sparse.spdiags(diag_rows, positions, 10, 10).todense()
Это дает:
[[2 0 0 0 3 0 0 0 0 0]
[0 2 0 0 0 3 0 0 0 0]
[0 0 2 0 0 0 3 0 0 0]
[1 0 0 2 0 0 0 0 0 0]
[0 1 0 0 2 0 0 0 0 0]
[0 0 1 0 0 2 0 0 0 0]
[0 0 0 1 0 0 2 0 0 0]
[0 0 0 0 1 0 0 0 0 0]
[0 0 0 0 0 1 0 0 0 0]
[0 0 0 0 0 0 1 0 0 0]]
Ответ @TheCorwoodRep действительно может быть выполнен в одной строке. Нет необходимости в отдельной функции.
np.eye(3,3,k=-1) + np.eye(3,3)*2 + np.eye(3,3,k=1)*3
Это дает:
array([[ 2., 3., 0.],
[ 1., 2., 3.],
[ 0., 1., 2.]])
Используйте функцию scipy.sparse.diags
.
Пример:
from scipy.sparse import diags
import numpy as np
#
n = 10
k = np.array([np.ones(n-1),-2*np.ones(n),np.ones(n-1)])
offset = [-1,0,1]
A = diags(k,offset).toarray()
Это возвращает:
array([[-2., 1., 0., 0., 0.],
[ 1., -2., 1., 0., 0.],
[ 0., 1., -2., 1., 0.],
[ 0., 0., 1., -2., 1.],
[ 0., 0., 0., 1., -2.]])
Так как тридиагональная матрица является разреженной матрицей с использованием разреженного пакета, это может быть хорошим вариантом, см. http://pysparse.sourceforge.net/spmatrix.html#matlab-implementation, есть примеры и сравнения с MATLAB даже...
Мой ответ строит ответ @TheCorwoodRep. Я просто разместил его, потому что сделал несколько изменений, чтобы сделать его более модульным, чтобы он работал для разных порядков матриц, а также менял значения k1
, k2
, k3
, т.е. определял, где появляется диагональ, автоматически позаботится о переполнении. При вызове функции вы можете указать, какие значения должны появляться на диагоналях.
import numpy as np
def tridiag(T,x,y,z,k1=-1, k2=0, k3=1):
a = [x]*(T-abs(k1)); b = [y]*(T-abs(k2)); c = [z]*(T-abs(k3))
return np.diag(a, k1) + np.diag(b, k2) + np.diag(c, k3)
D=tridiag(10,-1,2,-1)