Ini ialah arahan PDL::Threadingp yang boleh dijalankan dalam penyedia pengehosan percuma OnWorks menggunakan salah satu daripada berbilang stesen kerja dalam talian percuma kami seperti Ubuntu Online, Fedora Online, emulator dalam talian Windows atau emulator dalam talian MAC OS.
JADUAL:
NAMA
PDL::Threading - Tutorial untuk ciri Threading PDL
PENGENALAN
Salah satu ciri PDL yang paling berkuasa ialah menjalar, yang boleh menghasilkan sangat padat dan
kod PDL yang sangat pantas dengan mengelakkan berbilang gelung bersarang untuk pengguna C dan BASIC
biasa dengan. Masalahnya ialah ia memerlukan sedikit masa untuk membiasakan diri, dan pengguna baharu mungkin tidak
menghargai faedah benang.
Bahasa berasaskan vektor lain, seperti MATLAB, menggunakan subset teknik benang, tetapi
PDL bersinar dengan mengeneralisasikannya sepenuhnya untuk semua jenis aplikasi berasaskan vektor.
TERMINOLOGI: PIDDLE
MATLAB biasanya merujuk kepada vektor, matriks dan tatasusunan. Perl sudah mempunyai tatasusunan, dan
istilah "vektor" dan "matriks" biasanya merujuk kepada koleksi satu dan dua dimensi
data. Tidak mempunyai istilah yang baik untuk menggambarkan objek mereka, pemaju PDL mencipta istilah itu
"piddle" untuk memberi nama kepada jenis data mereka.
A piddle terdiri daripada satu siri nombor yang disusun sebagai set data N-dimensi. Piddles
menyediakan storan yang cekap dan pengiraan pantas bagi matriks N-dimensi besar. Mereka adalah
sangat dioptimumkan untuk kerja berangka.
BERFIKIR IN TERMA OF PEMIKIRAN
Jika anda telah menggunakan PDL untuk sementara waktu, anda mungkin telah menggunakan threading tanpa
menyedarinya. Mulakan cangkerang PDL (taip "perldl" atau "pdl2" pada terminal). Kebanyakan contoh
dalam tutorial ini gunakan shell PDL. Pastikan PDL::NiceSlice dan PDL::AutoLoader adalah
didayakan. Sebagai contoh:
% pdl2
shell perlDL v1.352
...
ReadLines, NiceSlice, MultiLine didayakan
...
Nota: AutoLoader tidak didayakan ('gunakan PDL::AutoLoader' disyorkan)
pdl>
Dalam contoh ini, NiceSlice telah didayakan secara automatik, tetapi AutoLoader tidak. Bagi membolehkan
itu, taip "use PDL::AutoLoader".
Mari kita mulakan dengan dua dimensi piddle:
pdl> $a = jujukan(11,9)
pdl> p $a
[
[ 0 1 2 3 4 5 6 7 8 9 10]
[11 12 13 14 15 16 17 18 19 20 21]
[22 23 24 25 26 27 28 29 30 31 32]
[33 34 35 36 37 38 39 40 41 42 43]
[44 45 46 47 48 49 50 51 52 53 54]
[55 56 57 58 59 60 61 62 63 64 65]
[66 67 68 69 70 71 72 73 74 75 76]
[77 78 79 80 81 82 83 84 85 86 87]
[88 89 90 91 92 93 94 95 96 97 98]
]
Kaedah "maklumat" memberi anda maklumat asas tentang a piddle:
pdl> p $a->maklumat
PDL: Double D [11,9]
Ini memberitahu kita bahawa $a ialah 11 x 9 piddle terdiri daripada nombor kejituan berganda. Jika kita
ingin menambah 3 pada semua elemen dalam piddle "nxm", bahasa tradisional akan menggunakan dua
gelung bersarang:
# Kod Pseudo. Cara tradisional untuk menambah 3 pada tatasusunan.
untuk (x=0; x <n; x++) {
untuk (y=0; y < m; y++) {
a(x,y) = a(x,y) + 3
}
}
Nota: Perhatikan bahawa indeks bermula pada 0, seperti dalam Perl, C dan Java (dan tidak seperti MATLAB dan IDL).
Tetapi dengan PDL, kita hanya boleh menulis:
pdl> $b = $a + 3
pdl> p $b
[
[ 3 4 5 6 7 8 9 10 11 12 13]
[ 14 15 16 17 18 19 20 21 22 23 24]
[ 25 26 27 28 29 30 31 32 33 34 35]
[ 36 37 38 39 40 41 42 43 44 45 46]
[ 47 48 49 50 51 52 53 54 55 56 57]
[ 58 59 60 61 62 63 64 65 66 67 68]
[ 69 70 71 72 73 74 75 76 77 78 79]
[ 80 81 82 83 84 85 86 87 88 89 90]
[ 91 92 93 94 95 96 97 98 99 100 101]
]
Ini adalah contoh paling mudah untuk threading, dan ia adalah sesuatu yang semua perisian berangka
alat lakukan. Operasi "+ 3" telah digunakan secara automatik sepanjang dua dimensi. Sekarang andaikan
anda ingin menolak satu baris daripada setiap baris dalam $a:
pdl> $line = turutan(11)
pdl> p $line
[0 1 2 3 4 5 6 7 8 9 10]
pdl> $c = $a - $line
pdl> p $c
[
[ 0 0 0 0 0 0 0 0 0 0 0]
[11 11 11 11 11 11 11 11 11 11 11]
[22 22 22 22 22 22 22 22 22 22 22]
[33 33 33 33 33 33 33 33 33 33 33]
[44 44 44 44 44 44 44 44 44 44 44]
[55 55 55 55 55 55 55 55 55 55 55]
[66 66 66 66 66 66 66 66 66 66 66]
[77 77 77 77 77 77 77 77 77 77 77]
[88 88 88 88 88 88 88 88 88 88 88]
]
Dua perkara yang perlu diperhatikan di sini: Pertama, nilai $a masih sama. Cuba "p $a" untuk menyemak.
Kedua, PDL secara automatik menolak $baris daripada setiap baris dalam $a. Mengapa ia berbuat demikian? mari
lihat pada dimensi $a, $line dan $c:
pdl> p $line->info => PDL: Double D [11]
pdl> p $a->info => PDL: Double D [11,9]
pdl> p $c->info => PDL: Double D [11,9]
Jadi, kedua-dua $a dan $line mempunyai bilangan elemen yang sama dalam dimensi ke-0! Apa PDL kemudian
lakukan adalah benang di atas dimensi yang lebih tinggi dalam $a dan mengulangi operasi yang sama 9 kali ke
semua baris pada $a. Ini adalah PDL threading dalam tindakan.
Bagaimana jika anda ingin menolak $line daripada baris pertama dalam $a sahaja? Anda boleh melakukannya dengan
menyatakan baris secara eksplisit:
pdl> $a(:,0) -= $line
pdl> p $a
[
[ 0 0 0 0 0 0 0 0 0 0 0]
[11 12 13 14 15 16 17 18 19 20 21]
[22 23 24 25 26 27 28 29 30 31 32]
[33 34 35 36 37 38 39 40 41 42 43]
[44 45 46 47 48 49 50 51 52 53 54]
[55 56 57 58 59 60 61 62 63 64 65]
[66 67 68 69 70 71 72 73 74 75 76]
[77 78 79 80 81 82 83 84 85 86 87]
[88 89 90 91 92 93 94 95 96 97 98]
]
Lihat PDL::Indexing dan PDL::NiceSlice untuk mengetahui lebih lanjut tentang menentukan subset daripada piddles.
Kuasa sebenar benang datang apabila anda menyedari bahawa piddle boleh mempunyai sebarang bilangan
dimensi! Mari buat piddle 4 dimensi:
pdl> $piddle_4D = jujukan(11,3,7,2)
pdl> $c = $piddle_4D - $line
Kini $c ialah piddle dengan dimensi yang sama dengan $piddle_4D.
pdl> p $piddle_4D->info => PDL: Double D [11,3,7,2]
pdl> p $c->info => PDL: Double D [11,3,7,2]
Kali ini PDL telah mengulirkan tiga dimensi yang lebih tinggi secara automatik, menolak $line
sepanjang perjalanan.
Tetapi, mungkin anda tidak mahu menolak daripada baris (dimensi 0), tetapi daripada lajur
(dimensi 1). Bagaimanakah cara saya menolak lajur nombor daripada setiap lajur dalam $a?
pdl> $cols = turutan(9)
pdl> p $a->info => PDL: Double D [11,9]
pdl> p $cols->info => PDL: Double D [9]
Sememangnya, kita tidak boleh hanya menaip "$a - $cols". Dimensi tidak sepadan:
pdl> p $a - $cols
PDL: PDL::Ops::tolak(a,b,c): Parameter 'b'
PDL: Dimensi benang tersirat tidak sepadan 0: sepatutnya 11, ialah 9
Bagaimanakah kita memberitahu PDL bahawa kita mahu menolak daripada dimensi 1?
MEMANIPULASI DIMENSI
Terdapat banyak fungsi PDL yang membolehkan anda menyusun semula dimensi tatasusunan PDL. Mereka adalah
kebanyakannya diliputi dalam PDL::Slices. Tiga yang paling biasa ialah:
xchg
mv
menyusun semula
Kaedah: "xchg"
Kaedah "xchg" "pertukaran"dua dimensi dalam piddle:
pdl> $a = jujukan(6,7,8,9)
pdl> $a_xchg = $a->xchg(0,3)
pdl> p $a->info => PDL: Double D [6,7,8,9]
pdl> p $a_xchg->info => PDL: Double D [9,7,8,6]
| |
VV
(malap 0) (malap 3)
Perhatikan bahawa dimensi 0 dan 3 telah ditukar tanpa menjejaskan dimensi lain.
Perhatikan juga bahawa "xchg" tidak mengubah $a. Pembolehubah asal $a kekal tidak disentuh.
Kaedah: "mv"
Kaedah "mv" "bergerak" satu dimensi, dalam piddle, mengalihkan dimensi lain sebagai
perlu.
pdl> $a = jujukan(6,7,8,9) (malap 0)
pdl> $a_mv = $a->mv(0,3) |
pdl> V _____
pdl> p $a->info => PDL: Double D [6,7,8,9]
pdl> p $a_mv->info => PDL: Double D [7,8,9,6]
----- |
V
(malap 3)
Perhatikan bahawa apabila dimensi 0 dialihkan ke kedudukan 3, semua dimensi lain perlu
beralih pula. Perhatikan juga bahawa "mv" tidak mengubah $a. Pembolehubah asal $a kekal
tidak disentuh.
Kaedah: "susun semula"
Kaedah "susun semula" ialah generalisasi kaedah "xchg" dan "mv". ia"menyusun semula"
dimensi dalam apa jua cara yang anda tentukan:
pdl> $a = jujukan(6,7,8,9)
pdl> $a_reorder = $a->reorder(3,0,2,1)
pdl>
pdl> p $a->info => PDL: Double D [6,7,8,9]
pdl> p $a_reorder->info => PDL: Double D [9,6,8,7]
| | | |
VV v V
dimensi: 0 1 2 3
Perhatikan apa yang berlaku. Apabila kami menulis "susun semula(3,0,2,1)" kami mengarahkan PDL untuk:
* Utamakan dimensi 3.
* Letakkan dimensi 0 di sebelah.
* Letakkan dimensi 2 di sebelah.
* Letakkan dimensi 1 di sebelah.
Apabila anda menggunakan kaedah "susun semula", semua dimensi dikocok. Perhatikan bahawa "susun semula"
tidak mengubah $a. Pembolehubah asal $a kekal tidak disentuh.
GOTCHA: HUBUNGAN VS PENYERAHAN
Menghubungkan
Secara lalai, piddles adalah dikaitkan bersama-sama supaya perubahan pada satu akan kembali dan menjejaskan
asal as baik.
pdl> $a = jujukan(4,5)
pdl> $a_xchg = $a->xchg(1,0)
Di sini, $a_xchg is tidak a berasingan objek. Ia hanyalah cara yang berbeza untuk melihat $a. mana-mana
perubahan dalam $a_xchg akan muncul dalam $a juga.
pdl> p $a
[
[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]
[12 13 14 15]
[16 17 18 19]
]
pdl> $a_xchg += 3
pdl> p $a
[
[ 3 4 5 6]
[ 7 8 9 10]
[11 12 13 14]
[15 16 17 18]
[19 20 21 22]
]
Tugasan
Kadangkala, memaut bukanlah tingkah laku yang anda mahukan. Kalau nak buat piddle
bebas, gunakan kaedah "salinan":
pdl> $a = jujukan(4,5)
pdl> $a_xchg = $a->copy->xchg(1,0)
Sekarang $a dan $a_xchg adalah objek berasingan sepenuhnya:
pdl> p $a
[
[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]
[12 13 14 15]
[16 17 18 19]
]
pdl> $a_xchg += 3
pdl> p $a
[
[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]
[12 13 14 15]
[16 17 18 19]
]
pdl> $a_xchg
[
[ 3 7 11 15 19]
[ 4 8 12 16 20]
[ 5 9 13 17 21]
[ 6 10 14 18 22]
]
MELETAKKAN IT SEMUA KAMI
Sekarang kami bersedia untuk menyelesaikan masalah yang mendorong keseluruhan perbincangan ini:
pdl> $a = jujukan(11,9)
pdl> $cols = turutan(9)
pdl>
pdl> p $a->info => PDL: Double D [11,9]
pdl> p $cols->info => PDL: Double D [9]
Bagaimanakah kita memberitahu PDL untuk menolak $cols sepanjang dimensi 1 dan bukannya dimensi 0? The
cara paling mudah ialah menggunakan kaedah "xchg" dan bergantung pada pautan PDL:
pdl> p $a
[
[ 0 1 2 3 4 5 6 7 8 9 10]
[11 12 13 14 15 16 17 18 19 20 21]
[22 23 24 25 26 27 28 29 30 31 32]
[33 34 35 36 37 38 39 40 41 42 43]
[44 45 46 47 48 49 50 51 52 53 54]
[55 56 57 58 59 60 61 62 63 64 65]
[66 67 68 69 70 71 72 73 74 75 76]
[77 78 79 80 81 82 83 84 85 86 87]
[88 89 90 91 92 93 94 95 96 97 98]
]
pdl> $a->xchg(1,0) -= $cols
pdl> p $a
[
[ 0 1 2 3 4 5 6 7 8 9 10]
[10 11 12 13 14 15 16 17 18 19 20]
[20 21 22 23 24 25 26 27 28 29 30]
[30 31 32 33 34 35 36 37 38 39 40]
[40 41 42 43 44 45 46 47 48 49 50]
[50 51 52 53 54 55 56 57 58 59 60]
[60 61 62 63 64 65 66 67 68 69 70]
[70 71 72 73 74 75 76 77 78 79 80]
[80 81 82 83 84 85 86 87 88 89 90]
]
Strategi Umum:
Alihkan dimensi yang anda mahu kendalikan ke permulaan dimensi piddle anda
senarai. Kemudian biarkan benang PDL melebihi dimensi yang lebih tinggi.
CONTOH: CONWAY'S PERMAINAN OF LIFE
Okay, cukup teori. Mari lakukan sesuatu yang lebih menarik: Kami akan menulis Conway Permainan
of Kehidupan dalam PDL dan lihat betapa hebatnya PDL!
. Permainan of Kehidupan ialah simulasi yang dijalankan pada grid dua dimensi yang besar. Setiap sel dalam grid
boleh sama ada hidup atau mati (diwakili oleh 1 atau 0). Generasi sel seterusnya dalam
grid dikira dengan peraturan mudah mengikut bilangan sel hidup di dalamnya
kejiranan terdekat:
1) Jika sel kosong mempunyai tepat tiga jiran, sel hidup dijana.
2) Jika sel hidup mempunyai kurang daripada dua jiran, ia mati kerana makan berlebihan.
3) Jika sel hidup mempunyai 4 atau lebih jiran, ia mati kerana kelaparan.
Hanya generasi pertama sel ditentukan oleh pengaturcara. Selepas itu, yang
simulasi berjalan sepenuhnya mengikut peraturan ini. Untuk mengira generasi akan datang, anda
perlu melihat setiap sel dalam medan 2D (memerlukan dua gelung), hitung bilangan
sel hidup bersebelahan dengan sel ini (memerlukan dua gelung lagi) dan kemudian mengisi seterusnya
grid penjanaan.
Klasik pelaksanaan
Berikut ialah cara klasik untuk menulis program ini dalam Perl. Kami hanya menggunakan PDL untuk menangani
sel individu.
#!/usr/bin/perl -w
gunakan PDL;
gunakan PDL::NiceSlice;
# Buat papan untuk permainan kehidupan.
$nx saya = 20;
$ny saya = 20;
# Generasi semasa.
$a saya = sifar($nx, $ny);
# Generasi seterusnya.
$n saya = sifar($nx, $ny);
# Masukkan glider mudah.
$a(1:3,1:3) .= pdl ( [1,1,1],
[0,0,1],
[0,1,0] );
untuk ( $i saya = 0; $i < 100; $i++) {
$n = sifar($nx, $ny);
$new_a = $a->salinan;
untuk ($x = 0; $x < $nx; $x++) {
untuk ($y = 0; $y < $ny; $y++) {
# Untuk setiap sel, lihat jiran sekeliling.
untuk ($dx = -1; $dx <= 1; $dx++) {
untuk ($dy = -1; $dy <= 1; $dy++) {
$px = $x + $dx;
$py = $y + $dy;
# Balut di tepi.
jika ($px < 0) {$px = $nx-1};
jika ($py < 0) {$py = $ny-1};
jika ($px >= $nx) {$px = 0};
jika ($py >= $ny) {$py = 0};
$n($x,$y) .= $n($x,$y) + $a($px,$py);
}
}
# Jangan mengira sel pusat itu sendiri.
$n($x,$y) -= $a($x,$y);
# Bersenam jika sel hidup atau mati:
# Sel mati hidup jika n = 3
# Sel hidup mati jika n bukan 2 atau 3
jika ($a($x,$y) == 1) {
jika ($n($x,$y) < 2) {$new_a($x,$y) .= 0};
jika ($n($x,$y) > 3) {$new_a($x,$y) .= 0};
} Lain {
jika ($n($x,$y) == 3) {$new_a($x,$y) .= 1}
}
}
}
cetak $a;
$a = $new_a;
}
Jika anda menjalankan ini, anda akan melihat peluncur kecil merangkak menyerong merentasi grid sifar.
Pada mesin saya, ia mencetak beberapa generasi sesaat.
Diulirkan PDL pelaksanaan
Dan inilah versi berulir dalam PDL. Hanya empat baris kod PDL, dan salah satunya ialah
mencetak generasi terkini!
#!/usr/bin/perl -w
gunakan PDL;
gunakan PDL::NiceSlice;
$a saya = sifar(20,20);
# Masukkan glider mudah.
$a(1:3,1:3) .= pdl ( [1,1,1],
[0,0,1],
[0,1,0] );
$n saya;
untuk ( $i saya = 0; $i < 100; $i++) {
# Kira bilangan jiran setiap sel.
$n = $a->julat(ndcoords($a)-1,3,"berkala")->susun semula(2,3,0,1);
$n = $n->sumover->sumover - $a;
# Kira generasi akan datang.
$a = ((($n == 2) + ($n == 3))* $a) + (($n==3) * !$a);
cetak $a;
}
Versi PDL berulir adalah lebih pantas:
Klasik => 32.79 saat.
Berbenang => 0.41 saat.
penjelasan
Bagaimanakah versi berulir berfungsi?
Terdapat banyak fungsi PDL yang direka untuk membantu anda menjalankan penjalinan PDL. Di dalam ini
contoh, fungsi utama ialah:
Kaedah: "julat"
Pada tahap yang paling mudah, kaedah "julat" ialah cara yang berbeza untuk memilih sebahagian daripada a
piddle. Daripada menggunakan notasi "$a(2,3)", kami menggunakan piddle lain.
pdl> $a = jujukan(6,7)
pdl> p $a
[
[ 0 1 2 3 4 5]
[ 6 7 8 9 10 11]
[12 13 14 15 16 17]
[18 19 20 21 22 23]
[24 25 26 27 28 29]
[30 31 32 33 34 35]
[36 37 38 39 40 41]
]
pdl> p $a->julat( pdl [1,2] )
13
pdl> p $a(1,2)
[
[13]
]
Pada ketika ini, kaedah "julat" kelihatan sangat serupa dengan kepingan PDL biasa. Tetapi
kaedah "julat" adalah lebih umum. Sebagai contoh, anda boleh memilih beberapa komponen sekaligus:
pdl> $index = pdl [ [1,2],[2,3],[3,4],[4,5] ]
pdl> p $a->julat( $index )
[13 20 27 34]
Selain itu, "julat" mengambil parameter kedua yang menentukan saiz bongkah
kembali:
pdl> $saiz = 3
pdl> p $a->julat( pdl([1,2]) , $saiz )
[
[13 14 15]
[19 20 21]
[25 26 27]
]
Kita boleh menggunakan ini untuk memilih satu atau lebih kotak 3x3.
Akhir sekali, "julat" boleh mengambil parameter ketiga yang dipanggil keadaan "sempadan". Ia memberitahu PDL
apa yang perlu dilakukan jika kotak saiz yang anda minta melepasi tepi piddle. Kami tidak akan pergi
atas semua pilihan. Kami hanya akan mengatakan bahawa pilihan "berkala" bermakna piddle
"berbungkus". Sebagai contoh:
pdl> p $a
[
[ 0 1 2 3 4 5]
[ 6 7 8 9 10 11]
[12 13 14 15 16 17]
[18 19 20 21 22 23]
[24 25 26 27 28 29]
[30 31 32 33 34 35]
[36 37 38 39 40 41]
]
pdl> $saiz = 3
pdl> p $a->julat( pdl([4,2]) , $saiz , "berkala" )
[
[16 17 12]
[22 23 18]
[28 29 24]
]
pdl> p $a->julat( pdl([5,2]) , $saiz , "berkala" )
[
[17 12 13]
[23 18 19]
[29 24 25]
]
Perhatikan bagaimana kotak itu melilit sempadan piddle.
Kaedah: "ndcoords"
Kaedah "ndcoords" ialah kaedah kemudahan yang mengembalikan senarai terhitung
koordinat yang sesuai digunakan dengan kaedah "julat".
pdl> p $piddle = urutan(3,3)
[
[0 1 2]
[3 4 5]
[6 7 8]
]
pdl> p ndcoords($piddle)
[
[
[0 0]
[1 0]
[2 0]
]
[
[0 1]
[1 1]
[2 1]
]
[
[0 2]
[1 2]
[2 2]
]
]
Ini boleh menjadi agak sukar untuk dibaca. Pada asasnya ia mengatakan bahawa koordinat untuk setiap
elemen dalam $piddle diberikan oleh:
(0,0) (1,0) (2,0)
(1,0) (1,1) (2,1)
(2,0) (2,1) (2,2)
Menggabungkan "julat" and "ndcoords"
Apa yang benar-benar penting ialah "ndcoords" direka untuk bekerja bersama-sama dengan "julat", dengan no
Parameter $size, anda mendapat piddle yang sama kembali.
pdl> p $piddle
[
[0 1 2]
[3 4 5]
[6 7 8]
]
pdl> p $piddle->range( ndcoords($piddle) )
[
[0 1 2]
[3 4 5]
[6 7 8]
]
Mengapa ini berguna? Kerana sekarang kita boleh meminta satu siri "kotak" untuk keseluruhannya
piddle. Contohnya, kotak 2x2:
pdl> p $piddle->range( ndcoords($piddle) , 2 , "berkala" )
Output fungsi ini sukar dibaca kerana "kotak" di sepanjang dua terakhir
dimensi. Kita boleh membuat keputusan lebih mudah dibaca dengan menyusun semula dimensi:
pdl> p $piddle->range( ndcoords($piddle) , 2 , "periodik" )->urut semula(2,3,0,1)
[
[
[
[0 1]
[3 4]
]
[
[1 2]
[4 5]
]
...
]
Di sini anda boleh melihat dengan lebih jelas lagi
[0 1]
[3 4]
Adakah kotak 2x2 bermula dengan elemen (0,0) $piddle.
Kami belum selesai. Untuk permainan kehidupan, kami mahukan kotak 3x3 daripada $a:
pdl> p $a
[
[ 0 1 2 3 4 5]
[ 6 7 8 9 10 11]
[12 13 14 15 16 17]
[18 19 20 21 22 23]
[24 25 26 27 28 29]
[30 31 32 33 34 35]
[36 37 38 39 40 41]
]
pdl> p $a->julat( ndcoords($a) , 3 , "berkala" )->susun semula(2,3,0,1)
[
[
[
[ 0 1 2]
[ 6 7 8]
[12 13 14]
]
...
]
Kami boleh mengesahkan bahawa ini ialah kotak 3x3 bermula dengan (0,0) elemen $a. Tetapi di sana
adalah satu masalah. Kami sebenarnya mahukan kotak 3x3 itu berpusat pada (0,0). Itu bukan a
masalah. Hanya tolak 1 daripada semua koordinat dalam "ndcoords($a)". Ingat bahawa
Pilihan "berkala" mengurus segala-galanya.
pdl> p $a->julat( ndcoords($a) - 1 , 3 , "berkala" )->susun semula(2,3,0,1)
[
[
[
[41 36 37]
[ 5 0 1]
[11 6 7]
]
[
[36 37 38]
[ 0 1 2]
[ 6 7 8]
]
...
Sekarang kita melihat kotak 3x3 dengan elemen (0,0) di tengah kotak.
Kaedah: "sumover"
Kaedah "sumover" menambah hanya dimensi pertama. Jika kita menerapkannya dua kali, kita akan menjadi
menambah semua elemen setiap kotak 3x3.
pdl> $n = $a->julat(ndcoords($a)-1,3,"berkala")->susun semula(2,3,0,1)
pdl> p $n
[
[
[
[41 36 37]
[ 5 0 1]
[11 6 7]
]
[
[36 37 38]
[ 0 1 2]
[ 6 7 8]
]
...
pdl> p $n->sumover->sumover
[
[144 135 144 153 162 153]
[ 72 63 72 81 90 81]
[126 117 126 135 144 135]
[180 171 180 189 198 189]
[234 225 234 243 252 243]
[288 279 288 297 306 297]
[216 207 216 225 234 225]
]
Gunakan kalkulator untuk mengesahkan bahawa 144 ialah jumlah semua elemen dalam kotak 3x3 pertama
dan 135 ialah hasil tambah semua unsur dalam kotak 3x3 kedua.
Mengira jiran
Kami hampir sampai!
Menambah semua elemen dalam kotak 3x3 adalah tidak agak apa yang kita mahu. Kami tidak mahu mengira
kotak tengah. Nasib baik, ini adalah penyelesaian yang mudah:
pdl> p $n->sumover->sumover - $a
[
[144 134 142 150 158 148]
[ 66 56 64 72 80 70]
[114 104 112 120 128 118]
[162 152 160 168 176 166]
[210 200 208 216 224 214]
[258 248 256 264 272 262]
[180 170 178 186 194 184]
]
Apabila digunakan pada Permainan Kehidupan Conway, ini akan memberitahu kita berapa ramai jiran hidup setiap satu
sel mempunyai:
pdl> $a = sifar(10,10)
pdl> $a(1:3,1:3) .= pdl ( [1,1,1],
..( > [0,0,1],
..( > [0,1,0] )
pdl> p $a
[
[0 0 0 0 0 0 0 0 0 0.
[0 1 1 1 0 0 0 0 0 0.
[0 0 0 1 0 0 0 0 0 0.
[0 0 1 0 0 0 0 0 0 0.
[0 0 0 0 0 0 0 0 0 0.
[0 0 0 0 0 0 0 0 0 0.
[0 0 0 0 0 0 0 0 0 0.
[0 0 0 0 0 0 0 0 0 0.
[0 0 0 0 0 0 0 0 0 0.
[0 0 0 0 0 0 0 0 0 0.
]
pdl> $n = $a->julat(ndcoords($a)-1,3,"berkala")->susun semula(2,3,0,1)
pdl> $n = $n->sumover->sumover - $a
pdl> p $n
[
[1 2 3 2 1 0 0 0 0 0.
[1 1 3 2 2 0 0 0 0 0.
[1 3 5 3 2 0 0 0 0 0.
[0 1 1 2 1 0 0 0 0 0.
[0 1 1 1 0 0 0 0 0 0.
[0 0 0 0 0 0 0 0 0 0.
[0 0 0 0 0 0 0 0 0 0.
[0 0 0 0 0 0 0 0 0 0.
[0 0 0 0 0 0 0 0 0 0.
[0 0 0 0 0 0 0 0 0 0.
]
Sebagai contoh, ini memberitahu kita bahawa sel (0,0) mempunyai 1 jiran hidup, manakala sel (2,2) mempunyai 5
jiran yang tinggal.
Mengira yang seterusnya generasi
Pada ketika ini, pembolehubah $n mempunyai bilangan jiran hidup untuk setiap sel. Sekarang kita
menggunakan peraturan permainan kehidupan untuk mengira generasi akan datang.
Jika sel kosong mempunyai tepat tiga jiran, sel hidup akan dihasilkan.
Dapatkan senarai sel yang mempunyai tepat tiga jiran:
pdl> p ($n == 3)
[
[0 0 1 0 0 0 0 0 0 0.
[0 0 1 0 0 0 0 0 0 0.
[0 1 0 1 0 0 0 0 0 0.
[0 0 0 0 0 0 0 0 0 0.
[0 0 0 0 0 0 0 0 0 0.
[0 0 0 0 0 0 0 0 0 0.
[0 0 0 0 0 0 0 0 0 0.
[0 0 0 0 0 0 0 0 0 0.
[0 0 0 0 0 0 0 0 0 0.
[0 0 0 0 0 0 0 0 0 0.
]
Dapatkan senarai kosong sel yang mempunyai tepat tiga jiran:
pdl> p ($n == 3) * !$a
Jika sel hidup mempunyai kurang daripada 2 atau lebih daripada 3 jiran, ia akan mati.
Dapatkan senarai sel yang mempunyai tepat 2 atau 3 jiran:
pdl> p (($n == 2) + ($n == 3))
[
[0 1 1 1 0 0 0 0 0 0.
[0 0 1 1 1 0 0 0 0 0.
[0 1 0 1 1 0 0 0 0 0.
[0 0 0 1 0 0 0 0 0 0.
[0 0 0 0 0 0 0 0 0 0.
[0 0 0 0 0 0 0 0 0 0.
[0 0 0 0 0 0 0 0 0 0.
[0 0 0 0 0 0 0 0 0 0.
[0 0 0 0 0 0 0 0 0 0.
[0 0 0 0 0 0 0 0 0 0.
]
Dapatkan senarai hidup sel yang mempunyai tepat 2 atau 3 jiran:
pdl> p (($n == 2) + ($n == 3)) * $a
Menyatukan semuanya, generasi seterusnya ialah:
pdl> $a = ((($n == 2) + ($n == 3)) * $a) + (($n == 3) * !$a)
pdl> p $a
[
[0 0 1 0 0 0 0 0 0 0.
[0 0 1 1 0 0 0 0 0 0.
[0 1 0 1 0 0 0 0 0 0.
[0 0 0 0 0 0 0 0 0 0.
[0 0 0 0 0 0 0 0 0 0.
[0 0 0 0 0 0 0 0 0 0.
[0 0 0 0 0 0 0 0 0 0.
[0 0 0 0 0 0 0 0 0 0.
[0 0 0 0 0 0 0 0 0 0.
[0 0 0 0 0 0 0 0 0 0.
]
bonus ciri ini: Grafik!
Jika anda telah memasang PDL::Graphics::TriD, anda boleh membuat versi grafik program
dengan hanya menukar tiga baris:
#!/usr/bin/perl
gunakan PDL;
gunakan PDL::NiceSlice;
gunakan PDL::Graphics::TriD;
$a saya = sifar(20,20);
# Masukkan glider mudah.
$a(1:3,1:3) .= pdl ( [1,1,1],
[0,0,1],
[0,1,0] );
$n saya;
untuk ( $i saya = 0; $i < 100; $i++) {
# Kira bilangan jiran setiap sel.
$n = $a->julat(ndcoords($a)-1,3,"berkala")->susun semula(2,3,0,1);
$n = $n->sumover->sumover - $a;
# Kira generasi akan datang.
$a = ((($n == 2) + ($n == 3))* $a) + (($n==3) * !$a);
# Paparan.
nokeeptwiddling3d();
imagrgb [$a];
}
Tetapi jika kita benar-benar ingin melihat sesuatu yang menarik, kita harus membuat beberapa perubahan lagi:
1) Mulakan dengan koleksi rawak 1 dan 0.
2) Jadikan grid lebih besar.
3) Tambahkan tamat masa kecil supaya kami dapat melihat permainan berkembang dengan lebih baik.
4) Gunakan gelung sementara supaya atur cara boleh berjalan selama yang diperlukan.
#!/usr/bin/perl
gunakan PDL;
gunakan PDL::NiceSlice;
gunakan PDL::Graphics::TriD;
gunakan Masa::HiRes qw(usleep);
$a saya = rawak(100,100);
$a = ($a < 0.5);
$n saya;
manakala (1) {
# Kira bilangan jiran setiap sel.
$n = $a->julat(ndcoords($a)-1,3,"berkala")->susun semula(2,3,0,1);
$n = $n->sumover->sumover - $a;
# Kira generasi akan datang.
$a = ((($n == 2) + ($n == 3))* $a) + (($n==3) * !$a);
# Paparan.
nokeeptwiddling3d();
imagrgb [$a];
# Tidur selama 0.1 saat.
tidur(100000);
}
KESIMPULAN: UMUM STRATEGI
Strategi umum ialah: Bergerak yang dimensi anda mahu kepada beroperasi on kepada yang permulaan of Matlamat
piddle's dimensi senarai. Kemudian biarkan PDL thread lebih yang yang lebih tinggi dimensi.
Threading ialah alat berkuasa yang membantu menghapuskan gelung untuk dan boleh menjadikan kod anda lebih banyak
ringkas. Mudah-mudahan tutorial ini telah menunjukkan mengapa ia berbaloi untuk menguasai benang
dalam PDL.
HAKCIPTA
Hak Cipta 2010 Matthew Kenworthy ([e-mel dilindungi]) dan Daniel Carrera
([e-mel dilindungi]). Anda boleh mengedarkan dan/atau mengubah suai dokumen ini di bawah syarat yang sama
sebagai lesen Perl semasa.
Lihat: http://dev.perl.org/licenses/
Gunakan PDL::Threadingp dalam talian menggunakan perkhidmatan onworks.net