V čisto prvi "lekciji" sem se rekel, da morata biti tabeli, ki ju želimo seštevati, množiti ali karkoli že, enakih dimenzij.
Zlagal sem se.
K tabeli z n stolpci in poljubnim številom vrstic lahko prištejemo (primnožimo, odštejemo ...) enodimenzionalno tabelo z n elementi. Prištel jih bo k vsaki vrstici. Vendar nam to pri tej nalogi ne bo pomagalo. :)
Bolj zanimivo je tole:
import numpy as np
= np.array([[1], [2], [3], [4]])
f = np.array([1, 10, 100]) g
f
array([[1],
[2],
[3],
[4]])
g
array([ 1, 10, 100])
Pomnožimo ju: f
bo prispeval vrstice in g
stolpce. Če se dimenzije ne ujemajo, ne bo nič hudega.
* g f
array([[ 1, 10, 100],
[ 2, 20, 200],
[ 3, 30, 300],
[ 4, 40, 400]])
Vsak element je produkt ustreznih elementov. Ker je f
prispeval vrstico, g
stolpec, je
* g)[2, 1] (f
30
enak
2][0] * g[1] f[
30
(K f[2]
smo morali dodati [0]
, saj gre za
dvodimenzionalno tabelo, mi pa bi radi prišli do števila.)
To se da nadaljevati v tretjo dimenzijo.
= np.array([[[1]], [[5]], [[8]]]) e
* f * g e
array([[[ 1, 10, 100],
[ 2, 20, 200],
[ 3, 30, 300],
[ 4, 40, 400]],
[[ 5, 50, 500],
[ 10, 100, 1000],
[ 15, 150, 1500],
[ 20, 200, 2000]],
[[ 8, 80, 800],
[ 16, 160, 1600],
[ 24, 240, 2400],
[ 32, 320, 3200]]])
Zdaj e
prispeva prvi indeks, f
drugega,
g
tretjega.
* f * g)[1, 2, 0] (e
15
1][0][0] * f[2][0] * g[0] e[
15
Vrstni red množenj ni pomemben. Pomembno je, koliko dimenzij ima kdo.
* e * f g
array([[[ 1, 10, 100],
[ 2, 20, 200],
[ 3, 30, 300],
[ 4, 40, 400]],
[[ 5, 50, 500],
[ 10, 100, 1000],
[ 15, 150, 1500],
[ 20, 200, 2000]],
[[ 8, 80, 800],
[ 16, 160, 1600],
[ 24, 240, 2400],
[ 32, 320, 3200]]])
Kako si pripraviti matriko, kot je e
? Se moramo res
izgubljati v teh oglatih oklepajih? Tu nam pomaga še en trik pri
indeksiranju: kot enega od indeksov lahko podamo None
. Ta
bo v tabelo, ki jo dobimo kot rezultat, dodal novo dimenzijo velikosti
1.
Tabela e
je oblike
e.shape
(3, 1, 1)
Lahko bi začeli z
= np.array([1, 5, 0])
e
e.shape
(3,)
in mu dodali manjkajoči dimenziji z dvema None
.
None, None] e[:,
array([[[1]],
[[5]],
[[0]]])
None, None].shape e[:,
(3, 1, 1)
Kar smo počeli zgoraj, je torej ekvivalentno temu:
= np.array([1, 2, 3, 4])
f = np.array([1, 10, 100])
g = np.array([1, 2, 3])
e
None, None] * f[:, None] * g e[:,
array([[[ 1, 10, 100],
[ 2, 20, 200],
[ 3, 30, 300],
[ 4, 40, 400]],
[[ 2, 20, 200],
[ 4, 40, 400],
[ 6, 60, 600],
[ 8, 80, 800]],
[[ 3, 30, 300],
[ 6, 60, 600],
[ 9, 90, 900],
[ 12, 120, 1200]]])
Obratna operacija je flatten
. Ta splošči tabelo v eno
dimenzijo.
= np.array([[3, 6, 1], [2, 5, 7], [1, 2, 8]])
a
a
array([[3, 6, 1],
[2, 5, 7],
[1, 2, 8]])
a.flatten()
array([3, 6, 1, 2, 5, 7, 1, 2, 8])
Tale naloga ni nadležna, zahteva pa nekaj razmišljanja, nekaj znanja
Pythona in spretno uporabo numpy
-ja. Ni preprosta, ni pa
ena tistih, s katerimi se zafrkavaš v nedogled in si slabe volje celo
potem, ko ti uspe. Vsaj meni se ni zdela takšne.
Rešite jo, pa četudi najprej v čistem Pythonu, brez
numpy
-ja.
Pazite, v drugem delu primer iz opisa naloge uporablja druge podatke.
Spoilerji.
Trik je v tem, da bo elementov več, kot jih gre v pomnilnik. Mej med
njimi pa ne. Predstavljajmo si, da vsaka koordinata, na katero naletimo
pri prižiganju in ugašanju, prereže reaktor. Šestkrat - dvakrat po
x
, dvakrat po y
, dvakrat po z
.
Pri reševanju prvega dela je vsak element matrike ustrezal eni kocki
reaktorja. Zdaj bo vsak element ustrezal celemu bloku. Bloke bo potrebno
oštevilčiti, po vrsti. Slovar je vaš prijatelj, gre pa tudi z običajnimi
indeksi.
Na koncu nas ne bo zanimalo število prižganih blokov temveč kock. Za to bo potrebno izračunati prostornine blokov. Tu in predvsem tu pa bo prišlo prav, kar smo se pravkar naučili.