6. 内積とフーリエ展開
Pythonで学ぶ線形代数学
1次元直交射影
code: proj.py
from numpy import random, array, inner, sqrt
import matplotlib.pyplot as plt
a, b = random.normal(0, 1, 2)
e = array(b, -a) / sqrt(a ** 2 + b ** 2)
for n in range(100):
v = random.uniform(-2, 2, 2)
w = inner(e, v) * e
plt.plot([v0, w0], [v1, w1])
plt.plot([v0, w0], [v1, w1], marker='.')
plt.axis('scaled'), plt.xlim(-2, 2), plt.ylim(-2, 2), plt.show()
ソースコード: proj.py
https://gyazo.com/f27e30b65bfab0825c7ca83caf13f64a
グラム・シュミットの直交化法
code: gram_schmidt.py
from numpy import array, vdot, sqrt
def proj(x, E, inner=vdot):
return sum(inner(e, x) * e for e in E)
def gram_schmidt(A, inner=vdot):
E = []
while A != []:
a = array(A.pop(0))
b = a - proj(a, E, inner)
c = sqrt(inner(b, b))
if c >= 1.0e-15:
E.append(b / c)
return E
if __name__ == '__main__':
A = 1, 2, 3], 2, 3, 4, [3, 4, 5
E = gram_schmidt(A)
for n, e in enumerate(E):
print(f'e{n+1} = {e}')
print(array([vdot(e1, e2) for e2 in E for e1 in E]))
ソースコード: gram_schmidt.py
2次元直交射影
code: proj2d.py
from vpython import proj, curve, vec, hat, arrow, label, box
def proj2d(x, e): return x - proj(x, e)
def draw_fig(c):
curve(pos=c), curve(pos=[c1, c6])
curve(pos=[c2, c7]), curve(pos=[c3, c8])
o, e, u = vec(0, 0, 0), hat(vec(1, 2, 3)), vec(5, 5, 5)
x, y, z = vec(1, 0, 0), vec(0, 1, 0), vec(0, 0, 1)
box(axis=e, up=proj2d(y, e),
width=20, height=20, length=0.1, opacity=0.5)
arrow(axis=3 * e)
for ax, lbl in (x, 'x'), (y, 'y'), (z, 'z'):
curve(pos=-5 * ax, 10 * ax, color=vec(1, 1, 1) - ax)
label(pos=10 * ax, text=lbl)
curve(pos=proj2d(-5 * ax, e), proj2d(10 * ax, e), color=ax)
label(pos=proj2d(10 * ax, e), text=f"{lbl}'")
c0 = o, x, x + y, y, o, z, x + z, x + y + z, y + z, z
c1 = u + 2 * v for v in c0
c2 = proj2d(v, e) for v in c1
draw_fig(c1), draw_fig(c2)
ソースコード: proj2d.py
https://gyazo.com/24978fd2af3ebfdb570e6939140f2190
code: screen.py
from numpy import array
import matplotlib.pyplot as plt
from gram_schmidt import gram_schmidt
def curve(pos, color=(0, 0, 0)):
A = array(pos)
plt.plot(A:, 0, A:, 1, color=color)
def draw_fig(c):
curve(pos=c), curve(pos=[c1, c6])
curve(pos=[c2, c7]), curve(pos=[c3, c8])
o, e, u = array(0, 0, 0), array(1, 2, 3), array(5, 5, 5)
x, y, z = array(1, 0, 0), array(0, 1, 0), array(0, 0, 1)
E = array(gram_schmidt(e, x, y, z)1:)
for v, t in (x, "x'"), (y, "y'"), (z, "z'"):
curve(pos=E.dot(-5 * v), E.dot(10 * v), color=v)
plt.text(*E.dot(10 * v), t, fontsize=24)
c0 = o, x, x + y, y, o, z, x + z, x + y + z, y + z, z
c1 = u + 2 * v for v in c0
c2 = E.dot(v) for v in c1
draw_fig(c2), plt.axis('equal'), plt.show()
ソースコード: screen.py
https://gyazo.com/a72b8e5edc1c6fbca70d24f60b7c2f3e
問6.4.
code: lena5.py
from vpython import *
from gram_schmidt2 import gram_schmidt
canvas(background=color.white)
x, y, z, v = 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 2, 3
E = gram_schmidt(v, x, y, z)
x, y, z, v = vec(*x), vec(*y), vec(*z), vec(*v)
e0, e1, e2 = vec(*E0), vec(*E1), vec(*E2)
for e in x, y, z:
curve(pos=e * (-5), e * 10, color=e)
arrow(axis=v, color=color.yellow)
with open('lena.txt', 'r') as fd:
Data = eval(fd.read())
for x, y in Data:
points(pos=10 * x * e1 + 10 * y * e2,
color=color.black, radius=2)
ソースコード: lena5.py
データ lena.txt
https://gyazo.com/660bac51da718b8039373a36dca30adc
関数空間
code: integral.py
from numpy import array, sqrt
def integral(f, D):
N = len(D) - 1
w = (D-1 - D0) / N
x = array([(Dn + Dn + 1) / 2 for n in range(N)])
return sum(f(x)) * w
def inner(f, g, D):
return integral(lambda x: f(x).conj() * g(x), D)
norm = {
'L1': lambda f, D: integral(lambda x: abs(f(x)), D),
'L2': lambda f, D: sqrt(inner(f, f, D)),
'Loo': lambda f, D: max(abs(f(D))),
}
if __name__ == '__main__':
from numpy import linspace, pi, sin, cos
D = linspace(0, pi, 1001)
print(f'<sin|cos> = {inner(sin, cos, D)}')
print(f'||f_1||_2 = {norm"L2"(lambda x: x, D)}')
ソースコード: integral.py
実行結果
code: python
<sin|cos> = 4.5760562204146845e-17
||f_1||_2 = 3.214875266047432
最小2乗法
code: lstsqr.py
from numpy import linspace, cumsum, vdot, sort
from numpy.random import uniform, normal
from gram_schmidt import gram_schmidt, proj
import matplotlib.pyplot as plt
n = 20
x = sort(uniform(-1, 1, n))
z = 4 * x**3 - 3 * x
sigma = 0.2
y = z + normal(0, sigma, n)
E = gram_schmidt(x**0, x**1, x**2, x**3)
y0 = proj(z, E)
plt.figure(figsize=(15,5))
plt.errorbar(x, z, yerr=sigma, fmt='ro')
plt.plot(x, y0, color='g'), plt.plot(x, y, color='b'), plt.show()
ソースコード: lstsqr.py
https://gyazo.com/3a14e792d27381cc00c6b344909a3148
三角級数
code: trigonometric.py
from numpy import inner, pi, sin, cos, sqrt, ones
from gram_schmidt import proj
def f(k, t):
if k < 0:
return sin(2 * k * pi * t) * sqrt(2)
elif k == 0:
return ones(len(t))
elif k > 0:
return cos(2 * k * pi * t) * sqrt(2)
def lowpass(K, t, g):
n = len(t)
FK = f(k, t) for k in range(-K, K + 1)
return proj(g, FK, inner=lambda x, y: inner(x, y) / n)
if __name__ == '__main__':
from numpy import arange
import matplotlib.pyplot as plt
t = arange(0, 1, 1 / 1000)
fig, ax = plt.subplots(1, 2, figsize=(15, 5))
for k in range(-3, 0):
ax0.plot(t, f(k, t))
for k in range(4):
ax1.plot(t, f(k, t))
plt.show()
ソースコード: trigonometric.py
https://gyazo.com/335f25cfffe212d421da9078211ff0c6
ローパスフィルタ
code: brown.py
from numpy import arange, cumsum, sqrt
from numpy.random import normal
from trigonometric import lowpass
#from fourier import lowpass
import matplotlib.pyplot as plt
n = 1000
dt = 1 / n
t = arange(0, 1, dt)
g = cumsum(normal(0, sqrt(dt), n))
fig, ax = plt.subplots(3, 3, figsize=(16, 8), dpi=100)
for k, K in enumerate(0, 1, 2, 4, 8, 16, 32, 64, 128):
i, j = divmod(k, 3)
gK = lowpass(K, t, g)
axij.plot(t, g), axij.plot(t, gK)
axij.text(0.1, 0.5, f'K = {K}', fontsize = 20)
axij.set_xlim(0, 1)
plt.show()
ソースコード: brown.py
https://gyazo.com/f39a5bd9396d4052599f66763f2765a5
フーリエ級数
code: fourier.py
from numpy import arange, exp, pi, vdot
from gram_schmidt import proj
def f(k, t): return exp(2j * pi * k * t)
def lowpass(K, t, z):
dt = 1 / len(t)
FK = f(k, t) for k in range(-K, K + 1)
return proj(z, FK, inner=lambda x, y: vdot(x, y) * dt)
if __name__ == '__main__':
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
k = 2
t = arange(0, 1, 1 / 1000)
x = z.real for z in f(k, t)
y = z.imag for z in f(k, t)
fig = plt.figure()
ax = Axes3D(fig)
ax.scatter(t, x, y, s=1)
ax.plot(t, x, y)
plt.show()
ソースコード: fourier.py
https://gyazo.com/b8d402b41170eaf18cfbeece6b802615
直交多項式
code: poly_np1.py
from numpy import array, linspace, sqrt, ones, pi
import matplotlib.pyplot as plt
from gram_schmidt import gram_schmidt
m = 10000
D = linspace(-1, 1, m + 1)
x = array([(Dn + Dn + 1) / 2 for n in range(m)])
inner = {
'Ledendre': lambda f, g: f.dot(g) * 2 / m,
'Chebyshev1': lambda f, g: f.dot(g / sqrt(1 - x**2)) * 2 / m,
'Chebyshev2': lambda f, g: f.dot(g * sqrt(1 - x**2)) * 2 / m,
}
A = x ** n for n in range(6)
E = gram_schmidt(A, inner=inner'Ledendre')
for e in E:
plt.plot(x, e)
plt.show()
ソースコード: poly_np1.py
https://gyazo.com/a669ce2b984610dddf028c6a09049c35
code: poly_np2.py
from numpy import linspace, exp, sqrt
from numpy.polynomial.chebyshev import Chebyshev
from numpy.polynomial.legendre import Legendre
from numpy.polynomial.laguerre import Laguerre
from numpy.polynomial.hermite import Hermite
import matplotlib.pyplot as plt
x1 = linspace(-1, 1, 1001)
x2 = x11:-1
x3 = linspace(0, 10, 1001)
x4 = linspace(-3, 3, 1001)
f, x, w = Legendre, x1, 1
# f, x, w = Chebyshev, x2, 1
# f, x, w = Chebyshev, x2, 1/sqrt(1 - x2**2)
# f, x, w = Laguerre, x3, 1
# f, x, w = Laguerre, x3, exp(-x3)
# f, x, w = Hermite, x4, 1
# f, x, w = Hermite, x4, exp(-x4**2)
for n in range(6):
e = f.basis(n)(x)
plt.plot(x, e * w)
plt.show()
ソースコード: poly_n2p.py
https://gyazo.com/616ab4f27a0d337c6f2bcd7e449c8143
code: poly_sp1.py
from sympy import integrate, sqrt, exp, oo
from sympy.abc import x
D = {
'Ledendre': ((x, -1, 1), 1),
'Chebyshev1': ((x, -1, 1), 1 / sqrt(1 - x**2)),
'Chebyshev2': ((x, -1, 1), sqrt(1 - x**2)),
'Laguerre': ((x, 0, oo), exp(-x)),
'Hermite': ((x, -oo, oo), exp(-x**2)),
}
dom, weight = D'Ledendre'
def inner(expr1, expr2):
return integrate(f'({expr1}) * ({expr2}) * ({weight})', dom)
def gram_schmidt(A):
E = []
while A != []:
a = A.pop(0)
b = a - sum(inner(e, a) * e for e in E)
c = sqrt(inner(b, b))
E.append(b / c)
return E
E = gram_schmidt(1, x, x**2, x**3)
for n, e in enumerate(E):
print(f'e{n}(x) = {e}')
ソースコード: poly_sp1.py
実行結果
code: python
e0(x) = sqrt(2)/2
e1(x) = sqrt(6)*x/2
e2(x) = 3*sqrt(10)*(x**2 - 1/3)/4
e3(x) = 5*sqrt(14)*(x**3 - 3*x/5)/4
code: poly_sp2.py
from sympy.polys.orthopolys import (
legendre_poly,
chebyshevt_poly,
chebyshevu_poly,
laguerre_poly,
hermite_poly,
)
from sympy.abc import x
e = legendre_poly
for n in range(4):
print(f'e{n}(x) = {e(n, x)}')
ソースコード: poly_sp2.py
実行結果
code: python
e0(x) = 1
e1(x) = x
e2(x) = 3*x**2/2 - 1/2
e3(x) = 5*x**3/2 - 3*x/2
ベクトル列の収束
code: limit.py
from numpy import array, sin, cos, pi, inf
from numpy.linalg import norm
import matplotlib.pyplot as plt
def A(t):
return array(cos(t), -sin(t)], [sin(t), cos(t))
x = array(1, 0)
P, L1, L2, Loo = [], [], [], []
M = range(1, 100)
for m in M:
xm = A(pi / 2 / m).dot(x)
P.append(xm)
L1.append(norm(x - xm, ord=1))
L2.append(norm(x - xm))
Loo.append(norm(x - xm, ord=inf))
fig, ax = plt.subplots(1, 2, figsize=(10, 5))
for p in P:
ax0.plot(p0, p1, marker='.', color='black')
ax1.plot(M, L1), plt.text(1, L10, 'L1', fontsize=16)
ax1.plot(M, L2), plt.text(1, L20, 'L2', fontsize=16)
ax1.plot(M, Loo), plt.text(1, Loo0, 'Loo', fontsize=16)
ax1.set_xlim(0, 20)
plt.show()
ソースコード: limit.py
https://gyazo.com/8ebe0a7862289d68842379dea6c3adeb
フーリエ解析
code: sound.py
from numpy import arange, fft
import scipy.io.wavfile as wav
class Sound:
def __init__(self, wavfile):
self.file = wavfile
self.rate, Data = wav.read(f'{wavfile}.wav')
dt = 1 / self.rate
self.len = len(Data)
self.tmax = self.len / self.rate
self.time = arange(0, self.tmax, dt)
self.data = Data.astype('float') / 32768
self.fft = fft.fft(self.data)
def power_spectrum(self, rng=None):
spectrum = abs(self.fft) ** 2
if rng is None:
r1, r2 = -self.len / 2, self.len / 2
else:
r1, r2 = rng0 * self.tmax, rng1 * self.tmax
R = arange(int(r1), int(r2))
return R / self.tmax, spectrumR
def lowpass(self, K):
k = int(K * self.tmax)
U = self.fft.copy()
Urange(k + 1, self.len - k) = 0
V = fft.ifft(U).real
Data = (V * 32768).astype('int16')
wav.write(f'{self.file}{K}.wav', self.rate, Data)
return V
ソースコード: sound.py
code: spectrum.py
import matplotlib.pyplot as plt
from sound import Sound
sound1, sound2 = Sound('CEG'), Sound('mono')
fig, ax = plt.subplots(1, 2, figsize=(15, 5))
ax0.plot(*sound1.power_spectrum((-1000, 1000)))
ax1.plot(*sound2.power_spectrum())
plt.show()
ソースコード: spectrum.py
https://gyazo.com/da0b6fa20fd1e6c36d29739c006c54ba
code: lowpass.py
import matplotlib.pyplot as plt
from sound import Sound
sound = Sound('mono')
X, Y = sound.time, sound.data
Y3000 = sound.lowpass(3000)
fig, ax = plt.subplots(1, 2, figsize=(10, 5), dpi=100)
ax0.plot(X, Y), ax0.plot(X, Y3000)
ax0.set_ylim(-1, 1)
ax1.plot(X, Y), ax1.plot(X, Y3000)
ax1.set_xlim(0.2, 0.21), ax1.set_ylim(-1, 1)
plt.show()
ソースコード: lowpass.py
https://gyazo.com/f4944dd03f85d7cb2f5001098fabdbc9