%%html
<style type="text/css">
input.good:checked + label {color: green}
input.bad:checked + label {color: red}
input.good:checked + label::after {color: green; content: ' Õige vastus!'}
input.bad:checked + label::after {color: red; content: ' Vale vastus!'}
.output_wrapper, .output {
height:auto !important;
max-height:10000px;
}
.output_scroll {
box-shadow:none !important;
webkit-box-shadow:none !important;
}
</style>
Dünaamiline piljard on süsteem mis kirjeldab hõõrdevaba punktosake liikumist potentsiaalivabas piirkonnas, mis on piiratud lõpmatu potentsiaali seintega, kus tekib tagasi põrkamine.
Dünaamiline piljard on süsteem, mis kirjeldab hõõrdevaba punktmassi liikumist potentsiaalvabas piirkonnas $\mathcal{D} \subset \mathbb{R}^2$, mis on piiratud lõpmatu potentsiaaliseinaga $\partial\mathcal{D} = \Gamma$. Seega võime dünamikat kirjeldada kahe osana. Seinalt eemal mass liigub vabalt, seega kehtib
$$\dot{\vec{q}} = \vec{v}\,, \quad \dot{\vec{v}} = 0\,,$$kus $\vec{q}$ on massi asukoht ja $\vec{v}$ on tema kiirus. Seinal $\Gamma$ toimub elastiline kokkupõrge, mille järel massi liikumise suund äkitselt muutub. Seda kirjeldab hüpe
$$\vec{q} \mapsto \vec{q}\,, \quad \vec{v} \mapsto \vec{v} - 2(\vec{v} \cdot \vec{n})\vec{n}\,,$$kus $\vec{n}$ on seina ühiknormaal, ja me kasutame konventsiooni et $\vec{n}$ näitab piljardlaua sisse. Siin on näha et mõlemal juhul $\|\vec{v}\|$ jääb konstantseks, seega võime kasutada ühikkiirust $\|\vec{v}\| = 1$ ja kasutada faasiruumi koordinaate $(x, y, \omega)$ nii et
$$\vec{q} = (x, y)\,, \quad \vec{v} = (\cos\omega, \sin\omega)\,.$$Selle alusel leiame, et faasiruum on $\mathcal{D} \times S^1$. Kui me lisaks defineerime relatsiooni
$$(\vec{q}, \vec{v}) \sim (\vec{q}', \vec{v}') \quad \Leftrightarrow \quad \vec{q} = \vec{q}' \in \Gamma \wedge \vec{v}' = \vec{v} - 2(\vec{v} \cdot \vec{n})\,,$$võime defineerida faasiruumi kui $Q = \mathcal{D} \times S^1 / \sim$, ja pideva süsteemi dünaamikat kirjeldab esimest järku diferentsiaalvõrrand.
Pidevast süsteemist on võimalik tuletada diskreetset süsteemi Poincaré lõike abil. Antud juhul leiame, et võimalik Poincaré lõige on
$$S = \Gamma \times S^1 / \sim$$ja koosneb faasiruumi punktidest kus toimub kokkupõrge seinaga. Poincaré kujutus $P: S \to S$ kirjeldab, kuidas järgnevad kokkupõrked on omavahel seotud. Selle funktsiooni kirjeldamiseks on kasulik defineerida koordinaate lõikel $S$. Kõigepealt defineerime koordinaati $r$ rajal $\Gamma$, mille abil me saame igat rajapunkti kirjeldada kui $\vec{f}(r) \in \Gamma \subset \mathbb{R}^2$. Selle abil saame defineerida puutujavektorit $\vec{t} = \frac{d\vec{f}}{dr}$, ja kui me valime $r$ selliseks et ta kirjeldab kaarepikkust, on $\|\vec{t}\| = 1$. Lisaks defineerime koordinaati $\varphi$ nii, et punktmassi kiirus pärast kokkupõrget avaldub kui
$$\vec{v} = \vec{n}\cos\varphi + \vec{t}\sin\varphi\,.$$Edaspidi kasutame koordinaate $(r, \varphi)$ erinevate piljardsüsteemide kirjeldamiseks. Süsteemi defineerime kahe funktsiooni kaudu:
Arvutamiseks kasutame NumPy, joonistamiseks kasutame PyPlot ja erinevaid graafika pakette.
%matplotlib inline
from PIL import Image
import IPython.display as disp
from io import BytesIO
import numpy as np
import matplotlib.pyplot as plt
plt.rc('figure', figsize=(10, 10))
Lisaks defineerime abifunktsiooni, et kuvata tulemusi vikerkaare värvides.
def rcolor(x):
k = np.floor(1530 * x) % 1530
r = np.maximum(0, np.minimum(255, 510 - np.abs(k - 1020)))
g = np.maximum(0, np.minimum(255, 510 - np.abs(k - 510)))
b = np.maximum(0, np.minimum(255, np.abs(k - 765) - 255))
return (r, g, b)
Järgnev abifuntsioon simuleerib $n$ kokkupõrget alustades algtingimusest $(r_0, \varphi_0)$.
def bounce(fcm, fxy, r0, phi0, n):
res = [[r0, phi0]]
r = r0
phi = phi0
for _ in range(n):
[r, phi] = fcm(r, phi)
res.append([r, phi])
cm = np.array(res)
xy = np.transpose(fxy(cm[:, 0]))
return [cm, xy]
Lõpuks defineerime funktsiooni kokkupõrkekujutuse joonistamiseks.
def collmap(fcm, rmin, rmax, nr, nphi):
r0 = np.linspace(rmin, rmax, nr)
phi0 = np.linspace(-np.pi / 2, np.pi / 2, nphi)
cm = np.array([fcm(r, phi) for r in r0 for phi in phi0]).reshape(nr, nphi, 2)
cr = np.moveaxis(np.array(rcolor((cm[:, :, 0] - rmin) / (rmax - rmin)), dtype=np.uint8), 0, 2)
cphi = np.moveaxis(np.array(rcolor((cm[:, :, 1] / np.pi) + 0.5), dtype=np.uint8), 0, 2)
b = BytesIO()
imr = Image.fromarray(cr)
imr.save(b, format='png')
disp.display_png(b.getvalue(), raw=True)
b = BytesIO()
imr = Image.fromarray(cphi)
imr.save(b, format='png')
disp.display_png(b.getvalue(), raw=True)
Kõige lihtsam piljardlaud on ümmargune. Rajakujutust võib defineerida kui
$$x = \cos r\,, \quad y = \sin r\,,$$kus $r \in [-\pi, \pi]$:
def xy_circle(r):
x = np.cos(r)
y = np.sin(r)
return [x, y]
rr = np.linspace(0, 2 * np.pi, 101)
[xx, yy] = xy_circle(rr)
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(xx, yy, 'r')
ax.grid()
plt.show()
Järgmisena defineerime kokkupõrkekujutust. Selleks me võime kasutada omadust et ringi keskpunkt $\vec{0}$ ja üksteisele järgnevad kokkupõrkepunktid $\vec{q}, \vec{q}'$ moodustavad võrdhaarset kolmnurka, mille nurkade summa rahuldab
$$\pi = r' - r + 2\varphi\,,$$ja seega kehtib
$$r' = r + \pi - 2\varphi\,.$$Lisaks tagame, et $-\pi \leq r' \leq \pi$. Kuna kolmnurk on võrdhaarne, järeldub lõpuks et $\varphi' = \varphi$.
def cm_circle(r0, phi0):
r = r0 + np.pi - 2 * phi0
phi = phi0
while r > np.pi:
r = r - 2 * np.pi
while r < -np.pi:
r = r + 2 * np.pi
return [r, phi]
Siin on võimalik leida erinevaid trajektoore. Kui $\varphi_0 / \pi \in \mathbb{Q}$, tekib perioodiline trajektoor:
[cm, xy] = bounce(cm_circle, xy_circle, -np.pi / 2, np.pi / 10, 100)
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(xx, yy, 'r')
ax.plot(xy[:, 0], xy[:, 1], 'b')
ax.grid()
plt.show()
fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(cm[:, 0], cm[:, 1])
ax.grid()
plt.show()
Kui $\varphi_0 / \pi \notin \mathbb{Q}$, tekib mitteperioodiline trajektoor.
[cm, xy] = bounce(cm_circle, xy_circle, -np.pi / 2, 0.3, 100)
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(xx, yy, 'r')
ax.plot(xy[:, 0], xy[:, 1], 'b')
ax.grid()
plt.show()
fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(cm[:, 0], cm[:, 1])
ax.grid()
plt.show()
Lõpuks uurime kokkupõrkekujutust. Ülemine pilt näitab, et $r' = r + \pi - 2\varphi$, ja alumine näitab, et $\varphi' = \varphi$.
collmap(cm_circle, -np.pi, np.pi, 401, 401)
Järgmisena uurime ruudukujulist piljardlauda. Selleks defineerime rajakujutust, kus $r \in [0, 4)$. Siin täisosa $R = \lfloor r \rfloor \in \{0, 1, 2, 3\}$ määrab ruudu küljeid ja murdosa $\tilde{r} = r - \lfloor r \rfloor$ määrab positisiooni külje peal:
def xy_square(r):
side = np.floor(r)
off = r - side
x = np.cos(side * np.pi / 2) - np.sin(side * np.pi / 2) * (2 * off - 1)
y = np.sin(side * np.pi / 2) + np.cos(side * np.pi / 2) * (2 * off - 1)
return [x, y]
rr = np.linspace(0, 4, 5)
[xx, yy] = xy_square(rr)
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(xx, yy, 'r')
ax.grid()
plt.show()
Eukleidilise geomeetria ja trigonomeetria abil saame kokkupõrkekujutust tuletada kolmel erineval juhul:
def cm_square(r0, phi0):
side0 = np.floor(r0)
off0 = r0 - side0
hit = off0 + np.tan(phi0)
if hit > 1:
side = (side0 + 1) % 4
off = (1 - off0) / (hit - off0)
phi = np.pi / 2 - phi0
elif hit < 0:
side = (side0 + 3) % 4
off = 1 + off0 / (hit - off0)
phi = -np.pi / 2 - phi0
else:
side = (side0 + 2) % 4
off = 1 - hit
phi = -phi0
r = side + off
return [r, phi]
Sellisel juhul on võimalik leida perioodilist trajektoori kui $\tan\varphi_0 \in \mathbb{Q}$:
[cm, xy] = bounce(cm_square, xy_square, 0.5, np.arctan(2/3), 100)
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(xx, yy, 'r')
ax.plot(xy[:, 0], xy[:, 1], 'b')
ax.grid()
plt.show()
fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(cm[:, 0], cm[:, 1])
ax.grid()
plt.show()
Kui $\tan\varphi_0 \notin \mathbb{Q}$, tekib mitteperioodiline trajektoor:
[cm, xy] = bounce(cm_square, xy_square, 0.5, np.pi / 3, 100)
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(xx, yy, 'r')
ax.plot(xy[:, 0], xy[:, 1], 'b')
ax.grid()
plt.show()
fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(cm[:, 0], cm[:, 1])
ax.grid()
plt.show()
Lõpuks joonistame ka kokkupõrkekujutust:
collmap(cm_square, 0, 4, 401, 401)
Kolmnurga dünaamika on väga sarnane ruuduga. Sel juhul valime $r \in [0, 3)$, kus täisosa $R = \lfloor r \rfloor \in \{0, 1, 2\}$ määrab kolmnurga küljeid ja murdosa $\tilde{r} = r - \lfloor r \rfloor$ määrab positisiooni külje peal:
def xy_triangle(r):
side = np.floor(r)
off = r - side
x = np.sin(side * 2 * np.pi / 3) + np.cos(side * 2 * np.pi / 3) * (2 * off - 1) * np.sqrt(3)
y = -np.cos(side * 2 * np.pi / 3) + np.sin(side * 2 * np.pi / 3) * (2 * off - 1) * np.sqrt(3)
return [x, y]
rr = np.linspace(0, 3, 4)
[xx, yy] = xy_triangle(rr)
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(xx, yy, 'r')
ax.grid()
plt.show()
Kokkupõrkekujutust on samuti lihtne tuletada:
def cm_triangle(r0, phi0):
side0 = np.floor(r0)
off0 = r0 - side0
hit = (off0 - 0.5) * 2 + np.tan(phi0) * np.sqrt(3)
if hit > 0:
side = (side0 + 1) % 3
off = (1 - off0) * (np.sqrt(3) + np.tan(np.pi / 6 - phi0)) / (np.sqrt(3) - np.tan(np.pi / 6 - phi0))
phi = np.pi / 3 - phi0
else:
side = (side0 + 2) % 3
off = 1 - off0 * (np.sqrt(3) + np.tan(np.pi / 6 + phi0)) / (np.sqrt(3) - np.tan(np.pi / 6 + phi0))
phi = -np.pi / 3 - phi0
r = side + off
return [r, phi]
Kolmnurga puhul on lihtne leida perioodilisi trajektoore:
[cm, xy] = bounce(cm_triangle, xy_triangle, 0.7, np.pi / 6, 100)
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(xx, yy, 'r')
ax.plot(xy[:, 0], xy[:, 1], 'b')
ax.grid()
plt.show()
fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(cm[:, 0], cm[:, 1])
ax.grid()
plt.show()
Samuti on ka mitteperioodilised trajektoorid:
[cm, xy] = bounce(cm_triangle, xy_triangle, 0.5, 0.4, 100)
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(xx, yy, 'r')
ax.plot(xy[:, 0], xy[:, 1], 'b')
ax.grid()
plt.show()
fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(cm[:, 0], cm[:, 1])
ax.grid()
plt.show()
Lõpuks joonistame ka kokkupõrkekujutust:
collmap(cm_triangle, 0, 3, 481, 481)
Järgmine piljardlaud mida me uurime on ellips. Rajakujutust võib defineerida kui
$$x = a\cos r\,, \quad y = b\sin r\,,$$kus $a, b$ on poolteljed ja $r \in [-\pi, \pi]$:
aa = 2
bb = 1
def xy_ellipse(r):
return [aa * np.cos(r), bb * np.sin(r)]
rr = np.linspace(0, 2 * np.pi, 101)
[xx, yy] = xy_ellipse(rr)
fig = plt.figure(figsize=[6 * aa, 6 * bb])
ax = fig.add_subplot(111)
ax.plot(xx, yy, 'r')
ax.grid()
plt.show()
Järgmisena tuletame kokkupõrkekujutust. Selleks defineerime puutujavektori
$$\vec{t} = (-a\sin r, b\cos r)$$ja normaalivektori
$$\vec{n} = (-b\cos r, -a\sin r)\,.$$Punktosake trajektoor on sirge läbi $\vec{q} = (a\cos r, b\sin r)$, mille suunavektor on
$$\vec{d} = \vec{n}\cos\varphi + \vec{t}\sin\varphi\,.$$Järgmine kokkupõrkepunkt $\vec{q}' = (x', y')$ seega rahuldab
$$\vec{q}' = \vec{q} + s\vec{d}$$mõne $s$ korral, ja asub ellipsi peal, seega
$$\frac{x'^2}{a^2} + \frac{y'^2}{b^2} = 1\,.$$Kuna ka $\vec{q}$ asub ellipsi peal, on selles võrrandil lahend $s = 0$. Sellega jagades jääb lineaarne võrrand, mille lahend on
$$s = -2\frac{p_xd_xb^2 + p_yd_ya^2}{d_x^2b^2 + d_y^2a^2}\,.$$Nüüd on lihtne leida rajapunkti, kus kehtib
$$\tan r' = \frac{ay}{bx}\,.$$Lõpuks arvutame puutujavektori
$$\vec{t}' = (-a\sin r', b\cos r')\,,$$mille abil leiame nurka $\varphi'$ kui
$$\sin\varphi' = \frac{\vec{d} \cdot \vec{t}'}{\|\vec{d}\| \|\vec{t}'\|}\,.$$def cm_ellipse(r0, phi0):
[x0, y0] = xy_ellipse(r0)
xt0 = -aa * np.sin(r0)
yt0 = bb * np.cos(r0)
dx = xt0 * np.sin(phi0) - yt0 * np.cos(phi0)
dy = yt0 * np.sin(phi0) + xt0 * np.cos(phi0)
s = -2 * (x0 * dx * bb * bb + y0 * dy * aa * aa) / (dx * dx * bb * bb + dy * dy * aa * aa)
x = x0 + s * dx
y = y0 + s * dy
r = np.arctan2(y / bb, x / aa)
xt = -aa * np.sin(r)
yt = bb * np.cos(r)
phi = np.arcsin((xt * dx + yt * dy) / np.sqrt(xt * xt + yt * yt) / np.sqrt(dx * dx + dy * dy))
return [r, phi]
Kõige lihtsamad trajektoorid on sirged. Esimene on vertikaalne:
[cm, xy] = bounce(cm_ellipse, xy_ellipse, np.pi/2, 0, 10)
fig = plt.figure(figsize=[6 * aa, 6 * bb])
ax = fig.add_subplot(111)
ax.plot(xx, yy, 'r')
ax.plot(xy[:, 0], xy[:, 1], 'b')
ax.grid()
plt.show()
fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(cm[:, 0], cm[:, 1])
ax.grid()
plt.show()
Teine on horisontaalne:
[cm, xy] = bounce(cm_ellipse, xy_ellipse, 0, 0, 10)
fig = plt.figure(figsize=[6 * aa, 6 * bb])
ax = fig.add_subplot(111)
ax.plot(xx, yy, 'r')
ax.plot(xy[:, 0], xy[:, 1], 'b')
ax.grid()
plt.show()
fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(cm[:, 0], cm[:, 1])
ax.grid()
plt.show()
Lisaks leiame veel perioodilisi trajektoore:
[cm, xy] = bounce(cm_ellipse, xy_ellipse, np.arctan(0.5), np.pi / 4, 10)
fig = plt.figure(figsize=[6 * aa, 6 * bb])
ax = fig.add_subplot(111)
ax.plot(xx, yy, 'r')
ax.plot(xy[:, 0], xy[:, 1], 'b')
ax.grid()
plt.show()
fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(cm[:, 0], cm[:, 1])
ax.grid()
plt.show()
Üldiselt on 3 liiki trajektoore. Välised trajektoorid ei lõika lõiget fookuste vahel, ja tekib ellips kuhu trajektoorid ei satu:
[cm, xy] = bounce(cm_ellipse, xy_ellipse, 0, 0.2, 100)
fig = plt.figure(figsize=[6 * aa, 6 * bb])
ax = fig.add_subplot(111)
ax.plot(xx, yy, 'r')
ax.plot(xy[:, 0], xy[:, 1], 'b')
ax.grid()
plt.show()
fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(cm[:, 0], cm[:, 1])
ax.grid()
plt.show()
Kui trajektoor lõikab lõiget fookuste vajel, siis ta teeb seda iga kord kokkopõrgete vahel, ja ümbritsev joon on hüperbool:
[cm, xy] = bounce(cm_ellipse, xy_ellipse, np.pi / 2, 0.3, 100)
fig = plt.figure(figsize=[6 * aa, 6 * bb])
ax = fig.add_subplot(111)
ax.plot(xx, yy, 'r')
ax.plot(xy[:, 0], xy[:, 1], 'b')
ax.grid()
plt.show()
fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(cm[:, 0], cm[:, 1])
ax.grid()
plt.show()
Trajektoor, mis läbib fookust, läbib teist fookust pärast kokkupõrget, ja koondub horisontaaltelje peale:
[cm, xy] = bounce(cm_ellipse, xy_ellipse, np.pi / 2, np.pi / 3, 100)
fig = plt.figure(figsize=[6 * aa, 6 * bb])
ax = fig.add_subplot(111)
ax.plot(xx, yy, 'r')
ax.plot(xy[:, 0], xy[:, 1], 'b')
ax.grid()
plt.show()
fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(cm[:, 0], cm[:, 1])
ax.grid()
plt.show()
Kokkupõrkekujutus on järgnevalt:
collmap(cm_ellipse, -np.pi, np.pi, 401, 401)
Väga lihtne ja samas väga huvitav piljardlaud on Bunimovichi staadion, mis koosneb ruudust ja kahes poolringist. Sel juhul valime $r \in [0, 4)$, kus täisosa $R = \lfloor r \rfloor \in \{0, 1, 2, 3\}$ määrab küljeid ja murdosa $\tilde{r} = r - \lfloor r \rfloor$ määrab positisiooni külje peal. Antud juhul $R \in \{0, 2\}$ on ümmargused ja $R \in \{1, 3\}$ on sirged:
def xy_stadium(r):
side = np.floor(r)
off = r - side
x = np.cos(side * np.pi / 2) * (1 + np.sin(off * np.pi)) - np.sin(side * np.pi / 2) * (2 * off - 1)
y = np.sin(side * np.pi / 2) - np.cos(side * np.pi / 2) * np.cos(off * np.pi)
return [x, y]
rr = np.linspace(0, 4, 201)
[xx, yy] = xy_stadium(rr)
fig = plt.figure(figsize=[12, 6])
ax = fig.add_subplot(111)
ax.plot(xx, yy, 'r')
ax.grid()
plt.show()
Kokkupõrkekujutus on tuletatav trigonomeetria abil:
def intersect(y0, theta0):
m = np.tan(theta0)
a = 1 + m * m
b = 2 * y0 * m
c = y0 * y0 - 1
x = (np.sqrt(b * b - 4 * a * c) - b) / a / 2
y = m * x + y0
rho = np.arccos(-y)
phi = theta0 + np.pi / 2 - rho
return [rho / np.pi, phi]
def cm_stadium(r0, phi0):
side0 = np.floor(r0)
off0 = r0 - side0
if side0 % 2: # Alustame sirgest.
hit = off0 + np.tan(phi0)
if hit > 1: # Paremale.
side = (side0 + 1) % 4
[off, phi] = intersect(2 * (1 - off0) / np.tan(phi0) - 1, np.pi / 2 - phi0)
elif hit < 0: # Vasakule.
side = (side0 + 3) % 4
[off, phi] = intersect(1 + 2 * off0 / np.tan(phi0), -np.pi / 2 - phi0)
else: # Vastasseinale.
side = (side0 + 2) % 4
off = 1 - hit
phi = -phi0
else: # Alustame ringjoonest.
off = off0 + 1 - 2 * phi0 / np.pi
if off <= 1 or off >= 2: # Sama ringjoon.
if off >= 2:
off = off - 2
side = side0
phi = phi0
else:
x = -np.sin(off0 * np.pi)
y = np.cos(off0 * np.pi)
theta0 = (off0 - 0.5) * np.pi - phi0
y0 = y + (2 - x) * np.tan(theta0)
if y0 > 1: # Vasakule.
side = (side0 + 3) % 4
off = 1 - ((1 - y) / np.tan(theta0) + x) / 2
phi = theta0 - np.pi / 2
elif y0 < -1: # Paremale.
side = (side0 + 1) % 4
off = (-(y + 1) / np.tan(theta0) + x) / 2
phi = theta0 + np.pi / 2
else: #Vastasseinale
side = (side0 + 2) % 4
[off, phi] = intersect(y0, theta0)
r = side + off
return [r, phi]
Trajektoorid on üldjuhul kaootilised.
[cm, xy] = bounce(cm_stadium, xy_stadium, 0.5, 0.1, 100)
fig = plt.figure(figsize=[12, 6])
ax = fig.add_subplot(111)
ax.plot(xx, yy, 'r')
ax.plot(xy[:, 0], xy[:, 1], 'b')
ax.grid()
plt.show()
fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(cm[:, 0], cm[:, 1])
ax.grid()
plt.show()
Lõpuks joonistame ka kokkupõrkekujutust:
collmap(cm_stadium, 0, 4, 401, 401)