Как построить скалярные функции матриц в matplotlib с использованием matrix_power? - PullRequest
0 голосов
/ 04 марта 2019

У меня есть следующий код для построения скаляра x против скаляра f(x), где есть некоторое умножение матриц внутри функции:

import numpy as np
import matplotlib.pyplot as plt
from numpy.linalg import matrix_power
P=np.array([\
 [0,0,0.5,0,0.5],\
 [0,0,1,0,0], \
 [.25,.25,0,.25,.25], \
 [0,0,.5,0,.5], \
 [0,0,0,0,1], \
 ])
t=np.array([0,1,0,0,0])
ones=np.array([1,1,1,1,0])

def f(x):
    return t.dot(matrix_power(P,x)).dot(ones)
x=np.arange(1,20)
plt.plot(x, f(x))

Теперь функция сама по себе работает нормально.

>>> f(1)
1.0
>>> f(2)
0.75 

Но при построении графика возникает ошибка exponent must be an integer.

Другими словами, как я могу оценить эту функцию для массива?например,

f(np.array([1,2]))

Я пытался заменить линию сюжета на plt.plot(x, map(f,x))

Но это не помогло.

Как это исправить

1 Ответ

0 голосов
/ 04 марта 2019
In [1]: P=np.array([\ 
   ...:  [0,0,0.5,0,0.5],\ 
   ...:  [0,0,1,0,0], \ 
   ...:  [.25,.25,0,.25,.25], \ 
   ...:  [0,0,.5,0,.5], \ 
   ...:  [0,0,0,0,1], \ 
   ...:  ])                                                                     
In [2]:                                                                         
In [2]: P                                                                       
Out[2]: 
array([[0.  , 0.  , 0.5 , 0.  , 0.5 ],
       [0.  , 0.  , 1.  , 0.  , 0.  ],
       [0.25, 0.25, 0.  , 0.25, 0.25],
       [0.  , 0.  , 0.5 , 0.  , 0.5 ],
       [0.  , 0.  , 0.  , 0.  , 1.  ]])

In [4]: np.linalg.matrix_power(P,3)                                             
Out[4]: 
array([[0.   , 0.   , 0.25 , 0.   , 0.75 ],
       [0.   , 0.   , 0.5  , 0.   , 0.5  ],
       [0.125, 0.125, 0.   , 0.125, 0.625],
       [0.   , 0.   , 0.25 , 0.   , 0.75 ],
       [0.   , 0.   , 0.   , 0.   , 1.   ]])

In [5]: np.linalg.matrix_power(P,np.arange(0,4))                                
---------------------------------------------------------------------------    
TypeError: exponent must be an integer

Так что просто дайте ему целое число, которое он хочет:

In [10]: [f(i) for i in range(4)]                                               
Out[10]: [1.0, 1.0, 0.75, 0.5]

pylab.plot(np.arange(25), [f(i) for i in np.arange(25)]) 

Из matrix_power кода:

a = asanyarray(a)
_assertRankAtLeast2(a)
_assertNdSquareness(a)

try:
    n = operator.index(n)
except TypeError:
    raise TypeError("exponent must be an integer")
....

Вот что он делает для n=3:

In [5]: x = np.arange(9).reshape(3,3)                                           
In [6]: np.linalg.matrix_power(x,3)                                             
Out[6]: 
array([[ 180,  234,  288],
       [ 558,  720,  882],
       [ 936, 1206, 1476]])
In [7]: x@x@x                                                                   
Out[7]: 
array([[ 180,  234,  288],
       [ 558,  720,  882],
       [ 936, 1206, 1476]])

Вы можете определить функцию matrix_power, которая принимает массив степеней:

def matrix_power(P,x):
    return np.array([np.linalg.matrix_power(P,i) for i in x])

При этом matrix_power(P,np.arange(25)) приведет к (25,5,5) массив.И ваш f(x) на самом деле работает с этим, возвращая (25,) массив формы.Но мне интересно, было ли это просто случайным или преднамеренным?Вы написали f, имея в виду массив мощности 3d?

t.dot(matrix_power(P,x)).dot(ones) 
...