¨Ubungen zu â Modellierung verteilter Systemeâ
¨Ubungen zu â Modellierung verteilter Systemeâ
¨Ubungen zu â Modellierung verteilter Systemeâ
Sie wollen auch ein ePaper? Erhöhen Sie die Reichweite Ihrer Titel.
YUMPU macht aus Druck-PDFs automatisch weboptimierte ePaper, die Google liebt.
Technische Universität München SoSe 2013<br />
Institut für Informatik Lösungsblatt 4<br />
Prof. Dr. M. Broy, Dr. A. Malkis Ausgabe: 28. Mai 2013<br />
M. Gleirscher, V. Koutsoumpas, D. Marmsoler Besprechung: 6. Juni 2013<br />
Übungen <strong>zu</strong> ”<br />
<strong>Modellierung</strong> <strong>verteilter</strong> Systeme“<br />
Aufgabe 1 Bank<br />
Gegeben ist die Spezifikation des Gesamtsystems Bank sowie dessen Verteilung auf zwei Teilsysteme<br />
Bargeldbe<strong>zu</strong>g und Kontoverwaltung (Abbildung 1):<br />
x: A U C<br />
y: B U D<br />
Bank<br />
(a)<br />
Bank<br />
a: A<br />
b: B<br />
Bargeldbe<strong>zu</strong>g<br />
i1: I1<br />
i2: I2<br />
c: C<br />
Kontoverwaltung<br />
(b)<br />
d: D<br />
var s : Array[n] Nat<br />
Abbildung 1: (a) Schnittstellensicht des Systems Bank, im Kontext dessen Nutzer. (b) Die Komponenten<br />
Bargeldbe<strong>zu</strong>g (Abstraktion eines Bankomaten bzw. eines Schalters) und Kontoverwaltung (Abstraktion<br />
eines Schalters bzw. eines Online-Portals) des Systems Bank.<br />
Gegeben sind ebenso folgende, informell beschriebene Eigenschaften:<br />
(1) Annahme über den Nutzer: ”<br />
Keine Überziehung: Falls <strong>zu</strong> keinem Zeitpunkt die Summe der erfolgreichen<br />
Bargeldabhebungen höher als die Summe der Einzahlungen ist, boniert das System dies<br />
mit leicht erhöhten Zinsen.“ Anmerkung: Um das Modell für die Aufgabe knapp <strong>zu</strong> halten, ist die<br />
Kontoverzinsung im Modell nicht <strong>zu</strong> berücksichtigen.<br />
(2) Ungezeitete Lebendigkeitseigenschaft: ”<br />
Unendlich oft sollen vom Nutzer Auszahlungen mindestens<br />
in Höhe aller Einzahlungen getätigt werden können.“<br />
Führen Sie nun folgende Schritte durch:
(a) Entwerfen Sie je eine knapp gehaltene Moore-Maschine für die Teilsysteme Bargeldbe<strong>zu</strong>g (Auszahlung)<br />
und Kontoverwaltung (Einzahlung, Auszahlungsprüfung).<br />
(b) Führen Sie nun die zeitasynchrone, nachrichtensynchrone Komposition Bargeldbe<strong>zu</strong>g ‖ Kontoverwaltung<br />
durch und erstellen Sie eine Schnittstellenabstraktion der Ergebnismaschine.<br />
(c) Stellen Sie die beiden Zustandsmaschinen aus (a) als konstruktive Spezifikation von Stromfunktionen<br />
dar und leiten das Ergebnis der Komposition der beiden Stromfunktionen f 1 ⊗ f 2 her.<br />
(d) Die Ergebnisse aus (b) und (c) stellen das System Bank dar. Prüfen Sie nun anhand Ihrer Kompositionsergebnisse,<br />
ob die Eigenschaften (1) und (2) vom System Bank erfüllt werden.<br />
Lösung der Aufgabe 1<br />
Teilaufgabe a) Die Abbildungen 2 und 3 zeigen zwei Vorschläge für die gefragten Moore-Maschinen. Für<br />
die Teilaufgabe c) sei mit diesen Zustandsübergangsdiagrammen auch die beiden Strukturen (∆ b , Σ b0 ) für den<br />
Bargeldbe<strong>zu</strong>g und (∆ k , Σ k0 ) für die Kontoverwaltung gegeben.<br />
aabbruch;<br />
i1check(false,x,id)<br />
Bereit<br />
ahebeAb(x,id)<br />
Fernprüfung<br />
i2!prüfe(x,id)<br />
-<br />
Abhebung<br />
b!geld(x,id)<br />
i1check(true,x,id)<br />
Abbildung 2: Moore-Maschine für Bargeldbe<strong>zu</strong>g<br />
{s[1..n]:=0}<br />
Bereit<br />
czahleEin(x,id)<br />
{s[id]:=s[id]+x}<br />
Einzahlung<br />
d!ok<br />
c<strong>zu</strong>rück<br />
i2prüfe(x,id)<br />
- {if (s[id]>=x AND customerOk(id))<br />
then s[id]:=s[id]-x}<br />
Prüfung<br />
i1!check(s[id]>=x AND customerOk(id),x,id)<br />
i2prüfe(x,id)<br />
Abbildung 3: Moore-Maschine für Kontoverwaltung
Teilaufgabe b) Abbildung 4 zeigt im ersten Schritt die asynchron in Zeit und Nachrichten “roh” komponierte<br />
Moore-Maschine für Bank. Kurzbezeichnungen für Ein- und Ausgabeaktionen:<br />
QT ≡ “aabbruch; i1check(false,x,id)”,<br />
OK ≡ “i1check(true,x,id)”,<br />
ZE ≡ “czahleEin(x,id) {s[id]:=s[id]+x}”,<br />
V R ≡ “i1!check(s[id]>=x AND customerOk(id),x,id)”,<br />
UP ≡ “- {if (s[id]>=x AND customerOk(id)) then s[id]:=s[id]-x}”<br />
Es gibt 17 Klassen von Zuständen (sog. Kontroll<strong>zu</strong>stände), die wir im Zustandsübergangsdiagramm (ZÜD)<br />
durch 17 Knoten unterscheiden. Das Kreuzprodukt der Kontroll<strong>zu</strong>stände und der Auswahl je einer Ausgabeaktion<br />
ergibt 3∗3∗2 = 18, lediglich die Kontroll<strong>zu</strong>stände “Bereit/Bereit” sind schon vereinigt, da es dort in beiden<br />
Maschinen keine Ausgabeaktionen gibt. Die Funktion customerOk(id) : N → Bool prüft, ob der Nutzer mit<br />
dem Identifikator id ein Kunde der Bank ist.<br />
OK<br />
i2prüfe(x,id)<br />
Abhebung<br />
Prüfung<br />
VR<br />
UP<br />
Abhebung<br />
Bereit<br />
b!geld(x,id)<br />
i2prüfe(x,id)<br />
OK<br />
i2prüfe(x,id)<br />
ZE<br />
ZE<br />
-<br />
c<strong>zu</strong>rück<br />
ZE<br />
Fernprüfung<br />
Bereit<br />
Abhebung<br />
Einzahlung<br />
d!ok<br />
-<br />
-<br />
Bereit<br />
Prüfung<br />
Fernprüfung<br />
Einzahlung<br />
d!ok<br />
c<strong>zu</strong>rück<br />
-<br />
UP<br />
QT<br />
UP<br />
QT<br />
{s[1..n] :=0}<br />
i2prüfe(x,id)<br />
i2prüfe(x,id)<br />
UP<br />
i2prüfe(x,id)<br />
OK<br />
OK<br />
c<strong>zu</strong>rück<br />
Fernprüfung<br />
Prüfung<br />
VR<br />
QT<br />
ZE<br />
Bereit<br />
Bereit<br />
Abhebung<br />
Einzahlung<br />
b!geld(x,id)<br />
c<strong>zu</strong>rück<br />
-<br />
i2prüfe(x,id)<br />
ahebeAb(x,id)<br />
c<strong>zu</strong>rück<br />
-<br />
Bereit<br />
Einzahlung<br />
Fernprüfung<br />
Bereit<br />
i2!prüfe(x,id)<br />
i2prüfe(x,id)<br />
QT<br />
ZE<br />
UP<br />
QT<br />
OK<br />
ahebeAb(x,id)<br />
i2prüfe(x,id)<br />
Fernprüfung<br />
Einzahlung<br />
i2!prüfe(x,id)<br />
Bereit<br />
Einzahlung<br />
d!ok<br />
i2prüfe(x,id)<br />
ahebeAb(x,id)<br />
Abhebung<br />
Bereit<br />
UP<br />
c<strong>zu</strong>rück<br />
Abhebung<br />
Prüfung<br />
b!geld(x,id)<br />
ahebeAb(x,id)<br />
OK<br />
QT<br />
Fernprüfung<br />
Prüfung<br />
i2!prüfe(x,id)<br />
ahebeAb(x,id)<br />
i2prüfe(x,id)<br />
VR<br />
Bereit<br />
Prüfung<br />
Bargeldbe<strong>zu</strong>g<br />
Kontoverwaltung<br />
Abbildung 4: Asynchron in Zeit und Nachrichten “roh” komponierte Moore-Maschine für Bank.<br />
Abbildung 5 zeigt im zweiten Schritt die nachrichtensynchrone Reduktion der Moore-Maschine für Bank,<br />
wobei keine Nachrichtensynchronität mit dem Benutzer berücksichtigt ist. D.h. ohne Eingabepuffer verliert
Bank z.B. ungünstig kommende “aabbruch” Nachrichten. Entsprechende Transitionen und Zustände sind<br />
entfernt worden. Dies betrifft auch Zusammenhangskomponenten im ZÜD, die (von “Bereit/Bereit” aus) nicht<br />
mehr erreichbar sind. Man beachte, dass uns diese Transformation eine Verklemmungssituation herbeiführt.<br />
Die nötige <strong>zu</strong>sätzliche “i2prüfe”-Transition und deren Konsequenzen im Zustand “Prüfung” betrachten wir im<br />
Rahmen der Aufgabe nicht mehr. Schon hier könnte man bei allen nachrichtensynchronen Übergängen der beiden<br />
Maschinen die Kontroll<strong>zu</strong>stände (hier “Fernprüfung/Bereit” und “Fernprüfung/Einzahlung”) eliminieren, dies<br />
erfolgt aber erst im nächsten Schritt.<br />
Fernprüfung<br />
Prüfung<br />
{s[1..n] :=0}<br />
Bereit<br />
Einzahlung<br />
ahebeAb(x,id)<br />
i2!prüfe(x,id)<br />
Bereit<br />
Prüfung<br />
UP<br />
Bereit<br />
Bereit<br />
c<strong>zu</strong>rück<br />
c<strong>zu</strong>rück<br />
Bereit<br />
Einzahlung<br />
QT<br />
Fernprüfung<br />
Bereit<br />
i2!prüfe(x,id)<br />
i2prüfe(x,id)<br />
ahebeAb(x,id)<br />
-<br />
ZE<br />
d!ok<br />
ahebeAb(x,id)<br />
ahebeAb(x,id)<br />
-<br />
-<br />
Fernprüfung<br />
Prüfung<br />
i2prüfe(x,id)<br />
Fernprüfung<br />
Einzahlung<br />
VR<br />
i2!prüfe(x,id)<br />
OK<br />
Abhebung<br />
Bereit<br />
ZE<br />
Abhebung<br />
Einzahlung<br />
Abhebung<br />
Prüfung<br />
UP<br />
d!ok<br />
b!geld(x,id)<br />
c<strong>zu</strong>rück<br />
Bargeldbe<strong>zu</strong>g<br />
Kontoverwaltung<br />
Potentielle Verklemmung<br />
Abbildung 5: Nachrichtensynchrone Reduktion der Moore-Maschine für Bank.<br />
Abbildung 6 zeigt im dritten Schritt die Schnittstellenabstraktion der Moore-Maschine für Bank. Alle Kommunikation<br />
über i1 und i2 sowie interne Zuweisungen/Referenzen auf s werden eliminiert (leere Transitionen<br />
werden eliminiert; Zustände, welche keine nutzersichtbaren Ausgaben produzieren bzw. keine Nutzereingaben<br />
entgegen nehmen wurden verschmolzen: Unsichtbare Transitionen bzw. Leerschritte (nicht die mit der leeren<br />
Nachricht “–”) werden <strong>zu</strong> Schleifen (bei Hin- und Rücktransitionen) oder verschwinden (bei Transitionen in<br />
eine Richtung). Man beachte die nichtdeterministische Ausgabe “−; y!geld(x, id)” (der Strichpunkt ; vereinigt<br />
hier zwei Transitionen oder Ausgaben zwecks kompakterer Notation) im grünen Zustand sowie den nichtdeterministischen<br />
Übergang mit “−” von dort aus. Damit erhalten wir eine Spezifikation, die nach wie vor eine<br />
Verklemmung aber <strong>zu</strong>sätzlich noch mehr Verhalten <strong>zu</strong>lässt als die ursprüngliche Komposition. Teilaufgabe d)<br />
zeigt auf Basis von Strömen, wie eine solche Spezifikation wieder sinnvoll eingeschränkt werden kann, in dem<br />
<strong>zu</strong>sätzlich geforderte Verhaltenseigenschaften potentielle Spezifikationsänderungen nach sich ziehen. Alternativ<br />
<strong>zu</strong>r Teilaufgabe c) ist mit diesem Zustandsübergangsdiagramm auch die Struktur (∆ bank , Σ bank0 ) für die Bank<br />
gegeben.
Fernprüfung<br />
Prüfung<br />
Bereit<br />
Bereit<br />
xzahleEin(x,id)<br />
x<strong>zu</strong>rück<br />
Bargeldbe<strong>zu</strong>g<br />
Kontoverwaltung<br />
Potentielle Verklemmung<br />
Bereit<br />
Einzahlung<br />
-<br />
y!ok<br />
xhebeAb(x,id)<br />
xhebeAb(x,id)<br />
Bereit<br />
Prüfung<br />
UP<br />
xabbruch; -<br />
xhebeAb(x,id)<br />
"Fernprüfung|Abhebung"<br />
"Bereit|Prüfung|Einzahlung"<br />
-;<br />
y!geld(x,id)<br />
x<strong>zu</strong>rück<br />
Abhebung<br />
Bereit<br />
UP<br />
xzahleEin(x,id)<br />
Abhebung<br />
Einzahlung<br />
y!ok<br />
xhebeAb(x,id)<br />
-<br />
Bereit<br />
Einzahlung<br />
x<strong>zu</strong>rück<br />
Abbildung 6: Schnittstellenabstraktion der Moore-Maschine für Bank.<br />
Teilaufgabe c) Im Folgenden werden wir die beiden Komponenten Bargeldbe<strong>zu</strong>g und Kontoverwaltung als<br />
stromverarbeitende Funktionen darstellen. Wir beginnen damit die Menge der Kanäle für Bargeldbe<strong>zu</strong>g und<br />
Kontoverwaltung wie folgt <strong>zu</strong> definieren:<br />
• Bargeldbe<strong>zu</strong>g: I b = {a, i1}, O b = {b, i2}.<br />
• Kontoverwaltung: I k = {c, i2}, O k = {d, i1}.<br />
Nun können wir die syntaktischen Schnittstellen der beiden Teilsysteme wie folgt definieren:<br />
• Bargeldbe<strong>zu</strong>g: (I b ◮ O b ).<br />
• Kontoverwaltung: (I k ◮ O k ).<br />
Schließlich können wir die semantischen Schnittstellen der Systeme als Funktionen über die <strong>zu</strong>gehörigen syntaktischen<br />
Schnittstellen definieren. Beachten sie dass wir im Folgenden eine Historie als Sequenz von Belegungen<br />
behandeln. Eine Historie −→ I bzw. −→ O einer Komponente mit Schnittstelle (I ◮ O) ist somit eine Sequenz von<br />
funktionen der Art<br />
I → M bzw. O → M.<br />
Im Folgenden werden wir zwei verschiedene Techniken <strong>zu</strong>r rekursiven Definition von stromverarbeitenden Funktionen<br />
einsetzen:
• Direkte Definition über Ein-/Ausgabe: Die Funktion wird rekursiv über das Muster der Eingabebelegungen<br />
definiert.<br />
• Definition unter Verwendung lokaler Zustände: Die Funktion wird rekursiv über das Muster von Eingabebelegungen<br />
in Abhängigkeit einer weiteren Hilfsfunktion definiert. Die Hilfsfunktion repräsentiert eine<br />
Art Daten<strong>zu</strong>stand und wird verwendet um den Kontostand der Kunden <strong>zu</strong> kapseln.<br />
Im Folgenden werden wir die stromverarbeitende Funktion für die Komponente Bargeldbe<strong>zu</strong>g als Ein-/Ausgabe<br />
Funktion definieren. Das Schnittstellenverhalten f b : −→ I b → −→ O b ist dabei wie folgt definiert, wobei das Symbol<br />
ɛ für die leere Übertragung steht und i, i ′ , i ′′ sowie o, o ′ , o ′′ Kanalbelegungen darstellen und rest ∈ −→ I b und<br />
x, id ∈ N:<br />
f b (〈〉) = 〈〉 (1)<br />
i(a) = hebeab(x, id) ∧ i(i1) = ɛ<br />
⇒ f b (〈i〉) = 〈o〉 (2)<br />
∧o(i2) = prüfe(x, id) ∧ o(b) = ɛ<br />
i(a) = hebeab(x, id) ∧ i ′ (i1) = check(true, x, id) ∧ i(i1) = i ′ (a) = ɛ<br />
⇒ f b (〈i〉) = 〈o〉 (3)<br />
∧o(i2) = prüfe(x, id) ∧ o ′ (b) = geld(x, id) ∧ o(b) = o ′ (i2) = ɛ<br />
i(a) = hebeab(x, id) ∧ (i ′ (i1) = check(false, x, id) ∧ i ′ (a) = ɛ ∨ i ′ (a) = abbruch ∧ i ′ (i1) = ɛ) ∧ i(i1) = ɛ<br />
⇒ f b (〈i〉ˆ〈i ′ 〉ˆ〈rest〉) = 〈o〉ˆ〈o ′ 〉ˆf b (〈rest〉) (4)<br />
∧o(i2) = prüfe(x, id) ∧ o(b) = o ′ (b) = o ′ (i2) = ɛ<br />
i(a) = hebeab(x, id) ∧ i ′ (i1) = check(true, x, id) ∧ i(i1) = i ′ (a) = i ′′ (a) = i ′′ (i1) = ɛ<br />
⇒ f b (〈i〉ˆ〈i ′ 〉ˆ〈i ′′ 〉ˆ〈rest〉) = 〈o〉ˆ〈o ′ 〉ˆ〈o ′′ 〉ˆf b (〈rest〉) (5)<br />
∧o(i2) = prüfe(x, id) ∧ o ′ (b) = geld(x, id) ∧ o(b) = o ′ (i2) = o ′′ (b) = o ′′ (i2) = ɛ<br />
Beachten Sie dass f b Präfix-monoton ist, also i 1 ⊑ i 2 ⇒ f b (i 1 ) ⊑ f b (i 2 ) gilt. Dies ist notwendig um sicher<strong>zu</strong>stellen<br />
dass die Funktion auch realisierbar ist. Des weiteren ist <strong>zu</strong> beachten dass die Funktion partiell ist, dass<br />
also nicht jede Eingabehistorie eine Ausgabehistorie liefert.<br />
Um sicher<strong>zu</strong>stellen dass die so definierte Funktion in der Tat eine Abstraktion der Zustandsmaschinen aus<br />
Teilaufgabe a ist, also f b = Abs((∆ b , Σ b0 )) gilt, muss die Abstraktion folgender Bedingung (siehe Foliensatz<br />
6, Folie 25) genügen, wobei Abläufe eine Funktion ist welche alle möglichen Abläufe einer Zustandsmaschine<br />
liefert:<br />
Vermutung. f b (i) = o ⇔ ∃σ n ∈ Abläufe((∆ b , Σ b0 )). σ 0 ∈ Σ b0 ∧ ∀n ∈ N.(σ n+1 , o(n + 1)) = ∆(σ n , i(n + 1))<br />
Ohne Beweis.<br />
Analog da<strong>zu</strong> können wir die stromverarbeitende Funktion der Komponente Kontoverwaltung definieren. Hier<br />
werden wir die stromverarbeitende Funktion aber als Funktion mit lokalen Zuständen definieren. Der Zustand<br />
ist in diesem Fall das Guthaben eines jeden Kunden. Wir können das Schnittstellenverhalten der Komponente
f k : −→ I k → −→ O k dann einfach als f k = f h [nil] definieren, wobei f h : s → ( −→ I k → −→ O k ) eine Funktion ist, die das<br />
Schnittellenverhalten in Abhängigkeit eines Zustandes s : N → N festlegt, wobei s(id) den aktuellen Betrag<br />
eines Kunden mit Identifikation id liefert und nil : N → N die Funktion ist welche den Betrag 0 für jeden<br />
Kunden <strong>zu</strong>rückgibt, also nil(id) = 0 für alle Kunden id. Die Funktion f h wird wie folgt definiert, wobei das<br />
Symbol ɛ für die leere Übertragung steht und i, i ′ , i ′′ sowie o, o ′ , o ′′ Kanalbelegungen darstellen und rest ∈ −→ I k :<br />
f h [s](〈〉) = 〈〉 (1)<br />
i(c) = zahleEin(x, id) ∧ i(i2) = ɛ<br />
⇒ f h [s](〈i〉) = o (2)<br />
∧o(d) = ok ∧ o(i1) = ɛ<br />
i(c) = zahleEin(x, id) ∧ i ′ (i2) = prüfe(x, id) ∧ i(i2) = i ′ (c) = ɛ<br />
⇒ f h [s](〈i〉ˆ〈i ′ 〉) = 〈o〉ˆ〈o ′ 〉 (3)<br />
∧o(d) = ok ∧ o ′ (i1) = check(s(id) > x ∧ customerOk(id), x, id) ∧ o(i1) = o ′ (d) = ɛ<br />
i(i2) = prüfe(x, id) ∧ i(d) = ɛ<br />
⇒ f h [s](〈i〉) = 〈o〉 (4)<br />
∧o(i1) = check(s(id) > x ∧ customerOk(id), x, id) ∧ o(d) = ɛ<br />
i(c) = zahleEin(x, id) ∧ i ′ (c) = <strong>zu</strong>rück ∧ i(i2) = i ′ (i2) = ɛ<br />
⇒ f h [s](〈i〉ˆ〈i ′ 〉ˆ〈rest〉) = 〈o〉ˆ〈o ′ 〉ˆf k [s ′ ](〈rest〉) (5)<br />
{<br />
∧o(d) = ok ∧ o(i1) = o ′ (d) = o ′ (i1) = ɛ ∧ s ′ s(z) wenn z ≠ id<br />
(z) =<br />
s(z) + x sonst<br />
i(c) = zahleEin(x, id) ∧ i ′ (i2) = prüfe(x, id) ∧ i(i2) = i ′ (c) = i ′′ (c) = i ′′ (i2) = ɛ ∧ s(id) > x ∧ customerOk(id)<br />
⇒ f h [s](〈i〉ˆ〈i ′ 〉ˆ〈i ′′ 〉ˆ〈rest〉) = 〈o〉ˆ〈o ′ 〉ˆ〈o ′′ 〉ˆf k [s ′ ](〈rest〉) (6)<br />
∧o(d) = ok ∧ o ′ (i1) = check(s(id) > x ∧ customerOk(id), x, id) ∧ o(i1) = o ′ (d) = o ′′ (d) = o ′′ (i1) = ɛ<br />
{<br />
∧s ′ s(z) wenn z ≠ id ∨ s(id) ≤ x ∨ ¬customerOk(id)<br />
(z) =<br />
s(z) − x sonst<br />
Beachten Sie dass auch f k Präfix-monoton ist, also i 1 ⊑ i 2 ⇒ f k (i 1 ) ⊑ f k (i 2 ) gilt. Dies ist notwendig um<br />
sicher<strong>zu</strong>stellen dass die Funktion auch realisierbar ist. Des weiteren ist <strong>zu</strong> beachten dass die Funktion partiell<br />
ist, dass also nicht jede Eingabehistorie eine Ausgabehistorie liefert.<br />
Um sicher<strong>zu</strong>stellen dass die so definierte Funktion in der Tat eine Abstraktion der Zustandsmaschine aus<br />
Teilaufgabe a ist, also f k = Abs((∆ k , Σ k0 )) gilt, muss die Abstraktion wie schon <strong>zu</strong>vor folgender Bedingung<br />
genügen:<br />
Vermutung. f k (i) = o ⇔ ∃σ n ∈ Abläufe((∆ b , Σ k0 )). σ 0 ∈ Σ k0 ∧ ∀n ∈ N.(σ n+1 , o(n + 1)) = ∆(σ n , i(n + 1))<br />
Ohne Beweis.
Parallele Komposition der Funktionen: Es gibt nun verschiedene Möglichkeiten die Komposition<br />
der beiden stromverarbeitenden Funktionen <strong>zu</strong> definieren. Da wir die Komposition in Teilaufgabe b schon<br />
anhand der Zustandsmaschinen vorgenommen haben und wir wissen dass die Abstraktion durch Komposition<br />
distribuiert, also Abs((∆1, Σ1) ‖ (∆2, Σ2)) = Abs(∆1, Σ1) ⊗ Abs(∆2, Σ2) gilt (siehe Foliensatz 7, Folie 27),<br />
könnten wir einfach eine Funktion für die Zustandsmaschine aus Abbildung 6 angeben, genau so wie wir das<br />
schon <strong>zu</strong>vor für Bargeldbe<strong>zu</strong>g und Kontoverwaltung gemacht haben.<br />
Wir werden im Folgenden jedoch eine alternative Definition anbieten. Wir werden die Komposition der<br />
beiden Funktionen als kleinsten Fixpunkt des folgenden Gleichungssystems definieren. Zunächst definieren wir<br />
aber die Ein-/Ausgabekanäle des <strong>zu</strong>sammengesetzten Systems: I = (I b ∪ I k ) \ (O b ∪ O k ) = {a, i1} ∪ {c, i2} \<br />
{b, i2} ∪ {d, i1} = {a, c} und O = (O b ∪ O k ) \ (I b ∪ I k ) = {b, i2} ∪ {d, i1} \ {a, i1} ∪ {c, i2} = {b, d}. Die<br />
Menge L = (I b ∪ I k ) ∩ (O b ∪ O k ) = ({a, i1} ∪ {c, i2}) ∩ ({b, i2} ∪ {d, i1}) = {i1, i2} sind dabei die Menge<br />
der internen Kanäle des Systems. Die Schnittstelle des <strong>zu</strong>sammengesetzten Systems ist somit durch (I ◮ O)<br />
gegeben. Wir definieren nun eine Funktion f bank : −→ I → −→ O wobei f bank = f b ⊗ f k als kleinster Fixpunkt des<br />
folgenden Gleichungssystems definiert ist. Im Folgenden bezeichnet z | C ′ die Restriktion der Belegung z auf<br />
die Teilmenge C ′ ⊆ C.<br />
• f bank (z) | O b = f b (z | I b )<br />
• f bank (z) | O k = f k (z | I k )<br />
Da f b und f k Präfix-monoton sind und die Menge der stromverarbeitenden Funktionen <strong>zu</strong>sammen mit der<br />
Präfix-ordnung eine ketten vollständige Ordnung bilden, kann man nun zeigen dass der kleinste Fixpunkt<br />
dieses Systems auch wirklich existiert und eindeutig ist (Satz von Kleene). Dadurch ist also die Funktion f bank<br />
wohldefiniert und wir können sie als Definition verwenden.<br />
Die Komposition sollte übrigens wiederum folgender Eigenschaft genügen:<br />
Vermutung. f bank (i) = o ⇔ ∃σ n ∈ Abläufe((∆ bank , Σ bank0 )).σ 0 ∈ Σ bank0 ∧ ∀n ∈ N.(σ n+1 , o(n + 1)) =<br />
∆(σ n , i(n + 1))<br />
Ohne Beweis.<br />
Teilaufgabe d)<br />
Für beide Eigenschaften definieren wir nun eine Hilfsfunktion<br />
fct sum = (s : Stream) N : returnFirstPar(first(s)) + sum(rest(s))<br />
sum(〈〉) = 0<br />
wobei returnFirstPar(String) den ersten Parameterwert eines Terms <strong>zu</strong>rück gibt. So kann die Eigenschaft (1)<br />
wie folgt spezifiziert werden:<br />
Selbiges für die Eigenschaft (2):<br />
sum({zahleEin( , id)} ⊗ x, id) ≥ sum({geld( , id)} ⊗ y, id) (7)<br />
sum({zahleEin( , id)} ⊗ x, id) ≤ sum({geld( , id)} ⊗ y, id) (8)<br />
M ⊗ x filtert aus dem Strom x alle Nachrichten heraus, die nicht in der Nachrichtenmenge M sind.<br />
TODO: Prüfung anhand von Abbildung 6.<br />
Aufgabe 2 Stromverarbeitende Funktionen<br />
• Syntaktische und semantische Korrektheit von Strömen<br />
Sei M = {⊥, 0, 1, 2, . . .}. Seien x, y ∈ M \ {⊥} Elemente aus einem Strom und seien s, t ∈ M ω<br />
Ströme über M mit der Trägermenge M ω = (M \ {⊥}) ∗ ∪ (M \ {⊥}) ∞ und s ≠ 〈 〉. Geben Sie für<br />
die folgenden Terme an, ob diese syntaktisch und ggf. semantisch korrekt, also wahr oder falsch,<br />
sind:
(a) first(〈1, 2, 3〉) = 1<br />
(b) rest(〈1, 2, ⊥, 3, 4〉) = rest(〈1, 2〉)<br />
(c) sˆt = tˆs<br />
(d) first(sˆt) = first(s)<br />
(e) (xˆs)ˆt = xˆ(sˆt)<br />
(f) first(rest(first(〈1, 2, 3〉))) = ⊥<br />
(g) rest(rest(rest(x&(y&s)))) = rest(s)<br />
• Stromverarbeitende Funktionen<br />
(a) Spezifizieren Sie eine Komponente, die zwei sortierte (monotone) Eingabeströme natürlicher<br />
Zahlen vereint und als einen sortierten Ausgabestrom wieder ausgibt. Geben Sie da<strong>zu</strong> die<br />
Signatur und die Spezifikation dieser Komponente an.<br />
(b) Modellieren Sie nun eine realisierende Funktion Ihrer Spezifikation.<br />
(c) Modellieren Sie eine Komponente mit zwei Eingabekanälen und einem Ausgabenkanal, jeweils<br />
vom Typ Nat, die wiederholt die ersten zwei Zahlen von den Eingabeströmen multipliziert<br />
und das Ergebnis auf dem Ausgabestrom ausgibt.<br />
• Axiomatische Spezifikation stromverarbeitender Funktionen<br />
In dieser Aufgabe wollen wir stromverarbeitende Funktionen durch Schnittstellen<strong>zu</strong>sicherungen<br />
spezifizieren. Eine Warteschlange soll Daten vom Typ Data speichern und bei Eingabe des Zeichens<br />
∇ einen gespeicherten Wert nach dem FIFO Prinzip <strong>zu</strong>rückgeben. Beispielsweise soll bei einem<br />
Input<br />
〈1, 2, ∇, 4, ∇〉<br />
der Output<br />
berechnet werden.<br />
〈 , , 1, , 2〉<br />
Modellieren Sie die Komponente indem Sie Schnittstellen<strong>zu</strong>sicherungen angeben.
Lösung der Aufgabe 2<br />
Syntaktische und semantische Korrektheit von Strömen<br />
Diskussion: Syntax vs. Semantik<br />
(a) first(〈1, 2, 3〉) = 1<br />
Richtig<br />
(b) rest(〈1, 2, ⊥, 3, 4〉) = rest(〈1, 2〉)<br />
Richtig, da 1&2& ⊥ &3&4 = 〈1, 2〉<br />
⊥ schneidet den Strom ab. Man sieht das, wenn man den Strom auf Normalform (1&2& . . .)<br />
bringt, dann kann man Axiome der Vorlesung anwenden.<br />
(c) sˆt = tˆs<br />
Syntaktisch richtig, aber semantisch falsch. Konkatenation ist nicht kommutativ.<br />
(d) first(sˆt) = first(s)<br />
Richtig, da s nicht leer ist.<br />
(e) (xˆs)ˆt = xˆ(sˆt)<br />
Syntaktisch falsch, da x eine Nachricht ist und ˆ ist daher nicht anwendbar.<br />
Richtig wären: (x & s)ˆt = x & (sˆt) und (〈x〉ˆs)ˆt = 〈x〉ˆ(sˆt)<br />
(f) first(rest(first(〈1, 2, 3〉))) = ⊥<br />
Syntaktisch falsch, da first eine Nachricht <strong>zu</strong>rück gibt. rest ist dafür nicht definiert. Zusätzliche<br />
Diskussion ob es überhaupt Fälle geben kann, in denen es sinnvoll ist ⊥ in Axiomen<br />
<strong>zu</strong> verwenden. Ja, z.B. in rest(〈〉) =⊥.<br />
(g) rest(rest(rest(x&(y&s)))) = rest(s)<br />
Richtig<br />
Stromverarbeitende Funktionen<br />
• Aufgabe a)<br />
fct merge : Stream Nat, Stream Nat → Stream Nat<br />
sorted(a) ∧ sorted(b) ∧ c = merge(a, b)<br />
=⇒ sorted(c)<br />
∧ ∀i, j : a i ≤ b j ⇒ ∃k : c k = a i<br />
∧ ∀i, j : a i ≥ b j ⇒ ∃k : c k = b j<br />
∧ ∀k : ∃i: c k = a i ∨ c k = b i<br />
sorted(〈 〉)<br />
sorted(〈x〉)<br />
sorted(x&y&s) ⇐⇒ (x ≤ y ∧ sorted(y&s))
• Aufgabe b)<br />
fct merge = (a: Stream Nat, b: Stream Nat)Stream Nat:<br />
if a = 〈 〉 then b<br />
else if b = 〈 〉 then a<br />
else if first(a) ≤ first(b) then first(a)ˆmerge(rest(a), b)<br />
else first(b)ˆmerge(a, rest(b))<br />
• Aufgabe c)<br />
fct smult(s1, s2 : StreamNat)StreamNat :<br />
(first(s1) ∗ first(s2))&smult(rest(s1), rest(s2))<br />
Axiomatische Spezifikation stromverarbeitender Funktionen<br />
Zunächst können wir uns überlegen, wie eine stromverarbeitende Funktion für die Warteschlange aussehen<br />
könnte. Seien nun I = Data ∪ {▽} die Menge der Eingabesymbole und O = Data ∪ { } die Menge der<br />
Ausgabesymbole. Seien außerdem d ∈ Data, ds ∈ Stream Data, s ∈ Stream I. Wir charakterisieren die stromverarbeitende<br />
Funktion q durch:<br />
q(〈〉) = 〈〉<br />
q(〈d〉 ∧ ds ∧ 〈▽〉 ∧ s)) = 〈 〉 ∧ q(ds) ∧ 〈d〉 ∧ q(s)<br />
q(d&ds) = &q(ds)<br />
An der zweiten Gleichung sehen wir, dass immer wenn ein ▽ im Eingabestrom vorkommt, das erste Element<br />
auf den Ausgabestrom geschrieben wird. Die Anzahl der Datenelemente im Ausgabestrom ist also stets gleich<br />
der ▽ Elemente im Eingabestrom. Genauso ist die Anzahl der -Elemente im Ausgabestrom gleich der Anzahl<br />
der Datenelemente im Eingabestrom. Wir müssen außerdem noch sicherstellen, dass die richtigen Datenelemente<br />
in der richtigen Reihenfolge auf den Strom geschrieben werden.<br />
Wir formulieren die Schnittellen<strong>zu</strong>sicherung über den Eingabekanal i ∈ Stream I und den Ausgabekanal<br />
o ∈ Stream O. Seien außerdem x ∈ Stream I und y ∈ Stream O und n ∈ N.<br />
∀x, y : x ⊑ i ∧ y ⊑ o∧ ‖ x ‖=‖ y ‖⇒<br />
Data#y = {▽}#x<br />
∧ { }#y = Data#x<br />
Nun sollten wir diese Zusicherungen noch auf Eingaben einschränken, die wohlgeformt sind, also nie mehr<br />
▽ erhalten als Daten. Da<strong>zu</strong> definieren wir:<br />
valid(i) :⇔ ∀z : z ⊑ i ⇒ Data#z ≥ {▽}#z
Aufgabe 3 Programmieraufgabe: Synchronisation von Prozessen<br />
• Bäckerei-Problem<br />
Beim Betreten des Geschäfts erhält jeder Kunde eine Wartenummer. Der Kunde mit der kleinsten<br />
Nummer wird als nächster bedient. Da es keine Garantie gibt, dass zwei Kunden nicht die gleiche<br />
Wartenummer kriegen, wird im Falle zwei gleicher Nummern der Prozess (Kunde) mit dem<br />
kleinsten Namen als erster bedient. Das bedeutet, wenn P i und P j die gleiche Nummer erhalten<br />
und i < j, dann wird der Prozess P i als erstes bedient.<br />
– Schreiben Sie ein Programm in Pseudo-Code für das Backery-Problem.<br />
Hinweis: Da die Prozessnamen einzigartig und total geordnet sind, ist der Algorithmus<br />
komplett deterministisch.<br />
– Schreiben Sie ein Programm für das Backery-Problem, indem Sie binäre Semaphoren benutzen.<br />
– Optional: Schreiben Sie ein Programm in Java, dass den gleichen Sachverhalt umsetzt und<br />
vergleichen Sie die 2 Programme.<br />
• Das Philosophen-Problem<br />
Fünf Philosophen sitzen gemeinsam an einem runden Tisch, an dem sie unabhängig voneinander<br />
von Zeit <strong>zu</strong> Zeit essen. Jeder Philosoph hat rechts neben seinem Teller nur eine Gabel, benötigt<br />
aber <strong>zu</strong>m Essen zwei Gabeln, also auch die seines linken Nachbarn. Aus diesem Grund können nicht<br />
alle Philosophen gleichzeitig essen, sondern sie müssen sich bezüglich ihrer kritischen Abschnitte<br />
Essen synchronisieren.<br />
– Geben Sie eine Programmlösung unter Verwendung der P- und V-Operationen an, bei der es<br />
<strong>zu</strong> keinerlei Verklemmungen kommen kann.<br />
Hinweis:<br />
∗ Die Philosophen sollen als Prozesse modelliert werden<br />
∗ Jeder Philosoph kann sich in einem der folgende drei Zustände befinden (denkend, hungrig<br />
und essend)
Abbildung 7: Das Philosophen-Problem<br />
Lösung der Aufgabe 3<br />
Backery problem<br />
• Lösung a)<br />
var choosing : array [ 0 . . . n−1] o f boolean ;<br />
number : array [ 0 . . . n−1] o f i n t e g e r ;<br />
i n i t i a l i z e choosing to f a l s e and number to 0<br />
repeat<br />
choosing [ i ]:= true ;<br />
number [ i ]:= max( 0 , number [ 1 ] , . . . , number [ n−1])+1<br />
choosing [ i ]:= f a l s e ;<br />
f o r j :=0 to n−1<br />
do begin<br />
while choosing [ j ] do no−op<br />
while number [ j ]!=0 and ( number [ j ] , j ) < ( number [ i ] , i ) do no−op ;<br />
end ;<br />
c r i t i c a l s e c t i o n ;<br />
number [ i ] : = 0 ;<br />
remainder s e c t i o n<br />
u n t i l f a l s e ;
• Lösung b)<br />
semaphore mutex ;<br />
semaphore s e r v e ;<br />
semaphore s h a r e j ;<br />
number : array [ 0 . . . n−1] o f i n t e g e r ;<br />
repeat<br />
P( mutex ) ;<br />
number [ i ]:= max( 0 , number [ 1 ] , . . . , number [ n−1])+1;<br />
V( mutex ) ;<br />
P( s h a r e j ) ;<br />
f o r j :=0 to n−1<br />
do begin<br />
while number [ j ]!=0 and number [ j ]
– Wenn ein Philosoph essen will, versucht er die Gabeln <strong>zu</strong> beiden Seiten seines Tellers <strong>zu</strong> bekommen.<br />
Schat er es, kann er für eine Zeit lang essen. Ist er mit Essen fertig, legt er die Gabeln wieder auf<br />
den Tisch <strong>zu</strong>rück und denkt weiter nach.<br />
– Frage: Wie kann ein Programm aussehen, bei dem alle Philosophen immer mal wieder essen können<br />
und keiner am Tisch verhungert.<br />
• Lösungsansatz 1:<br />
Der naheliegendste Versuch ist, einen hungrigen Philosophen <strong>zu</strong>erst nach seiner linken Gabel greifen <strong>zu</strong><br />
lassen. Sobald er die linke Gabel hat, greift er nach der rechten Gabel. Das Problem bei einer solchen<br />
Vorgehensweise ist dass wenn alle Philosophen gleichzeitig ihre linke Gabel schnappen, kommt es <strong>zu</strong> einer<br />
Verklemmung, einem Deadlock, und es geht nicht weiter. Eine modizierte Version dieser Vorgehensweise<br />
ist, dass ein hungriger Philosoph <strong>zu</strong>erst seine linke Gabel nimmt und dann prüft, ob die rechte Gabel<br />
verfügbar ist. Ist dies der Fall, kann er sie nehmen. Wenn nicht, legt er seine linke Gabel wieder <strong>zu</strong>rück<br />
und wiederholt den Vorgang nach einer gewissen Zeit. Auch dieses Vorgehen kann <strong>zu</strong> einem Problem<br />
führen. Wenn alle Philosophen im Gleichtakt vorgehen, kommt es <strong>zu</strong> einem Lifelock.<br />
• Lösungsansatz 2:<br />
Bei einem Lifelock nimmt jeder Philosoph seine linke Gabel, stellt fest, dass die rechte Gabel nicht frei<br />
ist und legt die linke <strong>zu</strong>rück und so weiter. In einer solchen Situation laufen die Prozesse zwar, aber sie<br />
kommen nicht in ihrer Abarbeitung weiter. Man spricht hier auch vom Aushungern. Eine Möglichkeit,<br />
die <strong>zu</strong>mindest meistens funktioniert ist, dass die Philosophen eine nicht eine feste, sondern eine <strong>zu</strong>fällig<br />
lange Zeit warten, bis sie den Vorgang wiederholen. So ist die Möglichkeit eines Lifelock sehr gering, aber<br />
es kann dennoch zeitweise <strong>zu</strong> einem Aushungern kommen. Eine funktionierende Möglichkeit ist, dass man<br />
das Aufnehmen der Gabeln, Essen und Ablegen der Gabeln als kritischen Abschnitt ansehen und unter<br />
gegenseitigem Ausschluss ablaufen lässt. In diesem Fall darf immer nur ein Philosoph essen, obwohl die<br />
Bestecke für zwei gleichzeitig essende Philosophen reichen würden<br />
• Lösungsansatz 3:<br />
Eine Lösung, bei der immer zwei Philosophen essen können und weder Deadlocks noch Lifelocks entstehen<br />
können, ist wie folgt: In einem Feld wird verfolgt, ob ein Philosoph gerade nachdenkt, isst oder hungrig<br />
ist, also versucht die Gabeln <strong>zu</strong> bekommen. Ein Philosoph kann nur in den Zustand essen übergehen,<br />
wenn seine beiden Nachbarn gerade nicht am Essen sind. Es existiert pro Philosoph ein Semaphor, so<br />
dass hungrige Philosophen blockieren können, falls die benötigten Gabeln in Gebrauch sind. Erst gelangt<br />
ein hungriger Philosoph alleine in den kritischen Bereich. Er prüft, ob seine beiden Nachbarn essen. Falls<br />
ja, blockiert er solange. Falls nein, beginnt er <strong>zu</strong> essen und verlässt den kritischen Bereich. Ist er fertig<br />
mit Essen, muss er in den kritischen Bereich kommen, seinen Status auf nachdenken setzen, die Gabeln<br />
freigeben und den kritischen Bereich verlassen.<br />
#d e f i n e N 5 /∗ Number o f p h i l o s p h e r s ∗/<br />
#d e f i n e RIGHT( i ) ( ( ( i )+1) %N)<br />
#d e f i n e LEFT( i ) ( ( ( i )==N) 0 : ( i )+1)<br />
typedef enum { THINKING, HUNGRY, EATING } p h i l s t a t e ;<br />
p h i l s t a t e s t a t e [N ] ;<br />
semaphore mutex =1;<br />
semaphore s [N ] ; /∗ one per philosopher , a l l 0 ∗/<br />
void t e s t ( i n t i ) {<br />
i f ( s t a t e [ i ] == HUNGRY &&<br />
s t a t e [LEFT( i ) ] != EATING &&<br />
s t a t e [RIGHT( i ) ] != EATING ) { s t a t e [ i ] = EATING; V( s [ i ] ) ; }<br />
}
void g e t f o r k s ( i n t i ) {<br />
P( mutex ) ;<br />
s t a t e [ i ] = HUNGRY;<br />
t e s t ( i ) ;<br />
V( mutex ) ;<br />
P( s [ i ] ) ;<br />
}<br />
void p u t f o r k s ( i n t i ) {<br />
P( mutex ) ;<br />
s t a t e [ i ]= THINKING;<br />
t e s t (LEFT( i ) ) ;<br />
t e s t (RIGHT( i ) ) ;<br />
V( mutex ) ;<br />
}<br />
void p h i l o s o p h e r ( i n t p r o c e s s ) {<br />
while ( 1 ) {<br />
think ( ) ;<br />
g e t f o r k s ( p r o c e s s ) ;<br />
eat ( ) ;<br />
p u t f o r k s ( p r o c e s s ) ;<br />
}<br />
}<br />
Aufgabe 4 Gezeitete Ströme<br />
Sei M 1 = {reset}, M 2 = {alarm}, M = {alarm, reset} und n ∈ N + .<br />
(a) Geben Sie einen gezeiteten Strom s über M an, so dass ∀ x ∈ N 0 : (((x>0 ⇒ (s(x) enthält reset))∧<br />
(∀y ∈N + : x < y ≤ x + n ⇒ (s(y) enthält reset nicht))) ⇒ (s(x + n) enthält alarm)).<br />
(b) Geben Sie timeabs(s) an.<br />
(c) Seien I = {r} mit type(r) = M 1 die Eingabekanalmenge, O = {a} mit type(a) = M 2 die Ausgabekanalmenge.<br />
i) Geben Sie eine Funktion f : ⃗ I → ⃗ O, die<br />
i. zeitunabhängig bzw.<br />
ii. nicht zeitunabhängig<br />
ist und die folgende Schnittstellen<strong>zu</strong>sicherung erfüllt:<br />
∀ x ∈ N 0 : (((x > 0 ⇒ (r(x) enthält reset)) ∧ (∀ y ∈ N + : x < y ≤ x + n ⇒<br />
(r(y) enthält reset nicht))) ⇒ (a(x + n) enthält alarm)).<br />
ii) Für eine zeitunabhängige Funktion f wie oben geben Sie die Zeitabstraktion an.<br />
iii) Erfülle eine Funktion g : ⃗ I → ⃗ O nun die folgende Schnittstellen<strong>zu</strong>sicherung:<br />
∀ x ∈ N 0 : (((x > 0 ⇒ (r(x) enthält reset)) ∧ (∀ y ∈ N + : x < y ≤ x + n ⇒<br />
(r(y) enthält reset nicht))) ⇐⇒ (a(x + n) enthält alarm)).<br />
Kann g zeitunabhängig bzw. nicht zeitunabhängig sein und warum<br />
Lösung der Aufgabe 4<br />
(a) Ein trivialer Strom ist s = λx ∈ N + . 〈alarm〉.<br />
Ein weniger trivialer Strom ist s ′ = λx ∈ N + .<br />
{<br />
〈alarm reset〉 , wenn x ≡ 0 mod n ,<br />
ɛ ,<br />
sonst.
(b) timeabs(s) = 〈alarm alarm alarm . . .〉 und timeabs(s ′ ) = 〈alarm reset alarm reset alarm reset . . .〉.<br />
(c) i) • f = λs∈I. ⃗ λa∈O. λx∈N + . 〈alarm〉.<br />
⎧<br />
Diese Funktion ( ist konstant, insbesondere zeitunabhängig. )<br />
⎪⎨<br />
(s(r)(1) enthält reset) ∨<br />
• f = λs∈I. ⃗ 〈alarm〉 , wenn<br />
,<br />
λa∈O. λx∈N + .<br />
(x>n ∧ (s(r)(x − n) enthält reset))<br />
⎪⎩<br />
ɛ , sonst.<br />
ist nicht zeitunabhängig. { Denn betrachte zwei Belegungen von I<br />
〈reset〉 , wenn x=1 ,<br />
s 1 = λr ∈I. λx∈N + .<br />
ɛ , sonst<br />
und<br />
{<br />
〈reset〉 , wenn x=2 ,<br />
s 2 = λr ∈I. λx∈N + .<br />
ɛ , sonst.<br />
Es gilt timeabs(s 1 )(r) = 〈reset〉 = timeabs(s 2 )(r). Aber<br />
f(s 1 ) = λa∈O. λx∈N + . 〈alarm〉 { und<br />
〈alarm〉 , wenn x=n+2 ,<br />
f(s 2 ) = λa∈O. λx∈N + .<br />
ɛ , sonst ,<br />
also timeabs(f(s 1 )(a)) = alarm ∞ ≠ 〈alarm〉 = timeabs(f(s 2 )(a)).<br />
ii) Zum Beispiel λx ∈ M ω . λy ∈N + . 〈alarm〉 oder λx ∈ M ω . λy ∈{1, 2}. 〈alarm〉.<br />
iii) Wir zeigen, dass so ein { g immer nicht zeitunabhängig ist. Seien<br />
〈reset〉 , wenn x ≡ 0 mod (n+1) ,<br />
t 1 = λr ∈I. λx∈N + .<br />
ɛ , sonst.<br />
und<br />
t 2 = λr ∈I. λx∈N + . 〈reset〉.<br />
Dann timeabs(t 1 (r)) = reset ∞ = timeabs(t 2 (r)). Nun gibt es gibt eine Funktion h: N + → N 0 , so<br />
dass<br />
{<br />
〈alarm h(x) 〉 , wenn x ≡ n mod (n + 1) ,<br />
g(t 1 )(a) = λx∈N + .<br />
ɛ ,<br />
sonst,<br />
timeabs(g(t 1 )(a)) = alarm ∞ ,<br />
g(t 2 )(a) = λx∈N + . ɛ und<br />
timeabs(g(t 2 )(a)) = ɛ. Also<br />
timeabs(g(t 1 )(a)) ≠ timeabs(g(t 2 )(a)).<br />
Ein Beispiel einer solchen Abbildung<br />
⎧<br />
ist (<br />
)<br />
⎪⎨<br />
(x=n ∨ (x>n ∧ (s(r)(x−n) enthält reset))) ∧<br />
g = λs∈I. ⃗ 〈alarm〉 , wenn<br />
,<br />
λa∈O. λx∈N + .<br />
(∀y ∈ N + ∩ (x − n, x]: s(r)(y) enthält reset nicht)<br />
⎪⎩<br />
ɛ , sonst.