![]()
EINFÜHRUNG |
Eine der wichtigsten Fragestellungen überhaupt besteht darin zu verstehen oder vorauszusagen, wie sich ein System im Laufe der Zeit verhält. Dies ist umso schwieriger, je mehr Einflussparametern das System ausgesetzt ist. Will man das System mit dem Computer simulieren, so kann dies nur in diskreten Zeitschritten geschehen, was für sich kontinuierlich verändernde Systeme immer nur eine Approximation darstellt, die zwar mit kleineren Zeitschritten immer genauer wird, wobei sich aber der Rechenaufwand dabei massiv vergrössern kann. Es gibt viele Systeme, bei denen der Übergang vom aktuellen Systemzustand Zi zum Nachfolgezustand Zkdurch Wahrscheinlichkeiten geregelt ist und nur vom Zustand i abhängt (also nicht von noch weiter zurückliegenden). Willst du beispielsweise mit einem Würfel alle 6 Zahlen erwürfeln, so kannst du diesen Prozess als Durchlauf einer Reihe von Zuständen Z0 bis Z6 auffassen und grafisch als Markoff-Kette darstellen. Die Übergangswahrscheinlichkeiten pi vom Zustand i zum Nachfolgezustand kannst du im folgenden Schema eintragen:
|
MITTLERE WARTEZEITEN |
Statt nach Wahrscheinlichkeiten zu fragen, willst du abklären, wie oft du im Mittel würfeln musst, um von einem bestimmten Anfangszustand in einen bestimmten Endzustand zu gelangen. Wenn die in gleichen Zeitschritten würfelst, so fragst du dich also, wie lange im Mittel der Prozess dauert. Diese Zeit nennst du die (mittlere) Wartezeit. Offensichtlich ist beim vorher beschriebenen Würfelprozess die Wartezeit um von Z0 zu Z6 die Summe der Wartezeiten für alle Übergänge. Wie gross sind aber die einzelnen Wartezeiten? In deinem ersten Programm findest du experimentell die wichtigste Eigenschaft von Wartezeitproblemen heraus.: Ist p die Wahrscheinlichkeit um von Z1 nach Z2 zu gelangen, so beträgt die Wartezeit (in einer geeigneten Einheit) u = 1/p.
from gpanel import * from random import randint n = 10000 p = 1/6 def sim(): k = 1 r = randint(1, 6) while r != 6: r = randint(1, 6) k += 1 return k makeGPanel(-5, 55, -200, 2200) drawGrid(0, 50, 0, 2000) title("Waiting on a 6") h = [0] * 51 lineWidth(5) count = 0 repeat n: k = sim() count += k if k <= 50: h[k] += 1 line(k, 0, k, h[k]) mean_exp = count / n lineWidth(1) setColor("red") count = 0 for k in range(1, 1000): pk = (1 - p)**(k - 1) * p nk = n * pk count += nk * k if k <=50: line(k, 0, k, nk) mean_theory = count / n title("Experiment: " + str(mean_exp) + "Theory: " + str(mean_theory)) |
MEMO |
|
Das Resultat ist intuitiv einleuchtend: Da die Wahrscheinlichkeit, eine bestimmte Augenzahl zu würfeln p= 1/6 ist, benötigst du im Mittel u = 1 / p = 6 Würfe um diese Augenzahl zu erhalten. Es ist auch instruktiv, die theoretischen Werte der Häufigkeiten als rote Linie einzutragen. Dazu überlegst du dir, dass für die Wahrscheinlichkeiten eine 6 zu werfen, gilt:
Für die theoretischen Häufigkeiten multiplizierst du diese Wahrscheinlichkeiten mit der Anzahl n der Versuche [mehr...
Mit ein wenig Algebra kann man exakt beweisen, dass der Erwartungswert der Für die Wartezeit, alle 6 Zahlen zu erwüfeln, ergibt sich damit als exakter Wert die Summe der Reziprokwerte der pi also: u = 1 + 6/5 + 6/4 + 6/3 + 6/2 + 6 = 14.7 |
AUSBREITUNG EINER KRANKHEIT |
Du gehst von der folgenden Geschichte aus, die zwar erfunden ist, aber durchaus gewisse Parallelen zu aktuellen Lebensgemeinschaften hat.
Es ist elegant, die Population durch eine Liste mit booleschen Werten zu modellieren, wobei gesund mit False und krank mit True codiert sind. Der Vorteil dieser Datenstruktur besteht darin, dass sich die Wechselwirkung beim Zusammentreffen von zwei Personen in der Funktion pair() mit einer logischen OR-Verknüpfung ausdrücken lässt:
from random import randint n = 10000 def sim(): z = [] i = 0 while True: r = randint(1, 6) i += 1 if not r in z: z.append(r) if len(z) == 6: return i count = 0 repeat n: count += sim() print("Mean waiting time:", count / n) |
MEMO |
Du findest ein zeitliches Verhalten, bei dem die Zunahme zuerst langsam, dann rasant und dann wieder langsam ist. Qualitativ ist dir dieses Verhalten sicher plausibel, denn zuerst ist die Wahrscheinlichkeit gering, dass sich ein Kranker mit einem Gesunden trifft, da sich vor allem Gesunde untereinander treffen. Am Schluss ist die Wahrscheinlichkeit wiederum gering, dass ein übrig gebliebener Gesunder einem Kranken begegnet, da sich vor allem Kranke untereinander treffen [mehr... Der Verlauf entspricht tendenziell dem logistischen Wachstum]. |
from gpanel import * from random import randint def pair(): # Select two distinct inhabitants a = randint(0, 99) b = a while b == a: b = randint(0, 99) z[a] = z[a] or z[b] z[b] = z[a] def nbInfected(): count = 0 for i in range(100): if z[i]: count += 1 return count makeGPanel(-50, 550, -10, 110) title("The spread of an illness") drawGrid(0, 500, 0, 100) lineWidth(2) setColor("blue") z = [False] * 100 tmax = 500 t = 0 a = randint(0, 99) z[a] = True # random infected inhabitant move(t, 1) while t <= tmax: pair() infects = nbInfected() t += 1 draw(t, infects) Du kannst die Ausbreitung der Krankheit aber auch als Markoff-Kette auffassen. Ein bestimmter Zustand ist durch die Zahl der Infizierten charakterisiert. Die Wartezeit, bis alle krank sind, ist die Summe der Wartezeiten für die Übergänge von k Kranken zu k+1 Kranken für k von 1 bis 99. Dazu benötigst du die Wahrscheinlichkeit pk für diesen Übergang. Es gilt:
from random import randint n = 1000 # number experiment def pair(): # Select two distinct inhabitants a = randint(0, 99) b = a while b == a: b = randint(0, 99) z[a] = z[a] or z[b] z[b] = z[a] def nbInfected(): count = 0 for i in range(100): if z[i]: count += 1 return count def sim(): global z z = [False] * 100 t = 0 a = randint(0, 99) z[a] = True # random infected inhabitant while True: pair() t += 1 if nbInfected() == 100: return t count = 0 for i in range(n): u = sim() print("Experiment #", i + 1, "Waiting time:", u) count += u print( "Mean waiting time:", count / n) |
MEMO |
Mit der Theorie der Markoff-Ketten ergibt sich eine mittlere Wartezeit von 463 Stunden, also rund 20 Tage.. |
WARTEZEITPARADOXON |
Da sie auch dann noch im Mittel alle 6 Minuten vorbei kommen, nimmst du vielleicht an, dass sich an der mittleren Wartezeit von 3 Minuten nichts ändert. Die erstaunliche, und darum paradoxe Antwort ist, dass die mittlere Wartezeit nun grösser als 3 Minuten wird. In einer animierten Simulation sollst du herausfinden, wie gross die Wartezeit unter der Annahme ist, dass die Busse gleichverteilt im Bereich 2 und 10 Minuten (in der Simulation sind es Sekunden) hintereinander fahren. Dabei verwendest du mit Vorteil die Game-Library JGameGrid ein, da sich die beteiligten Objekte, wie Busse und Fahrgäste als Sprite-Objekte modellieren lassen.
Der Programmcode erfordert einige Erklärungen:
from gpanel import * n = 100 def p(k): return 2 * k * (n - k) / n / (n - 1) makeGPanel(-10, 110, -0.1, 1.1) drawGrid(0, 100, 0, 1.0) count = 0 for k in range(1, n - 1): if k == 1: move(k, p(k)) else: draw(k, p(k)) count += 1 / p(k) title("Time until everyone is ill: " + str(count))
|
MEMO |
Die Simulation zeigt, dass die mittlere Wartezeit mit rund 3.5 Minuten deutlich länger als die vermuteten 3 Minuten ist. Du kannst dir diese Verlängerung wie folgt erklären: Kommen die Busse gleichverteilt einmal mit 2 Minuten und mit 10 Minuten Abstand, so ist es viel wahrscheinlicher, dass deine Ankunft in das Warteintervall von 2 bis 10 Minuten fällt als in das Warteintervall von 0 bis 2 Minuten. Daher wartest du sicher länger als 3 Minuten. |
AUFGABEN |
|