นี่คือคำสั่ง PDL::Threadingp ที่สามารถเรียกใช้ในผู้ให้บริการโฮสติ้งฟรีของ OnWorks โดยใช้หนึ่งในเวิร์กสเตชันออนไลน์ฟรีของเรา เช่น Ubuntu Online, Fedora Online, โปรแกรมจำลองออนไลน์ของ Windows หรือโปรแกรมจำลองออนไลน์ของ MAC OS
โครงการ:
ชื่อ
PDL::Threading - บทช่วยสอนสำหรับฟีเจอร์การทำเกลียวของ PDL
บทนำ
หนึ่งในคุณสมบัติที่ทรงพลังที่สุดของ PDL คือ เกลียวซึ่งสามารถผลิตได้กระทัดรัดและ
รหัส PDL ที่รวดเร็วมากโดยหลีกเลี่ยงการซ้อนหลายลูปที่ผู้ใช้ C และ BASIC อาจเป็น
คุ้นเคยกับ. ปัญหาคือต้องใช้เวลาทำความคุ้นเคยและผู้ใช้ใหม่อาจไม่
ชื่นชมประโยชน์ของการร้อยด้าย
ภาษาที่ใช้เวกเตอร์อื่น ๆ เช่น MATLAB ใช้เทคนิคการทำเธรดชุดย่อย แต่
PDL เปล่งประกายด้วยการทำให้เป็นแบบทั่วไปอย่างสมบูรณ์สำหรับแอปพลิเคชันที่ใช้เวกเตอร์ทุกประเภท
คำศัพท์: ถ่ายปัสสาวะ
โดยทั่วไปแล้ว MATLAB จะอ้างถึงเวกเตอร์ เมทริกซ์ และอาร์เรย์ Perl มีอาร์เรย์อยู่แล้วและ
คำว่า "เวกเตอร์" และ "เมทริกซ์" โดยทั่วไปหมายถึงคอลเล็กชันหนึ่งและสองมิติของ
ข้อมูล. ไม่มีคำศัพท์ที่ดีในการอธิบายวัตถุของพวกเขา นักพัฒนา PDL ได้สร้างคำว่า
"ถ่ายปัสสาวะ" เพื่อตั้งชื่อให้กับประเภทข้อมูลของตน
A ถ่ายปัสสาวะ ประกอบด้วยชุดตัวเลขที่จัดเป็นชุดข้อมูล N- มิติ พิดเดิ้ล
ให้การจัดเก็บที่มีประสิทธิภาพและการคำนวณที่รวดเร็วของเมทริกซ์ N- มิติขนาดใหญ่ พวกเขาคือ
เหมาะอย่างยิ่งสำหรับงานเชิงตัวเลข
กำลังคิด IN เงื่อนไข OF เธรด
หากคุณเคยใช้ PDL มาสักระยะแล้ว คุณอาจเคยใช้การทำเกลียวโดยไม่มี
ตระหนักถึงมัน เริ่มเชลล์ PDL (พิมพ์ "perldl" หรือ "pdl2" บนเทอร์มินัล) ตัวอย่างส่วนใหญ่
ในบทช่วยสอนนี้ให้ใช้เชลล์ PDL ตรวจสอบให้แน่ใจว่า PDL::NiceSlice และ PDL::AutoLoader เป็น
เปิดใช้งาน ตัวอย่างเช่น:
% pdl2
เชลล์ perlDL v1.352
...
ReadLines, NiceSlice, เปิดใช้งาน MultiLines
...
หมายเหตุ: ไม่ได้เปิดใช้งาน AutoLoader (แนะนำให้ใช้ PDL::AutoLoader)
pdl>
ในตัวอย่างนี้ NiceSlice ถูกเปิดใช้งานโดยอัตโนมัติ แต่ AutoLoader ไม่ได้เปิดใช้งาน การเปิดใช้งาน
มันพิมพ์ "use PDL::AutoLoader"
เริ่มต้นด้วยสองมิติ ถ่ายปัสสาวะ:
pdl> $a = ลำดับ (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]
]
วิธี "ข้อมูล" ให้ข้อมูลพื้นฐานเกี่ยวกับa ถ่ายปัสสาวะ:
pdl> p $a->info
PDL: ดับเบิ้ลดี [11,9]
สิ่งนี้บอกเราว่า $a เป็น 11 x 9 ถ่ายปัสสาวะ ประกอบด้วยตัวเลขที่มีความแม่นยำสองเท่า ถ้าเรา
ต้องการเพิ่ม 3 องค์ประกอบทั้งหมดใน piddle "nxm" ภาษาดั้งเดิมจะใช้ two
for-ลูปที่ซ้อนกัน:
#รหัสหลอก. วิธีดั้งเดิมในการเพิ่ม 3 ลงในอาร์เรย์
สำหรับ (x=0; x < n; x++) {
สำหรับ (y=0; y < m; y++) {
ก(x,y) = ก(x,y) + 3
}
}
หมายเหตุ: สังเกตว่าดัชนีเริ่มต้นที่ 0 เช่นเดียวกับใน Perl, C และ Java (และไม่เหมือนกับ MATLAB และ IDL)
แต่ด้วย PDL เราสามารถเขียนได้ว่า:
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]
]
นี่เป็นตัวอย่างที่ง่ายที่สุดของการทำเกลียว และเป็นสิ่งที่ซอฟต์แวร์ตัวเลขทั้งหมด
เครื่องมือทำ การดำเนินการ "+ 3" ถูกนำไปใช้กับสองมิติโดยอัตโนมัติ ตอนนี้สมมติว่า
คุณต้องการลบบรรทัดจากทุกแถวใน $a:
pdl> $line = ลำดับ(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]
]
สองสิ่งที่ควรทราบที่นี่: อันดับแรก ค่าของ $a ยังคงเท่าเดิม ลอง "p $a" เพื่อตรวจสอบ
ประการที่สอง PDL จะลบ $line ออกจากแต่ละแถวใน $a โดยอัตโนมัติ ทำไมมันทำอย่างนั้น? Let's
ดูขนาดของ $a, $line และ $c:
pdl> p $line->info => PDL: ดับเบิ้ล D [11]
pdl> p $a->info => PDL: ดับเบิ้ล D [11,9]
pdl> p $c->info => PDL: ดับเบิ้ล D [11,9]
ดังนั้น ทั้ง $a และ $line มีจำนวนองค์ประกอบเท่ากันในมิติที่ 0! PDL แล้วไง
did เป็นเธรดบนมิติที่สูงกว่าใน $a และทำซ้ำการดำเนินการเดียวกัน 9 ครั้งถึง
ทุกแถวของ $a นี่คือการทำงานของเธรด PDL
เกิดอะไรขึ้นถ้าคุณต้องการลบ $line จากบรรทัดแรกใน $a เท่านั้น? คุณสามารถทำได้โดย
ระบุบรรทัดอย่างชัดเจน:
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]
]
ดู PDL::Indexing และ PDL::NiceSlice เพื่อเรียนรู้เพิ่มเติมเกี่ยวกับการระบุชุดย่อยจาก piddles
พลังที่แท้จริงของการร้อยด้ายจะเกิดขึ้นเมื่อคุณรู้ว่าพิดเดิ้ลสามารถมีจำนวน
มิติ! มาทำพิดเดิ้ล 4 มิติกันเถอะ:
pdl> $piddle_4D = ลำดับ (11,3,7,2)
pdl> $c = $piddle_4D - $line
ตอนนี้ $c เป็น piddle ที่มีมิติเท่ากับ $piddle_4D
pdl> p $piddle_4D->info => PDL: ดับเบิ้ล D [11,3,7,2]
pdl> p $c->info => PDL: ดับเบิ้ล D [11,3,7,2]
คราวนี้ PDL ได้เธรดบนมิติที่สูงกว่าสามส่วนโดยอัตโนมัติ โดยลบ $line
ทุกทาง.
แต่บางทีคุณอาจไม่ต้องการลบออกจากแถว (มิติ 0) แต่จากคอลัมน์
(มิติที่ 1). ฉันจะลบคอลัมน์ของตัวเลขออกจากแต่ละคอลัมน์ใน $a ได้อย่างไร
pdl> $cols = ลำดับ(9)
pdl> p $a->info => PDL: ดับเบิ้ล D [11,9]
pdl> p $cols->info => PDL: ดับเบิล D [9]
แน่นอนว่าเราไม่สามารถพิมพ์ "$a - $cols" ได้ ขนาดไม่ตรงกัน:
pdl> p $a - $cols
PDL: PDL::Ops::ลบ (a,b,c): พารามิเตอร์ 'b'
PDL: ขนาดเธรดโดยนัยที่ไม่ตรงกัน 0: ควรเป็น 11 คือ 9
เราจะบอก PDL ว่าต้องการลบออกจากมิติที่ 1 แทนได้อย่างไร?
การจัดการ DIMENSIONS
มีฟังก์ชัน PDL มากมายที่ช่วยให้คุณจัดเรียงมิติข้อมูลของอาร์เรย์ PDL ใหม่ได้ พวกเขาคือ
ส่วนใหญ่ครอบคลุมใน PDL::Slices สามสิ่งที่พบบ่อยที่สุดคือ:
xchg
mv
สั่งใหม่
วิธีการ: "xchg"
วิธี "xchg" "แลกเปลี่ยน" สองมิติในพิณ:
pdl> $a = ลำดับ (6,7,8,9)
pdl> $a_xchg = $a->xchg(0,3)
pdl> p $a->info => PDL: ดับเบิ้ล D [6,7,8,9]
pdl> p $a_xchg->info => PDL: ดับเบิ้ล D [9,7,8,6]
| |
VV
(ติ่มซำ 0) (ติ่มซำ 3)
สังเกตว่ามิติ 0 และ 3 ถูกแลกเปลี่ยนโดยไม่กระทบกับมิติอื่น
โปรดสังเกตว่า "xchg" จะไม่เปลี่ยนแปลง $a ตัวแปรเดิม $a ยังคงไม่ถูกแตะต้อง
วิธีการ: "เอ็มวี"
วิธีการ "mv" "ย้าย" หนึ่งมิติ, ในแอ่ง, ขยับมิติอื่นเป็น
จำเป็น
pdl> $a = ลำดับ (6,7,8,9) (ติ่มซำ 0)
pdl> $a_mv = $a->mv(0,3) |
pdl> วี _____
pdl> p $a->info => PDL: ดับเบิ้ล D [6,7,8,9]
pdl> p $a_mv->info => PDL: ดับเบิ้ล D [7,8,9,6]
-
V
(ติ่มซำ 3)
สังเกตว่าเมื่อมิติ 0 ถูกย้ายไปยังตำแหน่ง 3 มิติอื่นๆ ทั้งหมดจะต้องเป็น
เปลี่ยนไปเช่นกัน โปรดสังเกตว่า "mv" จะไม่เปลี่ยนแปลง $a ตัวแปรเดิม $a ยังคงอยู่
ไม่ถูกแตะต้อง
วิธีการ: "เรียงลำดับใหม่"
วิธีการ "เรียงลำดับใหม่" เป็นลักษณะทั่วไปของวิธี "xchg" และ "mv" มัน "เรียงลำดับใหม่"
มิติข้อมูลในแบบที่คุณระบุ:
pdl> $a = ลำดับ (6,7,8,9)
pdl> $a_reorder = $a->เรียงลำดับใหม่(3,0,2,1)
pdl>
pdl> p $a->info => PDL: ดับเบิ้ล D [6,7,8,9]
pdl> p $a_reorder->info => PDL: ดับเบิ้ล D [9,6,8,7]
- - - -
VV v V
ขนาด: 0 1 2 3
สังเกตว่าเกิดอะไรขึ้น เมื่อเราเขียน "reorder(3,0,2,1)" เราสั่งให้ PDL:
* ใส่มิติที่ 3 ก่อน
* ใส่มิติ 0 ต่อไป
* ใส่มิติ 2 ต่อไป
* ใส่มิติ 1 ต่อไป
เมื่อคุณใช้วิธี "จัดลำดับใหม่" มิติข้อมูลทั้งหมดจะถูกสับเปลี่ยน สังเกตว่า "เรียงลำดับใหม่"
ไม่เปลี่ยนแปลง $a ตัวแปรเดิม $a ยังคงไม่ถูกแตะต้อง
GOTCHA: ลิงค์ VS ASSIGNMENT
การเชื่อมโยง
โดยค่าเริ่มต้น piddles are ที่เชื่อมโยง ร่วมกัน เพื่อให้การเปลี่ยนแปลงหนึ่งจะกลับไปและส่งผลกระทบต่อ
เป็นต้นฉบับ as ดี.
pdl> $a = ลำดับ (4,5)
pdl> $a_xchg = $a->xchg(1,0)
ที่นี่ $a_xchg is ไม่ a แยก วัตถุ. มันเป็นเพียงวิธีที่แตกต่างในการดู $a ใด ๆ
การเปลี่ยนแปลงใน $a_xchg จะปรากฏใน $a ด้วย
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]
]
การมอบหมาย
บางครั้ง การเชื่อมโยงไม่ใช่พฤติกรรมที่คุณต้องการ ถ้าอยากทำพิดเดิ้ล
อิสระใช้วิธี "คัดลอก":
pdl> $a = ลำดับ (4,5)
pdl> $a_xchg = $a->copy->xchg(1,0)
ตอนนี้ $a และ $a_xchg เป็นวัตถุที่แยกจากกันโดยสิ้นเชิง:
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]
]
พัตต์ IT ทั้งหมด ด้วยกัน
ตอนนี้เราพร้อมที่จะแก้ปัญหาที่กระตุ้นการสนทนาทั้งหมดนี้:
pdl> $a = ลำดับ (11,9)
pdl> $cols = ลำดับ(9)
pdl>
pdl> p $a->info => PDL: ดับเบิ้ล D [11,9]
pdl> p $cols->info => PDL: ดับเบิล D [9]
เราจะบอกให้ PDL ลบ $cols ตามมิติที่ 1 แทนที่จะเป็นมิติ 0 ได้อย่างไร ดิ
วิธีที่ง่ายที่สุดคือใช้วิธี "xchg" และพึ่งพาการเชื่อมโยง 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]
]
กลยุทธ์ทั่วไป:
ย้ายมิติข้อมูลที่คุณต้องการใช้งานไปยังจุดเริ่มต้นของมิติพิดเดิลของคุณ
รายการ. จากนั้นให้ PDL ทำงานบนมิติที่สูงขึ้น
ตัวอย่าง: คอนเวย์ GAME OF ชีวิต
เอาล่ะทฤษฎีเพียงพอ มาทำอะไรที่น่าสนใจกว่านี้หน่อย: เราจะเขียน คอนเวย์ เกม
of ชีวิต ใน PDL แล้วมาดูกันว่า PDL จะทรงพลังขนาดไหน!
งานวิ่งการกุศล เกม of ชีวิต เป็นการจำลองการทำงานบนตารางสองมิติขนาดใหญ่ แต่ละเซลล์ในตาราง
สามารถมีชีวิตอยู่หรือตายได้ (แสดงด้วย 1 หรือ 0) เซลล์รุ่นต่อไปใน
ตารางคำนวณด้วยกฎง่ายๆ ตามจำนวนเซลล์ที่มีชีวิตในนั้น
บริเวณใกล้เคียง:
1) ถ้าเซลล์ว่างมีเพื่อนบ้านครบสามคนพอดี เซลล์ที่มีชีวิตจะถูกสร้างขึ้น
2) ถ้าเซลล์ที่มีชีวิตมีเพื่อนบ้านน้อยกว่าสองคน เซลล์นั้นตายเพราะให้อาหารมากไป
3) ถ้าเซลล์ที่มีชีวิตมีเพื่อนบ้านตั้งแต่ 4 คนขึ้นไป เซลล์นั้นตายเพราะความอดอยาก
โปรแกรมเมอร์กำหนดเฉพาะเซลล์รุ่นแรกเท่านั้น หลังจากนั้น
การจำลองทำงานอย่างสมบูรณ์ตามกฎเหล่านี้ ในการคำนวณคนรุ่นต่อไป คุณ
ต้องดูแต่ละเซลล์ในฟิลด์ 2D (ต้องการสองลูป) คำนวณจำนวน
เซลล์ที่มีชีวิตที่อยู่ติดกับเซลล์นี้ (ต้องการอีกสองลูป) แล้วเติมถัดไป
ตารางรุ่น
คลาสสิก การดำเนินงาน
นี่เป็นวิธีคลาสสิกในการเขียนโปรแกรมนี้ในภาษา Perl เราใช้ PDL เพื่อระบุที่อยู่เท่านั้น
แต่ละเซลล์
#!/usr/bin/perl -w
ใช้ PDL;
ใช้ PDL::NiceSlice;
#ทำกระดานสำหรับเกมชีวิต
$nx ของฉัน = 20;
$ny ของฉัน = 20;
#รุ่นปัจจุบัน.
$a ของฉัน = ศูนย์($nx, $ny);
# รุ่นต่อไป.
ของฉัน $n = ศูนย์($nx, $ny);
#ใส่เครื่องร่อนง่ายๆ
$a(1:3,1:3) .= pdl ( [1,1,1],
[0,0,1]
[0,1,0] );
สำหรับ ($i ของฉัน = 0; $i <100; $i++) {
$n = ศูนย์($nx, $ny);
$new_a = $a->คัดลอก;
สำหรับ ($x = 0; $x < $nx; $x++) {
สำหรับ ($y = 0; $y < $ny; $y++) {
# สำหรับแต่ละเซลล์ ดูที่เพื่อนบ้านโดยรอบ
สำหรับ ($dx = -1; $dx <= 1; $dx++) {
สำหรับ ($dy = -1; $dy <= 1; $dy++) {
$px = $x + $dx;
$py = $y + $dy;
#พันรอบขอบ.
ถ้า ($px < 0) {$px = $nx-1};
ถ้า ($py < 0) {$py = $ny-1};
ถ้า ($px >= $nx) {$px = 0};
ถ้า ($py >= $ny) {$py = 0};
$n($x,$y) .= $n($x,$y) + $a($px,$py);
}
}
#ไม่นับเซลล์ส่วนกลางเอง
$n($x,$y) -= $a($x,$y);
# ดูว่าเซลล์มีชีวิตอยู่หรือตาย:
# เซลล์ที่ตายแล้วจะมีชีวิตอยู่ถ้า n = 3
# เซลล์ที่มีชีวิตตายถ้า n ไม่ใช่ 2 หรือ 3
ถ้า ($a($x,$y) == 1) {
ถ้า ($n($x,$y) < 2) {$new_a($x,$y) .= 0};
ถ้า ($n($x,$y) > 3) {$new_a($x,$y) .= 0};
} else {
ถ้า ($n($x,$y) == 3) {$new_a($x,$y) .= 1}
}
}
}
พิมพ์ $a;
$a = $new_a;
}
หากคุณเรียกใช้สิ่งนี้ คุณจะเห็นเครื่องร่อนขนาดเล็กรวบรวมข้อมูลในแนวทแยงผ่านตารางศูนย์
ในเครื่องของฉัน มันพิมพ์ออกมาสองสามรุ่นต่อวินาที
threaded PDL การดำเนินงาน
และนี่คือเวอร์ชันเธรดใน PDL รหัส PDL เพียงสี่บรรทัด และหนึ่งในนั้นคือ
พิมพ์ออกมารุ่นใหม่ล่าสุด!
#!/usr/bin/perl -w
ใช้ PDL;
ใช้ PDL::NiceSlice;
$a ของฉัน = ศูนย์ (20,20);
#ใส่เครื่องร่อนง่ายๆ
$a(1:3,1:3) .= pdl ( [1,1,1],
[0,0,1]
[0,1,0] );
$n ของฉัน;
สำหรับ ($i ของฉัน = 0; $i <100; $i++) {
# คำนวณจำนวนเพื่อนบ้านต่อเซลล์
$n = $a->range(ndcoords($a)-1,3,"periodic")->เรียงลำดับใหม่(2,3,0,1);
$n = $n->ซัมโอเวอร์->ซัมโอเวอร์ - $a;
#คำนวณคนรุ่นต่อไป
$a = ((($n == 2) + ($n == 3))* $a) + (($n==3) * !$a);
พิมพ์ $a;
}
เวอร์ชัน PDL แบบเธรดนั้นเร็วกว่ามาก:
คลาสสิก => 32.79 วินาที
เธรด => 0.41 วินาที
คำอธิบาย
เวอร์ชันเธรดทำงานอย่างไร
มีฟังก์ชัน PDL มากมายที่ออกแบบมาเพื่อช่วยคุณดำเนินการเกลียว PDL ในเรื่องนี้
ตัวอย่าง หน้าที่หลักคือ:
วิธีการ: "พิสัย"
ในระดับที่ง่ายที่สุด วิธี "ช่วง" เป็นอีกวิธีหนึ่งในการเลือกส่วนของ a
ถ่ายปัสสาวะ. แทนที่จะใช้สัญกรณ์ "$a(2,3)" เราใช้ piddle อื่นแทน
pdl> $a = ลำดับ (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->range( pdl [1,2] )
13
pdl> p $a(1,2)
[
[13]
]
ณ จุดนี้ วิธีการ "ช่วง" จะดูคล้ายกับการแบ่งส่วน PDL ปกติมาก แต่
วิธี "range" นั้นกว้างกว่า ตัวอย่างเช่น คุณสามารถเลือกส่วนประกอบหลายอย่างพร้อมกัน:
pdl> $index = pdl [ [1,2], [2,3], [3,4], [4,5] ]
pdl> p $a->range( $index )
[13 20 27 34]
นอกจากนี้ "ช่วง" จะใช้พารามิเตอร์ตัวที่สองซึ่งกำหนดขนาดของก้อนไปยัง
กลับ:
pdl> $ขนาด = 3
pdl> p $a->range( pdl([1,2]) , $size )
[
[13 14 15]
[19 20 21]
[25 26 27]
]
เราสามารถใช้สิ่งนี้เพื่อเลือกกล่อง 3x3 หนึ่งกล่องขึ้นไป
สุดท้าย "ช่วง" สามารถใช้พารามิเตอร์ที่สามที่เรียกว่าเงื่อนไข "ขอบเขต" มันบอก PDL
จะทำอย่างไรถ้ากล่องขนาดที่คุณขอไปเกินขอบของ piddle เราไม่ไป
เหนือตัวเลือกทั้งหมด เราจะบอกว่าตัวเลือก "เป็นระยะ" หมายความว่า piddle
"ล้อมรอบ". ตัวอย่างเช่น:
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> $ขนาด = 3
pdl> p $a->range( pdl([4,2]) , $size , "เป็นระยะ" )
[
[16 17 12]
[22 23 18]
[28 29 24]
]
pdl> p $a->range( pdl([5,2]) , $size , "เป็นระยะ" )
[
[17 12 13]
[23 18 19]
[29 24 25]
]
สังเกตว่ากล่องพันรอบขอบพิดเดิ้ลอย่างไร
วิธีการ: "ndcoords"
วิธี "ndcoords" เป็นวิธีการอำนวยความสะดวกที่ส่งคืนรายการที่แจกแจงเป็น
พิกัดที่เหมาะสมกับการใช้งานด้วยวิธีการ "ช่วง"
pdl> p $piddle = ลำดับ(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]
]
]
นี้อาจเป็นเรื่องยากที่จะอ่าน โดยพื้นฐานแล้วจะบอกว่าพิกัดของทุกๆ
องค์ประกอบใน $piddle กำหนดโดย:
(0,0) (1,0) (2,0)
(1,0) (1,1) (2,1)
(2,0) (2,1) (2,2)
รวม "พิสัย" และ "ndcoords"
สิ่งที่สำคัญจริงๆ คือ "ndcoords" ออกแบบมาเพื่อทำงานร่วมกับ "range" โดยไม่มี
พารามิเตอร์ $size คุณจะได้ piddle ตัวเดิมกลับมา
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]
]
ทำไมสิ่งนี้ถึงมีประโยชน์? เพราะตอนนี้เราสามารถขอชุด "กล่อง" ได้ทั้งหมด
ถ่ายปัสสาวะ. ตัวอย่างเช่น 2x2 กล่อง:
pdl> p $piddle->range( ndcoords($piddle) , 2 , "เป็นระยะ" )
เอาต์พุตของฟังก์ชันนี้อ่านยากเนื่องจาก "กล่อง" ตามสองตัวสุดท้าย
มิติ. เราสามารถทำให้ผลลัพธ์อ่านง่ายขึ้นโดยการจัดเรียงมิติข้อมูลใหม่:
pdl> p $piddle->range( ndcoords($piddle) , 2 , "periodic" )->reorder(2,3,0,1)
[
[
[
[0 1]
[3 4]
]
[
[1 2]
[4 5]
]
...
]
ที่นี่คุณสามารถเห็นได้ชัดเจนยิ่งขึ้นว่า
[0 1]
[3 4]
กล่อง 2x2 เริ่มต้นด้วยองค์ประกอบ (0,0) ของ $piddle หรือไม่
เรายังทำไม่เสร็จ สำหรับเกมแห่งชีวิตเราต้องการกล่อง 3x3 จาก $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->range( ndcoords($a) , 3 , "periodic" )->reorder(2,3,0,1)
[
[
[
[ 0 1 2]
[ 6 7 8]
[12 13 14]
]
...
]
เราสามารถยืนยันได้ว่านี่คือกล่อง 3x3 ที่เริ่มต้นด้วยองค์ประกอบ (0,0) ของ $a แต่มี
เป็นปัญหาหนึ่ง เราอยากให้กล่อง 3x3 เป็น ศูนย์กลาง บน (0,0) นั่นไม่ใช่
ปัญหา. เพียงลบ 1 จากพิกัดทั้งหมดใน "ndcoords($a)" จำไว้ว่า
ตัวเลือก "เป็นระยะ" จะดูแลทุกอย่างรอบตัว
pdl> p $a->range( ndcoords($a) - 1 , 3 , "periodic" )->reorder(2,3,0,1)
[
[
[
[41 36 37]
[ 5 0 1]
[11 6 7]
]
[
[36 37 38]
[ 0 1 2]
[ 6 7 8]
]
...
ตอนนี้เราเห็นกล่อง 3x3 ที่มีองค์ประกอบ (0,0) อยู่ตรงกลางของกล่อง
วิธีการ: "ซัมโอเวอร์"
วิธี "ซัมโอเวอร์" จะเพิ่มเฉพาะมิติแรกเท่านั้น ถ้าเราทาสองครั้ง เราก็จะ
เพิ่มองค์ประกอบทั้งหมดของแต่ละกล่อง 3x3
pdl> $n = $a->range(ndcoords($a)-1,3,"periodic")->reorder(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->ซัมโอเวอร์->ซัมโอเวอร์
[
[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]
]
ใช้เครื่องคิดเลขยืนยันว่า 144 คือผลรวมขององค์ประกอบทั้งหมดในกล่อง 3x3 แรก
และ 135 คือผลรวมขององค์ประกอบทั้งหมดในกล่อง 3x3 ที่สอง
การนับ เพื่อนบ้าน
เราเกือบจะอยู่ที่นั่นแล้ว!
การเพิ่มองค์ประกอบทั้งหมดในกล่อง 3x3 ไม่ใช่ ทีเดียว สิ่งที่เราต้องการ ไม่อยากนับ
กล่องกลาง โชคดีที่นี่เป็นวิธีแก้ไขที่ง่าย:
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]
]
เมื่อนำไปใช้กับ Conway's Game of Life สิ่งนี้จะบอกเราว่ามีเพื่อนบ้านที่อาศัยอยู่กี่คน
เซลล์มี:
pdl> $a = ศูนย์ (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->range(ndcoords($a)-1,3,"periodic")->reorder(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]
]
ตัวอย่างเช่น สิ่งนี้บอกเราว่าเซลล์ (0,0) มีเพื่อนบ้านที่มีชีวิตอยู่ 1 คน ในขณะที่เซลล์ (2,2) มี 5
เพื่อนบ้านที่อาศัยอยู่
คิดเลข ถัดไป รุ่น
ณ จุดนี้ตัวแปร $n มีจำนวนเพื่อนบ้านที่อาศัยอยู่สำหรับทุกเซลล์ ตอนนี้เรา
ใช้กฎของเกมแห่งชีวิตเพื่อคำนวณรุ่นต่อไป
ถ้าเซลล์ว่างมีเพื่อนบ้านเพียงสามคน เซลล์ที่มีชีวิตจะถูกสร้างขึ้น
รับรายชื่อเซลล์ที่มีเพื่อนบ้านเพียงสามคนเท่านั้น:
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]
]
รับรายชื่อ ไม่มีข้อมูล เซลล์ที่มีเพื่อนบ้านสามคนพอดี:
pdl> p ($n == 3) * !$a
ถ้าเซลล์ที่มีชีวิตมีเพื่อนบ้านน้อยกว่า 2 หรือมากกว่า 3 เพื่อนบ้าน เซลล์นั้นก็จะตาย
รับรายชื่อเซลล์ที่มีเพื่อนบ้านเพียง 2 หรือ 3 แห่ง:
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]
]
รับรายชื่อ ที่อาศัยอยู่ เซลล์ที่มีเพื่อนบ้าน 2 หรือ 3 คนพอดี:
pdl> p (($n == 2) + ($n == 3)) * $a
เมื่อนำทั้งหมดมารวมกัน คนรุ่นต่อไปคือ:
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]
]
โบนัส คุณสมบัติ: กราฟิก!
หากคุณติดตั้ง PDL::Graphics::TriD ไว้ คุณสามารถสร้างโปรแกรมเวอร์ชันกราฟิกได้
โดยเพียงแค่เปลี่ยนสามบรรทัด:
#!/usr/bin/perl
ใช้ PDL;
ใช้ PDL::NiceSlice;
ใช้ PDL::Graphics::TriD;
$a ของฉัน = ศูนย์ (20,20);
#ใส่เครื่องร่อนง่ายๆ
$a(1:3,1:3) .= pdl ( [1,1,1],
[0,0,1]
[0,1,0] );
$n ของฉัน;
สำหรับ ($i ของฉัน = 0; $i <100; $i++) {
# คำนวณจำนวนเพื่อนบ้านต่อเซลล์
$n = $a->range(ndcoords($a)-1,3,"periodic")->เรียงลำดับใหม่(2,3,0,1);
$n = $n->ซัมโอเวอร์->ซัมโอเวอร์ - $a;
#คำนวณคนรุ่นต่อไป
$a = ((($n == 2) + ($n == 3))* $a) + (($n==3) * !$a);
# แสดง.
nokeeptwiddling3d();
imgrgb [$a];
}
แต่ถ้าเราต้องการเห็นสิ่งที่น่าสนใจจริงๆ เราควรจะทำการเปลี่ยนแปลงเพิ่มเติมอีกเล็กน้อย:
1) เริ่มต้นด้วยคอลเล็กชันสุ่ม 1 และ 0
2) ทำให้กริดใหญ่ขึ้น
3) เพิ่มการหมดเวลาเล็กน้อยเพื่อให้เราเห็นว่าเกมมีวิวัฒนาการดีขึ้น
4) ใช้ while loop เพื่อให้โปรแกรมทำงานได้นานเท่าที่จำเป็น
#!/usr/bin/perl
ใช้ PDL;
ใช้ PDL::NiceSlice;
ใช้ PDL::Graphics::TriD;
ใช้เวลา::HiRes qw(usleep);
$a ของฉัน = สุ่ม (100,100);
$a = ($a < 0.5);
$n ของฉัน;
ในขณะที่ (1) {
# คำนวณจำนวนเพื่อนบ้านต่อเซลล์
$n = $a->range(ndcoords($a)-1,3,"periodic")->เรียงลำดับใหม่(2,3,0,1);
$n = $n->ซัมโอเวอร์->ซัมโอเวอร์ - $a;
#คำนวณคนรุ่นต่อไป
$a = ((($n == 2) + ($n == 3))* $a) + (($n==3) * !$a);
# แสดง.
nokeeptwiddling3d();
imgrgb [$a];
# นอนหลับเป็นเวลา 0.1 วินาที
หลับ(100000);
}
สรุป: ทั่วไป กลยุทธ์
กลยุทธ์ทั่วไปคือ: ย้าย มิติ เธอ ต้องการ ไปยัง ทำงาน on ไปยัง เริ่มต้น of ธุรกิจ
piddle's มิติ รายการ. แล้วก็ ให้ PDL ด้าย เกินกว่า สูงกว่า มิติข้อมูล
Threading เป็นเครื่องมือที่ทรงพลังที่ช่วยขจัด for-loop และสามารถสร้างโค้ดของคุณได้มากขึ้น
กระชับ หวังว่าบทช่วยสอนนี้จะแสดงให้เห็นว่าเหตุใดการร้อยเกลียวจึงคุ้มค่า
ใน PDL
ลิขสิทธิ์
ลิขสิทธิ์ 2010 Matthew Kenworthy ([ป้องกันอีเมล]) และ แดเนียล คาร์เรร่า
([ป้องกันอีเมล]). คุณสามารถแจกจ่ายและ/หรือแก้ไขเอกสารนี้ภายใต้เงื่อนไขเดียวกัน
เป็นใบอนุญาต Perl ปัจจุบัน
โปรดดูที่: http://dev.perl.org/licenses/
ใช้ PDL::Threadingp ออนไลน์โดยใช้บริการ onworks.net