Auswertungsregeln für Listenfunktionen in Python: operationale

Transcription

Auswertungsregeln für Listenfunktionen in Python: operationale
Auswertungsregeln für Listenfunktionen in
Python: operationale Semantik
Operationale Semantik einer
imperativen Programmiersprache mit Listen;
hier Python
Modellierung der Verzeigerung zwischen Objekten
mittels Variablennamen als Ersatz für Adressen.
Modellierung des Speichers als abstrakte Schnittstelle
Dazu: Heap (Halde) und Heap-Variablen
P raktische Inf ormatik
1, W S
2004/05, F olien P ython−4,
(14. Januar2005)
Seite 1
Datenstruktur Heap, Halde
Definition Eine Halde (Heap) besteht aus:
•
•
Menge von Heap-Variablen: VH
Menge von HH-Bindungen an Heapvariablen
Möglichkeiten sind:
x 7→ v:
v ist Basiswert (Zahl, Character oder Nil)
x 7→ ⊥,
x 7→ None
x 7→ [x1|x2]: Wobei [x1|x2] Paar (Box) aus zwei Heap-Variablen ist
Zusatzbedingungen
• Einige Heap-Variablen sind als Wurzel-Variablen markiert.
• pro Heap-Variable ist nur eine HH-Bindung im Heap
• Heap-Variablen, die in einer Box vorkommen,
müssen eine HH-Bindung im Heap haben.
P raktische Inf ormatik
1, W S
2004/05, F olien P ython−4,
(14. Januar2005)
Seite 2
Datenstruktur Heap, Halde
Die beiden Formen der HH-Bindung
x
x
v
P raktische Inf ormatik
x1
1, W S
2004/05, F olien P ython−4,
x2
(14. Januar2005)
Seite 3
Heapvariablen
Eine Heapvariable x repräsentiert einen Basiswert
oder ein komplexes Heap-Objekt:
einen gerichteten Graphen ausgehend von x.
Beispiel Wenn H = {x 7→ [x1|x2], x1 7→ 1, x2 7→ Nil)},
dann repräsentiert x die Liste [1]
x
x1
x2
Nil
1
Der Programmvariablen z:
wird mittels {z 7→ x} ein Objekt zugeordnet
wobei x Heapvariable ist, die das Objekt repräsentiert.
P raktische Inf ormatik
1, W S
2004/05, F olien P ython−4,
(14. Januar2005)
Seite 4
Umgebungen mit Heaps
Gegeben ein Heap (Halde) H
x 7→ y
R
(PH-) Bindung:
Umgebungsrahmen:
(R1, R2, H)
x Programm- und y Heap-Variable
R Menge von PH-Bindungen zum
Heap H
R1 ist lokaler Umgebungsrahmen,
Umgebung
(Variablenumgebung, R2 ist globaler Umgebungsrahmen;
Zustand)
H ist Halde .
Annahme Wurzel-Variablen von H sind mindestens die Heap-Variablen,
die in den Variablenumgebungen R1, R2 als Ziele vorkommen.
Beachte In Implementierungen:
Umgebung ist als Stack organisiert.
Zur Optimierung werden Werte auf einem Auswertungsstack abgelegt
und verarbeitet.
P raktische Inf ormatik
1, W S
2004/05, F olien P ython−4,
(14. Januar2005)
Seite 5
Beispiele
Darstellung der Liste [100]
mit Umgebung und Halde:
PH-Bindung:
Halde
z1
z1 7→ z2
{z2 7→ [z3|z4],
z3 7→ 100,
z4 7→ Nil}
z2
P raktische Inf ormatik
1, W S
z3
z4
100
Nil
2004/05, F olien P ython−4,
(14. Januar2005)
Seite 6
Beispiele
Darstellung einer zyklischen Liste
Druckbild: [[[[[...]]]]]]
AB
AA
Nil
Die Halde dazu sieht so aus: {AA 7→ [AA|AB], AB 7→ Nil}
P raktische Inf ormatik
1, W S
2004/05, F olien P ython−4,
(14. Januar2005)
Seite 7
Erreichbarkeitsrelation
H,∗
Erreichbarkeitsrelation −−→ des Heaps H:
H,∗
x −−→ y, wenn
•
•
x = y, oder
∃ x1, . . . , xn, so dass x = x1 und y = xn und
für alle i = 1, . . . n − 1 entweder
xi 7→ [xi+1|x0i+1] ∈ H oder
xi 7→ [x0i+1|xi+1] ∈ H
Heap-Variable x ist erreichbar (aktiv),
H,∗
wenn sie von einer Wurzelvariable x0 aus erreichbar, d.h. : x0 −−→ x,
andernfalls ist x unerreichbar (redundant).
H,∗
Alternativ: −−→ ist die reflexiv-transitive Hülle der Relation:
x → y, wenn x 7→ [y|y 0] ∈ H oder x 7→ [y 00|y] ∈ H
P raktische Inf ormatik
1, W S
2004/05, F olien P ython−4,
(14. Januar2005)
Seite 8
Speicherbereinigung, garbage collection
HH-Bindungen von unerreichbaren Variablen kann man aus dem Heap
entfernen.
Das ist die Aufgabe des Garbage-Collectors
Als Wurzelvariablen nimmt man sinnvollerweise:
•
•
Heap-Variablen, auf die vom Stack aus referenziert wird
Heap-Variablen, auf die das Programm referenziert.
P raktische Inf ormatik
1, W S
2004/05, F olien P ython−4,
(14. Januar2005)
Seite 9
Regeln der (erweiterten) operationalen
Semantik
zweite Variante der operationalen Semantik von Python,
die auch zyklische Listen beschreiben kann.
Notationen
[[.]]:
(Z, s) →e (Z 0, x)
P raktische Inf ormatik
1, W S
innen syntaktische Konstrukte, außen: Aktionen
oder Werte.
Werte s im Zustand Z aus,
Resultat ist ein Objekt, repräsentiert durch die
Heapvariable x;
Z 0 ist der neue Zustand
2004/05, F olien P ython−4,
(14. Januar2005)
Seite 10
Auswertung eines Listenausdrucks
Python-Listenausdruck: [a1, . . . , an]; Halde H
(n ≥ 1):
Die Regel beschreibt einen Schritt der Auswertung:
(Z; [[a1]]) →e (Z1; x1)
(Z1; [[[a2, . . . , an]]]) →e (Z2; x2)
Z2 = (R2,1, R2,2, H2)
(Z; [[[a1, . . . , an]]]) →e (R2,1, R2,2, H2 ∪ {x 7→ [x1|x2]}); x
Am Ende der Listen verwenden wir die spezielle Konstante Nil:
((R1, R2, H); [[[]]]) →e ((R1, R2, H ∪ {x 7→ Nil}); x)
P raktische Inf ormatik
1, W S
2004/05, F olien P ython−4,
(14. Januar2005)
Seite 11
Die Alias-Namens-Problematik: Beispiel
a = [1,2]
b = a
Nach a = [1,2]:
Bindungen:
Heap:
. . . , a 7→ u1, . . .
{u1 7→ [u2|u3], u2 7→ 1, u3 7→ [u4|u5], u4 7→ 2, u5 7→ Nil, . . .}
Nach b = a
Bindungen:
Heap:
. . . , a 7→ u1, . . . , b 7→ u1, . . .
{u1 7→ [u2|u3], u2 7→ 1, u3 7→ [u4|u5], u4 7→ 2, u5 7→ Nil, . . .}
a
u1
b
u2
u3
1, W S
u5
Nil
2
1
P raktische Inf ormatik
u4
2004/05, F olien P ython−4,
(14. Januar2005)
Seite 12
Auswertung von append
Auswertung von a.append(b) wobei a, b Variablen.
((R1, R2, H); [[a.append(b)]]) →e ((R1, R2, H 0); None)
Bedingungen:
vor der Auswertung
nach der Auswertung
H = H0 ∪ {x 7→ Nil}
x letzte Heap-Variable zu a mit x 7→ Nil
b 7→ x1 ist in R1
H 0 = H0 ∪ {x 7→ [x1|x2], x2 7→ Nil}
x2 ist neu erzeugte Heap-Variable
a, b sind auch die Namen der Programm-Variablen
Effekt: {x 7→ Nil} wurde ersetzt durch {x 7→ [x1 | x2]}
P raktische Inf ormatik
1, W S
2004/05, F olien P ython−4,
(14. Januar2005)
Seite 13
Auswertung von append
Veranschaulichung der Auswertung von a.append(b):
Vorher:
a
u1
b
x
x1
Nil
w
Nachher:
a
u1
b
x
x1
x1 x2
Nil
w
Dadurch wird (die Liste) b als letztes Element an die Liste angehängt.
P raktische Inf ormatik
1, W S
2004/05, F olien P ython−4,
(14. Januar2005)
Seite 14
Beispiel zu append
Zyklische Struktur mittels append-Anwendungen
Liste mit unendlicher Verschachtelungstiefe:
Nach a = [1, 2]; a.append(a)
Halde:
{u1 7→ [u2|u3], u2 7→ 1, u3 7→ [u4|u5], u4 7→ 2, u5 7→ [u1|u7], u7 7→ Nil, . . .}
a
u1
u2 u3
1
u4 u5
u1 u7
Nil
2
Beachte: u1 tritt zweimal auf, muss aber das gleiche Ziel haben.
P raktische Inf ormatik
1, W S
2004/05, F olien P ython−4,
(14. Januar2005)
Seite 15
operationelle Semantik von insert
Fall: insert innerhalb der Liste
((R1, R2, H); [[a.insert(i, b)]]) →e ((R1, R2, H 0); None)
Hierbei muss gelten:
H 0 = H0 ∪ {xi 7→ [y1|y2], y2 7→ [ei+1|xi+1]},
wobei xi Heap-Variable zum i-ten Listen-Tail
H = H0 ∪ {xi 7→ [ei+1|xi+1]},
b 7→ y1 ∈ R1, und
y2 neue Heap-Variable.
P raktische Inf ormatik
1, W S
2004/05, F olien P ython−4,
(14. Januar2005)
Seite 16
operationelle Semantik von insert (2)
vorher:
ei
xi
ei+1
...
xi+1
nach insert:
ei
xi
ei+1
y1
P raktische Inf ormatik
1, W S
...
xi+1
y2
2004/05, F olien P ython−4,
(14. Januar2005)
Seite 17
operationelle Semantik von insert (3)
Fall: insert am Ende der Liste
((R1, R2, H); [[a.insert(i, b)]]) →e ((R1, R2, H 0); None)
Hierbei muss gelten:
H 0 = H0 ∪ {xi 7→ [y1|y2], y2 7→ Nil}, wobei i ≥ len(a)
H = H0 ∪ {xi 7→ Nil}, b 7→ y1 ∈ S,
y2 neue Heap-Variable.
P raktische Inf ormatik
1, W S
2004/05, F olien P ython−4,
(14. Januar2005)
Seite 18
operationelle Semantik von map
operationelle Semantik von map:
aus kleineren Operationen zusammensetzen:
Zum Beispiel als operationale Semantik der Funktion:
def map_demo(f,xs):
if len(xs) == 0:
return [];
else:
wert = map_demo(f, xs[1:len(xs)]);
wert.insert(0,f(xs[0]));
## Seiteneffekt (wie cons)
return wert;
P raktische Inf ormatik
1, W S
2004/05, F olien P ython−4,
(14. Januar2005)
Seite 19
operationelle Semantik von a[i] = b
((R1, R2, H); [[a[i] = b]]) → (R1, R2, H 0)
mit H 0 = H0 ∪ {xi 7→ [z|y2]}
wobei
H = H0 ∪ {xi 7→ [y1|y2]},
xi Heap-Variable zum i-ten Listen-Tail, und
b 7→ z ∈ R1
P raktische Inf ormatik
1, W S
2004/05, F olien P ython−4,
(14. Januar2005)
Seite 20
Indirektionen
Indirektionen sind Bindungen
x1 7→ x2,
wobei x1, x2 Heap-Variablen sind.
(Gibt es in Python nicht.)
Objekt zu x1:
im Heap
ist das Objekt zu x2
bzw. Suche über weitere Indirektionen
Diese Indirektionen sind nicht sichtbar in der Programmiersprache
•
•
•
•
leicht komplizierteres formales Modell
Indirektionszyklen sind möglich
Verwendung in Implementierungen z.T. wegen der Effizienz
Notwendig ist dann das Verkürzen von Indirektionsketten
P raktische Inf ormatik
1, W S
2004/05, F olien P ython−4,
(14. Januar2005)
Seite 21
Implementierung der Halde in einem
Speichermodell
Speichermodell RAM-Speicher
(Random Access Memory)
S ist endliche Folge der Länge L von Bytes (1 Byte = 8 Bit)
indiziert mit 0, . . . , L − 1.
L ist die Größe des Speichers.
Der gespeicherte Wert unter Adresse i ist das Byte S(i)
Adresse: Anfangsindex einer Subfolge (in Binärdarstellung).
Die benötigte Adresslänge in Bits ist dlog2(L)e.
Zugriffsfunktion get(S, i, l) ergibt Subfolge von S der Länge l ab i.
00101001
0
1
P raktische Inf ormatik
3
2
1, W S
4
5
2004/05, F olien P ython−4,
(14. Januar2005)
Seite 22
Implementierung der Halde unter Benutzung des
RAM-Speichers
Wort
=
Adresse zu 32 Bit
Adresse eines Wortes
Heapvariable
Ein Paar [x1|x2]
=
=
=
=
P raktische Inf ormatik
1, W S
2004/05, F olien P ython−4,
Folge von 4 Bytes,
im Speicher direkt hintereinander,
d.h. S(i), S(i + 1), S(i + 2), S(i + 3).
Folge von 4 Bytes
erster Index.
Wort
2 Worte, die hintereinander sind, d.h.
S(i), . . . , S(i + 7).
(14. Januar2005)
Seite 23
Beispiel zur Haldenimplementierung
Betrachte die Bindungen
b 7→ x, x 7→ 4,
mit 32 Bit-Adressen implementiert
mit Programmvariable b, Heapvariable x
Wenn b den Wert 100 hat
dann ergibt a = get(H, 100, 4) eine Adresse (den Wert von x),
und get(H, a, 1) ergibt den Wert 4
200
100
x
b
100
P raktische Inf ormatik
4
1, W S
2004/05, F olien P ython−4,
200
(14. Januar2005)
Seite 24
Typmarkierungen der Werte
In dieser Implementierung fehlen Typmarkierungen der Werte:
Indirektionen, Paare, Nil, und Zahlen sind ununterscheidbar.
Eine Erweiterung könnte sein:
Adresse:
Paar:
Ganze Zahl:
Nil:
kein Wert:
P raktische Inf ormatik
1, W S
1
1
1
1
1
Byte
Byte
Byte
Byte
Byte
Markierung
Markierung
Markierung
Markierung
Markierung
2004/05, F olien P ython−4,
(14. Januar2005)
(z.B.
(z.B.
(z.B.
(z.B.
(z.B.
Seite 25
binär
binär
binär
binär
binär
1), und 4 Byte Adresse.
2), und 8 Byte Adressen.
3), und 4 Byte Zahl.
4).
5).
Bemerkungen zur Halden-Implementierung
Andere Halden-Implementierung sind möglich.
• die Adressen eines Adresspaares (einer Box) [x1|x2] müssen nicht
hintereinander sein
• Adressen brauchen keine aufsteigende Folge von Bytes zu sein
• Die Länge der Adressen kann 6= 32 sein.
P raktische Inf ormatik
1, W S
2004/05, F olien P ython−4,
(14. Januar2005)
Seite 26
Felder, Arrays in Python
In Python:
Listen und Tupel sind gleichzeitig eindimensionale Arrays
dürfen heterogen sein.
Mehrdimensionale Arrays und Matrizen
als Array von Arrays, bzw. mit Listen von Listen
Zugriffszeit auf S[i] ist konstant, wenn Index und Array bekannt sind.
Handhabung eines Feldes im Programm ist teilweise umständlich:
Indexberechnungen sind notwendig
explizite oder implizite Größenänderungen eines Arrays
verbrauchen Ressourcen.
P raktische Inf ormatik
1, W S
2004/05, F olien P ython−4,
(14. Januar2005)
Seite 27
Beispiele
Transposition einer 2-dimensionalen quadratischen Matrix in Python
def transpose(a,n):
for i in range(n):
for j in range(i+1,n):
a[i][j], a[j][i] = a[j][i] , a[i][j]
return a
def testtranspose(n):
b = range(n)
for i in range(n):
b[i] = range(n)
for i in range(n):
print b[i];
c = transpose(b,n)
print " "; print "Nach Transposition:"
for i in range(n):
print c[i]
P raktische Inf ormatik
1, W S
2004/05, F olien P ython−4,
(14. Januar2005)
Seite 28
Beispiel: Matrixmultiplikation, Determinante
für quadratische Matrizen
def matrixMult(a,b):
leng = len(a);
c = range(leng);
for i in range(leng):
c[i] = range(leng);
for j in range(leng):
c[i] [j] = 0;
for i in range(leng):
for j in range(leng):
sum = 0
for k in range(leng):
sum = sum + a[i][k]*b[k][j]
c[i][j] = sum
return c
P raktische Inf ormatik
1, W S
2004/05, F olien P ython−4,
(14. Januar2005)
Seite 29
Beispiel: Matrixmultiplikation, Determinante
def testmatmult(leng):
a = range(leng);
b = range(leng);
print a;
print b;
for i in range(leng):
a[i] = range(leng);
b[i] = range(leng);
for j in range(leng):
a[i] [j] = i;
b[i] [j] = j;
print a;
print b;
return (matrixMult(a,b))
P raktische Inf ormatik
1, W S
2004/05, F olien P ython−4,
(14. Januar2005)
Seite 30
Beispiel: Determinante
def determinante(a):
n = len(a);
if n <= 0:
return 1;
else:
if n == 1:
return a[0][0]
else:
sum = 0;
flip = -1;
for i in range(n):
flip = (-1)*flip;
b = matrixcopy(a);
for j in range(n):
b[j].pop(0);
P raktische Inf ormatik
1, W S
2004/05, F olien P ython−4,
(14. Januar2005)
Seite 31
b.pop(i);
sum = sum + flip*a[i] [0] * determinante(b);
return(sum);
Achtung: Laufzeit O(2n), aber es existiert ein O(n3)-Algorithmus
Operationale Semantik: Test mit C
C:
wichtige und verbreitete imperative Programmiersprache
für maschinennahes Programmieren,
insbesondere Betriebssysteme.
C-Compiler ergeben effizienten Code.
Abstraktionsgrad nicht so hoch wie Python oder Haskell
Wir untersuchen die Eigenschaften der operationalen Semantik von C.
P raktische Inf ormatik
1, W S
2004/05, F olien P ython−4,
(14. Januar2005)
Seite 33
Zitate zu C
Aus Kernighan/Ritchie: Programmieren in C:
Diese Regeln sind außerordentlich kompliziert, denn sie
”
müssen mit einer Mischung von Funktionen alten und neuen
Stils fertigwerden. Wenn möglich, sollten Mischungen vermieden werden.“
Die Reihenfolge, in der Argumente bewertet werden, ist nicht
”
festgelegt; man beachte, dass sich verschiedene Übersetzer
hierin unterscheiden. Die Argumente und Funktionsbezeichner
werden jedoch vollständig bewertet [d.h. ausgewertet], mit allen Nebenwirkungen, bevor die Ausführung der Funktion beginnt...“
P raktische Inf ormatik
1, W S
2004/05, F olien P ython−4,
(14. Januar2005)
Seite 34
Zitate zu C (2)
Ein anderes Zitat zum Versuch einer Andeutung der (funktionalen)
operationellen Semantik von C:
. . . In anderen Worten, wenn das n-te Kode-Fragment durch
”
die Funktion fn repräsentiert wird, und s0 ist der Anfangszustand, dann ist der Endzustand definiert durch
sn = fn(fn−1(. . . f1(f0(s0)) . . .))
Die
Ausführung
. . . Parallelismus.“
P raktische Inf ormatik
1, W S
2004/05, F olien P ython−4,
der
(14. Januar2005)
einzelnen
Seite 35
Funktionen
erlaubt
Operationale Semantik eines C-Operators
i++
•
•
( i Programmvariable)
hat aktuellen Wert von i als Return-Wert
bewirkt einen Seiteneffekt i := i+1
Die operationale Semantik-Regel zu i++:
v = wert(i, Z)
P raktische Inf ormatik
1, W S
2004/05, F olien P ython−4,
w = v + 1 Z 0 = update(i, w, Z)
(Z; [[i++]]) →e (Z 0; v)
(14. Januar2005)
Seite 36
Operationale Semantik des Präfix-Operators ++
Unterschied zwischen ++i und i++:
Returnwert von ++i ist (Wert von i)+1.
Die operationale Semantik-Regel zu ++i:
v = wert(i, Z) w = v + 1 Z 0 = update(i, w, Z)
(Z; [[++i]]) →e (Z 0; w)
Vergleiche mit:
v = wert(i, Z)
P raktische Inf ormatik
1, W S
2004/05, F olien P ython−4,
w = v + 1 Z 0 = update(i, w, Z)
(Z; [[i++]]) →e (Z 0; v)
(14. Januar2005)
Seite 37
Beispiel
Betrachte das C-Code-Fragment
i = 7;
j = i++ * i++
Erwarteter Zustand danach:
Die Multiplikation wertet i++ zweimal aus:
erstes i++
zweites i++
Der Wert von j
ergibt 7,
ergibt 8,
ergibt j = 7 ∗ 8 = 56.
In Java ergibt sich der richtige Zustand
P raktische Inf ormatik
1, W S
2004/05, F olien P ython−4,
(14. Januar2005)
Seite 38
danach i = 8
danach i = 9.
Beispiel: Ausprobieren in C
Der C-Code
i = 7;
j = i++ * i++;
kompiliert in gcc ergibt den Zustand
j = 49, i = 8
P raktische Inf ormatik
1, W S
2004/05, F olien P ython−4,
(14. Januar2005)
Seite 39
Beispiel: Erklärungsversuch
Compiler versucht, Doppelauswertung von i++ zu vermeiden
und ändert daher das Programm ab:
i = 7;
j = (let x = i++ in
x*x);
bzw. in let-freier Schreibweise:
i = 7;
x = i++;
j = x*x;
P raktische Inf ormatik
1, W S
2004/05, F olien P ython−4,
(14. Januar2005)
Seite 40
Beispiel: Erklärungsversuch (2)
Es ergibt sich:
Nach Auswertung von x:
Danach x ∗ x auswerten
{x 7→ 7, i 7→ 8, . . .}.
j = 49,
Fazit:
Vermutlich eine (optimierende) Programmtransformation,
die die operationale Semantik in diesem Fall nicht erhält.
P raktische Inf ormatik
1, W S
2004/05, F olien P ython−4,
(14. Januar2005)
Seite 41

Documents pareils