Demo notebook for linear operators as matrices
Demo notebook for linear operators as matrices#
In this notebook we explore implementing linear operators in Python as matrices (using numpy).
import numpy as np
First make a vector with specified spacing:
t = np.arange[0,10,1]
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-2-f09977b052e8> in <module>
----> 1 t = np.arange[0,10,1]
TypeError: 'builtin_function_or_method' object is not subscriptable
Oops, I thought I was using Mathematica. Fix the brackets and check that we got what we wanted:
t = np.arange(0,10,1)
print(t)
[0 1 2 3 4 5 6 7 8 9]
Useful matrix functions include np.identity and np.ones:
print( np.identity(5) )
[[1. 0. 0. 0. 0.]
[0. 1. 0. 0. 0.]
[0. 0. 1. 0. 0.]
[0. 0. 0. 1. 0.]
[0. 0. 0. 0. 1.]]
print( np.ones(5) )
[1. 1. 1. 1. 1.]
print( np.ones((5,5)) )
[[1. 1. 1. 1. 1.]
[1. 1. 1. 1. 1.]
[1. 1. 1. 1. 1.]
[1. 1. 1. 1. 1.]
[1. 1. 1. 1. 1.]]
Ok, now try an operator that multiplies by \(\omega_0^2\):
omega0 = 2
D_op = omega0**2 * np.identity(10)
print(D_op)
[[4. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
[0. 4. 0. 0. 0. 0. 0. 0. 0. 0.]
[0. 0. 4. 0. 0. 0. 0. 0. 0. 0.]
[0. 0. 0. 4. 0. 0. 0. 0. 0. 0.]
[0. 0. 0. 0. 4. 0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0. 4. 0. 0. 0. 0.]
[0. 0. 0. 0. 0. 0. 4. 0. 0. 0.]
[0. 0. 0. 0. 0. 0. 0. 4. 0. 0.]
[0. 0. 0. 0. 0. 0. 0. 0. 4. 0.]
[0. 0. 0. 0. 0. 0. 0. 0. 0. 4.]]
Try it out! It is tempting to use *
but for linear algebra we use @
. Compare:
print(D_op * t)
[[ 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
[ 0. 4. 0. 0. 0. 0. 0. 0. 0. 0.]
[ 0. 0. 8. 0. 0. 0. 0. 0. 0. 0.]
[ 0. 0. 0. 12. 0. 0. 0. 0. 0. 0.]
[ 0. 0. 0. 0. 16. 0. 0. 0. 0. 0.]
[ 0. 0. 0. 0. 0. 20. 0. 0. 0. 0.]
[ 0. 0. 0. 0. 0. 0. 24. 0. 0. 0.]
[ 0. 0. 0. 0. 0. 0. 0. 28. 0. 0.]
[ 0. 0. 0. 0. 0. 0. 0. 0. 32. 0.]
[ 0. 0. 0. 0. 0. 0. 0. 0. 0. 36.]]
print(D_op @ t)
[ 0. 4. 8. 12. 16. 20. 24. 28. 32. 36.]
Ok, let’s make it more general (note the difference between these two):
t_min = 0
t_max = 10
delta_t = 1
t = np.arange(t_min, t_max, delta_t)
print(t)
[0 1 2 3 4 5 6 7 8 9]
t_min = 0
t_max = 10
delta_t = 1
t = np.arange(t_min, t_max, delta_t)
print(t)
num_t = len(t)
print(num_t)
[0 1 2 3 4 5 6 7 8 9]
10
omega0 = 2
D_op = omega0**2 * np.identity(num_t)
print(D_op)
[[4. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
[0. 4. 0. 0. 0. 0. 0. 0. 0. 0.]
[0. 0. 4. 0. 0. 0. 0. 0. 0. 0.]
[0. 0. 0. 4. 0. 0. 0. 0. 0. 0.]
[0. 0. 0. 0. 4. 0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0. 4. 0. 0. 0. 0.]
[0. 0. 0. 0. 0. 0. 4. 0. 0. 0.]
[0. 0. 0. 0. 0. 0. 0. 4. 0. 0.]
[0. 0. 0. 0. 0. 0. 0. 0. 4. 0.]
[0. 0. 0. 0. 0. 0. 0. 0. 0. 4.]]
Now try the simplest derivative operator, building it from shifted diagonal matrices.
print( np.diag(np.ones(5), 0) )
[[1. 0. 0. 0. 0.]
[0. 1. 0. 0. 0.]
[0. 0. 1. 0. 0.]
[0. 0. 0. 1. 0.]
[0. 0. 0. 0. 1.]]
print( np.diag(np.ones(5), 1) )
[[0. 1. 0. 0. 0. 0.]
[0. 0. 1. 0. 0. 0.]
[0. 0. 0. 1. 0. 0.]
[0. 0. 0. 0. 1. 0.]
[0. 0. 0. 0. 0. 1.]
[0. 0. 0. 0. 0. 0.]]
print( np.diag(np.ones(5), -1) )
[[0. 0. 0. 0. 0. 0.]
[1. 0. 0. 0. 0. 0.]
[0. 1. 0. 0. 0. 0.]
[0. 0. 1. 0. 0. 0.]
[0. 0. 0. 1. 0. 0.]
[0. 0. 0. 0. 1. 0.]]
Diff_op = (1 * np.diag(np.ones(num_t-1), 1) + (-1) * np.diag(np.ones(num_t), 0)) / delta_t
print(Diff_op)
[[-1. 1. 0. 0. 0. 0. 0. 0. 0. 0.]
[ 0. -1. 1. 0. 0. 0. 0. 0. 0. 0.]
[ 0. 0. -1. 1. 0. 0. 0. 0. 0. 0.]
[ 0. 0. 0. -1. 1. 0. 0. 0. 0. 0.]
[ 0. 0. 0. 0. -1. 1. 0. 0. 0. 0.]
[ 0. 0. 0. 0. 0. -1. 1. 0. 0. 0.]
[ 0. 0. 0. 0. 0. 0. -1. 1. 0. 0.]
[ 0. 0. 0. 0. 0. 0. 0. -1. 1. 0.]
[ 0. 0. 0. 0. 0. 0. 0. 0. -1. 1.]
[ 0. 0. 0. 0. 0. 0. 0. 0. 0. -1.]]
Try it!
print(Diff_op @ t)
[ 1. 1. 1. 1. 1. 1. 1. 1. 1. -9.]
print(Diff_op @ t**2, '\n', 2*t)
[ 1. 3. 5. 7. 9. 11. 13. 15. 17. -81.]
[ 0 2 4 6 8 10 12 14 16 18]
Build a better derivative operator by making it symmetric:
Diff_sym_op = (1 * np.diag(np.ones(num_t-1), 1) + (-1) * np.diag(np.ones(num_t-1), -1)) / (2*delta_t)
print(Diff_sym_op)
[[ 0. 0.5 0. 0. 0. 0. 0. 0. 0. 0. ]
[-0.5 0. 0.5 0. 0. 0. 0. 0. 0. 0. ]
[ 0. -0.5 0. 0.5 0. 0. 0. 0. 0. 0. ]
[ 0. 0. -0.5 0. 0.5 0. 0. 0. 0. 0. ]
[ 0. 0. 0. -0.5 0. 0.5 0. 0. 0. 0. ]
[ 0. 0. 0. 0. -0.5 0. 0.5 0. 0. 0. ]
[ 0. 0. 0. 0. 0. -0.5 0. 0.5 0. 0. ]
[ 0. 0. 0. 0. 0. 0. -0.5 0. 0.5 0. ]
[ 0. 0. 0. 0. 0. 0. 0. -0.5 0. 0.5]
[ 0. 0. 0. 0. 0. 0. 0. 0. -0.5 0. ]]
print(Diff_sym_op @ t**2, '\n', 2*t)
[ 0.5 2. 4. 6. 8. 10. 12. 14. 16. -32. ]
[ 0 2 4 6 8 10 12 14 16 18]
print(Diff_sym_op @ t**3, '\n', 3*t**2)
[ 0.5 4. 13. 28. 49. 76. 109. 148. 193. -256. ]
[ 0 3 12 27 48 75 108 147 192 243]
Try with smaller spacing delta_t
to get more accuracy.