Übung 3 zu Verteilte und Parallele Programmierung: Parallele Zelluläre Automaten (Teil 2) (PD Stefan Bosse) [4.2024] |
In den Übungen werden alternativ drei verschiedene Lua VM Implementierungen verwendet:
Es wird die parallele LuaJit VM lvm für das jeweilige eigene Betriebssystem benötigt
# lvm myprog.lua
# lvm weblvm.lua
Service thread 2 started.
[2@1592562880] HTTP server (2) listening to http://0.0.0.0:4610
Monitor thread 4 started.
[4@1592562880] HTTP server (4) listening to http://0.0.0.0:4611
Unter seltenen Bedingungen (Race conditions!) kann lvm fehlerhaft arbeiten und "abstürzen" (IO Fehler) → lvm neu starten, und die Snippets im Notebook nochmals ausführen!
caluaP.lua
weblvm.lua
▸
◼
|
✗
↻
≡
|
Wichtig: Da Shared Memory verwendet wird (intern über ein SM-Matrix Objekt) dürfen die Zustandsdatenvariablen der Zellen nur noch vom Typ number sein (Integer, Float)!
Boolesche Ausdrücke müssen in numerische Werte kodiert werden, z.B. mit der conditional(bexpr,vtrue,vfalse)
Hilfsfunktion.
Weiterhin ist bei paralleler partitionierter Berechnung die randomisierte Initialisierung abzuändern. Es sollte eine globale geteilte Matrix für alle Partitionen verwendet werden, die mit Pseudozufallszahlen in einem Prozess berechnet wird.
┌─────┐ ┌─────┐ ┌─────┬─────┐
│ │ │ 1 │ │ 1 │ 2 │
│ 1 │ ├─────┤ ├─────┼─────┤
│ │ │ 2 │ │ 3 │ 4 │
└─────┘ └─────┘ └─────┴─────┘
┌─────┬─────┐ ┌─────┬─────┐ ┌─────┬─────┬─────┬─────┐
│ 1 │ 2 │ │ 1 │ 2 │ │ 1 │ 2 │ 3 │ 4 │
├─────┼─────┤ ├─────┼─────┤ ├─────┼─────┼─────┼─────┤
│ 3 │ 4 │ │ 3 │ 4 │ │ 5 │ 6 │ 7 │ 8 │
├─────┼─────┤ ├─────┼─────┤ ├─────┼─────┼─────┼─────┤
│ 5 │ 6 │ │ 5 │ 6 │ │ 9 │ 10 │ 11 │ 12 │
└─────┴─────┘ ├─────┼─────┤ ├─────┼─────┼─────┼─────┤
│ 7 │ 8 │ │ 13 │ 14 │ 15 │ 16 │
└─────┴─────┘ └─────┴─────┴─────┴─────┘
Wichtig: Die Partitionierung in x- und y-Richtung muss ganzzahlig sein, d.h. die Größe der Automatenwelt muss durch die Anzahl Spalten und Zeilen ganzzahlig teilbar sein!
Der Zustand einer Zelle besteht aus einer oder mehreren Variablen
I.A. ist eine Variable ein Sensor, der von der Nachbarzellen gelesen wird
I.A. ist eine andere Variable der zustandsbestimmende Aktor einer Zelle, die auch die Farbe einer Zelle bestimmt
Die Nachbarzellen sind durch das Objekt self.neighbors erreichbar (direkt mit dem Shared Memory Modell, indirekt durch get/set Methoden über Kommunikationskanäle im Distributed Memory Modell). Die Felder und relativen Positionen sind wie folgt gezeigt:
if model.neighbors == 4 then
-- Neumann
self.neighbors = {
left = {-1,0},
right = {1,0},
bottom = {0,1},
top = {0,-1}
}
elseif model.neighbors == 8 then
-- Moore
self.neighbors = {
left = {-1,0},
right = {1,0},
bottom = {0,1},
top = {0,-1},
topleft = {-1,-1},
topright = {1,-1},
bottomleft = {-1,1},
bottomright = {1,1}
}
end
┌──────────┬──────────┬──────────┬────▶ x
│ │ │ │
│ topleft │ top │ topright │
│ │ │ │
├──────────┼──────────┼──────────┤
│ │ │ │
│ left │ pixel │ right │
│ │ │ │
├──────────┼──────────┼──────────┤
│ │ │ │
│ bottom- │ bottom │ bottom- │
│ left │ │ right │
├──────────┴──────────┴──────────┘
│
│
▼ y
▸
◼
|
✗
↻
≡
|
▸
◼
|
✗
↻
≡
|
▸
◼
|
✗
↻
≡
|
simulator:draw
Methode überträgt das aktuelle Zellenbild an das Notebook wo es im nachfolgenden Fenster entsprechend der Farbpalette dargestellt wird.Nachfolgendes Snippet ausführen (Play Button drücken) - es wird zunächst keine Grafik sichtbar werden!
▸
|
✗
|
▸
◼
|
✗
↻
≡
|
▸
◼
|
✗
↻
≡
|
▸
◼
|
✗
↻
≡
|
Verschiedene Modelle (Pseudonotation) zum Ausprobieren.
state : {open,wasOpen}
before : wasOpen=open
acitivty :
surrounding = count(neighbors,wasopen==true)
open=(wasOpen and surrounding >= A) or surrounding >= B
initialize : open=random()>density
state : {alive,wasAlive,simulated}
before : wasAlive=alive
activity :
surrounding = count(neighbors,wasopen==true)
simulated < 20?
alive = surrounding == 1 or surrounding == 2 and alive;
simulated > 20 and surrounding == 2?
alive = true;
simulated = self.simulated+1
initialize : alive = random() > 0.6; simulated=0
state : {alive,wasAlive}
before : wasAlive=alive
activity :
surrounding = count(neighbors, wasAlive==true)
alive = surrounding == 3 or surrounding == 2 and alive
initialize : alive = random() > 0.5
Implementiere den Maze Algorithmus (oben) mit N=128 × 128 (120 für P=6) und teste die Berechnung für Partitionsgrößen P={1,2,4,6,8,16}. Verwende den UPRIGHT Scheduler.
Wie verändert sich die Rechenzeit mit der Anzahl der Partitionen P? Erstelle einen Plot (für P={1,2,4,6,8,16}. Berechne den Speed-up aus den gemessenen Zeitwerten für einen Simulationsschritt und pro Zelle, trage die Werte in dem y-Array ein. Messe die Zeit für 20 Simulationsschritte.
▸
|
✗
≡
|
▸
|
✗
≡
|
simulator:draw
)!
▸
|
✗
≡
|