Medientechnisches Wissen: Band 2 Informatik, Programmieren, Kybernetik 9783110496253, 9783110496246

This multivolume textbook offers students and media scientists an introduction to the disciplines of the natural science

329 23 7MB

German Pages 454 Year 2018

Report DMCA / Copyright

DOWNLOAD FILE

Polecaj historie

Medientechnisches Wissen: Band 2 Informatik, Programmieren, Kybernetik
 9783110496253, 9783110496246

Table of contents :
Inhalt
Vorwort
Teil I: Informatik (Thorsten Schöler)
1. Einführung
2. Einleitung
3. Theoretische Informatik
4. Technische Informatik
5. Algorithmen und Datenstrukturen
6. Bäume
7. Gestreute Speicherung, Hashing
8. Präfixbäume
9. Graphen
10. Schwere Probleme und Heuristiken
11. Zusammenfassung und Ausblick
12. Lektüreempfehlungen
Literatur
Teil II: Programmieren für Medienwissenschaftler (Stefan Höltgen & Johannes Maibaum)
1. Einleitung
2. Assembler
3. BASIC
4. C
5. Python
Teil III: Kybernetik ( Thomas Fischer)
1. Einführung
2. Determinismus und Determinierbarkeit
3. Zirkuläre Kausalität
4. Zwischen Wirk- und Zweckursachen
5. Ausgangspunkt Subjekt
6. Systeme, Systemgrenzen und Wiedereintritt
7. Von Determinierbarkeit zu Nicht-Determinierbarkeit
8. Ausblick
9. Lektüreempfehlungen
Literatur
Schlagwortverzeichnis

Citation preview

Thorsten Schöler, Stefan Höltgen, Johannes Maibaum, Thomas Fischer Medientechnisches Wissen 2 De Gruyter Studium

Weitere empfehlenswerte Titel Medientechnisches Wissen, Band 1 S. Höltgen (Hrsg.), 2017 ISBN 978-3-11-047748-1, e-ISBN (PDF) 978-3-11-047750-4, e-ISBN (EPUB) 978-3-11-047762-7

Medientechnisches Wissen, Band 3 S. Höltgen, 2019 ISBN 978-3-11-049626-0, e-ISBN (PDF) 978-3-11-049627-7, e-ISBN (EPUB) 978-3-11-049359-7

Medientechnisches Wissen, Band 4 S. Höltgen (Hrsg.), 2020 ISBN 978-3-11-058179-9, e-ISBN (PDF) 978-3-11-058180-5, e-ISBN (EPUB) 978-3-11-058182-9

Mathematik B. Ulmann, 2015 ISBN 978-3-11-037511-4, e-ISBN (PDF) 978-3-11-037513-8, e-ISBN (EPUB) 978-3-11-039785-7

Thorsten Schöler, Stefan Höltgen, Johannes Maibaum, Thomas Fischer

Medientechnisches Wissen Band 2: Informatik, Programmieren, Kybernetik Herausgegeben von Stefan Höltgen

Herausgeber Dr. Stefan Höltgen Humboldt-Universität zu Berlin Inst. für Musikwissenschaft und Medienwissenschaft Georgenstr. 47 10117 Berlin [email protected]

ISBN 978-3-11-049624-6, e-ISBN (PDF) 978-3-11-049625-3, e-ISBN (EPUB) 978-3-11-049358-0 Library of Congress Control Number: 2018959324 Bibliographic information published by the Deutsche Nationalbibliothek Die Deutsche Nationalbibliothek verzeichnet diese Publikation in der DeutschenNationalbibliografie; detaillierte bibliografische Daten sind im Internet über http://dnb.dnb.de abrufbar. © 2019 Walter de Gruyter GmbH, Berlin/Boston Redaktion: Maria Kuban Einbandabbildung: Martin Meier Druck und Bindung: CPI books GmbH, Leck www.degruyter.com

Inhalt Vorwort | 1

Teil I: Informatik (Thorsten Schöler) 1

Einführung | 7

2

Einleitung | 8

3 3.1 3.1.1 3.1.2 3.1.3 3.1.4 3.1.5 3.1.6 3.2 3.2.1 3.2.2 3.2.3 3.2.4 3.2.5

Theoretische Informatik | 10 Formale Sprachen | 10 Grammatik | 11 Reguläre Sprachen (Typ 3) | 13 Kontextfreie Sprachen (Typ 2) | 15 Kontextsensitive Sprachen (Typ 1) | 16 Rekursiv aufzählbare Sprachen (Typ 0) | 16 Zusammenfassung formaler Sprachen | 17 Automatentheorie | 18 Endliche Zustandsautomaten | 18 Kellerautomaten | 21 Turingmaschine | 24 Zusammenfassung Automatentheorie | 27 Registermaschine | 27

4 4.1 4.2

Technische Informatik | 29 Geschichtlicher Hintergrund | 29 Aktuelle Entwicklungen in der technischen Informatik | 37

5 5.1 5.1.1 5.1.2 5.1.3 5.1.4 5.2 5.2.1 5.2.2 5.3 5.3.1

Algorithmen und Datenstrukturen | 40 Algorithmen | 40 Eigenschaften von Algorithmen | 41 Textuelle Beschreibungsverfahren | 42 Laufzeitanalyse von Algorithmen | 47 Implementierung von Algorithmen | 51 Datenstrukturen | 54 Listen | 55 Stapel- oder Kellerspeicher | 56 Sortieralgorithmen | 57 Insertionsort | 58

VI | Inhalt 5.3.2 5.3.3 5.3.4 5.3.5 5.3.6

Selectionsort | 60 Bubblesort | 61 Quicksort | 63 Mergesort | 64 Heapsort | 66

6 6.1 6.2 6.3 6.4 6.5

Bäume | 69 Definitionen | 69 Knoten- und blattorientierte Bäume | 71 Binäre Suchbäume | 71 AVL-Bäume | 74 B-Bäume | 78

7 7.1 7.2 7.3 7.4

Gestreute Speicherung, Hashing | 82 Kollisionen | 84 Offenes Hashing, getrennte Verkettung | 85 Geschlossenes Hashing | 86 Weitere Anwendungen | 86

8

Präfixbäume | 88

9 9.1 9.2 9.2.1 9.2.2 9.3 9.3.1 9.3.2 9.4

Graphen | 90 Grundlegendes zu Graphen | 90 Breiten- und Tiefensuche | 92 Breitensuche | 92 Tiefensuche | 94 Minimale Spannbäume | 101 Algorithmus von Kruskal | 101 Algorithmus von Prim | 103 Kürzeste Wege | 103

10 Schwere Probleme und Heuristiken | 106 10.1 Problem des Handlungsreisenden | 107 10.1.1 Durch Ausprobieren (brute force) | 108 10.1.2 Nearest-Neighbour-Insertion | 109 10.1.3 Nearest-Insertion-Heuristik | 109 10.1.4 Farthest-Insertion-Heuristik | 110 10.1.5 Random-Insertion-Heuristik | 110 10.1.6 Minimaler-Spannbaum-Heuristik | 111 10.1.7 Tourverschmelzungsheuristik | 112 10.2 Rucksackproblem | 116

Inhalt

11

Zusammenfassung und Ausblick | 125

12

Lektüreempfehlungen | 127

| VII

Literatur | 129

Teil II: Programmieren für Medienwissenschaftler (Stefan Höltgen & Johannes Maibaum) 1

Einleitung | 133

2 2.1 2.1.1 2.1.2 2.1.3 2.2 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.2.6 2.2.7 2.3 2.4 2.4.1 2.4.2 2.4.3 2.5 2.5.1 2.5.2 2.5.3 2.6 2.7 2.8

Assembler | 136 Einführung | 136 Assembler | 137 Hardwarenahe Programmierung | 139 Aufbau einer CPU | 139 Funktionen | 142 Die Busse | 142 Die Arithmetisch-Logische Einheit (ALU) | 143 Die Register | 143 Zahlensysteme: Dual, Dezimal, Hexadezimal | 144 Adressen und Speicher | 146 Memory-mapped I/O und ROM | 147 Adressierungsarten | 148 Der Befehlssatz der 6502 | 151 Der MOUSE-Computer | 154 Aufbau | 154 Speicherorganisation | 155 Besondere Adressen im ROM | 155 Programmierung | 157 Warteschleifen | 158 Selbstmodifizierender Code | 160 Interrupt Handling | 161 Assemblercode lesen | 164 Schluss | 167 Lektüreempfehlungen | 167

3 3.1 3.2

BASIC | 169 BBC BASIC | 170 Eigenschaften der Sprache | 172

VIII | Inhalt 3.2.1 3.2.2 3.2.3 3.2.4 3.3 3.3.1 3.3.2 3.3.3 3.4 3.5

Die Struktur von BASIC-Programmen | 173 Befehle | 174 Funktionen und Daten, Variablen und Konstanten | 174 BBC BASIC und Assembler | 175 Programmieren in BASIC | 176 Historische BASIC-Algorithmen | 177 Standard-Algorithmen in BASIC | 188 Computerarchäologie mit BASIC | 192 Schluss | 200 Lektüreempfehlungen | 201

4 C | 204 4.1 Zum Einstieg | 204 4.2 Die verwendete Plattform | 205 4.3 Erster Einstieg: Noch einmal Zahlenraten | 206 4.4 Zweiter Einstieg: „Hallo, Welt“ in C | 209 4.5 Noch einmal Assembler | 212 4.6 Datentypen | 214 4.7 Variablen | 217 4.8 Funktionen | 219 4.9 Kontrollstrukturen | 223 4.10 Zeiger (Pointer) | 226 4.10.1 Einen Zeiger erstellen | 227 4.10.2 Zeiger erlauben Funktionen mit mehr als einem „Rückgabewert“ | 227 4.10.3 Zeiger und Arrays | 229 4.11 Schluss | 234 4.12 Lektüreempfehlungen | 235 5 5.1 5.2 5.2.1 5.2.2 5.3 5.3.1 5.3.2 5.3.3 5.3.4 5.4 5.5 5.6 5.7

Python | 237 Ein interaktiver Einstieg | 238 Ein fast interaktiver Einstieg in die Objektorientierung | 241 Module | 247 Vererbung | 248 Zeichenketten, Sequenz- und Wörterbuchdatentypen | 250 Zeichenketten | 250 Listen | 253 Iterieren über Sequenzen | 255 „Wörterbücher“ (assoziative Datenfelder) | 258 Beispielprogramm: Markow-Ketten | 260 Beispielprogramm: Schlagzeile vorlesen | 264 Schluss | 267 Lektüreempfehlungen | 268

Inhalt

Teil III: Kybernetik (Thomas Fischer) Kybernetik | 274 1 1.1 1.2 1.3 1.4 1.5 1.6

Einführung | 275 Überblick | 275 Abgrenzung | 276 Technische Voraussetzungen und Hinweise | 277 Die medienwissenschaftliche Relevanz der Kybernetik | 278 Hintergrund | 280 Geschichte und Gesichter der Kybernetik | 285

2 2.1 2.2 2.3 2.4 2.5

Determinismus und Determinierbarkeit | 302 Widersprüchliche Grundannahmen | 302 Physikalische Umsetzung logischer Formalismen | 303 Klare Zustände: der Zweipunkt-Thermostat | 304 Programmierbare Abläufe: die Turingmaschine | 311 Deterministische Mechanismen: die Triviale Maschine | 316

3 3.1 3.2 3.3 3.4 3.5

Zirkuläre Kausalität | 321 A beeinflusst B und B beeinflusst A | 321 Logische Paradoxien | 322 Geburtsurkunde der Kybernetik | 324 Reflexivität | 325 Widerstand gegenüber zirkulärer Kausalität | 327

4 4.1 4.2 4.3 4.4

Zwischen Wirk- und Zweckursachen | 330 Das Vorhalteproblem der Luftabwehr | 330 Vorhersage auf der Basis von Beobachtung | 334 Stabilität und Stabilisierung | 336 Dynamische Stabilität | 337

5 5.1 5.2 5.3 5.4

Ausgangspunkt Subjekt | 341 Eine kritische Annäherung an „Information“ | 341 Konstruierende Wahrnehmung | 353 Radikaler Konstruktivismus | 360 Empirisch-wissenschaftliche Methodik | 364

6 6.1 6.2 6.3

Systeme, Systemgrenzen und Wiedereintritt | 369 Vom technischen zum ethischen Systembegriff | 369 Gedächtnis und Wiedereintritt | 373 Operative Geschlossenheit und Eigenform | 376

| IX

X | Inhalt 6.4

Selbstorganisation und gesellschaftliches Handeln | 383

7 7.1 7.2 7.3 7.4

Von Determinierbarkeit zu Nicht-Determinierbarkeit | 391 Potenzielle, gegebene und erforderliche Varietät | 392 Reduktion von Varietät | 396 Nicht-determinierbare Maschinen | 401 Amplifikation von Varietät | 408

8

Ausblick | 419

9

Lektüreempfehlungen | 420

Literatur | 424 Schlagwortverzeichnis | 434

Vorwort Dieser zweite Band der Reihe „Medientechnisches Wissen“ knüpft auf unterschiedliche Art und Weise an die Themen des ersten Bandes an und führt sie weiter. Ging es dort zentral um die medientechnisch-theoretischen Grundlagen (Logik und Informationstheorie), so widmen sich die Autoren dieses Buches nun in drei Teilbänden deren praktischen Anwendungsfällen in der Informatik und der Kybernetik, sowie in der Programmierung von Digitalcomputern. In einer Zeit, in der Digitalcomputer zur dominierenden Medientechnologie in nahezu allen Bereichen von Kultur, Technik und Wissenschaft geworden sind, ist das Wissen um deren Funktionsweisen von immanenter Wichtigkeit – und das nicht nur für Vertreter¹ jener Fachdisziplinen, die solche Technologien entwickeln. Forderungen nach einem verbindlichen Informatik-Unterricht und der möglichst frühen Einführung in eine Programmiersprache in Schulen reagieren auf diese Entwicklung. „Computer literacy“ als ein didaktisches Konzept, das bereits in den 1980er Jahren dem anwachsenden „Computeranalphabetismus“ (Kittler 1996) entgegenzutreten hoffte, stellt sich heute nicht mehr bloß der Ohnmacht des Endanwenders entgegen, sondern wird auch für die (ehemals „technikfernen“) Geistes- und Kulturwissenschaften zum wichtigen Handwerkszeug. Die „Digital Humanities“ stellen diesen Disziplinen Technologien als Forschungswerkzeuge zur Verfügung, die zunächst in ihrer Funktionalität verstanden werden müssen. Nur so wird/bleibt erkennbar, wie sich deren „[medien]technische Aprioris“ (Ernst 2007:28; Kittler 1986:180) in die Forschung einschreiben. Nietzsches „Unser Schreibzeug arbeitet mit an unserem Gedanken.“ (Nietzsche 2003:18) gilt mehr denn je, wenn künstliche Intelligenzen mithilfe neuronaler Netze Muster in Forschungsdaten suchen und finden und damit „Denkprozesse“ übernehmen. Medienwissenschaft kann hier eine Vermittlerrolle zukommen, indem sie die spezifischen Methoden und Theorien von Geistes- und Kulturwissenschaften mit technomathematischem und informatischem Wissen zu Medien verbindet und auf diese Weise einen Kanal für die interdisziplinäre Kommunikation öffnet. Dazu ist allerdings Theorie-, Fakten- und Methodenwissen auf beiden Seiten nötig, dessen Grundlagen unsere Lehrbuchreihe stiften möchte. Dies passiert kleinschrittig und ohne spezifische Kenntnisse (jenseits des Abiturs) vorauszusetzen. Im ersten Teilband werden vom Informatiker Thorsten Schöler die grundlegenden Begriffe und Konzepte der Informatik vorgestellt. Über die innere Strukturierung des Fachgebietes in theoretische, technische, praktische, angewandte Informatik sowie dem Arbeitsfeld „Informatik und Gesellschaft“ lassen sich unterschiedlichste Verbindungen zu medientechnischen Anwendungsfällen aufzeigen. Am Anfang steht hier

1 Zur Lektüreerleichterung wird in diesem Buch das generische Maskulin verwendet, womit aber alle Geschlechter gemeint und angesprochen sein sollen. https://doi.org/10.1515/9783110496253-001

2 | Vorwort die Vermittlung des Wissens, dass es sich bei Digitalcomputern um „implementierte Theorie“ handelt: Die Theorien von Automaten und ihren Sprachen, die zur universellen Rechenmaschine führen, stellen die epistemologische Grundlage für die Architekturen von Rechenmaschinen und Computern dar. Im Informatik-Teilband werden davon ausgehend, die technische Informatik und ihre Geschichte vorgestellt, dann Algorithmen und Datenstrukturen, Bäume und Graphen (als wichtige diagrammatische Beschreibungsmittel für Prozesse) und schließlich das Thema Komplexität, das die Probleme des Zeitverbrauchs von Berechnungsprozessen als ein wichtiges Grenzphänomen von Digitalcomputern vorstellt. Wo möglich, werden Codes (in der Programmiersprache Python) und Beispiele aus der Medientechnik zur Exemplifikation herangezogen. Der zweite Teilband stellt eine Programmierlehre für Medienwissenschaftler dar, in der in vier kurzen Einführungen vier Programmiersprachen vorgestellt werden. Diese berufen sich mehr noch als die anderen Teilbände auf den Einsatz assistierender Sekundärliteratur, denn in der Kürze der Darstellungen kann kaum systematisch in eine Programmiersprache eingeführt werden. Vielmehr soll es um die Kodifizierung medienwissenschaftlicher Fragestellungen gehen, die sowohl Digitalcomputer selbst als auch andere Medientechnologien betreffen. Programmieren soll dadurch sowohl als Schlüsselkompetenz zum Verständnis von Computern dienen, als auch als medienwissenschaftliches Werkzeug zum „operativen Argumentieren“ medientechnischer Sachverhalte. Hierzu wurden die vier Sprachen 6502-Assembler, BBC BASIC, C und Python ausgewählt, die von den Medienwissenschaftlern Stefan Höltgen und Johannes Maibaum in einzelnen Kapiteln vorgestellt werden. Der spezifische 8-Bit-Assembler des MOS 6502 hat bereits im Logikteilband (vgl. Band 1, Kap. I.7²) Einsatz gefunden und bezieht sich auf den in Band 4 (dort Kap. II) vorgestellten Selbstbaucomputer MOUSE, der hier vorerst als Emulation für Arduino eingesetzt wird. Das BASIC-Kapitel verfolgt neben den erwähnten Zwecken das Ziel, Programmieren zugleich in seiner Kulturgeschichte zu verorten und diese programmierend als „Re-Enactment“ aufzurufen. Mit der Programmiersprache C wird in das strukturierte Programmieren eingeführt und Aufgaben aus dem Bereich Steuerung und Regelung werden vorgeführt. Python schließlich dient der Möglichkeit, eine „Lesekompetenz“ für moderne objektorientierte Sprachen zu vermitteln und die in den Informatik- und Kybernetik-Teilbänden vorgestellten Beispiele zu verstehen. Die Einfachheit und weite Verbreitung Pythons macht die Sprache überdies zu einem idealen Programmiertool für Medienwissenschaftler. Der dritte Teilband rückt die Kybernetik mit ihren medienwissenschaftlichen Implikationen ins Zentrum der Betrachtung. Thomas Fischer, Kybernetiker und Desi-

2 Die Querverweise zu Kapiteln im selben Band werden wie folgt angegeben: Eine römische Ziffer gibt den Teilband an (hier: I für Informatik, II für Programmierlehre, III für Kybernetik), die nachfolgenden lateinischen Ziffern die jeweiligen Kapitelnummern. Wird zu anderen Bänden der Reihe verwiesen, wird die Angabe „Band“ mit der betreffenden Bandnummer vorangestellt.

Vorwort

| 3

gnwissenschaftler, führt hier systematisch in diese Disziplin ein. Ausgehend von ihrer historischen Entwicklung (mit einem Blick auf die so genannte „Kybernetik erster Ordnung“ – auch in Hinblick auf die Deutsche Kybernetik), stellt er die Grundprinzipien kybernetischen Denkens vor und exemplifiziert diese anhand technischer Apparaturen und in Experimenten. Mit dem Einsatz der „Kybernetik zweiter Ordnung“ gerät der Beobachter von Prozessen in den Blick und wird als Element solcher Prozesses selbst mitgedacht. Insbesondere in human- und sozialwissenschaftlichen Fragen lässt sich so Mensch-Maschine-Kopplung alternativ auffassen und ermöglicht es beispielsweise, Simulationen von kulturellen und gesellschaftlichen Prozessen durch Computer als kybernetische Prozesse zu verstehen. Die zahlreichen Experimente im Teilband laden dazu ein, kybernetische Theorien zu „aktualisieren“ und als eine wichtige Strukturwissenschaft (vgl. Artmann 2000:63ff.) für medienwissenschaftliches Denken zugänglich zu machen. Der vorliegende Band kann sowohl als Lehrgrundlage für Einführungskurse als auch als autodidaktische Lektüre dienen³. Neben den Experimenten, die im Buch vorgeschlagen sind, befinden sich hierfür auf der Webseite des DeGruyter-Verlages⁴ zusätzliche Informationen und Materialien. Um den Erfolg der Experimente zu gewährleisten, sollte die empfohlene Hardware und Software verwendet werden. (Die Autoren haben sich hier auf ein kostengünstiges Setup geeinigt: ein Arduino-Unound ein Raspberry-Pi-3-Computer.) Die Installation der Hardware- und SoftwareKomponenten wird in einem ebenfalls online vorliegenden Dokument beschrieben. Die Redaktion des zweiten Bandes der Reihe „Medientechnisches Wissen“ hat wieder Maria Priebe übernommen, wofür ihr großer Dank gilt. Unterstützt wurde der Entstehungsprozess vom Lehrstuhl für Medientheorien der Humboldt-Universität zu Berlin (namentlich Prof. Dr. Wolfgang Ernst). Technische Unterstützung haben die Autoren und der Herausgeber vom Redaktionsteam der Reihe sowie vom Lektorat des DeGruyter-Verlags erhalten. Auch hierfür sei expliziter Dank ausgedrückt. Berlin im Sommer 2018 Stefan Höltgen

3 Alle Abbildungen stammen, soweit nicht anders vermerkt, von den Autoren der Teilbände. 4 www.degruyter.com

4 | Vorwort

Literatur Artmann, S. (2010): Historische Epistemologie der Strukturwissenschaften. München: Fink. Ernst, W. (2007): Das Gesetz des Gedächtnisses. Medien und Archive am Ende (des 20. Jahrhunderts). Berlin: Kadmos. Kittler, F. A. (1986): Grammophon – Film – Typewriter. Berlin: Brinkmann & Bose. Kittler, F. A. (1996): Computeranalphabetismus. In: Matejovski, Dirk /Kittler, Friedrich (Hgg.): Literatur im Informationszeitalter. Frankfurt am Main/New York: Campus, S. 237–251. Nietzsche, F. (2003): Brief an Heinrich Köselitz in Venedig Ende Februar 1882 (Nr. 202). In: Ders.: Schreibmaschinentexte. Vollständige Edition Faksimiles und kritischer Kommentar. Aus dem Nachlass herausgegeben von Stephan Günzel und Rüdiger Schmidt-Grépály. Weimar: Universitätsverlag.

|

Teil I: Informatik (Thorsten Schöler)

1 Einführung Die durchgängige Digitalisierung der Gesellschaft ist nicht mehr aufzuhalten (Kröhling, 2017). Durch die allgegenwärtige Umwandlung von Informationen in Zahlenwerte, so die technische Definition von Digitalisierung (Schröder, 2006), können Übertragungs- und Verarbeitungsmöglichkeiten harmonisiert werden. Verstärkt durch die immer noch fortschreitende Miniaturisierung elektronischer, vor allem digitaler, Geräte können zunehmend Informationen und Daten erfasst, verarbeitet und ausgegeben werden. Betrachtet man heutige Medien, so stellt man fest, dass kaum noch Medien existieren, die ohne die Zuhilfenahme digitaler Technik umgesetzt werden können. So wie beispielsweise auch bei der lange Zeit noch analogen Radiotechnik. Kauft man heute ein zeitgemäßes DAB¹-Radio, so erwirbt man ein hochkomplexes Hardware/SoftwareSystem rund um ein Mikrocontroller-Modul, spezialisiert auf den digitalen Radioempfang. Im Endeffekt handelt es sich um einen hochintegrierten, komplexen Computer, der auf den digitalen Radioempfang spezialisiert und programmiert wurde. Digitale Verarbeitungsgeräte, wie das angesprochene DAB-Empfangsmodul und deren Software, bestimmen die modernen Medien. Der Zusammenhang zwischen Computer (Hardware) und Software kann durch eine Analogie aus der Musik veranschaulicht werden: Beschäftigt sich der Radio- und Fernsehtechniker mit dem Radio oder Fernsehgerät als Hardware, so beschäftigt sich der Komponist eines musikalischen Werkes mit der Software der Musikdarbietung. Ähnlich ist es in der Informatik: Der technische Informatiker beschäftigt sich auch mit der Konstruktion der Computer-Hardware, der praktische Informatiker selbst versteht sich eher als Komponist der datenverarbeitenden Werke, der Software. Es lohnt sich somit für Medienwissenschaftler und -techniker sich mit der Komposition digitaler Softwarewerke zu beschäftigen. Hierzu sollte man sich mit den theoretischen Grundlagen der Softwarekomposition, beispielsweise den Algorithmen und Datenstrukturen, sowie der Umsetzung dieser, mittels konkreter Programmiersprachen, beschäftigen. Um es mit einfachen Worten von Jörg Kantel, EDVLeiter am Berliner Max-Planck-Institut für Wissenschaftsgeschichte und Betreiber des Schockwellenreiter-Blogs², auszudrücken: Lernt programmieren, sonst werdet ihr programmiert! (Kantel, 2010)

In diesem Sinne führen die nächsten Kapitel durch die Informatik mit Fokus auf Algorithmen und Datenstrukturen, als theoretischen Grundlage für die Umsetzung eigener softwaretechnischer Kompositionen.

1 Digital Audio Broadcasting 2 Verfügbar unter http://schockwellenreiter.de/, Abruf: 24.08.2018. https://doi.org/10.1515/9783110496253-002

2 Einleitung Ein berühmtes Zitat der Informatik, welches oft dem niederländischen Informatiker Edsger Wybe Dijkstra in den Mund gelegt wird, lautet ins Deutsche übersetzt: In der Informatik geht es genau so wenig um Computer, wie es in der Astronomie um Teleskope geht. (Wikiquote, 2017)

Wie sich zeigen wird, geht es in der Informatik um viel mehr als nur um Computer, deren Untersuchung trotzdem einen wesentlichen Teil der wissenschaftlichen Disziplin darstellt. Computer auf Silizium-Halbleiter-Basis stellen aktuell das bestmögliche Werkzeug zur Informationsverarbeitung dar, dem Hauptgebiet der Informatik. Um was geht es nun in der Informatik? Eine geläufige Definition für den Begriff Informatik lautet wie folgt: Definition: Informatik „Die Informatik ist die Wissenschaft von der systematischen Darstellung, Speicherung, Verarbeitung und Übertragung von Informationen. Weiterhin der automatisierten Verarbeitung von Daten und Informationen durch Rechner“ (Claus and Schwill, 2006).

Welche Bereiche innerhalb der Informatik sind für diese systematische Informationsverarbeitung notwendig? Die Informatik als Wissenschaft kann in fünf wesentliche Teilgebiete unterteilt werden (Wikipedia, 2017b): Theoretische Informatik, praktische Informatik, technische Informatik, angewandte Informatik und, laut der Gesellschaft für Informatik, das Teilgebiet „Informatik und Gesellschaft“. In der theoretischen Informatik dreht sich alles um die theoretischen Grundkonzepte der Informationsverarbeitung, deren Grundlagen ihrerseits in der Mathematik, speziell beispielsweise in der Logik und Mengenlehre zu finden sind. Inhalte der theoretischen Informatik sind: – Automatentheorie – Formale Sprachen – Berechenbarkeitstheorie – Komplexitätstheorie Im Teilbereich der praktischen Informatik wird speziell die Umsetzung der Informationsverarbeitung abstrakt und konkreter auf Rechnersystemen untersucht. Inhalte sind z. B.: – Algorithmen – Datenstrukturen – Softwaretechnik (Software Engineering) https://doi.org/10.1515/9783110496253-003

2 Einleitung

– – – –

| 9

Programmiersprachen und Compiler Betriebssysteme Verteilte Systeme Mensch-Maschine-Interaktion (wird oft auch im Teilbereich Informatik und Gesellschaft betrachtet)

Wie Rechnersysteme aufgebaut sind, untersucht die technische Informatik mit ihren Bereichen: – Hardware-Entwurf – Rechnerarchitektur – Rechnernetze – Mikroprogrammierung Der Teilbereich der angewandten Informatik umschreibt die Anwendung all dieser Konzepte und Technologien zur Datenverarbeitung zum Beispiel in: – Computergrafik – Datenbanken – Künstlicher Intelligenz – Multimedia – Anwendungen der Wirtschaft, Verwaltung, Naturwissenschaft und Medizin Schließlich umschreibt der Teilbereich Informatik und Gesellschaft u. a. die Geschichte und Didaktik der Informatik, sowie den Bereich Mensch-Maschine-Schnittstelle (Human Computer Interface, HCI). Wie aus dieser umfangreichen Aufstellung heraus leicht nachzuvollziehen ist, müssen wir uns in diesem Kapitel auf ausgewählte, für Medienwissenschaftler interessante Bereiche der Informatik beschränken. Wir werden uns zunächst mit ausgesuchten Grundlagen der theoretischen Informatik vertraut machen. Anschließend werden wir einen Blick auf die technische Umsetzung dieser theoretischen Basis werfen. Den sehr pragmatischen Teil der Algorithmen und Datenstrukturen werden wir umfangreich beleuchten. Dazu gehören auch die wichtigen Datenstrukturen wie Graphen und Bäume, ebenso wie gestreute Speicherung (Hashing). Abschließend werfen wir noch einen Blick auf schwere Probleme in der Informatik und wie wir diese mithilfe von Heuristiken in den Griff bekommen können. Der Teilbereich „Informatik und Gesellschaft“ soll hier nicht näher betrachtet werden. Er besitzt große Schnittmengen zu Kultur-, Sozial-, Bildungs- und Medienwissenschaften. Eine ausführliche Betrachtung würde uns in diesem Rahmen vom Wesen der Informatik, der formalen Informationsverarbeitung, zu weit entfernen.

3 Theoretische Informatik In der theoretischen Informatik geht es um die mathematischen Grundlagen, auf der die Wissenschaft der Informationsverarbeitung aufgebaut ist. Die Grundlagen der Informatik sind konzeptioneller und struktureller Art. Sie sind nicht an eine spezielle Implementierung, wie z. B. in Halbleiterstrukturen, gebunden. Wichtige Inhalte der theoretischen Informatik sind formale Sprachen, Automatentheorie, Berechenbarkeit und Komplexität, Logik, formale Semantik, sowie die Algorithmen- und Informationstheorie. Die Theorie der formalen Sprachen ist zum Verständnis von Programmiersprachen sowie Protokollen zur Informationsübertragung essenziell. Formale Sprachen haben eine enge Beziehung zur Automatentheorie. Automaten stellen die Grundlage zur Verfügung, auf der Systeme, basierend auf formalen Sprachen, umgesetzt werden können. Große Teile der technischen Umsetzung von Datenverarbeitungsanlagen basieren auf diesen Automaten. Den Bereich der Algorithmen, Datenhaltung und Komplexitätsbetrachtungen behandeln wir ausführlich in Kapitel 5. Die Grundlagen der Logik wurden bereits im ersten Band dieser Reihe behandelt.

3.1 Formale Sprachen Als formale Sprachen werden mathematische Konstrukte bezeichnet, die einer definierten Grammatik über einem Alphabet folgen. Eine Grammatik ist ein Regelwerk, welches beschreibt, wie syntaktisch korrekte Ausdrücke in dieser Sprache gebildet werden. Ein Alphabet beschreibt die Menge der sogenannten Terminalsymbole, der Symbole aus der die Sprache konkret zusammengesetzt ist. Eine formale Sprache besitzt somit eine Syntax mit festen Regeln, sowie eine Semantik, die jedem syntaktisch korrektem Element eine Bedeutung zuordnet. Syntax und Semantik einer formalen Sprache müssen eindeutig sein. Ein einfaches Beispiel für eine formale Sprache ist die Sprache einer Verkehrsampel. Die Sprache verfügt über ein Alphabet A welches über die verschiedenen Ampelfarben¹ F = {rot, gelb, gr u¨ n} definiert werden kann: A = {{rot}, {rot, gelb}, {gr u¨ n}, {gelb}} Die Syntax definiert die gültige Abfolge der einzelnen Schriftzeichen: {rot} → {rot, gelb} → {gr u¨ n} → {gelb} → {rot}

1 vgl. hierzu auch Kapitel III.7.1. https://doi.org/10.1515/9783110496253-004

3.1 Formale Sprachen

⟨Satz⟩



⟨Subjekt⟩ ⟨Verb⟩ .

⟨Subjekt⟩



⟨Artikel⟩ ⟨Substantiv⟩

⟨Artikel⟩



Der ∣ Die ∣ Das

⟨Substantiv⟩



Klavier ∣ Katze ∣ Hund

⟨Verb⟩



schläft ∣ isst ∣ . . .

| 11

Abb. 3.1: Untermenge der Grammatik für die deutsche Sprache

Die zugehörige Semantik definiert, welche Bedeutung die einzelnen Schriftzeichen im Alphabet haben: – {rot} ∶ Anhalten – {gr u¨ n} ∶ Fahren – ... Weitere Beispiele für formale Sprachen im Bereich der Informatik sind Programmiersprachen (BASIC, C, C++, Java, ...), Auszeichnungssprachen für Dokumente (HTML, XML, ...) sowie Kommunikationsprotokolle (TCP/IP, ...).

3.1.1 Grammatik Die Grammatik einer formalen Sprache beschreibt ein Regelwerk, wie syntaktisch korrekte Ausdrücke in dieser Sprache formuliert werden können. Als Beispiel betrachten wir eine sehr eingeschränkte Untermenge der Grammatik für die deutsche Sprache, wie in Abbildung 3.1 gezeigt. Formal wird eine Grammatik durch ein 4-Tupel² beschrieben: G = (T, N, P, S). Mit T als der Menge der Terminalsymbole (der konkreten Bausteine einer formalen Sprache), N als der Menge der Nichtterminalsymbole (syntaktische Variablen, abstrakter ∗ ∗ Bausteine), P als der Menge der Produktionsregeln P ⊆ (N ∪ T) × (N ∪ T) mithilfe derer Ausdrücke formuliert werden können, sowie einem Startsymbol S ∈ N, der Urzelle aller Sätze. Zur formalen Beschreibung der Grammatik der Programmiersprache Algol 60 wurde von John Backus und Peter Naur 1960 erstmalig die sogenannte Backus-Naur-Form (BNF) verwendet (siehe auch Abbildung 3.1). Die Tabelle 3.1 zeigt einen Ausschnitt der BNF-Definition. Ein weiteres, einfaches Beispiel für die Definition einer beliebig lan-

2 Ein Tupel ist eine Zusammenfassung mathematischer Objekte als Liste. Im Gegensatz zum Begriff der Menge ist bei einem Tupel die Reihenfolge der Elemente relevant.

12 | 3 Theoretische Informatik Tab. 3.1: Ausschnitt der Backus-Naur-Form Sprachelement in BNF

Bedeutung

::= oder ⊨ ∣ < . . . > oder ⟨. . .⟩

„ist definert als“ oder „aus . . . wird . . . produziert“ Alternative Einfassung für Nichtterminalsymbole

⟨Summe⟩



⟨Summand⟩ ∣ ⟨Summand⟩ + ⟨Summe⟩

⟨Summand⟩



a ∣ b ∣ c

Abb. 3.2: Unendliche Summe von Summanden, definiert in der BNF

gen Summe von Summanden aus a, b, c in der BNF zeigt Abbildung 3.2 (Eirund et al., 2000). Als Nikolas Wirth die Programmiersprache Pascal entwickelte und definierte, führte er eine Erweiterung der BNF, die Erweiterte BNF (EBNF) ein. Die EBNF ist ein ISO-standardisiertes Beschreibungsverfahren, welches oft bei Programmiersprachen eingesetzt wird. Die EBNF umfasst die Erweiterungen und Vereinfachungen aus Tabelle 3.2. Eine beispielhafte Grammatik für algorithmische Ausdrücke in EBNF zeigt Abbildung 3.3. Per Konvention ist der linke Teil der ersten Produktionsregel das Startsymbol S. Die Menge der Nichtterminalsymbole N sowie die Menge der Terminalsymbole T ergibt sich implizit aus den Produktionsregeln P und ist hier nicht explizit angegeben. Beispiele für Ausdrücke, die mit dieser Grammatik erstellt werden können, sind: 0, 2 + 2, 17/4, 17 + (5 ⋅ −3), (2 + 1) ⋅ (3 − (7 + 2)). Tab. 3.2: Erweiterungen der Backus-Naur-Form (EBNF) Sprachelement in EBNF

Bedeutung

= ∣ < . . . > oder ⟨. . .⟩ (. . . ∣ . . .) [. . .] {. . .} . ...

„ist definiert als“ oder „aus . . . wird . . . produziert“ Alternative Einfassung für Nichtterminalsymbole Genaue eine Alternative aus der Auswahl Inhalt der Klammer ist optional (kann weggelassen werden) Inhalt der Klammer kann n ≥ 0-mal stehen Ende der Produktion Terminalsymbole (ohne Einfassung)

3.1 Formale Sprachen

⟨Ausdruck⟩



⟨Zahl⟩ ∣ ⟨Zahl⟩ ⟨Operation⟩ ⟨Ausdruck⟩ .

⟨Audruck⟩



(⟨Ausdruck⟩) .

⟨Zahl⟩



[-] {⟨Ziffer⟩}.

⟨Ziffer⟩



0 ∣ 1 ∣ 2 ∣ 3 ∣ 4 ∣ 5 ∣ 6 ∣ 7 ∣ 8 ∣ 9.

⟨Operation⟩



+ ∣ − ∣ ⋅ ∣ /.

| 13

Abb. 3.3: Grammatik für algorithmische Ausdrücke in EBNF Tab. 3.3: Chomsky-Hierarchie der formalen Grammatiken und Sprachen Klasse/Typ

Name

Erzeugende Grammatik

Typ 3 Typ 2 Typ 1 Typ 0

Regulär Kontextfrei Kontextsensitiv Rekursiv aufzählbar

Reguläre Grammatik Kontextfreie Grammatik Kontextsensitive Grammatik Beliebige Grammatik

Da nun die Grundlagen für das Verständnis und die Dokumentation von formalen Sprachen gelegt sind, können wir uns nun mit der Klassifikation der Sprachen und ihren Mächtigkeiten beschäftigen. Der amerikanische Sprachwissenschaftler Noam Chomsky beschäftigte sich in den 1950er-Jahren mit der hierarchischen Einordnung formaler Sprachen und deren Grammatiken in die von ihm definierte Chomsky-Hierarchie. Die Chomsky-Hierarchie umfasst vier Typen formaler Grammatiken, die Typen werden von 0 bis 3 durchnummeriert. Je höher die Typennummer, desto eingeschränkter ist die Grammatik der formalen Sprache (siehe Tabelle 3.3). Speziell für die Informatik interessant sind die Typ-1- bis Typ-3-Grammatiken und -Sprachen.

3.1.2 Reguläre Sprachen (Typ 3) Reguläre Sprachen werden entweder durch links- oder rechtsreguläre Grammatiken beschrieben. Eine Grammatik G = (T, N, P, S) heißt linksregulär, wenn alle Produktionsregeln die Form ⟨α⟩ ⊨ ⟨β⟩ γ oder ⟨α⟩ ⊨ γ haben, wobei ⟨α⟩, ⟨β⟩ ∈ N und ∗ γ ∈ T ³ sind. Nach ein wenig Studium der Produktionsregeln für links- oder rechtsreguläre Sprachen kann man erkennen, dass bestehende Ausdrücke in diesen Spra-



3 Der Einfachheit halber soll T alle möglichen Kombinationen beschreiben, welche aus der Menge T gebildet werden können

14 | 3 Theoretische Informatik chen jeweils links bzw. rechts durch Nichtterminalsymbole ergänzt werden. Sie wachsen somit links bzw. rechts durch neue Nichtterminalsymbole. Eine Grammatik G = (T, N, P, S) heißt rechtsregulär, wenn alle Produktionsregeln die Form ⟨α⟩ ⊨ γ ⟨β⟩ ∗ oder ⟨α⟩ ⊨ γ haben, wobei ⟨α⟩, ⟨β⟩ ∈ N und γ ∈ T sind. Treffen diese Bedingungen für alle Produktionsregeln P in G zu, so spricht man von einer Typ-3-Grammatik oder -Sprache. Diese Grammatiken sind regulär. Eine Sprache heißt regulär, wenn sie sich durch eine (ebenso) reguläre Grammatik erzeugen lässt. Beispiele für reguläre Grammatiken sind Zahlen in Binärschreibweise (siehe Abbildung 3.4) und Variablennamen der Programmiersprache C (siehe Abbildung 3.5).

⟨Zahl⟩



0

⟨Zahl⟩



1

⟨Zahl⟩



⟨Zahl⟩ 0

⟨Zahl⟩



⟨Zahl⟩ 1

Abb. 3.4: Grammatik für Zahlen in Binärschreibweise

⟨Variable⟩



⟨Buchstabe⟩ [ { ⟨Buchstabe⟩ ∣ ⟨Ziffer⟩ } ]

⟨Buchstabe⟩



a ∣ b ∣ ... ∣ Z ∣ _

⟨Ziffer⟩



0 ∣ 1 ∣ ... ∣ 9

Abb. 3.5: Grammatik für Variablennamen in der Programmiersprache C

Die Grenzen der regulären Grammatiken sind erreicht, sobald geklammerte Ausdrücke dargestellt werden sollen. Die Paarigkeit (identische Anzahl der öffnenden und schließenden Klammern) lässt sich nicht in einer regulären Grammatik ausdrücken. Hierzu muss die Grammatik weniger restriktiv formuliert werden. Reguläre Sprachen finden eine breite Anwendung in der Informatik, beispielsweise in Form von sogenannten regulären Ausdrücken. Das Kommandozeilenwerkzeug grep ermöglicht umfangreiche und hochperformante Suchen nach regulären Ausdrücken in Zeichenketten. Reguläre Ausdrücke werden auch in vielen Skriptsprachen,

3.1 Formale Sprachen

|

15

wie z. B. Perl, Python, awk⁴ und sed⁵, unterstützt. Ebenso werden reguläre Ausdrücke beim Compilerbau mit dem Werkzeug flex verwendet, um den zu analysierenden Zeichenstrom in einen Token⁶-Strom zu übersetzen.

3.1.3 Kontextfreie Sprachen (Typ 2) Kontextfreie Sprachen werden durch eine Grammatik G = (T, N, P, S) beschrieben, ∗ wenn alle Produktionsregeln die Form ⟨α⟩ ⊨ β haben, wobei ⟨α⟩ ∈ N und β ∈ (N∪T) sind. Die Beschränkung der Typ-1-Sprachen, dass Produktionsregeln P entweder mit einem Terminalsymbol aus T beginnen oder enden, ist bei Typ-2-Sprachen aufgehoben. Die Beschränkung, dass die linke Seite der Produktionsregeln nur Nichtterminalsymbole umfassen darf, bleibt weiterhin bestehen. Es sind nur die Beschränkungen der rechten Seite der Produktionsregeln aufgehoben. Eine Sprache heißt kontextfrei, wenn sie sich mit einer kontextfreien Grammatik (Typ-2-Grammatik) erzeugen lässt. Das klassische Beispiel der geklammerten Ausdrücke ist in Abbildung 3.6 gezeigt.

⟨Ausdruck⟩



( ⟨Ausdruck⟩ ⟨Operation⟩ ⟨Ausdruck⟩ ) ∣ ⟨Zahl⟩

⟨Operation⟩



+ ∣ − ∣ ⋅ ∣ /

⟨Zahl⟩



0 ∣ 1 ∣ ... ∣ 9

Abb. 3.6: Geklammerte Ausdrücke als Typ-2-Grammatik

Durch diese Grammatik können kontextfreie Ausdrücke wie z. B. ((7 + 3) ⋅ 5) gebildet oder auf ihren korrekten Aufbau hin untersucht werden. Durch Anwendung der ersten Regel in Abbildung 3.6 wird die äußere Klammerebene erzeugt, es bleibt der Ausdruck (7 + 3) ⋅ 5 bestehen. Eine weitere Anwendung der ersten Regel beschreibt die Multiplikation des verbleibenden Klammerterms mit 5; die Operation ⋅ als gültige Operation eines Audrucks beschreibt die zweite Regel; die Gültigkeit von 5 als Ausdruck bzw. Zahl wird durch Nacheinanderausführung der ersten und dritten Regel beschrieben. Es verbleibt der Ausdruck (7 + 3), welcher durch Anwendung der ersten

4 awk ist ein Unix-Kommandozeilenwerkzeug mit eigener Programmiersprache zur Manipulation von Texten. Details unter https://www.gnu.org/software/gawk/gawk.html, Abruf: 11.06.2018. 5 sed (Stream Editor) ist ein Unix-Kommandozeilenwerkzeug, ein sogenannter stream editor, der Manipulationen auf einem Textzeichenstrom ausführen kann. Details unter http://sed.sourceforge.net/, Abruf: 11.06.2018. 6 Ein Token ist die kleinste lexikalische Einheit einer formalen Sprache (z. B. ein Terminalsymbol).

16 | 3 Theoretische Informatik Regel in einen gültigen Ausdruck ⟨Ausdruck⟩ ⟨Operation⟩ ⟨Ausdruck⟩ zerlegt werden kann. Der erste Ausdruck kann über erneute Anwendung der ersten Regel durch die Zahl 7 ersetzt werden, die Operation durch + und der letzte Ausdruck kann durch die Zahl 3 ersetzt werden.

3.1.4 Kontextsensitive Sprachen (Typ 1) Von kontextsensitiven Sprachen des Typs 1 spricht man, wenn alle Produktionsregeln P einer Grammatik G = (T, N, P, S) der Form α ⊨ β entsprechen, wobei α, β ∈ ∗ (N ∪T) und ∣α∣ ≤ ∣β∣ gelten muss. Das bedeutet, dass die Anzahl der Symbole auf der linken Seite der Produktionsregel kleiner oder gleich der Anzahl der Symbole auf der rechten Seite der Produktionsregel sein muss. Die einzige Ausnahme bildet die Regel S ⊨ ϵ⁷, sofern das Startsymbol S nicht auf der rechten Seite einer Regel vorkommt. Eine Sprache heißt kontextsensitiv, wenn sie sich über eine kontextsensitive Grammatik abbilden lässt. Ein Beispiel für eine kontextsensitive Grammatik kann aus dem einfachen, konn n textfreien Beispiel für die Terme b c mit der Produktionsregel ⟨S⟩ ⊨ ϵ ∣ b ⟨S⟩ c. entwickelt werden. Wir entwickeln die Produktionsregeln weiter, so dass Terme der Form n n n a b c gebildet werden können. Die Produktionsregeln zeigt Tabelle 3.4. Die ersten beiden Regeln erzeugen die innere Struktur der Terme mittels a und weiteren Nichtterminalsymbolen aus N, die mit den verbleibenden Regeln durch die vorhandenen Terminalsymbole T ausgefüllt werden. In diesem Beispiel sind die weiteren Aufhebungen der Beschränkungen auf der linken Seite der Produktionsregeln gut zu erkennen. Bei Typ-1-Grammatiken sind hier, neben den Nichtterminalsymbolen aus N, auch Terminalsymbole aus T zugelassen. Diese beschreiben den Kontext für Nichtterminalsymbole, die in verschiedenen Produktionsregeln vorkommen können. So ist die Auswahl der anzuwendenden Produktionsregel der letzten vier Regeln in Tabelle 3.4, abhängig vom Kontext a oder b vor ⟨B⟩ bzw. ⟨C⟩, jeweils auf der linken Seite der Produktionsregel.

3.1.5 Rekursiv aufzählbare Sprachen (Typ 0) Als mächtigste Klasse der formalen Sprachen verbleiben noch die rekursiv aufzählbaren Sprachen des Typs 0. Eine Sprache heißt rekursiv aufzählbar oder Typ-0-Sprache, wenn sie sich durch eine beliebige Grammatik G = (T, N, P, S) erzeugen lässt. Diese formale Beschreibung ist die Abgrenzung zu weiteren Sprachen, welche nicht rekursiv aufzählbar sind. Diese existieren, sind allerdings in der Informatik von geringer Bedeutung. 7 ϵ steht für das leere Wort.

3.1 Formale Sprachen

| 17

Tab. 3.4: Beispiel für eine kontextsensitive Grammatik Produktionsregeln

Anmerkung

⟨S⟩ ⊨ a ⟨B⟩ ⟨C⟩ ∣ a ⟨S⟩ ⟨B⟩ ⟨C⟩ ⟨B⟩ ⟨C⟩ ⊨ ⟨C⟩ ⟨B⟩ a ⟨B⟩ ⊨ ab b ⟨B⟩ ⊨ bb b ⟨C⟩ ⊨ bc b ⟨C⟩ ⊨ cc

Erzeugt a (⟨B⟩ ⟨C⟩) Erlaubt ⟨B⟩ ⟨C⟩ in die richtige Reihenfolge zu bringen

n

n

n

n

N durch T ersetzen, wenn die Reihenfolge stimmt

3.1.6 Zusammenfassung formaler Sprachen Die Teilmengenbeziehung der vorgestellten formalen Sprachen (siehe Abbildung 3.7) zeigt, dass Typ-0-Sprachen alle weiteren formalen Sprachen des Typs 1, 2 und 3 einschließen. Gleiches gilt für die weiteren Typen, welche sich durch zusätzliche Einschränkungen von der jeweiligen Obermenge unterscheiden.

rekursiv aufzählbare Sprachen

kontextsensitive Sprachen

kontextfreie Sprachen

reguläre Sprachen

Abb. 3.7: Teilmengenbeziehung der formalen Sprachtypen

Tabelle 3.5 fasst die Produktionsregelbeschränkungen der einzelnen Sprachklassen in der Backus-Naur-Form zusammen. Gut zu erkennen sind wiederum die pro Sprachklasse verstärkten Einschränkungen bei den gültigen Produktionsregeln.

18 | 3 Theoretische Informatik Tab. 3.5: Zusammenfassung Produktionsregeln Sprachklasse

Produktionsregeln

Sprache

Typ 3: Reguläre Grammatik

⟨α⟩ ⊨ ⟨β⟩ γ, ⟨α⟩ ⊨ γ oder ⟨α⟩ ⊨ γ ⟨β⟩, ∗ ⟨α⟩ ⊨ γ mit ⟨α⟩, ⟨β⟩ ∈ N, γ ∈ T ∗ ⟨α⟩ ⊨ β mit ⟨α⟩ ∈ N, β ∈ (N ∪ T ) ∗ α ⊨ β mit α, β ∈ (N ∪ T ) , ∣α∣ ≤ ∣β∣ α⊨β

Regulär

Typ 2: Kontextfreie Grammatik Typ 1: Kontextsensitive Grammatik Typ 0: Beliebige formale Grammatik

Kontextfrei Kontextsensitiv Rekursiv aufzählbar

3.2 Automatentheorie Die Automatentheorie ist ein Teilgebiet der theoretischen Informatik, welches sich mit der modellhaften Betrachtung von sogenannten Modellrechnern (Automaten) und deren Fähigkeiten beschäftigt. Insbesondere werden Automaten betrachtet, welche formale Sprachen bearbeiten können. Dazu zählen insbesondere endliche Zustandsautomaten, Kellerautomaten und Turingmaschinen. Praktische Anwendung findet die Automatentheorie beim Entwurf von Programmiersprachen und im Compilerbau. Weiterhin werden im industriellen Umfeld Prozesse als endliche Zustandsautomaten modelliert und in einer Programmiersprache implementiert. So können ungewollte Zustände der Software vermieden werden, die Software kann formal validiert werden und somit hohen Anforderungen an die Verlässlichkeit genügen. Weiterhin werden Zustandsautomaten in der Didaktik eingesetzt um beispielsweise Prozessabläufe in Diagrammform zu notieren.

3.2.1 Endliche Zustandsautomaten Eine einfache Form eines Automaten stellen endliche Zustandsautomaten (englisch: finite state machine, FSM) dar. Automaten sind Modelle zustandsorientierter Maschinen. Sie bestehen aus Zuständen, in denen sich der Automat befinden kann, Zustandsübergängen zwischen den Zuständen sowie Aktionen, welche beim Eintreten bzw. Verlassen eines Zustandes bzw. beim Übergang zwischen Zuständen ausgeführt werden. Von einem endlichen Zustandsautomaten spricht man, wenn die Anzahl der Zustände, in denen sich der Automat befinden kann, endlich ist. Weiterhin spricht man von deterministischen endlichen Zustandsautomaten (DEA) wenn für jede mögliche Eingabe genau ein Zustandsübergang definiert ist. Ansonsten zeigt der Automat nichtdeterministisches Verhalten und wird als nicht-deterministischer endlicher Automat (NEA) bezeichnet. Einen einfachen Zustandsautomaten für eine Türsteuerung zeigt Abbildung 3.8. Ausgehend von einer geschlossenen Tür (Zustand 3) kann die Eingabe „öffnen“ erfolgen. Der Automat geht in den Zustand 4 „öffnend“ über und sobald der Sensor die Eingabe „Sensor offen“ meldet, geht der Automat in den Zustand 1 „offen“ über. Ana-

3.2 Automatentheorie

| 19

log verhält sich der Automat, wenn die Eingabe „schließen“ erfolgt. Während sich die Tür in den Zuständen „öffnend“ bzw. „schließend“ befindet, erfolgt der entsprechende Übergang in den entgegengesetzten Zustand durch die Eingaben „öffnen“ bzw. „schließen“.

4: öffnend Sensor offen 1: offen

öffnen

3: geschlossen

öffnen schließen

schließen

Sensor geschlossen

E

A mit Z, f

O = {ja, nein}

2: schließend

Abb. 3.8: Endlicher Zustandsautomat für eine Türsteuerung

Abb. 3.9: Deterministischer, endlicher Zustandsautomat (Symboldarstellung)

Formale Definition: Endlicher Zustandsautomat Die formale Definition für endliche Zustandsautomaten (wie in Abbildung 3.9) lässt sich durch ein 5Tupel A = (E, Z, z0 , f , F ) beschreiben. Mit dem Eingabealphabet E, der Menge der möglichen Zustände Z, dem Anfangszustand z0 ∈ Z, der Übergangsfunktion f ∶ E×Z → Z sowie der Menge der Endzustände F ⊆ Z. Die Ausgabe des Automaten kann als Wahrheitsfunktion definiert werden. Sie ist wahr, wenn der Automat sich nach Eingabe eines Eingabewortes in einem gültigen Endzustand aus F befindet. Man kann auch eine komplexere Ausgangsfunktion o ∶ E × Z → O definieren. Hier beschreibt O ein Ausgabealphabet, z. B. O = {wahr, falsch}.

Deterministische, endliche Zustandsautomaten bilden die Grundlage für Steuerwerke im Hardware-Entwurf, für Scanner und Parser im Compilerbau, als dynamische Modelle bei der objektorientierten Modellierung und als Grundlage für Netzwerkprotokolle. In der theoretischen Informatik interessiert vor allem der Zusammenhang, dass für jede reguläre Typ-3-Sprache ein deterministischer, endlicher Zustandsautomat existiert, der genau diese Sprache akzeptiert, mithin in einen gültigen Endzustand F übergeht. Ein Beispiel für einen deterministischen, endlichen Zustandsautomaten der eine vereinfachte Hexadezimalzahl-Darstellung in der Programmiersprache C akzeptiert zeigt Abbildung 3.10. Die Produktionsregeln der zugehörigen Typ-3-Sprache zeigt Abbildung 3.11.

20 | 3 Theoretische Informatik e = 0, 1, ...,9, a, b, ...,f

z0

e = 0x

e = 0x

präfix

e = 0, 1, ...,9, a, b, ...,f e = 0, 1, ...,9, a, b, ...,f e = 0x

F

Abb. 3.10: Deterministischer, endlicher Zustandsautomat, welcher Hexadezimalzahlen der Programmiersprache C akzeptiert

⟨Zahl⟩



0x { ⟨Ziffer⟩ }

⟨Ziffer⟩



0 ∣ 1 ∣ ... ∣ 9 ∣ a ∣ b ∣ ... ∣ f

Abb. 3.11: Produktionsregeln für Hexadezimalzahlen in der Programmiersprache C

Der Automat kann durch

A

=

(E, Z, z0 , f , F) mit

E

=

{0x, 0, 1, . . . , 9, a, b, . . . , f },

Z

=

{z0 , pr a¨ fix, F} und

z0

=

z0 sowie

f (siehe Abbildung 3.10) und F = F beschrieben werden. Der Automat in Abbildung 3.10 startet im Startzustand z0 . Bei Eingabe eines gültigen Präfix 0x, wechselt der Automat in den Zustand pr a¨ fix. Bei Eingabe aller anderen Symbole aus E verbleibt der Automat im Startzustand z0 . Wird nun im Zustand pr a¨ fix wiederum ein Präfix 0x eingegeben, verbleibt der Automat im Zustand pr a¨ fix. Bei Eingabe einer gültigen Ziffer aus E geht der Automat in den Endzustand F über. In F verbleibt der Automat auch bei Eingabe weiterer Ziffern aus E. Bei Eingabe eines gültigen Präfix 0x geht der Automat zurück in den Zustand pr a¨ fix. Der Begriff endlicher Zustandsautomat beinhaltet bereits die Vorgabe des Automaten nur über eine endliche Anzahl von Zuständen zu verfügen. Begreift man die Anzahl der Zustände als einfachen Zustandsspeicher, so kann nur eine begrenzte Menge von Information eingespeichert werden. Problematisch wird dies bei der Verarbeitung von Eingaben, welche eine unbegrenzte Schachtelungstiefe besitzen, wie z. B. geklammerte mathematische Terme. Einen Ausweg bieten die im nächsten Abschnitt beschriebenen Kellerautomaten.

3.2 Automatentheorie

| 21

O = {ja, nein} Kellerspeicher über K mit

E

...

A mit Z, f

a k ┴

Abb. 3.12: Kellerautomat (Symboldarstellung)

3.2.2 Kellerautomaten Ein Kellerautomat erweitert den deterministischen, endlichen Zustandsautomaten um einen Kellerspeicher⁸, mit theoretisch unendlicher Speichergröße. Kellerautomaten finden in der Informatik breite Anwendung als einfache (Zwischen-)Speicher. Beispielsweise in Hardware als Stack in Mikroprozessoren wie z. B. dem Zilog Z80 und dem MOS 6502, welche bereits in den 1980er-Jahren eine starke Verbreitung in massenproduzierten Heimcomputern hatten. In Software werden Kellerspeicher beispielsweise in der Programmiersprache Forth zur Übergabe von Werten usw. verwendet (siehe auch Abschnitt 5.2, Stapel- und Kellerspeicher). Der Kellerautomat (englisch pushdown automaton) in Abbildung 3.12 kann durch ein 7-Tupel A = (E, Z, K, ⊥, f , z0 , F), mit dem Eingabealphabet E, der endlichen Zustandsmenge Z, dem Kelleralphabet K, dem Kellerstartsymbol ⊥, der Übergangsfunk∗ tion f ∶ Z × K × (E ∪ {ϵ}) → Z × K , dem Startzustand z0 ∈ Z sowie der Menge der Endzustände F ⊆ Z, beschrieben werden. Der Kellerautomat kann ebenfalls durch eine Ausgangsfunktion o ∶ Z → O mit einem Ausgangsalphabet O erweitert werden. Die Erkennung von geklammerten mathematischen Termen kann durch den im Folgenden beschriebenen Kellerautomaten beispielhaft umgesetzt werden. Das Eingabealphabet E sowie das Kelleralphabet K können wie folgt beschrieben werden:

E

= {}

K

= {a, ⊥}

Zur Vereinfachung des Beispiels und der Zustandsübergangsregeln werden mathematische Klammern durch die Eingabealphabetsymbole < und > dargestellt. Der Automat verfügt über die Zustände:

8 vgl. Band 1, Kapitel I.5.2.2.

22 | 3 Theoretische Informatik Tab. 3.6: Zustandsübergänge bei der Erkennung geklammerter mathematischer Terme Schritt

Eingang

Zustand

Kellerinhalt

Regel

Folgezustand

Folgekellerinhalt

1 2 3 4 5 6

< < > > ϵ >

z0 z1 z1 z1 z1 z0

⊥ (a, ⊥) (a, a, ⊥) (a, ⊥) ⊥ ⊥

f1 f3 f4 f4 f5 f2

z1 z1 z1 z1 z0 = F z2

(a, ⊥) (a, a, ⊥) (a, ⊥) ⊥ ⊥ ⊥

z0



Startzustand

z1



Klammer geöffnet

z2



Fehlerzustand

Die Übergangsfunktionen des Kellerautomaten f (z, k, e) = (z , k ) mit dem aktuellen Zustand z, dem aktuellen Kellerspeicher k und dem aktuellen Eingangssymbol e ′ ′ sowie dem Folgezustand z und dem neuen Kellerspeicherinhalt k , können wie folgt definiert werden: ′



f1 (z0 , ⊥, )

=

(z2 , ⊥)

f3 (z1 , a, )

=

f (z1 , ϵ)

f5 (z1 , ⊥, ϵ)

=

f (z0 , ⊥)

sonst f (z, k, e)

=

f (z , k ) für alle z ∈ Z, k ∈ K, e ∈ E ∪ {ϵ} ′



Der gültige Endzustand des Kellerautomaten ist der Startzustand F = z0 . Die Funktionsweise des Kellerautomaten soll am Term T = (, ϵ, >) überprüft werden. Die Zustände (und Kellerspeicherinhalte), in denen sich der Automat jeweils befindet, sind in der Tabelle 3.6 dargestellt. In den Schritten 1 und 2 werden die öffnenden Klammern verarbeitet, die Anzahl der geöffneten Klammern wird über die Anzahl der Symbole a auf dem Kellerspeicher vermerkt. In den Schritten 3 und 4 werden die schließenden Klammern verarbeitet. Für jede schließende Klammer wird ein Kellersymbol a vom Kellerspeicher genommen. In Schritt 5 wird die Verarbeitung des Terms durch das Eingangsymbol ϵ abgeschlossen. Der Automat befindet sich im Endzustand F = z0 , der Term wurde als korrekt akzeptiert. In Schritt 6 wird ein Term fehlerhaft mit einer schließenden Klammer begonnen, dies wird korrekt durch die Regel f2 als Fehler erkannt, der Automat befindet sich anschließend im Fehlerzustand z2 . In der theoretischen Informatik interessiert der Zusammenhang, dass für jede kontextfreie Sprache (Typ 2) ein (nicht-deterministischer) Kellerautomat existiert, der ge-

3.2 Automatentheorie

| 23

Tab. 3.7: Zustandsübergänge bei der Erkennung von binären Palindromen Übergang

Eingang

Zustand

Kellerinhalt

Folgezustand

Kelleränderung

n++ letzte 0++ letzte 1++ 0-1-!0 !1 Ende? Fehler Erkannt

e ∈ {0, 1} 0 1 0 1 1 0 ϵ

z0 z0 z0 z0 z0 z1 z1 z1 z2 z3

K ∈ {0, 1, ⊥} 0 1 0 1 0 1 ⊥

z0 z1 z1 z1 z1 z2 z2 z3 z2 z3

push(e) push(0) push(1) pop(0) pop(1)

e ∈ {0, 1}



nau die Wörter dieser Sprache akzeptiert. Auch wenn die praktische Umsetzung (Implementierung, Programmierung) eines Kellerautomaten im Allgemeinen nicht vorgenommen wird, so ist der Kellerautomat, als Zwischenstufe auf einer formalen Mächtigkeitsskala, für Informatiker interessant. Er stellt eine geringe Erweiterung des einfachen endlichen Zustandsautomaten dar. Mit zwei Kellerspeichern ausgestattet, wird der Kellerautomat ebenso mächtig wie die Turingmaschine, welche im Anschluss vorgestellt werden soll. Ein nicht-deterministischer Kellerautomat kann ebenfalls durch ein 7-Tupel A = (E, Z, K, ⊥, f , z0 , F) beschrieben werden. Einzig die Übergangsrelationen f = Z × K × ∗ (E ∪ {ϵ}) → Z × K unterscheiden den nicht-deterministischen Automaten von seinem deterministischen Verwandten. Die Übergangsrelationen f können für identische Kombinationen von Z, K, (E ∪ {ϵ}) verschiedene (nicht-deterministische, mehrdeuti∗ ge) Übergänge nach Z ×K beschreiben. Es wird angenommen, dass ein „allwissendes Orakel“ jeweils den Übergang wählt, der am Ende zu einem gültigen Endzustand führt. Welche Bedeutung dieser Nicht-Determinismus des allwissenden Orakels im Akzeptieren von Typ-2-Sprachen hat, zeigt das folgende Beispiel zur Erkennung von Palindromen. Palindrome sind Zeichenketten oder Wörter, welche vorwärts wie rückwärts gelesen einen Sinn ergeben⁹. Die Tabelle 3.7 beschreibt die Zustandsübergänge in einem Kellerautomaten, der Palindrome mit gerader Anzahl der Binärziffern E = {0, 1} erkennen kann. Die Produktionsregel für diese Palindrome kann wie folgt beschrieben werden: ⟨Palindrom⟩ ⊨ 00 ∣ 11 ∣ 0 ⟨Palindrom⟩ 0 ∣ 1 ⟨Palindrom⟩ 1 Am Beispielpalindrom P = 101101 soll die Funktion des nicht-deterministischen Kellerautomaten veranschaulicht werden. Das erste Zeichen aus P, p0 = 1 wird mittels

9 Das Palindrom „Reliefpfeiler“ hat es als längstes deutsches Ein-Wort-Palindrom 1997 in das Guiness Buch der Rekorde geschafft. Länger ist noch das Palindrom „Retsinakanister“.

24 | 3 Theoretische Informatik des Übergangs n++ von z0 nach z0 akzeptiert, p0 wird auf dem Kellerspeicher abgelegt (push()-Operation). Gleiches gilt für das zweite Zeichen p1 = 0. Beim dritten Zeichen p2 = 1 erkennt das allwissende Orakel, dass dieses Zeichen das letzte Zeichen vor der Spiegelachse des Palindroms ist. Das Zeichen p2 = 1 wird auf dem Kellerspeicher abgelegt, der Automat wechselt – nicht-deterministisch – in den Zustand z1 , welches in der Regel als letzte 1++ beschrieben ist. Wäre das letzte Zeichen vor der Spiegelachse eine 0, so würde die Regel letzte 0 + + zum Einsatz kommen. Beim nächsten Zeichen p3 = 1 kommt aus dem Zustand z1 die Regel 1 − − zum Einsatz. Das Zeichen wird vom Kellerspeicher entfernt (pop()-Operation). Beim darauf folgenden Zeichen p4 = 0 kommt die Regel 0 − − zum Einsatz, das Zeichen wird ebenfalls vom Kellerspeicher entfernt, der Automat verharrt im Zustand z1 . Das letzte Zeichen des Palindroms p5 = 1 wird ebenfalls mittels der Regel 1 − − akzeptiert und das Zeichen vom Kellerspeicher entfernt. Falls bei der Überprüfung der zweiten Hälfte der Zeichen (Zustand z1 ) ein falsches Zeichen eingegeben würde, so würde der Automat aus dem Zustand z1 in den Fehlerzustand z2 wechseln und dort verharren (Regeln !0 und !1). Wird die Eingabe mittels e = ϵ abgeschlossen und der Kellerspeicher ist leer (K = ⊥), greift die Regel Ende? und der Automat geht in den Endzustand z3 über und verharrt dort (Regel Erkannt). Ein deterministischer Kellerautomat kann im Gegensatz zum hier vorgestellten nicht-deterministischen Kellerautomaten das Palindrom nicht erkennen, da ihm nicht bekannt ist, wann die Mitte des Palindroms erreicht ist, das weiß ja nur das allwissende Orakel des nicht-deterministischen Automaten. Er kann sich nicht entscheiden, ob das jeweils am Eingang anliegende Zeichen noch abzulegen oder bereits vom Kellerspeicher zu entfernen ist. Ein geschickt angelegter deterministischer Kellerautomat wäre eventuell in der Lage das Palindrom „agga“ zu erkennen. Er könnte allerdings nicht das Palindrom „aggaagga“ vom Nicht-Palindrom „aggaatta“ unterscheiden. Dieser Sachverhalt deutet darauf hin, dass nicht-deterministische Kellerautomaten mächtiger sind als deterministische Kellerautomaten. Wie können wir nun Automatenmodelle in Richtung Universalmaschine erweitern? Eine Antwort gibt der nächste Abschnitt.

3.2.3 Turingmaschine Die Turingmaschine beschreibt ein universelles Modell für symbolische Datenverarbeitung durch Automaten. Alan Turing hat das Modell 1936 vorgestellt (Turing, 1936). Interessanterweise hat er das Modell selbst nie als Turingmaschine bezeichnet. Ihren Namen bekam die Turingmaschine erst als Alonzo Church diese in einer seiner Veröffentlichungen als solche benannte.¹⁰

10 Quelle: http://www.historyofinformation.com/expanded.php?id=735, Abruf: 20.12.2017.

3.2 Automatentheorie

| 25

Die Turingmaschine ist ein wichtiger Meilenstein der Informatik. Bisher waren Rechner oder Computer (englisches Substantiv zu „to compute“) genau diesem Zweck gewidmet: zum Berechnen komplexer mathematischer Probleme. Erst Alan Turing und die Turingmaschine erweitern den Rechnerbegriff in Richtung der universellen Symbolverarbeitung. Eine erste Spezialrechenmaschine (nicht frei programmierbar und nicht turingmächtig), aufbauend auf dem Konzepts der Turingmaschine, findet sich 1943 im Colossus-Computer, der zum Brechen des kryptographischen Codes der Lorenz-Verschlüsselungsmaschinen des deutschen Militärs eingesetzt wurde (Kaufmann and Smarr, 1993). Weitere Details zum Brechen kryptographischer Codes, insbesondere des Enigma-Codes, finden sich in Kapitel III.7.3 dieses Buchs. Das Konzept der Turingmaschine ergibt sich aus einer modellhaften Betrachtung, wie menschliche „Symbolverarbeitung“ stattfindet, in der sogenannten „Papiermaschine“. Ein Mensch betrachtet ein Blatt Papier, verarbeitet die dort niedergeschriebenen Symbole und fügt neue Symbole hinzu. Das zweidimensionale Blatt Papier kann durch einen eindimensionalen Papierstreifen abstrahiert werden. Das menschliche Gehirn kann durch einen komplexen Automaten abstrahiert werden. Durch das Hinzufügen von nur drei einfachen Operationen auf einem Papierstreifen: Lesen, Schreiben und Schreib-/Lesekopf bewegen zu einem komplexen Automaten können alle Probleme gelöst werden, welche durch Computer gelöst werden können, beispielsweise sämtliche mathematischen Grundfunktionen wie Addition, Subtraktion, Multiplikation und Division. Eine Funktion, die durch eine Turingmaschine berechnet werden kann, nennt man auch eine turing-berechenbare Funktion. Eine Turingmaschine, wie in Abbildung 3.13, kann formal durch ein 7-Tupel A = (E, Z, B, #, f , z0 , F) mit einer endlichen Menge von Zuständen Z, einem Bandalphabet B, dem Eingabealphabet E ⊆ B, dem Leerzeichen (Blank-Symbol) # ∈ B \ E, einer Übergangsfunktion f ∶ Z × B → Z × B × {L, R}, einem Startzustand z0 ∈ Z und einer Menge von Endzuständen F ⊆ Z, beschrieben werden. Steuerung (endlicher Zustandsautomat) B, {L, R}

O = {ja, nein}

E

Band

...

T

u

r

i

n

g

#

M

Abb. 3.13: Turingmaschine (Symboldarstellung)

a

c

h

i

n

e

...

26 | 3 Theoretische Informatik Ausgehend von einem Startzustand z0 können Symbole aus B vom Band eingelesen werden und aus E auf das Band geschrieben werden. Weiterhin kann die Bandposition mit L (nach links) und R (nach rechts) verschoben werden. Die Maschine kann sich in verschiedenen internen Zuständen aus Z befinden. Zusätzlich zum Schreiben auf das Band kann ein Ausgabealphabet O definiert werden, beispielsweise O = {ja, nein}. Weitere Ausführungen rund um die Turingmaschine finden sich in Kapitel III.2.4 dieses Buchs. Ein einfaches Beispiel für die Verwendung einer Turingmaschine für die Addition zweier Ganzzahlen soll die Arbeitsweise der Turingmaschine verdeutlichen. Der Bandinhalt in Abbildung 3.14 zeigt die zwei Ganzzahlen 3 und 5, jeweils als Abfolge von Einsen auf dem Band, die von der Turingmaschine addiert werden sollen. Tab. 3.8: Übergangsfunktionen der Turingmaschine zur Addition von Ganzahlen

Zustand

Gelesenes Zeichen

Folgezustand

Geschriebenes Zeichen

Kopfbewegung

1 # 1 # 1 1 #

z0 z1 z1 z2 z3 z3 z4

1 1 1 # # 1 #

R R R L L L R

z0 z0 z1 z1 z2 z3 z3 z4

Übergangsfunktion Erster Summand „Operator“ Zweiter Summand Zählen durch Zurückspulen Neustart Endzustand

Abbildung 3.15 zeigt den Bandinhalt nach erfolgter Addition durch die Turingmaschine. Die Übergangsfunktionen der Turingmaschine zeigt Tabelle 3.8. Ausgehend vom Bandinhalt in Abbildung 3.14 mit dem Schreib-/Lesekopf positioniert über der ersten 1 starten wir im Ausgangszustand z0 und lesen das Zeichen 1 ein. Die Übergangsfunktion Erster Summand greift, überschreibt die 1 mit einer 1, bewegt den Kopf nach rechts und setzt den Folgezustand auf z0 . Durch diese Funktion werden die zum ersten Summand gehörenden Einser eingelesen. Kopfposition vor Zurückspulen

Kopfposition beim Start ...

#

1

1

1

#

1

1

1

Abb. 3.14: Bandinhalt vor Addition

1

1

#

...

...

#

1

1

1

1

1

1

1

Abb. 3.15: Bandinhalt nach Addition

1

#

...

3.2 Automatentheorie

| 27

Sobald der Kopf über dem „Operator“-Zeichen # liegt, kommt die Funktion „Operator“ zum Einsatz. Das #-Zeichen wird mit 1 überschrieben, der Automat wechselt in den Zustand z1 . Im Zustand z1 wird der durch nachfolgende Einser auf dem Band notierte zweite Summand eingelesen (Übergangsfunktion Zweiter Summand). Der Kopf wird solange nach rechts bewegt, bis er über dem abschließenden Zeichen # zu liegen kommt, der Zustand des Automaten wechselt in den Zustand z2 (siehe Kopfposition in Abbildung 3.15). Jetzt wird durch die Übergangsfunktionen Zählen durch Zurückspulen aus dem Zustand z2 heraus das Band nach links zurückgespult (Zustand z3 ). Aus dem Zustand z3 wechselt der Automat in den Zustand z4 (Endzustand), sobald das erste #Zeichen am linken Rand des Bandes gelesen wird. Nun kann mit einem neuen Bandinhalt neu gestartet werden.

3.2.4 Zusammenfassung Automatentheorie Wie bereits in den jeweiligen Abschnitten der Automaten angedeutet, existiert zu jedem Typ der formalen Sprachen ein entsprechender Automat, der Sprachen auf Basis der Typ-Grammatiken akzeptiert. Dieser Zusammenhang ist abschließend in Tabelle 3.9 dargestellt. Tab. 3.9: Sprachklassen und akzeptierende Automaten Sprachklasse Typ 0 Typ 1 Typ 2 Typ 3

Name

Erzeugende Grammatik

Akzeptierender Automat

Rekursiv aufzählbar Kontextsensitiv Kontextfrei Regulär

Beliebig Kontextsensitiv Kontextfrei Regulär

Turingmaschine Linear-beschränkte Turingmaschine Nicht-deterministische Kellerautomaten Endliche Zustandsautomaten

3.2.5 Registermaschine Wenn wir uns die Church’sche These in Erinnerung rufen, so sind mehrere Ansätze zu turingvollständigen Berechenbarkeitsmodellen möglich. Neben der Turingmaschine aus dem letzten Abschnitt, ist ebenso eine Registermaschine denkbar, die einfacher zu programmieren ist und eine größere Nähe zu aktuellen Rechnerarchitekturen aufweist. Die äquivalente Mächtigkeit von Turingmaschine und Registermaschine kann nachgewiesen werden, indem man einerseits ein Programm für die Turingmaschine entwickelt, welches eine Registermaschine nachstellt und ebenfalls ein Programm für die Registermaschine, welches eine Turingmaschine nachbildet (siehe auch Kapitel III.2.4).

28 | 3 Theoretische Informatik Eine Registermaschine (siehe auch (Hoffmann, 2012)) kann formal als 2-Tupel RM = (R, I) beschrieben werden. R beschreibt eine endliche Menge von Registern R = {R1 , R2 , . . . , }. I ist eine endliche Menge von Instruktionen, welche die Maschine ausführen kann: I = {L1 , L2 , . . . , }. Gültige Instruktionen sind: – Register inkrementieren: L i ∶ R j ← R j + 1 – Register dekrementieren: L i ∶ R j ← R j − 1 – Programm an beliebiger Stelle fortsetzen L i ∶ goto L n – Programm anhalten: L i ∶ stop – Wenn das Register Null enthält, Programm an bestimmter Stelle fortsetzen: L i ∶ if R j = 0 goto L n – Wenn das Register nicht Null enthält, Programm an bestimmter Stelle fortsetzen: L i ∶ if R j ≠ 0 goto L n Ein Programm besteht aus einer Abfolge von Instruktionen aus I, die jeweils mit einer Adresse (Sprungziel) L i versehen sind. Bevor ein Programm ausgeführt wird, werden alle Register R i mit Null initialisiert. Auch wenn der Befehlsumfang der Registermaschine sehr begrenzt ist, können damit umfangreiche Programme erstellt werden. Eng verbunden mit der vorgestellten Registermaschine sind die sogenannten GOTO-Programme, ein wichtiges Werkzeug in der Berechenbarkeitstheorie (Erk, 2009). GOTO-Programme verfügen über eine sehr einfache Syntax. Jede Programmzeile beginnt mit einer Marke (Zeilennummer, Label) L i und einem Doppelpunkt. Anstatt Register gibt es bei GOTO-Programmen Variablen x i sowie Konstanten c i . Weiterhin sind nur fünf Anweisungen (Befehle) vorgesehen: – Variable um eine Konstante erhöhen: L i ∶ x j ← x j + c k – Variable um eine Konstante verringern: L i ∶ x j ← x j − c k – Sprunganweisung: L i ∶ goto L n – Bedingter Sprung: L i ∶ if x j = c k then goto L n – Programm anhalten: L i ∶ stop Anhand der verfügbaren Instruktionen kann die Nähe der GOTO-Programme zu Registermaschinen erkannt werden.

4 Technische Informatik 4.1 Geschichtlicher Hintergrund Zur Vertiefung des hier kurz dargestellten geschichtlichen Hintergrunds der Informatik empfiehlt sich der Besuch der Informatik-Ausstellung im Deutschen Museum in München. Bei einem Besuch dort sollte als Andenken gleich noch der vorzüglich aufgebaute Ausstellungsführer (Bauer and Deutsches Museum, 2004) käuflich erworben werden. Neben allgemein zugänglichen Informationen sind interessante Details in diesem Kapitel dem Ausstellungsführer (Bauer and Deutsches Museum, 2004) entnommen. Die Wurzeln der Informatik reichen bis weit in die Vergangenheit zurück. Die ältesten bekannten, schriftlichen Rechenaufgaben aus Ägypten können auf etwa 1700 v. Chr. datiert werden. Ein weiteres, nennenswertes Beispiel ist der Euklidische Algorithmus zur Bestimmung des größten gemeinsamen Teilers zweier Ganzzahlen, der bereits um 300 v. Chr. formuliert wurde. Die Einführung des dezimalen Zahlensystems (indische oder auch arabische Ziffern) kann auf 500 n. Chr. datiert werden. Um 820 n. Chr. beschreibt Abu Abdallah Muhammad ibn Musa al-Chwarizmi in seinen Rechenbüchern den später nach ihm benannten Algorithmusbegriff, dem wir im Kapitel 5 auf den Grund gehen werden. Ab dem Jahr 1520 sorgte Adam Ries durch seine Rechenbücher für die Verbreitung des Dezimalsystems auch in Deutschland. Es ist zu vermuten, dass, seitdem die Menschen zählen und rechnen, Hilfsmittel hinzugezogen wurden. Als naheliegendes, erstes Hilfsmittel können die menschlichen Finger und Zehen genutzt werden. Neben schriftlichen Notizen zur Berechnung können erste mechanische Rechenhilfsmittel bis auf ca. 2700 bzw. 2300 v. Chr. zurückdatiert werden. Neben verschiedenen Gegenständen, die zum Abzählen und Addieren genutzt wurden, wie z. B. Kerbhölzern, Kerbknöchelchen, Zählsteinen und Zählbrettern, entwickeln sich Kugelzählmaschinen, auch als Abakus (siehe Abbildung 4.1) bekannt. Beim chinesischen Abakus des Typs 5+2 sind jeweils fünf Kügelchen, mit der Wertigkeit 1, von zwei weiteren Kügelchen, mit der Wertigkeit 5, durch eine Leiste getrennt. Es werden nur Kügelchen gezählt, die zur Trennleiste hin geschoben wurden. Somit sind auf jeder Stelle Zahlenwerte von 0 bis 15 möglich. Ebenso wie im bekannten Dezimalsystem können Überträge zur nächsten Stelle zur Bereinigung der Zahlenwerte notwendig werden. Das Prinzip der mechanischen Rechenmaschinen wurde weiter verfeinert. 1623 entwickelte Wilhelm Schickard, ein Professor für biblische Sprachen, Mathematik und Astronomie in Tübingen, eine mechanische Rechenmaschine, die Addition und Subtraktion ermöglichte. Die Maschine konnte bereits auch einen mehrfachen Übertrag korrekt berücksichtigen. Kurze Zeit später (1641) stellte auch Blaise Pascal, ein französischer Mathematiker, Physiker, Literat und Philosoph, seine Rechenmaschine „Pashttps://doi.org/10.1515/9783110496253-005

30 | 4 Technische Informatik

Abb. 4.1: Chinesischer Abakus

caline“ vor, bei der die Subtraktion durch eine Addition des Komplementwertes vorgenommen wurde (siehe auch Logik-Teilband). Kurze Zeit später, im Jahr 1674, erweitert Gottfried Wilhelm Leibniz Pascals Maschine um die Rechenarten Multiplikation und Division. Die Multiplikation wird durch wiederholte Addition, die Division durch mehrfache Subtraktion umgesetzt. Die von ihm erfundenen Staffelwalzen bildeten mehr als 100 Jahre lang die Grundlage für weitere mechanische Rechenmaschinen. Leibniz erkannte bereits die durch die Verwendung des Dezimalsystems entstehende Komplexität und mechanischen Schwierigkeiten bei der Umsetzung, speziell beim Übertrag, der nur über drei Stellen hinweg möglich war. Er entdeckte auch, dass sich die Rechenvorgänge einfacher maschinell durch eine binäre Kodierung umsetzen lassen. Aus dem Wunsch heraus, mehrere Rechenoperationen nacheinander ausführen zu können, um z. B. Rechentabellen zu erstellen, wurde nach Lösungen gesucht, Berechnungen programmgesteuert aufeinander folgen zu lassen. Charles Babbage stellte 1822 seine „Difference Engine“ vor. Sein Ziel war es, das Erstellen mathematischer Tabellen zu automatisieren. Die Difference Engine sollte in der Lage sein Polynome der n 2 Form f (x) = a n x + . . . + a2 x + a1 x + a0 nur durch die Verwendung der Addition (ohne Multiplikation) zu berechnen. Die Berechnung weiterer, stetig differenzierbarer Funktionen (daher der Name Difference Engine) kann durch Näherungspolynome

4.1 Geschichtlicher Hintergrund

| 31

approximiert werden. Seine Maschine sollte die Berechnung von Polynomen bis maximal sechsten Grades ermöglichen. Hierzu verkettete er sechs dezimale Addierwerke mit 20-stelliger Genauigkeit. Leider wurde die Difference Engine zu Lebzeiten Babbages nicht fertiggestellt. Erst 1991 und 2008 wurden im Science Museum in London die ersten funktionsfähigen Difference Engines gebaut und vorgestellt. Es soll nicht verschwiegen werden, dass in der Zwischenzeit, angeregt durch Charles Babbage, weitere Differenzenmaschinen hergestellt wurden. Zum Beispiel 1853 durch die Schweden Georg und Edvard Scheutz. Deren Maschine konnte die Zwischenergebnisse auch drucken. Charles Babbage führte seine Forschungen weiter und entwarf 1834 seine „Analytical Engine“. Sie sollte einen flexiblen Ablauf der Berechnungen, gesteuert über Lochkarten, ermöglichen. Es waren Befehle für arithmetische Operationen, Speicher und Zwischenspeicher, Schleifen und bedingte Sprünge vorgesehen. Auch verfügte sie bereits über eine Aufteilung in Steuer-, Rechen- und Speicherwerk. Weiterhin reifte die Erkenntnis, dass zur Umsetzung der Maschine neben der physischen Teile (Hardware) auch symbolische Teile (so etwas wie Software) notwendig sind. Leider wurde diese Maschine ebenfalls nicht fertiggestellt, da der Entwurf für die damalige Zeit mechanisch zu aufwendig für eine Umsetzung war. Weiterhin fehlte, aufgrund des Fehlschlags mit der Difference Engine, die finanzielle Unterstützung. Zusammen mit Charles Babbage soll auch Ada Lovelace genannt werden. Die britische Mathematikerin gilt heute als erste Programmiererin. Sie beschrieb in einem Diagramm das erste längere Programm zur Berechnung der Bernoulli-Zahlen für die Analytical Engine. Ebenfalls übersetzte sie die Beschreibung der Analytical Engine ins Englische und fügte umfangreiche Notizen der Beschreibung bei. Ihre Notizen hatten in etwa den doppelten Umfang der ursprünglichen Beschreibung der Analytical Engine. Mit der Z3 stellte Konrad Zuse 1941 den ersten programmgesteuerten, funktionsfähigen, auf Relais basierten Rechenautomaten vor. Die Z3 arbeitete mit einer Taktfrequenz von 5,3 Hz. Das Rechenwerk wurde aus 600 Relais aufgebaut, stellte die Grundrechenarten, Quadratwurzel und Umrechnungen zwischen binärer und dezimaler Zahlendarstellung zur Verfügung. Das Rechenwerk arbeitete auf zwei Registern R1 und R2. Der Speicher stellte 64 Wörter mit 22 Bit, aufgebaut aus 1 400 Relais, zur Verfügung. Die Z3 wurde über einen Lochstreifenleser programmiert, die Daten wurden über eine Tastatur mit Lampenfeld eingegeben. Der schrankwandgroße Rechner wog ca. 1 000 kg und hatte eine Leistungsaufnahme von ca. 4 kW. Die Z3 ermöglichte Fließkommaberechnungen (binäre Mantisse 14 Bit, Zweierexponent 7 Bit) auf einem binären Rechenwerk, die in einer Schleife ausgeführt werden konnten; sie ermöglichte keine bedingten Sprünge im Programmablauf. Als ersten vollelektronischen Rechner soll der von 1942 bis 1946 von J. W. Mauchly und J. P. Eckert in den Vereinigten Staaten von Amerika entwickelte ENIAC vorgestellt werden. ENIAC steht für „Electronical Numerical Integrator and Calculator“. Der ENIAC bestand aus 17 500 Elektronenröhren sowie 1 500 Relais. Er verbrauchte 174 kW elektrische Leistung bei einem Gewicht von 27 t. Eine auf den parallel angeordneten

32 | 4 Technische Informatik

Abb. 4.2: ENIAC-Simulator in Java

Komponenten ausgeführte Addition konnte der ENIAC in 0,2 ms berechnen, für eine Multiplikation benötigte er 2,9 ms. Die Programmierung erfolgte über eine variable Verdrahtung von Schalttafeln. Die Rechenabfolgen konnten so zwar geändert werden, der ENIAC war somit noch keine vollständige Universalmaschine (im Sinne der Turing-Mächtigkeit). Ihm fehlte in der ersten Ausbaustufe eine Art Befehlsspeicher, der die auszuführenden Algorithmen im Speicher beinhaltete und nicht in seiner Verkabelung. Erst in einer zweiten Ausbaustufe, welche die Verarbeitung verlangsamte, wurde nach Ideen von John von Neumann ein Befehlsspeicher nachgerüstet, der eine flexible Programmierung ermöglichte. Berechnungen wurden im Dezimalsystem durchgeführt. Der ENIAC diente hauptsächlich zur Berechnung von ballistischen Tabellen für das Militär. ENIAC-Simulation Till Zoppke hat im Rahmen seiner Diplomarbeit an der Freien Universität Berlin einen ENIAC-Simulator in Java umgesetzt (Zoppke, 2004). Der von ihm erstellte Simulator kann als als JAR-Datei heruntergeladen¹ und einfach in Betrieb genommen werden (siehe Abbildung 4.2). Fertige Algorithmen, bei-

1 http://zuse-z1.zib.de/simulations/eniac/index.html, Abruf: 12.08.2018

4.1 Geschichtlicher Hintergrund

| 33

spielsweise zum Finden des größten, gemeinsamen Teilers und zum Berechnen der Fibonacci-Reihe, erleichtern den Einstieg in die Arbeit mit ENIAC.

Die weitere Flexibilisierung der Programmierung in Richtung einer Universalmaschine wurde von John von Neumann, basierend auf den ENIAC-Erfahrungen, erforscht. Eine weitere röhrenbasierte Rechenanlage war der EDVAC („Electronic Discret Variable Electronic Computer“). Mit EDVAC wurde das Konzept der klaren Trennung zwischen Speicher, Rechen- und Steuerwerk aufgegriffen. Charles Babbages Konzept konnte von John von Neumann so weiter untersucht werden. Er erforschte die Idee, auch das Programm des Rechners, nicht nur die zu bearbeitenden Daten, im Arbeitsspeicher des Rechners abzulegen. Heute wird dieses Konzept für Rechenmaschinen mit dem Begriff Von-Neumann-Architektur bezeichnet. Von-Neumann-Architektur Die Von-Neumann-Architektur wird zur Umsetzung von universellen Rechenmaschinen verwendet, sie stellt alle dafür nötigen Komponenten bereit. Die Von-NeumannArchitektur sieht die folgenden Komponenten vor (siehe auch Abbildung 4.3): (1) Ein Rechenwerk (englisch Arithmetic Logic Unit, ALU), welches die arithmetische und logische Verarbeitung der Daten vornimmt, (2) ein Steuerwerk (englisch Control Unit), welches die Programmanweisungen interpretiert und den Rechner entsprechend steuert, (3) ein Speicherwerk (englisch Memory), in dem Daten und Programme abgelegt sind, (4) ein Bussystem zur Kommunikation der einzelnen Einheiten sowie (5) ein Ein/Ausgabewerk, welches die Kommunikation mit externen Komponenten und Benutzern übernimmt. CPU Steuerwerk

Rechenwerk (ALU)

Bussystem

Speicherwerk

Ein-/ Ausgabewerk

Abb. 4.3: Komponenten der Von-Neumann-Architektur

Das Steuerwerk zusammen mit dem Rechenwerk bilden die eigentliche Zentraleinheit (englisch Central Processing Unit). Die streng sequenzielle und über

34 | 4 Technische Informatik einen gemeinsamen Bus synchronisierte Abarbeitung innerhalb einer Von-NeumannArchitektur ist nach wie vor eine populäre Art Rechnersysteme zu strukturieren. Harvard-Architektur Im Gegensatz zu der an der Universität Princeton entwickelten Von-Neumann-Architektur, wurde mit den Entwicklungen rund um den Mark-I-Computer (ca. 1944) an der Universität in Harvard, die gleichnamige Harvard-Architektur gefunden.

Programm-/Befehlsspeicher

Steuerwerk Rechenwerke Rechenwerk 1

...

Rechenwerk n

Datenspeicher

Abb. 4.4: Komponenten der Harvard-Architektur

Bei der Harvard-Architektur sind Programm- und Datenspeicher logisch oder sogar physisch voneinander getrennt. Dies ermöglicht einen parallelen Zugriff über eigene Bussysteme auf die jeweiligen Befehle und Daten (siehe Abbildung 4.4). So können Daten und Befehle zeitgleich geladen bzw. geschrieben werden, im Gegensatz zur VonNeumann-Architektur, wo dieses strikt voneinander getrennt (seriell) erfolgen muss. Weiterhin kann z. B. der Programmspeicher als nur-lesbar ausgeführt werden (ROMs, EPROMs), hingegen der Datenspeicher als Schreib-/Lesespeicher (RAM). Diese Umsetzung der Harvard-Architektur findet man heutzutage oft bei Mikrocontrollern für eingebettete Systeme wie z. B. Mikrocontroller der Firmen PIC oder AVR. Der im Kapitel über Programmierung eingesetzte Arduino-Computer basiert auf dieser HardwareArchitektur. 1949 wurde von M. V. Wilkes mit EDSAC, dem „Electronic Delay Storage Automatic Calculator“, der erste funktionierende speicherprogrammierbare Rechner vorgestellt, welcher auf den Pionierarbeiten rund um EDVAC und ENIAC basiert. EDSAC war ein Binärrechner. Für eine seriell ausgeführte Addition benötigte er 1,5 ms, für eine Multiplikation 4,5 ms. Zur Einschätzung der Leistungsfähigkeit von EDSAC sei er-

4.1 Geschichtlicher Hintergrund

| 35

Abb. 4.5: Schalttafel mit Ringkernspeicher-Modul

wähnt, dass bereits seit 1951 automatische Programme zur Suche nach Programmierfehlern und erste Hilfsprogramme, welche Unterprogramme zusammenfügten, existierten. Man sprach hier bereits vom automatischen Programmieren und von „Compilern“. Der Startschuss für den Entwurf und die Entwicklung von höheren Programmiersprachen war gefallen. Beginnend mit den 1950er-Jahren entwickelte sich u. a. durch Ausgründungen von universitären Forschungsabteilungen und Firmengründungen eine Computerindustrie. Stark beschleunigt, durch die ab 1955 in Großserie hergestellten Transistoren und Fortschritten im Aufbau der Rechenanlagen, konnten die Leistungsfähigkeit und Zuverlässigkeit der Rechenanlagen stark erhöht werden. Um die Auslastung der teuren Rechenanlagen sicherzustellen, wurde die Stapelverarbeitung eingeführt. Ursprünglich stammt der Begriff Stapelverarbeitung von Lochkartenstapeln, auf denen sich die zu bearbeitenden Programme und Daten befanden. Programme und Daten wurden so von den Programmierern und Bedienern vorbereitet und konnten anschließend und ohne Unterbrechung von der Rechenanlage abgearbeitet werden, was zu einer hohen Auslastung der Rechenanlage führte. Zur Verwaltung der verschiedenen Bearbeitungsaufträge werden erste Betriebsprogramme und -systeme entwickelt, sogenannte Monitor-Programme.

36 | 4 Technische Informatik

Abb. 4.6: Unix V1 ausgeführt auf einer PDP-11 in SIMH

Beginnend ab ca. 1965 konnten durch die zunehmende Miniaturisierung sogenannte Minicomputer angeboten werden. Diese Rechner konnten die Rechenleistung für mehrere Mitarbeiter in Firmenabteilungen bereitstellen. Typische Preise für solche Minicomputer bewegten sich zwischen 1 000 und 10 000 US-Dollar. Neben diskreten Transistoren wurden später auch erste integrierte Schaltkreise eingesetzt. Der Arbeitsspeicher wurde meist mittels magnetischer Ringkernspeicher (siehe Abbildung 4.5) bereitgestellt. In den 1970er-Jahren wurden der Stapelbetrieb zunehmend durch Dialogsysteme mit Drucker- und Bildschirmterminals abgelöst. Der Bedarf an Betriebssystemen stieg, welche die gleichzeitige Nutzung der Rechnerressourcen (Multitasking) durch mehrere Benutzer (Multiuser) ermöglichten. Ab ca. 1969 wurde in den Bell Laboratories von Ken Thompson und Dennis Ritchie das wegweisende Multitasking- und MultiuserBetriebssystem Unix entwickelt, welches am 3. November 1971 in der ersten Ausgabe vorlag. Zunächst wurde Unix in Maschinencode für den PDP-7-Minicomputer der Digital Equipment Corporation (DEC) entwickelt. In den Jahren 1972 bis 1974 wurde Unix komplett neu in der damals ebenfalls entwickelten Programmiersprache C reimplementiert. Die erste Implementierung des Unix-Kerns in C wurde für die DEC-PDP-11-Rechner veröffentlicht. Die Programmiersprache C wurde von Dennis Ritchie speziell für die Programmierung unter Unix entwickelt. Im Github-Repository unix-v1 von Jim Huang²

2 Verfügbar unter https://github.com/jserv/unix-v1, Abruf: 21.08.2017.

4.2 Aktuelle Entwicklungen in der technischen Informatik

| 37

finden sich die restaurierten Quelltexte in Assembler und C für Unix in der Version 1. Im Repository ist ebenfalls ein C-Compiler, welcher das Kompilieren der historischen Unix-Quelltexte für die PDP-11-Emulation unter dem Computer History Simulation Project (SIMH)³ ermöglicht. Das auf der PDP-11-Emulation ablaufende UnixBetriebssystem zeigt Abbildung 4.6. In den nächsten Jahren wurden durch die zunehmende Miniaturisierung immer leistungsfähigere Rechner möglich. So entstanden in den 1970er-Jahren die ersten Mikroprozessoren, wie z. B. der Intel 4004, der erste in Serie gefertigte Mikroprozessor (damals noch speziell als Chipsatz für Taschenrechner entwickelt). Im Jahr 1974 folgte der erste 8-Bit-Universalprozessor, der Intel 8080. Gefolgt 1978 von der Intel 8086-CPU, die eine große Popularität durch die Verwendung in IBM und IBM-kompatiblen PCs erreichte. Der größte Konkurrent für die Intel 8086-CPU-Linie war die 68000-CPU-Linie des Herstellers Motorola, welche ab 1980 als leistungsfähige 16- und 32-Bit-Plattform zur Verfügung stand. In den 1980er-Jahren begann ebenfalls die Erfolgsgeschichte einer weiteren heute noch sehr populären Mikroprozessoren-Architektur. Das britische ComputerUnternehmen Acorn entwickelte 1983 eine zukunftsweisende Architektur für CPUs, der sie den Namen Acorn RISC⁴ Machines (ARM) gab. Der Name wurde später in „Advanced RISC Machines“ geändert. Die Weiterentwicklung dieser Architektur wurde 1990 in die Hände des Unternehmens ARM Limited gelegt. Erwähnt werden muss, dass ARM Limited keine eigenen Prozessoren fertigt, sondern das elektronische Design für die ARM-Architektur lizenziert und weiterentwickelt. Die eigentlichen Hersteller von Mikroprozessoren und -controllern können Rechte zum Entwickeln von Mikroprozessoren auf Basis des ARM-Design erwerben. Die ARM-Architektur ist heute auf Grund ihrer hohen Rechenleistung und ihres vergleichsweise niedrigen Energieverbrauchs die am weitesten verbreitete Architektur für mobile und eingebettete Geräte. Eine gute und lesenswerte Zusammenfassung dieser Entwicklungen gibt (Segars, 2011).

4.2 Aktuelle Entwicklungen in der technischen Informatik Aktuell dominieren, insbesondere auf dem Markt für mobile Geräte, zwei Mikroprozessorfamilien: Einerseits die Familie der ARM-Mikroprozessoren/-controller andererseits die Intel/AMD-x86-Prozessorenfamilie. Beide Architekturen stellen hohe Rechen-

3 Verfügbar unter http://simh.trailing-edge.com/, Abruf: 21.08.2017. 4 Englisch: Reduced Instruction Set Computer, ein gegenüber dem damals gebräuchlichen ComplexInstruction-Set-Computer (CISC) entwickeltes Prozessormodell mit reduzierter Anzahl von Prozessorbefehlen. Zur damaligen Zeit zeichneten sich RISC-Prozessoren durch vereinfachte Implementierung des eigentlichen Prozessors und somit einer höheren Rechengeschwindigkeit aus. Heutzutage verschwinden diese Vorteile; RISC-Prozessoren haben CISC-Verfahren übernommen und CISCProzessoren haben RISC-Verfahren übernommen.

38 | 4 Technische Informatik leistung bei guter Energieausbeute zur Verfügung. Die x86-Prozessoren finden sich in so gut wie allen Anwendungen im Büro, während die ARM-Prozessoren, auf Grund ihrer höheren Energieeffizienz, vornehmlich in mobilen Geräten zum Einsatz kommen. Bis zur Verwendung in klassischen Desktop-PCs und Notebooks, mit Ausnahme des kurzen Intermezzos in Archimedes-Rechnern und aktuellen Ideen bei Apple⁵, haben es die ARM-basierten Prozessoren noch nicht geschafft, allerdings behaupten sie sich im Bereich der eingebetteten Systeme, wie z. B. Raspberry Pis, Netzwerk-Routern, DSLModems, Digitalkameras, Navigationsgeräten, etc. Die Bedeutung des Marktes für eingebettete Systeme zeigt der folgende Zahlenvergleich⁶. Während 1998 noch ca. ein Drittel der verkauften Prozessoren in Arbeitsplatzrechnern zum Einsatz kam, waren es 2002 nur noch ca. ein Zehntel. Darüber hinaus hat sich die Anzahl der verkauften Prozessoren für eingebettete Systeme zwischen den Jahren 1998 und 2002 fast vervierfacht. Die Anzahl der verkauften Prozessoren für Desktop-Rechner blieb im gleichen Zeitraum, relativ gesehen, konstant. Bestimmt durch den Aufschwung im Bereich der künstlichen Intelligenz, der durch die aktuellen Verfahren des Deep Learnings erreicht wurde, gehen viele Mikrocontrollerhersteller dazu über, Spezialhardware für die Berechnung neuronaler Netze zu integrieren. Die Anbieter, welche Hardware-Produkte sowie Software anbieten, wie z. B. Apple mit seinen mobilen Geräten und dem Betriebssystem iOS sowie Google mit dem Betriebssystem Android, bieten eine gut in das Betriebssystem integrierte Softwareunterstützung zur Umsetzung von neuronalen Netzen auf diesen Endgeräten an. Als Beispiel soll hier TensorFlow⁷ Lite⁸ genannt werden, welches sich gut in Android-Anwendungen integrieren lässt. Diese Bibliotheken sind eng mit der jeweilig für die Berechnungen in neuronalen Netzen optimierten Hardware verknüpft und ermöglichen dadurch die effiziente Mustererkennung, welche die Grundlage für z. B. die Klassifikation von Bildern bzw. die Spracherkennung auf diesen Geräten bildet. Ohne diese spezielle Hardware-Unterstützung in den Geräten muss die rechenintensive Mustererkennung in Cloud-Systeme ausgelagert werden. Mehr über diese Entwicklun-

5 Projekt Kalamata, Quelle: https://www.bloomberg.com/news/articles/2018-04-02/apple-is-saidto-plan-move-from-intel-to-own-mac-chips-from-2020, Abruf: 11.06.2018. 6 Quelle: CSCE 212 Computer Architecture-Foliensatz, verfügbar unter http://slideplayer.com/slide/ 4954373, (Folie 6), Abruf: 20.02.2018. 7 TensorFlow ist die, mittlerweile von Google, angebotene Softwareumgebung zur effizienten Umsetzung von Berechnungen, die für z. B. neuronale Netze notwendig sind. Unter http://www.tensorflow. org (Abruf: 20.02.2018) finden sich Hintergrundinformationen zu TensorFlow. 8 Details zu TensorFlow Lite gibt der Blog-Eintrag unter https://developers.googleblog.com/2017/11/ announcing-tensorflow-lite.html (Abruf: 20.02.2018), bzw. die TensorFlow-Lite-Dokumentation unter https://www.tensorflow.org/mobile/tflite/ (Abruf: 20.02.2018).

4.2 Aktuelle Entwicklungen in der technischen Informatik

| 39

gen kann beispielsweise auf den Entwickler-Webseiten von Apple⁹ bzw. von Android¹⁰ gefunden werden. Selbst in diesen Cloud-Systemen wird Spezial-Hardware eingesetzt, um die Rechenleistung für die Berechnung in neuronalen Netzen bereitzustellen. In den Rechenzentren von Google werden beispielsweise spezielle Recheneinheiten, die sogenannten TensorFlow Processing Units (TPUs) eingesetzt. Umfangreiches Hintergrundwissen über TPUs kann (Jouppi, 2017) entnommen werden.

9 Verfügbar unter https://developer.apple.com/machine-learning/, Abruf: 20.02.2018. 10 Verfügbar unter https://developer.android.com/ndk/guides/neuralnetworks/index.html, Abruf: 20.02.2018.

5 Algorithmen und Datenstrukturen Nachdem nun der historische Werdegang der modernen Informatik und Rechner beleuchtet wurde, werden wir uns im Weiteren den theoretischeren Inhalten der Informatik zuwenden. In den nächsten Abschnitten werden wir uns mit den Themen Algorithmen, Datenstrukturen und der zugehörigen Berechenbarkeits- und Komplexitätstheorie beschäftigen. Um die Inhalte zu vertiefen, werden wir von Zeit zu Zeit Python (vgl. Kapitel II.4 in diesem Band) als Programmierumgebung verwenden. Speziell wollen wir uns mit Algorithmen-Grundlagen, deren Implementierung, Sortier-, Such- und Graphen-Algorithmen, String-Matching sowie abschließend den sogenannten schweren Problemen der Informatik mittels Heuristiken nähern. Dieser Ausschnitt der Informatik vermittelt einen kompakten Überblick über das Wesen und die Verwendung von Algorithmen und Datenstrukturen in diesem Fachgebiet. Er liefert somit den theoretischen Hintergrund für weitere Aufgaben und Herausforderungen der Datenverarbeitung.

5.1 Algorithmen Der Begriff Algorithmus ist eine Abwandlung des Namens Muhammed Al Chwarizmi, eines arabischen Mathematikers des Mittelalters. Sein mathematisches Lehrbuch über den Umgang mit indischen Ziffern beginnt mit den lateinischen Worten „Dixit Algorismi . . . “ („Algorismi hat gesagt . . . “) Muhammed Al Chwarizmi beschreibt beispielsweise den Umgang mit dem dezimalen Zahlensystem und die Einführung der Null in die Mathematik. Bereits 300 v. Chr. wurde der Euklidische Algorithmus beschrieben. Er beschreibt ein Vorgehen zur Bestimmung des größten gemeinsamen Teilers zweier Ganzzahlen. Euklid gilt als einflussreicher Mathematiker seiner Zeit und weit darüber hinaus. Er schuf Grundlagen der Zahlentheorie und Geometrie. Unter anderem auch den Satz: „Es gibt unendlich viele Primzahlen“. Seine konstruktiven Existenzbeweise sind ebenfalls vergleichbar mit dem Vorgehen nach einem Algorithmus. Vergleichbar mit (Balzert, 2008) kann folgende Definition für den Algorithmusbegriff gegeben werden: Definition: Algorithmus „Ein Algorithmus ist eine eindeutige, endliche Beschreibung eines allgemeinen, endlichen Verfahrens zur schrittweisen Ermittlung gesuchter Größen aus gegebenen Größen. Die Beschreibung erfolgt in einem Formalismus mithilfe von anderen Algorithmen und, letztlich, elementaren Algorithmen. Ein Algorithmus muss ausführbar sein.“ (Balzert, 2008)

Die Eigenschaften von Algorithmen sollen nun näher beleuchtet werden. https://doi.org/10.1515/9783110496253-006

5.1 Algorithmen

|

41

5.1.1 Eigenschaften von Algorithmen Die folgenden Begriffe und Eigenschaften helfen bei der genaueren Definition des Algorithmusbegriffs. Determiniertheit Ein Algorithmus ist eine Abbildung einer Menge von Eingabedaten auf eine Menge von Ausgabedaten. Ist diese Abbildung mathematisch gesehen eine Funktion, so spricht man von einem determinierten Algorithmus. Ein determinierter Algorithmus liefert bei gleichen Eingabedaten stets das gleiche Ergebnis. Beispielsweise erwartet man von einem Algorithmus, welcher die mathematische Funktion y = sin(x) berechnet, dass er für x = 2π immer, d. h. bei jedem Aufruf, auch das deterministische (zu erwartende) Ergebnis von exakt 0 liefert. Ein solcher Algorithmus sollte kein nicht-deterministisches Verhalten wie z. B. ein von 0 abweichendes Ergebnis oder, noch schlimmer, ein Fehlverhalten z. B. durch Abbruch der Berechnung zeigen. Determinismus Die schrittweise Abarbeitung eines Algorithmus wird als Determinismus bezeichnet. Ein Algorithmus heißt deterministisch, wenn zu jeder Zeit der Folgeschritt eindeutig bestimmbar ist. Deterministische Algorithmen sind auch immer determiniert. Die Umkehrung gilt jedoch nicht. In der Praxis wird Determinismus oft durch die Implementierung von deterministischen, endlichen Zustandsautomaten bzw. deterministischen Übergängen (z. B. Verzweigungen) innerhalb des Algorithmus sichergestellt. Übergänge in Zustände, wie z. B. „Das hat er ja noch nie gemacht“, sind durch sorgfältigen Entwurf und Umsetzung des Algorithmus auszuschließen. Endlichkeit (Finitheit) Ein Algorithmus beeinflusst zu jedem Zeitpunkt seiner Ausführung (vor, während, und – falls er endet – nach seiner Ausführung) nur einen endlichen Bereich. Es wird in statische Finitheit und dynamische Finitheit unterschieden. Jeder Algorithmus muss statisch finit sein, d. h. er wird durch einen endlich langen Text beschrieben. Ein Algorithmus ist dynamisch finit, wenn die von ihm verwendeten Objekte und Strukturen zu jedem Zeitpunkt endlich bleiben. Terminiertheit Ein Algorithmus terminiert, wenn er ausgehend von der Startsituation stets nach endlich vielen Schritten zu einem Ende kommt.

42 | 5 Algorithmen und Datenstrukturen Berechenbarkeit Eine Funktion f ∶ M → N heißt berechenbar, wenn es einen Algorithmus gibt, der für jeden Eingabewert m ∈ M für die f (m) definiert ist, nach endlich vielen Schritten anhält und ein Ergebnis f (m) = n liefert. Die Church’sche These besagt, dass die Klasse der berechenbaren Funktionen gleich der Klasse der Funktionen ist, die durch eine Turingmaschine berechnet werden kann. Die Turingmaschine und ihre Eigenschaften wurden bereits in Unterabschnitt 3.2.3 ausführlich vorgestellt. Korrektheit Ein Algorithmus heißt korrekt, wenn er die gewünschte Spezifikation erfüllt, sodass er auf alle Eingabedaten mit den gewünschten Ausgabedaten reagiert.¹ Effizienz Ein Algorithmus heißt effizient, wenn er das gegebene Problem in möglichst kurzer Zeit und/oder mit geringem Aufwand an Ressourcen (z. B. Hauptspeicher) löst. Beispielhafte Beurteilungen der Effizienz aus der Praxis beinhalten die Laufzeit (Anzahl auszuführender Operationen), Menge des verwendeten Haupt- und/oder Massenspeichers, Anzahl der Zugriffe auf Hintergrundspeicher, usw. Zur Beurteilung der Effizienz wird die Komplexitätstheorie (siehe Abschnitt über die Raum- und Zeitkomplexität in diesem Kapitel) verwendet.

5.1.2 Textuelle Beschreibungsverfahren Um sich nun konkret über Algorithmen austauschen zu können, benötigen wir ein Beschreibungsverfahren. Aus dem täglichen Leben kennen wir textuelle Beschreibungen für definierte Abläufe. Textuelle Beschreibungen von Algorithmen werden in verständlicher Schriftsprache bzw. Umgangssprache formuliert². Ein einfaches Beispiel für eine solche Beschreibung ist ein Kochrezept wie in Abbildung 5.1 dargestellt. Sie können auch in oder angelehnt an eine spezielle Programmiersprache formuliert werden. Ebenfalls möglich ist die Formulierung in einer mathematischen Kunst-

1 Der Nachweis einer formalen Korrektheit eines Algorithmus ist mathematisch/logisch aufwendig, hierzu kann die sogenannte formale Verifikation herangezogen werden. Zum Vergleich: Das bloße Testen des Algorithmus mit einem Ausschnitt der Eingabemenge bzw. nur eines Ausschnittes aller möglichen internen Zustände eines Algorithmus wird als Validieren bezeichnet. Eine umfangreiche Abhandlung über die formale Korrektheit von Software kann in (Peled, 2001) gefunden werden. 2 Alan Turing hat in (Kittler et al., 1987) geschrieben: „Wenn man auf Englisch, wo nötig unter Zuhilfenahme mathematischer Symbole, vollkommen unzweideutig erklären kann, wie eine Rechnung ausgeführt werden muss, so ist es stets auch möglich, einen beliebigen Digitalrechner zur Durchführung dieser Rechnung zu programmieren, vorausgesetzt, dass die Speicherkapazität ausreicht.“

5.1 Algorithmen |

43

Scheiterhaufen Zutaten – 8 alte Brötchen – 250 ml Milch – 30 g Butter – 40 g Zucker – 2 Eier – 50 g Rosinen – 2 bis 3 Äpfel – Zucker, Zimt nach Belieben Zubereitung Die alten Brötchen in Scheiben schneiden. Die Milch darüber verteilen. Die Butter schaumig schlagen, mit dem Zucker und den Eiern vermengen und über den mit Milch getränkten Brötchen verteilen. Die Rosinen untermischen. Die Äpfel in dünne Scheiben hobeln und mit Zimt und Zucker abschmecken. Die Brötchen abwechselnd mit den Äpfeln in eine Form schichten. Bei 200 °C bei Ober- und Unterhitze 40 Minuten im vorgeheizten Ofen backen. Guten Appetit! Abb. 5.1: Rezept für Scheiterhaufen (Quelle: Stefanie und Ursula Maier)

sprache, z. B. speziell für mathematische Formalismen innerhalb eines Algorithmus. Bei der textuellen Beschreibung von Algorithmen kommt es häufig zu Ungenauigkeiten: Alle 30 Sekunden sollen die Werte der Sensoren abgelesen werden. Wenn die Abweichung vom Sollwert 0,25 überschreitet ist die Normalisierungsprozedur auszuführen und anschließend sollen die Werte an das Analysepaket weitergegeben werden.

Ungenauigkeiten können sein: Passive Formulierungen (welche Komponente macht das?), fehlende Einheiten (0,25? Absoluter Wert, relativer Wert, . . . ). Es ist sehr genau darauf zu achten, diese Ungenauigkeiten durch genaue Formulierungen zu vermeiden. Weiterhin hilft eine Art Wörterbuch für Definitionen (Was ist die Normalisierungsprozedur?). Diese Probleme können oftmals durch die Verwendung von Pseudocode minimiert werden. Pseudocode Unter Pseudocode versteht man eine textuelle Zwischendarstellung zwischen Umgangssprache und einer formalen Programmiersprache, welche eine schrittweise Verfeinerung der Beschreibung ermöglicht. Strukturiert wird Pseudocode durch formale Syntaxelemente, die an existierende Programmiersprachen angelehnt sind. Informelle, verbale Einschübe können in weiteren Schritten verfeinert und formal strukturiert werden. Eine zu Beginn sehr grobe Darstellung wird so immer weiter verfeinert, de-

44 | 5 Algorithmen und Datenstrukturen tailliert und formalisiert. Für Pseudocode hat sich kein Industriestandard etabliert, allerdings findet man oft ähnliche Vorgehensweisen: – Einrückungen kennzeichnen Blockstrukturen – while-Schleifen – for-Schleifen – repeat/until-Schleifen – if/then-Verzweigungen – Kommentare (oft wie in Java mit „//“) – Zuweisungen, Mehrfachzuweisungen, lokale Variablen – Arrays mit Index (z. B. a[3]) – Objekte mit Attributen (z. B. Person.Name) – Call by value, call by reference – return für Rückgabewerte – Boolesche Ausdrücke – Fehlerbehandlung, . . . Ein einfaches Beispiel für die Verwendung von stark formell gehaltenem Pseudocode gibt Listing 5.1. Listing 5.1: Beispiel für Pseudocode 1 2 3 4 5

every 30 sec: sensorData = readSensors() if (sensorData.isInRange(0.25) == False): normaliseData(sensorData) analyseData(sensorData)

Neben den rein textuellen Beschreibungsverfahren haben sich grafische Beschreibungsverfahren etabliert, die im nächsten Abschnitt genauer betrachtet werden sollen. Grafische Beschreibung Viele Aspekte von Algorithmen und komplexeren Softwaresystemen lassen sich besser grafisch beschreiben. Ausgehend von einfacheren Verfahren für die Beschreibung z. B. von Abläufen, haben sich komplexere grafische Beschreibungssprachen etabliert, die auch die Dokumentation von hoch-komplexen Softwaresystemen erlauben. Beispiele sind Flussdiagramme, Programmablaufpläne, Struktogramme, die Unified Modeling Language (UML), sowie das visuelle Programmieren. Flussdiagramme und Programmablaufpläne Auf einfache Flussdiagramme stößt man relativ schnell, sobald sich Menschen über technische Abläufe auseinandersetzen. Der Kreativität sind hier keine Grenzen ge-

5.1 Algorithmen

|

45

setzt, die formalen Mittel sollen den Austausch und die Dokumentation von Abläufen unterstützen. Gemeinsamkeiten finden sich, wenn es z. B. um die grafische Gestaltung von Startpunkten, einzelnen Aktivitäten und Übergängen geht. Meistens werden Abläufe als gerichtete Graphen gezeichnet. Ein relativ weit verbreitetes und standardisiertes Verfahren zur grafischen Dokumentation von Programmabläufen bieten die Programmablaufpläne, welche nach DIN 66001 genormt sind. Für Start-/End-/Kontrollpunkte werden Rechtecke mit abgerundeten Ecken verwendet. Pfeile und Linien bilden die Verbindung der einzelnen Elemente untereinander. Rechtecke symbolisieren Tätigkeiten, Unterprogramme werden durch doppelte vertikale Kanten an Rechtecken dargestellt. Rauten symbolisieren Verzweigungen, Aus- und Eingaben werden durch Parallelogramme dargestellt. Ein Beispiel für einen Programmablaufplan für das Scheiterhaufen-Rezept aus Abbildung 5.1 zeigt Abbildung 5.2.

Start

Brötchen in Scheiben schneiden

Butter schaumig schlagen mit Zucker und Eiern vermengen

Äpfel hobeln und mit Zimt und Zucker abschmecken

Milch über Brötchen verteilen

Butter über Brötchen verteilen Rosinen untermischen

Scheibenweise in Form schichten Backen Stop

Abb. 5.2: Programmablaufplan für Scheiterhaufen-Rezept

Struktogramm Ein weiteres grafisches Verfahren zur Beschreibung von Algorithmen sind Struktogramme oder auch Nassi-Shneiderman-Diagramme, benannt nach den beiden amerikanischen Informatikern Isaac Nassi und Ben Shneiderman. Die bereits in den 1970er-

46 | 5 Algorithmen und Datenstrukturen Jahren entwickelten Diagramme sind nach DIN 66261 genormt. Sie unterstützen die schrittweise Verfeinerung beim Algorithmus-Entwurf. Struktogramme bestehen aus rechteckigen Strukturblöcken, die leicht ineinander geschachtelt werden können. Anweisungen werden in rechteckige Blöcke geschrieben, Verzweigungen werden durch Dreiecke beschrieben. Schleifen werden durch eingerückte Rechtecke dargestellt.Ein einfaches Beispiel für ein Struktogramm gibt Abbildung 5.3. In ihm ist der Algorithmus aus dem Pseudocode aus Listing 5.1 dargestellt. Wiederhole alle 30 Sekunden Lese Sensordaten Abweichung > 0,25 Nein

Ja Normalisieren

Übergebe Daten an Analysepaket

Abb. 5.3: Beispiel für ein Struktogramm

In der Softwaretechnik-Praxis wurden sowohl Programmablaufpläne als auch Struktogramme durch die Aktivitätsdiagramme der UML abgelöst. Unified Modeling Language (UML) Die Unified Modeling Language (UML) stellt ein umfangreiches Werkzeug zur grafischen Darstellung von komplexen Systemen, (nicht nur) Softwaresystemen, zur Verfügung. Die Aktivitätsdiagramme der UML sind den hier vorgestellten grafischen Mitteln zur Beschreibung von Algorithmen sehr ähnlich. Eine umfangreiche Betrachtung der UML und ihrer Modellierungsmethoden würde den Umfang dieses Kapitels sprengen. Daher sei auf die umfangreiche Fachliteratur zum Thema der objektorientierten Modellierung von Hard- und Softwaresystemen verwiesen. Ein erster Anlaufpunkt und Überblick über die Thematik kann in (Weilkiens, 2014) gefunden werden. Nachdem nun die Grundlage für die Beschreibung von Algorithmen gegeben ist, wollen wir dazu übergehen, das dynamische Laufzeitverhalten von Algorithmen zu betrachten. Neben der Effektivität interessiert uns besonders die Effizienz von Algorithmen.

5.1 Algorithmen |

47

5.1.3 Laufzeitanalyse von Algorithmen Bei der Laufzeitanalyse interessiert uns das Verhalten des Algorithmus während er ausgeführt wird. Ein Algorithmus soll effektiv und effizient sein. Effektiv ist ein Algorithmus, wenn er das gegebene Problem löst. Die Effizienz eines Algorithmus beschreibt dessen Eigenschaft, sparsam mit gegebenen Ressourcen umzugehen. Die Ressourcen, die einem Algorithmus zur Verfügung stehen, können in Speicherplatz (Raum) und Rechenzeit (Zeit) unterteilt werden. Daher wird bei den Komplexitätsbetrachtungen auch in Raum- und Zeitkomplexität unterschieden. Raumkomplexität Die Raumkomplexität beschreibt, wie viel Speicherplatz ein Algorithmus zur Ausführung und zur Lösung des gegebenen Problems benötigt. Die Raumkomplexität ist meist direkt abhängig vom Datenumfang bzw. der gegebenen Problemgröße n. Sie wächst meist linear mit der Menge der Daten an. Manchmal kann durch einen erhöhten Speicherbedarf die zeitliche Ausführung eines Algorithmus beschleunigt werden, z. B. durch das Abspeichern von Zwischenergebnissen. Ein weiteres Beispiel hierfür ist das sogenannte Loop Unrolling. Loop Unrolling beschreibt das Verfahren, Schleifen im Programmablauf mit bekannter Wiederholungszahl, explizit hintereinander zu codieren. Dies erhöht zwar den Speicherbedarf, verringert im Gegenzug aber die Anzahl komplexerer Anweisungen (z. B. Vergleiche und Verzweigungen). Ein einfaches Beispiel für Loop Unrolling gibt Listing 5.2. Listing 5.2: Loop Unrolling in Python 1 2 3

def loop_example(): for i in range(5): # Vergleich und falls nötig Verzweigung print('Hello world.')

4 5

def loop_unrolled_example():

6

print('Hello world.')

7

print('Hello world.')

8

print('Hello world.')

9

print('Hello world.')

10

print('Hello world.') # Höherer Speicherbedarf durch

Wiederholungen Die Raumkomplexität eines Algorithmus ist sicherlich interessant zu untersuchen, sie ist allerdings kein sehr selektives Kriterium für die Qualität eines Algorithmus. Die Raumkomplexität tritt in den Vordergrund, wenn der Algorithmus auf stark eingeschränkten Plattformen, wie eingebetteten Rechnern oder der in Kapitel II.1

48 | 5 Algorithmen und Datenstrukturen dieses Bandes verwendeten Lehrplattform MOUSE, implementiert werden soll. Für die Untersuchung der Algorithmenkomplexität hat die Zeitkomplexität eine höhere Bedeutung, wie der nächste Abschnitt zeigen wird. Zeitkomplexität Die Zeitkomplexität ist ein Maß dafür, wie viel Zeit ein Algorithmus zur Laufzeit für seine Ausführung benötigt. Sie ist normalerweise abhängig von den Eingabedaten, der Code-Qualität und der Plattform (Rechner, Betriebssystem, usw.), auf welcher der Algorithmus ausgeführt wird. Rein formal ist die Worst-Case-Zeitkomplexität interessant, sie gibt eine Aussage über das im schlechtesten Fall zu erwartende Laufzeitverhalten. Im allgemeinen ist die Average-Case-Zeitkomplexität aussagekräftiger, da diese näher am zu erwartenden Verhalten des Algorithmus liegt. Gegebenenfalls muss die Wahrscheinlichkeit für das Auftreten von ungünstig gewählten Eingabedaten (die letztlich zu einem Worst-CaseSzenario führen) berücksichtigt werden. Um eine theoretische Vergleichbarkeit der Zeitkomplexität verschiedener Algorithmen zu erreichen, suchen wir eine Beschreibung der Zeitkomplexität, unabhängig von den oben genannten Größen. Wir wollen die Zeitkomplexität einzig abhängig von der Problemgröße n beschreiben können. Wie können wir hierzu vorgehen? Zunächst einmal benötigen wir eine abstrakte Formulierung des zu untersuchenden Algorithmus (z. B. textuell oder grafisch). Weiterhin identifizieren wir elementare Operationen (wie z. B. Zuweisungen, Prüfungen, Verzweigungen) und deren Laufzeitkosten. Anschließend setzen wir diese Laufzeitkosten von unten nach oben (Bottomup) zu einem Modell der Laufzeitkosten zusammen. Ein einfaches Beispiel für die Berechnung der Laufzeitkomplexität wollen wir in Listing 5.3 durchführen. Listing 5.3: Beispiel zur Bestimmung der Laufzeitkomplexität in Python 1 2

def buildMultiplicationTable(n): print('Multiplication table\n') # Aufwand: 1

3 4 5 6

for i in range(1, n): # Aufwand: 2 mal n for j in range(1, n): # Aufwand: 2 mal n print (i, 'times', j, 'equals', i*j) # Aufwand: 2

7 8

buildMultiplicationTable(4)

Der Algorithmus gibt eine einfache Multiplikationstabelle auf dem Bildschirm aus. Die Laufzeitkosten für einfache Operationen können mit t simple = 1 und die Laufzeitkosten für die komplexen Operationen mit t complex = 2 angenommen werden. Die Laufzeitkosten für Schleifenoperationen sollen mit t branch = 2 angenommen werden. Die Laufzeit des gesamten Algorithmus berechnet sich zu:

5.1 Algorithmen

|

49

T = t simple + n(t branch + n(t branch + t complex )) eingesetzt zu 2

T = 1 + n(2 + n(2 + 2)) = 4n + 2n + 1 Somit kann festgestellt werden, dass die Laufzeit des Algorithmus quadratisch von der Problemgröße n abhängt. Das konstante Glied 1 sowie das lineare Glied 2n fallen 2 für sehr große Problemgrößen gegenüber n nicht mehr ins Gewicht, sie können vernachlässigt werden. Da uns in der Informatik letztlich die Aussage der quadratischen Laufzeit interessiert, wurde eine Kurzschreibweise eingeführt, welche die obigen Rechenschritte und Vereinfachungen ausdrückt. Diese Notation wird Groß-𝒪-Notation genannt. Die Groß-𝒪-Notation (mittels des Landau-Symbols 𝒪) ist eine abstrakte Angabe der Laufzeit, abhängig von der Problemgröße n, unabhängig von z. B. der Hardware/Softwareplattform und konkreten Compilern. Sie ist somit technologieunabhängig. Die Notation mittels Großbuchstaben O wurde 1894 erstmalig von Paul Bachmann eingeführt. Im deutschen Raum wurde sie als Landau-Notation durch den Zahlentheoretiker Edmund Landau populär. Auf Basis der vorgestellten Methodik können Algorithmen in verschiedene Komplexitätsklassen eingeordnet werden. Für unseren Algorithmus zur Darstellung einer Multiplikationstabelle (Listing 5.3) kann somit als obere 2 Schranke 𝒪(n ) angegeben werden. Für die Beurteilung weiterer Algorithmen können die folgenden Regeln zu Rate gezogen werden. Die Sequenz- oder auch Summenregel beschreibt das zeitliche Verhalten von Teilen eines Algorithmus P, dessen Programmteile P1 und P2 sequentiell bzw. hintereinander ausgeführt werden. Die Laufzeit für P1 in Abhängigkeit von der Problemgröße n kann mit T1 (n) = 𝒪(f (n)) mit f (n) einer allgemeinen Funktion abhängig von n beschrieben werden. Ebenso kann die Laufzeit für P2 mit T2 (n) = 𝒪(g(n)) beschrieben werden. Unter diesen Annahmen gilt für das zeitliche Gesamtverhalten T(n) von P: T(n) = T1 (n) + T2 (n) ⇒ T(n) = 𝒪(max(f (n), g(n))) Mit 𝒪(max(f (n), g(n))) ist für das zeitliche Verhalten diejenige Funktion bestimmend, die das größere asymptotische Verhalten zeigt. Vereinfacht ausgedrückt bestimmt der Programmteil mit der höheren Laufzeitkomplexität das Laufzeitverhalten von sequentiell ausgeführten Programmteilen. Die Schleifen- oder Produktregel beschreibt das zeitliche Verhalten eines Programmteils P1 , der in einer Schleife mehrfach ausgeführt wird. T1 (n) = 𝒪(f (n)) beschreibt wiederum das zeitliche Verhalten von P1 . Die zeitliche Komplexität der Wiederholungen kann durch eine Funktion g(n) beschrieben werden. Somit gilt für das zeitliche Gesamtverhalten:

50 | 5 Algorithmen und Datenstrukturen

T(n) = g(n) ⋅ T1 (n) ⇒ T(n) = 𝒪(g(n) ⋅ f (n)) Wird ein Programmteil P1 beispielsweise in einer Schleife n-mal ausgeführt, so wird dessen zeitliche Komplexität einfach mit n multipliziert: T(n) = n ⋅ T1 (n). Die Verzweigungsregel hilft bei der Beurteilung des zeitlichen Verhaltens zweier Programmteile P1 und P2 eines Algorithmus P, welche alternativ (entweder oder) ausgeführt werden, beispielsweise durch eine Verzweigung im Programmablauf (z. B. if-then-Struktur). Die Laufzeit von P1 sei durch T1 (n) = 𝒪(f (n)), die von P2 durch T2 (n) = 𝒪(g(n)) beschrieben. In diesem Fall gilt für die Gesamtlaufzeit von P: T(n) = T1 (n) oder T2 (n) ⇒ T(n) = 𝒪(max(f (n), g(n))) Somit dominiert, ähnlich wie bei der Summenregel, der Programmteil, der das asymptotisch größere zeitliche Verhalten aufweist, die zeitliche Komplexität des Gesamtalgorithmus. Im Worst-Case wird genau dieser Programmteil durchlaufen, nicht derjenige mit der geringeren zeitlichen Komplexität. Durch die Auslagerungsregel wird beschrieben, wie die Auslagerung des Programmablaufs in ein Unterprogramm berücksichtigt werden kann. Ein Programmteil P1 ist in ein Unterprogramm ausgelagert. Die Laufzeit von P1 kann durch T1 = 𝒪(f (n)) beschrieben werden. Durch den Unterprogrammaufruf entsteht ein zeitlicher Aufwand, welcher konstant ist. Er kann mit T call = 𝒪(1) und somit auch durch T call ≪ T1 beschrieben werden. Somit gilt für die Gesamtlaufzeit: T(n) = 1 + T1 (n) ⇒ T(n) = 𝒪(f (n)) Unter Berücksichtigung dieser Regeln kann nun die zeitliche Komplexität, auch komplexerer Algorithmen, systematisch und Bottom-up bestimmt werden. Komplexitätsklassen Werden verschiedene Algorithmen untersucht, so lassen sich Komplexitätsklassen für die obere Schranke der Laufzeitkomplexität finden, wie in Tabelle 5.1 gezeigt. Die Problemgröße wird wiederum mit n bezeichnet, p beschreibt den maximalen Grad des Polynoms und d die Basis eines exponentiellen Problems (oftmals 2). Wünschenswert ist es, einen Algorithmus zu finden, der das gegebene Problem in möglichst kleiner Laufzeitkomplexität löst. Als handhabbar haben sich Algorithmen der Komplexitätsklassen konstant bis zu polynomiell erwiesen. Eine erwähnenswerte Ausnahme ist die, aus Ermangelung besserer Implementierungsmöglichkeiten, in den 1970/1980er-Jahren gerne verwendete Warteschleife (englisch spin lock). Hier wird Rechenkapazität eingesetzt um auf ein Ereignis zu warten oder zu synchronisieren. Mehr dazu ist im Kapitel über Assembler-Programmierung (Kapitel II.2.5.1 zu finden. Algorithmen werden derart in die genannten Komplexitätsklassen eingeteilt, dass die Angabe der Komplexitätsklasse eine obere Schranke der Laufzeitkomplexität dar-

5.1 Algorithmen

|

51

Tab. 5.1: Komplexitätsklassen für Algorithmen 𝒪(1) 𝒪(log n) 𝒪(n) 𝒪(n log n) 2 𝒪(n ) 3 𝒪(n ) p 𝒪(n ) mit p ≥ 1 n 𝒪(d ) mit d ≥ 1

Konstant Logarithmisch Linear Linear logarithmisch Quadratisch Kubisch Polynomiell Exponentiell

p

stellt. Algorithmen in der Komplexitätsklasse 𝒪(n ) mit p ∈ N (polynomiell) gelten 100 als praktisch lösbar. Wie beurteilen Sie die Größe von p in der Praxis? Ist 𝒪(n ) noch praktisch lösbar? Die Erfahrung hat gezeigt, dass polynomielle Algorithmen bis p ≤ 4 noch praktisch lösbar sind. Da diese Klasse von Algorithmen eine hohe praktische Bedeutung besitzen, hat p sich für alle Algorithmen in der Komplexitätsklasse 𝒪(n ) (polynomiell) die Kurzschreibweise P etabliert; im Gegensatz zu NP (nicht deterministisch polynomiell), der Klasse von Algorithmen, deren Ergebnis nur in Polynomialzeit überprüft werden kann. Bei diesen Algorithmen ist noch keine praktikable Lösung in der Klasse P bekannt. Leider befinden sich die Algorithmen zur Lösung von einigen wichtigen Problemen in der Informatik, wie z. B. das Finden kürzester Wege, bereits in der Komplexitätsklasse „exponentiell“. Zur Lösung dieser kombinatorischen Probleme müssen alle möglichen Lösungskombinationen ausprobiert werden (deswegen exponentielles Wachstum). Als hilfreich erweist sich die Beschränkung des zu durchsuchenden Suchraums mittels Heuristiken. Heuristiken helfen beim Finden einer ausreichend guten Lösung (meist in polynomieller Zeit), welche nicht unbedingt die optimale Lösung des Problems darstellt. Es wird versucht mithilfe von vorhandenem Vorwissen über das zu bearbeitende Problem eine aktuell ausreichend gute Entscheidung/Lösung zu treffen – aus der jeweiligen Betrachtung des aktuellen Teilproblems heraus. Ausführlich werden Heuristiken im Kapitel 10 betrachtet.

5.1.4 Implementierung von Algorithmen Wie können Algorithmen nun konkret auf einer Rechnerplattform umgesetzt werden? Beim Studium verschiedener Implementierungen von Algorithmen fallen gemeinsame Muster ins Auge. Divide-and-Conquer Oftmals zerteilen Algorithmen größere (vermeintlich unbeherrschbare) Probleme in kleinere (beherrschbare) Probleme, die nachfolgend einfach gelöst werden können.

52 | 5 Algorithmen und Datenstrukturen Dieser Ansatz ist im Prinzip bereits seit dem Mittelalter bekannt: Divide et impera (lateinisch: teile und herrsche). Diese Redewendung beschreibt Niccolò Machiavellis politische Idee, das militärische oder politische Vorgehen, größere Gruppen in sich gegenüberstehende kleinere Gruppen zu zerteilen und diese so leichter beherrschbar zu machen. Die durch den Divide-and-Conquer-Ansatz zerteilten Probleme können oftmals einfach und rekursiv gelöst werden. Aber um die Rekursion zu verstehen, müssen wir zunächst die Rekursion verstehen . . . Rekursion Schon der Dichter Joachim Ringelnatz hat die Verschachtelung und, relativ treffend, die Rekursion in seinem Gedicht „Der Bandwurm“ beschrieben: Der Bandwurm „Es stand sehr schlimm um des Bandwurms Befinden. Ihn juckte immer etwas hinten. Dann konstatierte der Doktor Schmidt, Nachdem er den Leib ihm aufgeschnitten, Daß dieser Wurm an Würmern litt, Die wiederum an Würmern litten“ Joachim Ringelnatz (1924)

Eine Funktion wird als rekursiv bezeichnet, wenn sie sich mindestens einmal selbst aufruft (siehe Listing 5.4). Listing 5.4: Form einer rekursiven Funktion 1 2 3 4

def rekursiveFunktion():

... rekursiveFunktion() ...

Um nun eine Endlosschleife durch Selbstaufrufen zu vermeiden, müssen rekursive Algorithmen über eine Abbruchbedingung der Rekursion verfügen. Ein Beispiel für einen rekursiv implementierten Algorithmus zur Berechnung der Fakultätsfunktion zeigt Listing 5.5. Listing 5.5: Rekursive Fakultätsfunktion in Python 1 2 3 4 5

def fac(n): if n == 0: return 1 else: return n * fac(n - 1)

6 7

print('Die Fakultät von 23 ist', fac(23))

5.1 Algorithmen

| 53

Für den Fall, dass fac(n) mit n = 0 aufgerufen wird, wird die Funktion mit dem Rückgabewert 1 beendet (Rekursionsabbruch). Für alle anderen Fälle wird n mit dem (rekursiv) zu berechnenden Wert von fac(n-1) multipliziert.

Dynamische Programmierung Ein weiteres Konzept, das bei der Entwicklung von Algorithmen hilfreich sein kann, ist das Konzept der dynamischen Programmierung. Die dynamische Programmierung beschreibt das Vorgehen, oft wiederverwendete Zwischenergebnisse in einem Algorithmus zur Laufzeit zwischenzuspeichern. Dadurch erübrigt sich die erneute Berechnung des Zwischenergebnisses, der Algorithmus kann schneller abgearbeitet werden. Als Beispiel wollen wir die Berechnung der Fibonacci³-Zahlenfolge näher betrachten. Listing 5.6 zeigt eine rekursive und eine dynamische Implementierung. Listing 5.6: Rekursive und dynamische Implementierung des Fibonacci-Algorithmus in Python 1 2

def fibRec(n): if n < 2: return n

3 4

else: return fibRec(n - 1) + fibRec(n - 2)

5 6 7 8 9 10 11 12 13

def fibMemo():

pad = {0:0, 1:1} # Belege Hash-Tabelle mit Triviallösungen def func(n): if n not in pad: # Zugriff auf Hash-Tabelle in O(1) pad[n] = func(n-1) + func(n-2) return pad[n] return func

14 15

i = 36

16 17

print('Die Fibonacci-Zahl', i, 'ist', fibRec(i))

18 19 20

fm = fibMemo() print('Die Fibonacci-Zahl', i, '(dynamisch) ist', fm(i))

3 Die Fibonacci-Zahlenfolge geht auf Leonardo von Pisa (populärer Name Fibonacci, ca. 1170 bis 1250) zurück. Sie beschreibt zahlreiche natürliche Phänomene u. a. die Populationsentwicklung von Kaninchen.

54 | 5 Algorithmen und Datenstrukturen Die rekursive Implementierung ist leicht zu verstehen, sie folgt genau der Rechenvorschrift für Fibonacci-Zahlen. Die dynamische Implementierung ist etwas trickreicher. In Zeile 8 in Listing 5.6 wird zunächst ein Dictionary aufgesetzt, in dem nach und nach unsere Zwischenergebnisse abgelegt werden. Die Trivialergebnisse für 0 und 1 sind bereits vorbelegt. Wird nun eine Fibonacci-Zahl gesucht, wird zunächst in diesem Dictionary nachgesehen, ob diese bereits berechnet wurde. Falls ja, wird das Zwischenergebnis zurückgegeben. Falls nein, wird die neu zu bestimmende Fibonacci-Zahl rekursiv berechnet und dem Dictionary hinzugefügt. Sie steht so bei der nächsten Berechnung zur Verfügung. Da neu zu berechnende Fibonacci-Zahlen bestenfalls aus bereits berechneten Fibonacci-Zahlen ermittelt werden, wird die Berechnung stark beschleunigt. Da eine umfangreiche Abhandlung der Feinheiten bei der Implementierung von Algorithmen in diesem Kapitel nicht möglich ist, sei an dieser Stelle auf (Häberlein, 2012) verwiesen.

5.2 Datenstrukturen Durch die Verfügbarkeit moderner und umfangreicher Programmierumgebungen stehen sehr komfortable Datenstrukturen zur Verfügung, die die Beschränkungen einfacher Datenstrukturen der Vergangenheit vergessen lassen. Als Beispiel sei die Datenstruktur „Liste“ in Python genannt. Sie vereinigt Konzepte verschiedener Datenstrukturen wie z. B. des Arrays, des Stacks in einer komfortablen Art und Weise, wie Listing 5.7 zeigt. Listing 5.7: Beispiel zur Liste in Python 1

list = ['One', 2, 'Three']

2

list.append(4)

3

list.insert(0, 'Zero')

4

list[2] = 'Two'

5 6

print('Die Liste enthält die folgenden Elemente:')

7

for i in list:

8

print(i)

9 10

print('Letztes Element war:', list.pop())

Zunächst einmal erlaubt die Liste in Python das Ablegen verschiedener Datentypen (Zeile 1). Weiterhin können neue Elemente am Ende hinzugefügt werden (append()) wie z. B. bei einem Stack. Ebenso kann wahlfrei auf die Elemente zugegriffen werden, wie z. B. in einem Array in Zeile 4. Dort wird das zweite Element der Liste durch ein neues ersetzt. Auch können wahlfrei neue Elemente eingefügt wer-

5.2 Datenstrukturen

Erstes Element

| 55

Listenende

Daten

Daten

Daten

Abb. 5.4: Einfach verkettete Liste

den (siehe Zeile 3). Die Liste in Python vereinigt Eigenschaften vieler historischer Datenstrukturen, wie sie im Folgenden kurz vorgestellt werden sollen.

5.2.1 Listen Traditionell sind Listen Datenstrukturen, welche die dynamische Ablage von Elementen ermöglichen. Hierzu werden die Elemente als Datencontainer angelegt und geeignet miteinander verknüpft. Einfach verkettete Liste Im einfachsten Fall können diese Datencontainer durch Verweise auf den nächsten Datencontainer verknüpft werden, wie in Abbildung 5.4 dargestellt. In diesem Fall spricht man von einer einfach verketteten Liste. Die einfach verkettete Liste ist einerseits leicht zu implementieren, sie bietet die Möglichkeit neue Elemente an jeder Stelle einzuhängen. Der notwendige Mehraufwand für die Verknüpfung der Elemente bleibt im Rahmen. Der gravierende Nachteil dieser Implementierung soll trotzdem nicht verschwiegen werden: Die einfach verkettete Liste kann nur vorwärts durchsucht werden. Ein einfaches Suchen nach einem Element in der Liste liegt somit bereits in der Komplexitätsklasse 𝒪(n). Die verkette Liste hat ihre Bedeutung in Softwaresystemen, die einerseits dynamisch sind, andererseits mit sehr wenig Speicher auskommen müssen. Ein populäres und historisches Beispiel für den Einsatz einer einfach verketteten Liste ist das Dictionary der verfügbaren Wörter in der Programmiersprache Forth. Leo Brodie beschreibt in (Brodie, 1987) die Verwendung der einfach verketteten Liste. Der Nachteil, dass die Liste nur vorwärts durchwandert oder iteriert werden kann, kann durch eine doppelte Verknüpfung der Elemente umgangen werden. Hierzu wird, zusätzlich zum Verweis auf das Nachfolgeelement, ein Verweis auf das Vorgängerelement eingefügt. Man spricht von einer doppelt verketteten Liste.

56 | 5 Algorithmen und Datenstrukturen Warteschlangen Eine erste, einfache Anwendung für eine einfach verkettete Liste sind Warteschlangen (englisch Queue). Diese nach dem First-In-First-Out-Verfahren (FIFO) organisierte Datenstruktur wird beispielsweise zum temporären Zwischenspeichern vor dem eigentlichen Bearbeitungsschritt genutzt. So z. B. als Druckerwarteschlange, in der die einzelnen Druckaufträge zwischengespeichert werden. Eine Warteschlange ist somit eine Datenstruktur, die einerseits Daten (z. B. Druckaufträge) speichert und andererseits auch Funktionen zum Zugriff auf die Daten zur Verfügung stellt. Üblicherweise wird die Funktion zum Ablegen eines neuen Datensatzes am Ende der Warteschlange als put()- oder enqueue()-Operation bezeichnet. Das Entnehmen des am Beginn der Warteschlange befindlichen Datensatzes wird in der get()- oder dequeue()-Operation umgesetzt. Meist verfügen Warteschlagen auch über eine Funktion, die anzeigt, ob noch Elemente in der Warteschlange verfügbar sind, oft als isEmpty()-Operation. Eine einfache Umsetzung von Warteschlangen kann mithilfe von verketteten Listen geschehen. Das erste Element in der verketteten Liste ist der Warteschlangenkopf, neue Elemente werden am Ende der verketteten Liste angehängt.

5.2.2 Stapel- oder Kellerspeicher Neben der Warteschlange als klassische FIFO-Datenstruktur, gibt es auch sogenannte Last-In-First-Out-Datenstrukturen (LIFO). Ein Vertreter ist der Stapel- oder Kellerspeicher (englisch Stack, siehe auch Kapitel III.1.2.2 sowie Band 1, Kapitel II.5.2.2). In einem Stapel- oder Kellerspeicher sind ebenfalls beliebig viele Elemente ablegbar. Elemente können nur auf den Stapel (als oberstes Element) abgelegt werden. Dies geschieht mit der sogenannten push()-Operation. Die pop()-Operation im Gegenzug, liefert und entfernt das oben auf dem Stapel liegende Element. Die isEmpty()-Operation liefert ebenfalls Information darüber, ob sich noch Elemente auf dem Stapel befinden. Stapelspeicher kommen in nahezu jedem Mikroprozessor zum Einsatz. Sie werden für die Zwischenspeicherung von Daten, insbesondere beim Aufruf von Unterprogrammen, verwendet. Als etwas exotischeres Beispiel für die Verwendung eines Stapelspeichers kann die umgekehrte polnische Notation (UPN), so wie diese in HPTaschenrechnern umgesetzt wird, angesehen werden. Bei UPN-Taschenrechnern werden die Operanden eines mathematischen Terms zuerst auf einem Stapelspeicher abgelegt. Erst durch das nachfolgende Angeben des Operators, werden die jeweiligen Operanden verarbeitet. Die Eingabe einer einfachen Addition auf einem solchen Taschenrechner erfolgt durch die Tastenfolge: 2 , 3 , Enter , 4 , 2 , Enter .

5.3 Sortieralgorithmen

| 57

5 6 2 + * 12 4 / - . Abb. 5.5: Beispielprogramm in Forth

Nun enthält der Stapelspeicher die Elemente 23 und 42. Durch die Eingabe des Operators + werden die beiden Elemente addiert und das Ergebnis 65 auf dem Stapel abgelegt. Die UPN ermöglicht das Verarbeiten komplexer mathematischer Ausdrücke ohne die Verwendung von Klammern. Der Term (3 + 4) ⋅ 7 = würde durch die folgenden Eingaben berechnet werden: 3 , Enter , 4 , + , 7 , * . Um die Beispiele nachvollziehen zu können, kann beispielsweise der HP-35 RPN Calculator⁴ verwendet werden. Als ein weiteres Beispiel für die Verwendung von Stapelspeichern kann wiederum die Programmiersprache Forth genannt werden. Forth ist eine imperative, stackbasierte Programmiersprache, die sich nach wie vor auf stark eingebetteten Systemen großer Beliebtheit erfreut. Abbildung 5.5 zeigt ein einfaches Forth-Programm zur Berechnung des Terms 5 ⋅ (6 + 2) − 12/4 =. Das Programm berechnet das Ergebnis korrekt, wie leicht unter Verwendung von fig-FORTH auf dem Heimcomputer Sinclair ZX Spectrum (hier in einer Fuse⁵Emulation) nachvollzogen werden kann, wie Abbildung 5.6 zeigt. Um nun Algorithmen und Datenstrukturen in Aktion zu erleben, werfen wir im nächsten Abschnitt einen Blick auf einfache Algorithmen wie Sortierverfahren.

5.3 Sortieralgorithmen Das Sortieren, der Vorgang gegebene Elemente in eine Ordnung zu bringen, ist ein grundlegendes Verfahren der Datenverarbeitung. Bis heute nimmt das Sortieren von Daten einen großen Anteil der verfügbaren Rechenleistung ein. Bereits in den 1960erJahren wurde der Rechenaufwand für Sortiervorgänge auf ca. 25 % der verfügbaren Rechenleistung geschätzt. Wenn man einen Blick auf aktuelle Anwendungen wirft, so sind Sortiervorgänge nach wie vor allgegenwärtig. Man denkt z. B. an die Ausgabe einer nach Interpreten geordneten Liste von Musikstücken in einer Mediathek, der nach Datum sortierten Bil-

4 Verfügbar unter http://www.hpmuseum.org/simulate/hp35sim/hp35sim.htm, Abruf: 24.03.2017. 5 Der Fuse-Emulator kann unter http://fuse-emulator.sourceforge.net/ (Abruf: 11.06.2018) gefunden werden.

58 | 5 Algorithmen und Datenstrukturen

Abb. 5.6: fig-FORTH auf einer Emulation des Heimcomputers Sinclair ZX Spectrum

der in einer Bilddatenbank, den nach Ablaufdatum geordneten Auktionen in einem Online-Auktionshaus, usw. Es stellt sich die Frage, wie Daten effektiv und effizient sortiert werden können. Nach wie vor sind hier traditionelle Sortierverfahren im Einsatz. Auch wenn in aktuellen Programmierschnittstellen und Bibliotheken moderne, hybride Verfahren wie z. B. der Timsort⁶ eingesetzt werden, so basieren diese letztlich auf gut bekannten, traditionellen Sortierverfahren. Wir wollen im Folgenden einen Blick auf einfache, naive Sortierverfahren werfen. Im Anschluss betrachten wir fortgeschrittene Sortierverfahren, die nahe am mathematisch möglichen Optimum liegen.

5.3.1 Insertionsort Ein einfaches, naheliegendes Sortierverfahren ist der sogenannte Insertionsort. Das Verfahren ist auch als Sortieren durch Einfügen bekannt. Es beschreibt das intuitive Vorgehen, welches beispielsweise beim Aufnehmen von Spielkarten auf die Hand bei Kartenspielen zum Einsatz kommt: Die ausgeteilten Karten befinden sich auf einem Stapel vor dem Spieler. Nun wird Karte für Karte auf die Hand aufgenommen. Hierzu wird jede neue Karte ihrem Kartenwert entsprechend in der Hand einsortiert bzw. eingefügt. Das Verfahren wird so lange fortgeführt, bis der Spieler den gesamten vor ihm liegenden Kartenstapel sortiert in der Hand hält. Etwas formeller kann festgehalten werden: Pro Schritt wird ein unsortiertes Element aus einer Liste genommen und in eine sortierte Liste eingefügt (englisch: to in-

6 Beschrieben beispielsweise unter https://bugs.python.org/file4451/timsort.txt, Abruf: 21.12.2017.

5.3 Sortieralgorithmen

| 59

sert). Als eine erste Optimierung können die unsortierte Liste und die sortierte Liste gemeinsam in einer Liste gespeichert werden. Dieses Vorgehen vermindert den notwendigen Speicherplatz und wird als In-Place-Implementierung bezeichnet. Listing 5.8: Insertionsort in Python 1 2 3 4 5 6 7 8

def insertionSort(l): for j in range(1, len(l)): # l[j] als einzufügendes Element

key = l[j] i = j - 1 while i >= 0 and l[i] > key: # Sucht in sortierter Liste nach passendem Index für l[j] l[i+1] = l[i] # Bewegt passende Elemente um Platz für Einfügen zu schaffen i = i - 1 # Sucht von hinten nach vorne l[i+1] = key # Ersetzt Elemente entsprechend

9 10 11 12

nums = [42, 23, 11, 47] insertionSort(nums) print(nums)

Eine Implementierung des Insertionsort ist in Listing 5.8 gezeigt. Es handelt sich um eine In-Place-Implementierung, bei der die bereits sortierten Elemente zu Beginn der noch unsortierten (Rest-)Liste einsortiert werden. Zum genauen Verständnis des Algorithmus empfiehlt es sich, die Implementierung an einem einfachen Beispiel Schritt für Schritt durchzugehen, um die genaue Arbeitsweise nachzuvollziehen. Eine Laufzeitanalyse des Insertionsort führt zu folgenden Betrachtungen. Die bereits sortierte Liste muss für jedes (n) neu einzusortierende Element durchlaufen werden. Im schlimmsten Fall (worst case) von Anfang bis Ende (n), also n Mal, n − 1 Mal, n − 2 Mal, . . . Die Worst-Case-Laufzeit kann wie folgt bestimmt werden: n−1

L worst case (n) = ∑ k = k=1

n(n − 1) 2 ⇒ 𝒪(n ) 2

mit k als die Größe der bereits sortierten Liste. Im besten Fall (best case) ist für jedes zu sortierende Element nur ein Vergleich nötig: n−1

L best case (n) = ∑ 1 = n − 1 ⇒ 𝒪(n) k=1

60 | 5 Algorithmen und Datenstrukturen Die Average-Case-Laufzeit ist nicht so einfach zu bestimmen, da diese stark von der wirklichen Verteilung der zu sortierenden Elemente abhängt. Es kann gezeigt werden, dass die Average-Case-Laufzeit auch quadratische Komplexität aufweist: 2

L average case (n) ⇒ 𝒪(n ) Minimale Laufzeit von Sortierverfahren Bei den angestellten Laufzeitbetrachtungen am Beispiel des Insertionsort stellt sich die Frage: Wie viele Schritte sind mindestens erforderlich, um eine gegebene Anzahl von Elementen zu sortieren? Betrachten wir eine Liste von n Elementen, so kann diese in n! Permutationen vorliegen. Durch einfaches Vertauschen von zwei Elementen in der Liste können zwei Permutationen hergestellt werden, erneutes Vertauschen erzeugt vier Permutationen. k Durch k Tauschoperationen können 2 Permutationen erstellt werden. Also gilt: k

2 ≥ n! ⇒ k ≥ log2 (n!) n

n

n! kann nun zu n 2 ≤ n! ≤ n abgeschätzt werden. Nach Anwendung des Logarithmus n ⋅ log2 (n) ≤ log2 (n!) ≤ n ⋅ log2 (n) 2 mit n ⋅ log2 (n) ∈ 𝒪(n ⋅ log(n)) 2 ergibt sich die Komplexität zur Erstellung einer beliebigen (sortierten) Permutation einer Liste mit n Elementen in der Komplexitätsklasse 𝒪(n log(n)).

5.3.2 Selectionsort Ein dem Insertionsort sehr ähnliches Sortierverfahren stellt der Selectionsort (auch bekannt als MinSort, MaxSort oder ExchangeSort) dar. Im Gegenzug zum Insertionsort (sortiert unsortierte Elemente nach und nach in eine sortierte Liste) wird beim Selectionsort das nächste geeignete (quasi vorsortierte) Element ausgewählt (englisch „to select“) und am Beginn/Ende der bereits sortierten Liste hinzugefügt. Der Selectionsort kann ebenfalls mittels zweier Listen (unsortierte und sortierte Liste) oder auch als optimierte In-Place-Implementierung umgesetzt werden, wie Listing 5.9 zeigt.

5.3 Sortieralgorithmen

| 61

Listing 5.9: Selectionsort in Python 1 2

# Quelle: http://rosettacode.org/ # wiki/Sorting_algorithms/Selection_sort#Python

3 4 5 6 7 8

def selectionSort(lst): for i in range(0, len(lst) - 1): # Iteriert über Liste, Element

für Element mn = min(range(i, len(lst)), key = lst.__getitem__) # Finde Index für kleinstes Element lst[i], lst[mn] = lst[mn], lst[i] # Tausche kleinstes Element an korrekte Position im Array return lst

9 10 11 12

lst = [11, 33, 5, 7, 19, 22] selectionSort(lst) print(lst)

In Zeile 5 wird Element für Element durch die noch unsortierte (Rest-)liste gegangen (iteriert). Zeile 6 bestimmt den Index des kleinsten Elements in der zu verbleibenden unsortierten Restliste. In Zeile 7 wird das kleinste Element an das Ende der bereits sortierten Liste angehängt. Zeile 8 gibt die nun sortierte Liste zurück. Eine Komplexitätsanalyse des Selectionsorts ergibt für jedes zu sortierende Element eine n, n − 1, n − 2, . . . Schritte umfassende Suche nach dem kleinsten Element. Selectionsort liegt somit im schlechtesten Fall (worst case) in der Komplexitätsklasse 2 n⋅(n−1) Vergleiche. Somit 𝒪(n ). Selbst für den einfachsten Fall (best case) verbleiben 2 2

bleibt der Selectionsort auch im besten Fall in der Komplexitätsklasse 𝒪(n ).

5.3.3 Bubblesort Als letztes der sogenannten naiven Sortierverfahren soll ein nach wie vor sehr beliebtes Verfahren untersucht werden: Bubblesort. Bubblesort hat bei zeitgemäßen Programmierumgebungen keine praktische Bedeutung mehr. Hier finden sich hauptsächlich Verfahren mit besserem Laufzeitverhalten als die naiven Verfahren. Trotzdem hat sich Bubblesort als einfach zu verstehendes und leicht umzusetzendes Sortierverfahren seine Popularität bewahren können. Für den an historischen Rechnerarchitekturen und an effizienter Umsetzung von Algorithmen interessierten Leser finden sich in (Zaks, 1982) eine Implementierung des Bubblesorts in Z80-Assembler. Zusätzlich findet man eine BubblesortImplementierung in 6502-Assembler-Code in (Zaks, 1984). Beide Implementierungen können, zur Vertiefung des Verständnisses von Assembler-Programmierung (aus Kapitel II.1 in diesem Band), untersucht und verglichen werden.

62 | 5 Algorithmen und Datenstrukturen Beim Bubblesort werden in einer zunächst unsortierten Liste jeweils benachbarte Elemente paarweise und überlappend untersucht und – falls diese nicht dem Sortierkriterium entsprechen – vertauscht. Dieses Vorgehen wird solange durchgeführt, bis die Liste sortiert ist und keine weiteren Vertauschungen notwendig sind. Bubblesort hat seinen Namen daher, dass die Elemente wie Blasen in der Liste aufsteigen und an ihren Ort getauscht werden. Nach dem ersten Durchlauf des Verfahrens kann festgestellt werden, dass das dem Suchkriterium am besten entsprechende Element (größtes oder kleinstes Element) bereits an den Listenanfang getauscht wurde. Somit muss beim nächsten Durchgang nur noch die verbleibende Restliste (n − 1 Elemente) bearbeitet werden. Eine weitere Optimierung kann überprüfen, ob im jeweiligen Durchgang noch Vertauschungen notwendig waren. Falls nein, ist die Liste bereits sortiert, das Verfahren kann abgebrochen werden. Auch kann die Vertauschungsreihenfolge für jeden Vorgang umgedreht werden (einmal am Beginn der unsortierten Liste beginnen, das andere Mal am Ende der unsortierten Liste). Bubblesort ist sehr effizient bei bereits vorsortierten Listen, bei denen nur wenige Vertauschungen notwendig sind. Listing 5.10 zeigt eine optimierte, In-Place-Implementierung des Bubblesort-Algorithmus. In Zeile 8 wird überprüft, ob eine Vertauschung notwendig ist. Diese wird gegebenenfalls in Zeile 9 durchgeführt und in Zeile 10 als solche vermerkt. Listing 5.10: Bubblesort in Python 1

# Quelle: http://rosettacode.org/wiki/Bubble_Sort#Python

2 3 4 5 6 7 8 9 10 11

def bubble_sort(seq):

changed = True while changed: # Sortiere, solange es etwas zu sortieren gibt changed = False for i in range(len(seq) - 1): if seq[i] > seq[i+1]: seq[i], seq[i+1] = seq[i+1], seq[i] changed = True return None

12 13 14 15

lst = [27, 3, 17, 1, 2, 18] bubble_sort(lst) print(lst)

5.3 Sortieralgorithmen

|

63

5.3.4 Quicksort Quicksort wurde 1962 von C. A. Hoare in (Hoare, 1962) vorgestellt. Hoare selbst beschreibt seinen Algorithmus als „sehr vorteilhaft im Vergleich mit anderen bekannten Verfahren in Bezug auf Geschwindigkeit, Speicherökonomie und Einfachheit der Implementierung“. Aufgrund des Geschwindigkeitsvorteils gegenüber anderen bekannten Verfahren wurde der vorgestellte Sortieralgorithmus als Quicksort bezeichnet. Quicksort ist ein Divide-and-Conquer-Algorithmus, der die Menge der zu sortierenden Elemente in jeweils kleinere Mengen unterteilt. Hierzu wird ein sogenanntes PivotElement gesucht, welches die zu sortierenden Elemente bestmöglich in zwei Mengen mit gleicher Anzahl von Elementen unterteilt. Für die Bestimmung des Pivot-Elements können verschiedene Strategien verfolgt werden: Das erste Element in der Menge, ist ein zufällig gewähltes Element der Menge oder auch deren Median-Element. Jede dieser Strategien hat Vor- und Nachteile. Wählt man das erste oder ein zufälliges Element, welches schnell gefunden ist, kann nicht immer sichergestellt werden, dass die weiteren zu sortierenden Teilmengen gleich viele Elemente beinhalten. Wählt man, mit etwas Aufwand (vollständiges Auswerten oder Stichprobe), das Median-Element so bekommt man eine bestmögliche Aufteilung (mit entsprechenden Kosten). Es bleibt anzumerken, dass die Laufzeit des Quicksorts bei ungeschickter Wahl des Pivot-Elements entarten kann. Wenn das gewählte Pivot-Element jeweils das größte oder kleinste Element der Liste ist, so entsteht eine leere Liste und eine verbleibende Liste mit allen Elementen. Es wird nur das Pivot-Element sortiert. Quicksort liegt in diesem Worst2 Case-Fall in der Komplexitätsklasse 𝒪(n ) (wie auch die naiven Sortierverfahren). Im Gutfall kann nun anhand des Pivot-Elements die zu sortierende Menge in zwei Teilmengen unterteilt werden. Die eine Teilmenge beinhaltet alle Elemente, die laut Sortierkriterium kleiner sind als das Pivot-Element; die andere Teilmenge enthält alle Elemente, die größer als das Pivot-Element sind. Diese Teilmengen werden anschließend wiederum rekursiv mit dem Quicksort-Verfahren sortiert. Im letzten Schritt werden die, nun sortierten, Teillisten zu einer gesamten sortierten Liste zusammengefügt. Dieser Combine-Schritt ist einfach, da jeweils die linke Teilliste, gefolgt vom PivotElement und anschließend die rechte Teilliste aneinander gefügt werden müssen. Listing 5.11: Quicksort in Python 1

def quicksort(lst):

2

if len(lst) 2: hash = hash + 26 * asciiOrd(s[2])

9

if len(s) > 4: hash = hash + 26*26 * asciiOrd(s[4])

|

83

10 hash = hash % 37

11 12 13

return hash

14 15

for name in names:

16

print(name, "-->", hash(name))

Ein einfaches Beispiel, angelehnt an (Isernhagen and Helmke, 2004), soll das Vorgehen praktisch verdeutlichen. Es sollen deutsche Nachnamen in einer Hash-Tabelle abgelegt werden. Der Python-Quelltext in Listing 7.1 zeigt das Vorgehen. Die asciiOrd-Funktion (ab Zeile 3) gibt den ASCII-Wert des jeweiligen Zeichens zurück. Die hash-Funktion (ab Zeile 6) berechnet eine einfache Hash-Funktion aus dem ersten und falls vorhanden weiteren Zeichen des Namens. Die einzelnen ASCII2 Werte werden jeweils mit 26 bzw. 26 multipliziert und zum Hash-Wert aufaddiert. Anschließend wird der Hash-Wert mittels Modulo-Funktion (mit Wert 37) auf einen begrenzten Zahlenbereich abgebildet. Die berechneten Hash-Werte für die gegebenen Namen zeigt Tabelle 7.1. Tab. 7.1: Zuordnung Hash-Wert zu Nachname Name Hoeltgen Maibaum Westphal Kloeckl Fischer Voelz Ernst Schoeler Keller Ulmann Nockemann

Hash-Wert 5 35 11 24 25 5 14 18 3 18 31

Anhand der Hash-Werte, welche dem Index in einer Hash-Tabelle entsprechen, kann leicht gesehen werden, wie die einzelnen Nachnamen gestreut in der HashTabelle abgelegt werden. Ebenso kann gesehen werden, dass es bei der verwendeten Hash-Funktion bereits zu Doppelbelegungen in der Hash-Tabelle kommen würde. Die Nachnamen „Hoeltgen“ und „Voelz“ würden beide am Index 5 in der Hash-Tabelle zu liegen kommen, ebenso die Nachnamen „Schoeler“ und „Ulmann“ am Index 18.

84 | 7 Gestreute Speicherung, Hashing Bevor wir uns mit dem Problem der Doppelbelegung beschäftigen, wollen wir zuerst noch einen Blick auf das Verfahren generell werfen. Bei Verwendung von Ganzzahlen als Index i auf aktuellen Rechnern mit 64 Bit 64 Datenwortbreite ergeben sich 2 mögliche Positionen in einer Hash-Tabelle. Zur Ablage dieser Hash-Tabelle im Speicher müssten 16 Mio. Terabyte Speicher zur Verfügung stehen. Dieser Speicherbedarf ist nicht praktikabel, somit muss der Wertebereich für den Index begrenzt werden. Im Normalfall ist der verwendete Wertebereich der HashFunktion sehr viel kleiner als ihr Definitionsbereich. Welche Eigenschaften haben praktikable Hash-Funktionen? Zunächst sollen sie den verwendeten Schlüssel k auf einen praktikablen Wertebereich 0 ≤ h(k) ≤ n − 1, mit n als Größe der verwendeten Hash-Tabelle, abbilden. Diese Abbildung soll möglichst „zufallsartig“ erfolgen, die Werte sollen breit und gleichverteilt über den verfügbaren Wertebereich streuen. Dies vermeidet Kollisionen (Doppelbelegungen) und nutzt die Hash-Tabelle bestmöglich aus. Weiterhin sollen Hash-Funktionen einfach und schnell berechenbar sein. Bei der Entwicklung von Hash-Funktionen hat sich die Kongruenzmethode bewährt. Zunächst wird der Schlüssel k auf eine Ganzzahl abgebildet. Anschließend wird diese Ganzzahl mittels Restdivision (Modulo) auf den gültigen Wertebereich p der Hash-Funktion abgebildet. Der Wertebereich wird meist als Primzahl gewählt, welches eine breite Streuung gewährleistet: h(k) = integer(k)

mod p

Im obigen Beispiel werden die ASCII-Werte des ersten, und falls verfügbar des drit2 ten Zeichens (multipliziert mit 26) sowie des fünften Zeichen (multipliziert mit 26 ) aufaddiert. Anschließend wird die Restdivision mit 37 durchgeführt (Zeilen 7 bis 11 in Listing 7.1).

7.1 Kollisionen Trotz der sorgfältigen Entwicklung einer Hash-Funktion kann es zu Doppelbelegungen in der Hash-Tabelle kommen. Diese entstehen, wenn die Hash-Funktion h(k) zwei unterschiedliche Schlüssel k auf den gleichen Wert abbildet. Diese Doppelbelegungen werden als Kollisionen bezeichnet. Bei der Untersuchung von Kollisionen spielt der Belegungsgrad β eine Rolle: β = m , mit m als Anzahl der belegten Speicherstellen in Hash-Tabelle T und mit n, der n Anzahl der verfügbaren Speicherstellen in T. Je größer β wird, umso wahrscheinlicher werden Kollisionen in der Hash-Tabelle.

7.2 Offenes Hashing, getrennte Verkettung

| 85

7.2 Offenes Hashing, getrennte Verkettung Ein Mittel mit Kollisionen umzugehen ist das sogenannte offene Hashing oder die getrennte Verkettung. Hinter jedem Eintrag in der Hash-Tabelle kann sich nicht nur ein Datenelement verbergen, sondern (z. B. gespeichert als verkettete Liste) mehrere Datenelemente. So können bei einer Kollision die weiteren Datenelemente einfach an die verkettete Liste angehängt werden. Das Verfahren ermöglicht einen Belegungsgrad β > 1, da sich ja hinter jedem Schlüssel mehrere Datenelemente verbergen können. Daher der Name offenes Hashing. Das offene Hashing und die Belegung der HashTabelle sind in Abbildung 7.2 verdeutlicht. Im Beispiel ist an Index 5 eine Kollision aufgetreten, zuerst wurde der Eintrag „Hoeltgen“ dort in die verkettete Liste geschrieben, bei der Kollision wurde der Eintrag „Voelz“ an die verkettete Liste hinter dem Index 5 angehängt. Das gleiche Verfahren wird an Index 31, bei der Kollision der Indizes von „Schoeler“ und „Ulmann“ angewandt. 0 1 ... 3

Keller

... 5

Hoeltgen

Voelz

... 11 ... 14 ... 18 ... 24 25 ... 31 ... 35 36

Westphal Ernst Schoeler

Ulmann

Kloeckl Fischer Nockemann Maibaum

Abb. 7.2: Beispiel für offenes Hashing oder getrennte Verkettung

Durch stochastische Untersuchungen kann gezeigt werden, dass die durchschnittliche Listenlänge bei getrennter Verkettung β entspricht. Die durchschnittliche Laufzeit für erfolgloses Suchen verlängert sich um die mittlere Länge der Liste zu t fail = c + β mit c, der Laufzeit der Hash-Funktion. Die durchschnittliche Laufzeit einer erβ folgreichen Suche lässt sich mit t success = c + 2 abschätzen.

86 | 7 Gestreute Speicherung, Hashing

7.3 Geschlossenes Hashing Eine weitere Möglichkeit zum Umgang mit Kollisionen stellt das sogenannte geschlossene Hashing dar. Pro Eintrag in der Hash-Tabelle ist hier nur ein Datensatz möglich: β ≤ 1. Daher rührt der Name geschlossenes Hashing. Bei einer Kollision wird ein erneutes Hashing angestoßen. Ein einfaches Vorgehen, welches als lineares Sondieren bezeichnet wird, versucht bei einer Kollision den neuen Eintrag einfach an der nächstmöglichen Stelle in der Hash-Tabelle unterzubringen. Bei einer Kollision bei h(k) erfolgt ein erneuter Versuch bei (h(k) + 1) mod p und falls nötig weitere Versuche bei (h(k) + 2) mod p, . . . In unserem Beispiel würde bei Kollision bei Index 5 („Hoeltgen“) der Eintrag „Voelz“ mit dem ersten Sondierungsversuch an Index 5 + 1 = 6 abgelegt werden. Ein offensichtlicher Nachteil dieser Methode ist die mögliche Clusterbildung bei und nach oft kollidierenden Indizes. Die Performance kann, hier ohne den aufwendi1 1 gen stochastischen Beweis, mit 12 + 2(1−β) + 1 2 für das erfolglose Suchen und mit 2 2(1−β) für das erfolgreiche Suchen abgeschätzt werden. Durch die Verwendung einer doppelten Hash-Funktion kann die Clusterbildung des linearen Sondierens vermieden werden. Tritt eine Kollision auf, so wird die neue Einfügestelle nicht durch Aufaddieren einer Konstanten gefunden, sondern durch erneutes Hashing mit einer abweichenden Sondierungsfunktion. Hashing-Verfahren sind beliebte Vorgehensweisen zum Ablegen von und zum schnellen Zugriff auf Daten. Hashing-Verfahren werden z. B. eingesetzt um Methoden und Attribute von Objekten bei der objektorientierten Programmierung abzulegen. Ebenso werden JSON¹-Objekte und deren Einträge über Hashing-Verfahren verwaltet. Hashing-Verfahren werden auch zur Verwaltung von Punkten, Kanten und Flächen in der Computergrafik angewandt. Hashing-Verfahren sind in vielen Programmierumgebungen verfügbar. Es existieren weitere optimierte Verfahren für die verschiedensten Anwendungsgebiete. Die Laufzeitkomplexitätsabschätzung dieser Verfahren ist aufwendig und erfordert genaue Kenntnisse der konkreten Anwendung.

7.4 Weitere Anwendungen Ein weiteres wichtiges Anwendungsgebiet für Hashing-Verfahren ist die Kryptographie. Hier werden Hashing-Verfahren zum Beispiel zum Verschlüsseln von Passwörtern, PINs, Kreditkartennummern, usw. eingesetzt. Bei dieser Anwendung wird ausgenutzt, dass die Hashing-Funktion eine sogenannte Trapdoor-Funktion ist. Das Berechnen eines Hash-Wertes aus einem gegebenen Schlüssel ist einfach. Das Zurück-

1 JavaScript Object Notation

7.4 Weitere Anwendungen

|

87

Tab. 7.2: Beispiel für SHA-1-Hash-Werte Zeichenkette Lorem ipsum dolor sit amet, consectetur adipisici elit, sed eiusmod tempor incidunt ut labore et dolore magna aliqua. Morem ipsum dolor sit amet, consectetur adipisici elit, sed eiusmod tempor incidunt ut labore et dolore magna aliqua.

SHA-1-Hash-Wert 2fafc6f20821864a38f2664e8a0506dc5fe931b9

7504529847305133e3f7ca56d68d77e547ebf18e

berechnen eines Schlüssels aus einem Hash-Wert hingegen erfordert bestenfalls das Ausprobieren aller möglichen Schlüsselwerte. Ein bekanntes, allerdings schon veraltetes Verfahren, ist das SHA²-1-Verfahren. SHA-1 bildet eine beliebige Zeichenkette auf einen 160-Bit-Hash-Wert (40 Vier-BitWerte bzw. zehn 16-Bit-Werte) ab. Zwei SHA-1-Hash-Werte für zwei sich nur in einem Zeichen unterscheidende Zeichenketten zeigt Tabelle 7.2. Obwohl sich die beiden Zeichenketten nur um 1 Bit unterscheiden („L“ bzw. „M“ als erster Buchstabe der Zeichenketten) unterscheiden sich die berechneten SHA-1-Hash-Werte grundsätzlich voneinander. Im Februar 2017 ist es Forschern gelungen, zwei unterschiedliche PDF-Dokumente zu erzeugen, welche beide auf den gleichen SHA-1-Hash-Wert abgebildet werden (Stevens et al., 2017). Dazu wurden 9 Quintillion³ SHA-1-Hash-Werte ausprobiert, bis es zur gesuchten Kollision kam. Umgerechnet rechneten 110 GPUs⁴ ein Jahr lang an dieser Aufgabenstellung.

2 Secure Hash Algorithm 30 3 Eine Zahl mit 30 Nullen (10 ) 4 Graphics Processing Unit: Grafikprozessoren die für schnelle Berechnungen geeignet sind.

8 Präfixbäume Eine weitere interessante Methode Daten so abzuspeichern, dass diese gut durchsucht werden können, bieten Präfixbäume (englisch trie). Wie der Name schon andeutet, werden Zeichenketten gemäß ihrem Präfix baumartig abgelegt. In Abbildung 8.1 sind einige historische Computerbegriffe in Form eines Präfixbaums abgelegt.

A

Am

Ac

At

Ami

Ams

Aco

Ata

Amig

Amst

Acor

Atar

Amiga

Amstr

Acorn

Atari

Amstra

Amstrad

Abb. 8.1: Historische Computerfirmen und -bezeichnungen abgelegt als Präfixbaum

Folgt man in einem Trie den Kanten vom Wurzelknoten zu den Blättern, findet man alle gültigen Begriffe, welche in diesem Präfixbaum abgelegt sind. Dadurch, dass identische Präfixe nur einmal als Knoten abgelegt sind, sind Präfixbäume speichereffizient. Die Laufzeit einer Suche im Trie ist nicht proportional zur Anzahl der eingespeicherten Begriffe, sondern proportional zur Begriffslänge, die gesucht wird. Präfixbäume werden gerne bei Auswahlbildschirmen für Begriffe (wie z. B. bei Navigationssystemen oder bei Bahnkartenautomaten der Deutschen Bahn) eingesetzt. Die Bildschirmtastatur zeigt nur die Buchstaben an, für die im Trie ein weiterer Knoten existiert. Abbildung 8.2 zeigt den Ortsauswahlbildschirm eines Garmin-Navigationsgeräts bei der Eingabe des Zielorts Augsburg. Nach der Eingabe des dritten Buchstabens g schränkt das Gerät die Auswahl auf die Buchstaben ein, für die ein weiterer Ortsknoten existiert. Die weiteren gültigen Ortsnamen zeigt das Navigationsgerät zusätzlich in einer Liste am oberen Bildschirmrand an. https://doi.org/10.1515/9783110496253-009

8 Präfixbäume

|

89

Abb. 8.2: Ortsauswahl bei einem Garmin Nüvi 2598 LMT-D Navigationsgerät

Patricia-Tries Eine Erweiterung der Tries sind die Patricia¹-Tries. Sie wurden 1968 von Donald R. Morrison veröffentlicht. Die Daten im Trie werden hier komprimiert gespeichert. Sobald im Trie, zwischen Einträgen, keine Abzweigung vorhanden ist, werden die Einträge in Knoten zusammengefasst abgelegt. Das vorherige Beispiel, dieses Mal in Form eines Patricia-Tries, zeigt Abbildung 8.3. Beispielsweise werden die Zwischenknoten Ami und Amig zusammengefasst und nicht dargestellt. Gleiches gilt für die Zwischenknoten (ohne Abzweigungen) der Bezeichnungen Amstrad, Acorn und Atari. A

Am

Amiga

Acorn

Atari

Amstrad

Abb. 8.3: Historische Computerfirmen und -bezeichnungen abgelegt als Patricia-Trie

1 Practical Algorithm To Retrieve Information Coded In Alphanumeric

9 Graphen Ein Graph ist ein grundlegendes Prinzip zur Organisation von vernetzten Informationen – ein mathematisches Konstrukt bestehend aus Knoten und Kanten, den Verbindungen zwischen den Knoten. Graphen sind in der Informationsverarbeitung allgegenwärtig, als – Darstellung von Straßennetzen – Darstellung von vernetzten Teilnehmern in sozialen Netzwerken – Darstellung von vernetzten Seiten im Internet Ein einfaches Beispiel für einen Graphen zeigt Abbildung 9.1. Zu erkennen sind die Knoten A bis F sowie die gerichteten Kanten, die die Knoten verbinden.

9.1 Grundlegendes zu Graphen Zunächst wollen wir uns ansehen, wie Graphen definiert sind. Definitionen zu Graphen Formal gesehen wird ein Graph durch eine Menge V (vertices) der Knoten und eine Menge E (edges) der Kanten beschrieben: G = (V , E). Eine Kante e verbindet zwei Knoten u, v: e = u, v. Eine Kante von einem Knoten zu sich selbst nennt man Schlinge. Man unterscheidet in gerichtete Graphen (englisch digraph), bei denen die Kanten eine Orientierung besitzen. Anfangs- und Endknoten sind nicht austauschbar. Eine solche Kante wird in TupelSchreibweise notiert: e = (u, v). Im Gegensatz besitzen Kanten in ungerichteten Graphen keine Orientierung. Sie werden in Mengenschreibweise notiert: e = {u, v}.

Der Graph aus Abbildung 9.1 kann wie folgt in Mengenschreibweise notiert werden: G1 = (V1 , E1 ) V1 = {A, B, C, D, E, F} E1 = {(A, B), (A, C), (A, E), (B, C), (B, D), (B, E), (C, E), (C, F), (D, B), (E, F)}

C

F E

A

B

D

Abb. 9.1: Einfacher Beispielgraph https://doi.org/10.1515/9783110496253-010

9.1 Grundlegendes zu Graphen

| 91

Schon auf einem einfachen Graphen ergeben sich grundlegende Fragestellungen, wie z. B.: – Welches sind die Nachbarknoten j eines Knotens i? – Welchen Grad hat ein Knoten i, d. h. wie viele direkte Nachbarknoten hat Knoten i? Schon für diese einfachen Fragestellungen müssen Algorithmen gefunden werden, die eine maschinelle Verarbeitung der Informationen ermöglichen. Hierzu muss eine maschinenfreundliche Darstellungsform für Graphen gefunden werden. Eine kompakte Darstellungsform für Graphen bietet die Adjazenzmatrix. Die Adjazenzmatrix für den Beispielgraphen aus Abbildung 9.1 kann wie folgt aufgestellt werden: ⎛0 ⎜ ⎜ ⎜0 ⎜ ⎜ ⎜ ⎜0 A ij = ⎜ ⎜ ⎜ ⎜ 0 ⎜ ⎜ ⎜ ⎜ ⎜ ⎜0 ⎝0

1 0 0 1 0 0

1 1 0 0 0 0

0 1 0 0 0 0

1 1 1 0 0 0

0⎞ 0⎟ ⎟ ⎟ ⎟ ⎟ 1⎟ ⎟ ⎟ ⎟ ⎟ 0⎟ ⎟ ⎟ ⎟ ⎟ 1⎟ ⎟ 0⎠

Für jede im Graphen verfügbare Kante gibt es in der Adjazenzmatrix einen Eintrag. Die Startknoten von A bis F sind in den Zeilen angetragen, die jeweiligen Endknoten der Kanten (falls verfügbar) sind spaltenweise abzulesen. Die Kante (E, F) wird in A ij an Zeile 5 und Spalte 6 durch den Eintrag 1 dargestellt. Eine natürliche Erweiterung der bisherigen Graphnotation stellen Knoten- und Kantenmarkierungen dar. An jeden Knoten und jede Kante des Graphen können Markierungen der Menge M angebracht werden. Kantenmarkierungen können durch eine Funktion w e ∶ E → M, Knotenmarkierungen durch eine Funktion w v ∶ V → M angegeben werden. Wenn Knoten- bzw. Kantenmarkierungen vorhanden sind, spricht man von knotengewichteten bzw. kantengewichteten Graphen. Kantengewichte können ebenfalls in der Adjazenzmatrix vermerkt werden. Der Eintrag 1 stellvertretend für Kante vorhanden, wird durch das entsprechende Kantengewicht w e i,j ersetzt. Eine weitere gebräuchliche Notation für Graphen stellt die Adjazenzliste dar. Für den Graphen aus Abbildung 9.1 zeigt Tabelle 9.1 die entsprechende Adjazenzliste. Sie besteht aus einer Liste der Knoten. Für jeden Anfangsknoten besteht eine weitere Liste der Endknoten vorhandener Kanten (Adjazenzen). Besitzt ein Graph G im Vergleich zum vollständigen Graphen K = (V , V × V) wenige Kanten, so ist die Adjazenzmatrix schwach besetzt und eine Darstellung des Graphen als Adjazenzliste kompakter mit weniger Speicherbedarf. Eine Komplexitätsbetrachtung auf grundlegenden Graphenoperationen bei unterschiedlicher Datenhaltung (Adjazenzmatrix gegenüber Adjazenzliste) zeigt Tabelle 9.2. Im Allgemeinen gilt für Graphen deg(i) ≪ n. Somit ist die Wahl der bestmöglichen Repräsentation als Datenstruktur Abwägungssache des Informatikers und hängt vom jeweiligen Anwendungsfall ab.

92 | 9 Graphen Tab. 9.1: Adjazenzliste

Tab. 9.2: Laufzeitkomplexität grundlegender Operationen auf Graphen

Knoten

Adjazenzen

Operation

A B C D E F

{B, C, E} {C, D, E} {E, F } {B} {F } {}

Laufzeitkomplexität Adjazenz- Adjazenzmatrix liste

Finden einer Kante im Graphen Durchlaufen aller Kanten eines Knoten i

𝒪(1) 𝒪(n)

𝒪(n) 𝒪(deg(i))

9.2 Breiten- und Tiefensuche Wie sich bereits bei der Komplexitätsbetrachtung einfacher Operationen auf Graphen angedeutet hat, ist die Suche und das geschickte Traversieren (Durchwandern) eines Graphen eine wichtige und wiederkehrende Anwendung in der Informatik.

9.2.1 Breitensuche Die Breitensuche als Verfahren zum Durchwandern von Graphen kann geeignet unter Rückgriff auf eine Warteschlange als zentrale Datenstruktur umgesetzt werden. Ausgehend von einem Graphen G = (V , E) mit einem Startknoten s ∈ V liefert die Breitensuche eine Liste mit der Reihe nach besuchten Knoten des Graphen G. Führt man die Breitensuche manuell aus, arbeitet man mit Knotenmarkierungen für noch nicht bearbeitete Knoten (z. B. weiß), bereits bekannte jedoch noch nicht abgearbeitete Knoten (z. B. grau) und bereits abgearbeitete Knoten (z. B. schwarz). Weiterhin notiert man sich das Vorgehen anhand der Warteschlange der in Bearbeitung befindlichen Knoten. Ausgehend von Knoten A soll die Breitensuche auf unserem Beispielgraphen aus Abbildung 9.1 durchgeführt werden. Die Knotenmarkierungen werden durch drei Mengen X für die bereits abgearbeiteten Knoten, Q für die Warteschlange der noch zu bearbeitenden Knoten und V der unbekannten Knoten beschrieben. Bei mehreren zur Auswahl stehenden Knoten wählen wir den im Alphabet nächsten Knoten bevorzugt aus. 1. Schritt Ausgehend von Knoten A werden die Nachbarknoten B und C in die Warteschlange eingetragen.

9.2 Breiten- und Tiefensuche

| 93

X = {} Q = (B, C) V = {D, E, F} 2. Schritt Nachdem keine weiteren Nachbarknoten mehr gefunden wurden, kann Knoten A als abgearbeitet markiert werden. Die Suche wird mit dem nächsten Knoten aus der Warteschlange B fortgeführt. Die direkten Nachbarknoten (D und E) von B werden in die Warteschlange eingefügt. Diese Knoten werden aus V entfernt.

X = {A} Q = (B, C, D, E) V = {F} 3. Schritt Dieses Vorgehen wird nun für alle Knoten in Q wiederholt. B wird als abgearbeitet markiert und in X eingetragen, die Suche wird bei Knoten C fortgeführt. Knoten C verfügt über Knoten F als Nachbarn, dieser wird in Q eingetragen und aus V entfernt.

X = {A, B} Q = (C, D, E, F) V = {} Nächste Schritte Nun werden nach und nach die Knoten aus Q entnommen und untersucht. In unserem Beispiel werden keine neuen Nachbarknoten gefunden, die bearbeiteten Knoten aus Q werden nach und nach in X eingetragen. Sobald Q keine Knoten mehr enthält, ist die Breitensuche abgeschlossen.

X = {A, B, C, D, E, F} Q = () V = {}

94 | 9 Graphen Tab. 9.3: Laufzeitkomplexität grundlegender Operationen auf Graphen Ebene 0 2 4 6 8 10 12 14

Gesamtzahl Knoten

Rechenzeit

Speicherbedarf

1 111 11 111 6 10 8 10 10 10 12 10 14 10

1 ms 100 ms 11 s 18 min 31 h 128 d 35 y 3500 y

100 Byte 11 KiByte 1 MiByte 111 MiByte 11 GiByte 1 TiByte 111 TiByte 11 111 TiByte

Komplexitätsbetrachtung Zur Betrachtung der Laufzeitkomplexität der Breitensuche soll ein Graph mit dem Verzweigungsgrad b = 10 betrachtet werden. Die Anzahl der möglichen Knoten, ausged hend von einem Startknoten, auf jeder Ebene d entspricht n d = b . In Tabelle 9.3 sind die jeweiligen Schichten, die Knotenanzahl sowie der hypothetische Speicher- und Rechenzeitbedarf dargestellt. Für die Komplexitätsabschätzungen werden pro Rechenschritt 1 ms sowie für jeden Knoten 100 Byte Speicherbedarf zugrunde gelegt¹.

9.2.2 Tiefensuche Die Tiefensuche stellt ein weiteres Verfahren zum vollständigen Durchwandern eines Graphen dar. Die Tiefensuche verwendet, im Gegensatz zur Breitensuche, als Datenstruktur zur Verwaltung der in Bearbeitung befindlichen Knoten einen Stapelspeicher. Somit werden nicht zuerst die direkten Nachbarknoten eines Knotens betrachtet, sondern ein möglicher Pfad im Graphen bis zum Ende durchwandert. Erst, wenn dieser Pfad abgearbeitet ist, wird ein neuer Nachbarknoten betrachtet. Bei der Anwendung der Tiefensuche auf den Beispielgraphen aus Abbildung 9.1 werden ebenfalls die Mengen X für bearbeitete Knoten, V für noch nicht bearbeitete Knoten sowie S für den Stapelspeicher verwendet. 1. Schritt Wir starten mit der Tiefensuche bei Knoten A. Die direkten Nachbarknoten von A werden auf dem Stapelspeicher S abgelegt und aus V entfernt.

1 Die Rechenzeit wird in der Tabelle in SI-Einheiten angegeben, der Speicherbedarf mit IECBinärpräfixen notiert.

9.2 Breiten- und Tiefensuche

| 95

X = {A} S = (B, C) V = {D, E, F} 2. Schritt Im zweiten Schritt wird nun der zuletzt auf dem Stapel S abgelegte Knoten C betrachtet. C wird in X eingetragen, die direkten Nachbarknoten E und F von C werden auf dem Stapel abgelegt.

X = {A, C} S = (B, E, F) V = {D} 3. Schritt Im nächsten Schritt wird wiederum der zuoberst auf dem Stapel liegende Knoten F betrachtet. Er wird in X eingetragen, da er keine Nachbarknoten besitzt, ist dieser Schritt abgeschlossen und die Betrachtung des aktuellen Pfades zu Ende.

X = {A, C, F} S = (B, E) V = {D} 4. Schritt Nun wird der zuoberst auf dem Stapel liegende Knoten E betrachtet und der nächste Pfad durchwandert. E wird in X eingetragen. Da sein direkter Nachbarknoten F schon betrachtet wurde, endet dieser Pfad ebenfalls mit diesem Schritt.

X = {A, C, F, E} S = (B) V = {D} 5. Schritt Im fünften Schritt wird der Knoten B vom Stapel genommen und betrachtet. Sein Nachbarknoten D wird auf dem Stapel S abgelegt und aus V entfernt.

96 | 9 Graphen

X = {A, C, F, E, B} S = (D) V = {} Letzter Schritt Im letzten Schritt wird der Knoten D betrachtet, vom Stapel S entfernt und in X eingetragen. Da D über keine neuen Nachbarknoten verfügt, bleibt S leer. V ist auch bereits leer und das Verfahren kommt mit diesem Schritt zum Ende.

X = {A, C, F, E, B, D} S = () V = {} Backtracking Eine gebräuchliche Anwendung der Tiefensuche auf Graphen ist das sogenannte Backtracking zum Finden einer Problemlösung auf einem Graphen, der dem Lösungsraum des gegebenen Problems entspricht. Die Problemlösung wird durch ein Versuchs- und Irrtumsverfahren (trial and error) gesucht, indem eine mögliche Problemlösung begonnen wird und so weit ausgebaut wird, solange keine Widersprüche entstehen und die Lösung des Problems plausibel ist. Sobald es absehbar ist, dass auf dem eingeschlagenen Lösungsweg keine Lösung mehr möglich ist, erfolgt der Backtracking-Schritt. Es wird der aktuelle Lösungsschritt zurückgenommen und ein alternativer Schritt ausprobiert, um zur Lösung des Problems zu gelangen. Das Backtracking-Verfahren findet auf jeden Fall eine Lösung, da es den gesamten Suchraum mittels Tiefensuche durchsucht. Die Lösungszeit kann allerdings sehr lang sein, da der gesamte Suchraum durchsucht wird. Betrachtet man die Zeitkomplexität des Verfahrens genauer, so ergibt sich eine Tiefensuche mit z möglichen Verzweigungen bei einer Tiefe des Suchbaumes von N. 2 3 Die Anzahl der zu durchsuchenden Knoten ergibt sich somit zu 1 + z + z + z + . . . + N z . Man erkennt, dass das Verfahren sich in exponentieller Zeitkomplexität befindet: N 𝒪(z ). Folglich ist das Verfahren für größere Problemstellungen nicht geeignet. N-Damen-Problem Ein einfaches Beispiel, um das Backtracking-Verfahren nachvollziehen zu können, ist das N-Damen-Problem: Auf einem N-mal-N-Schachbrett sollen N Damen aus dem

9.2 Breiten- und Tiefensuche

| 97

Schachspiel so platziert werden, dass keine der Damen die anderen schlagen kann². Abbildung 9.2 zeigt eine Beispiellösung für das 8-Damen-Problem. Wie kann das Schachbrett für das N-Damen-Problem nun als Datenstruktur abgelegt werden?

qZ0Z0Z0Z Z0Z0l0Z0 6 0Z0Z0Z0l 5 Z0Z0ZqZ0 4 0ZqZ0Z0Z 3 Z0Z0Z0l0 2 0l0Z0Z0Z 1 Z0ZqZ0Z0

8 7

a

b

c

d

e

f

g

h

Abb. 9.2: Beispiellösung für das 8-Damen-Problem

Listing 9.1: Darstellung der N Damen in Python 1 2

# Dame in Zeile Index an Spalte q_n # queens = [q1, q2, q3, q4, q5, q6, q7, q8]

3 4

queens = [0, 4, 7, 5, 2, 6, 1, 3]

5 6 7

def board(vec): print("\n".join('.' * i + 'Q' + '.' * (len(vec)-i-1) for i in vec)

+ "\n===\n") 8 9

board(queens)

Eine überraschend einfache und kompakte Darstellung kann in Form eines eindimensionalen Arrays erfolgen, wie in Listing 9.1 gezeigt. Für jede Zeile des Schachbretts (numerischer Index in Abbildung 9.2), ist im Array ein Eintrag reserviert (Index 0 . . . N). Der Eintrag am jeweiligen Index zeigt an, an welcher Spalte (alphanumerischer Index am Schachbrett in Abbildung 9.2) sich die Dame in der jeweiligen Zeile befindet. Die Dame auf Feld a8 in Abbildung 9.2 ist im Array queens an Index 0 durch 2 Jede der Damen bedroht alle horizontalen, vertikalen und diagonalen Felder.

98 | 9 Graphen den Eintrag 0 vermerkt. Die Bedrohungen der Damen untereinander können, unter Verwendung des Arrays, ebenfalls überraschend einfach erkannt werden: – Bedrohungen durch eine Dame in der gleichen Zeile sind ausgeschlossen, da für jede Zeile im Array nur ein Eintrag möglich ist. – Bedrohungen durch eine Dame in der gleichen Spalte können dadurch ausgeschlossen werden, dass jeder Wert (Spaltenindex) im Array nur einmal vorkommen darf. – Diagonalbedrohungen können darüber ausgeschlossen werden, dass der Abstand im Index des Arrays nicht gleich der numerischen Differenz der jeweiligen Einträge im Array sein darf: ∣queens[i] − queens[j]∣ ≠ ∣i − j∣ Listing 9.2: Brute-Force-Löser für das N-Damen-Problem 1 2

# Quelle: http://rosettacode.org/wiki/ # N-queens_problem#Python:_Simple_Backtracking_Solution

3 4

from itertools import permutations

5

n = 8 cols = range(n) for vec in permutations(cols): if n == len(set(vec[i]+i for i in cols)) == len(set(vec[i]-i for i in cols)): print(vec) board(vec)

6 7 8 9 10

Das kurze Beispielprogramm in Python in Listing 9.2 erzeugt alle möglichen Permutationen für das cols-Array. Anschließend werden alle Permutationen auf Bedrohungen untersucht und die verbleibenden, gültigen Lösungen ausgegeben. Es handelt sich um einen sogenannten Brute-Force-Lösungsalgorithmus, der alle möglichen Kombinationen zur Lösung des Problems durchprobiert. Zur Verdeutlichung des Vorgehens unter Verwendung eines Backtracking-Algorithmus wollen wir das Problem auf ein 4-Damen-Problem reduzieren: Vier Damen werden auf einem 4x4-Schachbrett positioniert, sodass diese sich nicht schlagen können. Jeder Knoten in Abbildung 9.3 entspricht einer gültigen Kombination von einer bis vier Damen auf dem Schachbrett. Ausgehend vom Wurzelknoten 1 wird die erste Dame in der ersten Zeile (x1) platziert. Im Knoten 18 beispielsweise wurde die erste Dame in Zeile 1 und Spalte 2 platziert (x1 = 2). Eine ungültige Kombination, welche einen Backtracking-Schritt erfordert, entsteht, wenn die Dame in der zweiten Zeile ebenfalls in der zweiten Spalte platziert wird (x1 = 2 und x2 = 2). Durch die Erkennung der Bedrohung schließen wir diese Möglichkeit aus. Weitere, ebenfalls ungültige Positionen, die sich unterhalb

5

x4=4

4

7

10

12

x4=2

11

x4=4

6

x4=3

8

x3=2 x3=4

3

9

2

x2=3

x3=3 x3=4

x2=2

15

x4=3

14

17

x4=2

16

x3=2 x3=3

13

x2=4

21

x4=4

20

23

x4=3

22

x3=3 x3=4

19

18

26

x4=4

25

fail

28

x4=1

27

x3=1 x3=4

24

x1=2

31

x4=3

30

33

x4=1

32

x3=1 x3=3

29

x2=1 x2=2 x2=3 x2=4

x1=1

1

37

x4=4

36

34 x2=1

39

x4=2

38

x3=2 x3=4

35

x1=3

x2=4

42

x4=4

41

44

x4=1

43

x3=1 x3=4

40

x2=2

47

x4=2

46

x3=1

45

x1=4

49

x4=1

48

x3=2

53

x4=3

52

55

x4=2

54

x3=2 x3=3

51

x2=3

58

x4=3

57

60

x4=1

59

x3=1 x3=3

56

x2=1 x2=2

50

63

x4=2

62

65

x4=1

64

x3=1 x3=2

61

9.2 Breiten- und Tiefensuche

Abb. 9.3: Suchbaum zum 4-Damen-Problem

| 99

100 | 9 Graphen Tab. 9.4: Notationsübersicht zum 4-Damen-Problem

x1 x2 x3 x4

1

30

2 18

3

4 29

31

dieses Knotens entwickeln würden, werden nicht weiter betrachtet. Diese ungültigen Kombinationen werden deswegen nur stellvertretend für alle weiteren ungültigen Kombinationen im Suchbaum dargestellt. Ausgehend von Knoten 18 ergeben sich nun drei gültige Platzierungen für die zweite Dame: In der zweiten Zeile in den Spalten x2 = 1, 3 oder 4. Wird die Dame in der zweiten Zeile auf Spalte 4 platziert (x2 = 4), so landen wir im Suchbaum in Knoten 29. Platziert man nun die Dame in der dritten Zeile in der ersten Spalte (x3 = 1), landet man in Knoten 30. Die einzig verbleibende gültige Möglichkeit für die Dame in der vierten Zeile ist nun die Spalte drei (x4 = 3), dargestellt durch den Knoten 31 im Suchbaum. Die Belegung des Schachbretts für die gerade erarbeitete Lösung zeigt Tabelle 9.4. Somit sind im Suchbaum aus Abbildung 9.3 alle Lösungen für das 4-DamenProblem in den Blättern des Suchbaums dargestellt. Das Nachvollziehen eines möglichen Backtracking-Algorithmus für das N-DamenProblem ist durch zahlreiche Implementierungen möglich. Eine schöne erste Anlaufstelle ist die Seite Rosettacode.³ Dort sind eine Vielzahl von Algorithmen in einer großen Bandbreite von Programmiersprachen implementiert. Die Übersichtsseite zum N-Damen-Problem findet sich ebenfalls hier⁴. Fragen, die der geneigte Medienwissenschaftler sich beim Studium der verschiedenen Algorithmen stellen sollte, umfassen u. a.: – Wie werden die Damen abgelegt? – Wie werden Bedrohungen erkannt? – Wie werden gültige Lösungen gefunden? Die Aktualität des N-Damen-Problems als Beispiel für ein Optimierungsproblem zeigen auch umfangreiche Bibliotheken zu Optimierungsproblemen. Als Beispiel soll hier auf die Google Optimization Tools⁵ verwiesen werden.

3 https://rosettacode.org, Abruf: 23.05.2018. 4 Verfügbar unter https://rosettacode.org/wiki/N-queens_problem#Python:_Simple_Backtracking _Solution, Abruf: 17.07.2017. 5 Verfügbar unter https://developers.google.com/optimization/ (Abruf: 23.05.2018). Das N-DamenBeispiel findet sich unter https://developers.google.com/optimization/puzzles/queens, Abruf: 17.07.2017.

9.3 Minimale Spannbäume

|

101

9.3 Minimale Spannbäume Ein weiteres praxisrelevantes Beispiel für einen Graphalgorithmus ist das Finden von minimalen Spannbäumen (englisch minimal spanning trees). Definition: Minimaler Spannbaum Ein minimaler Spannbaum ist das kostengünstigste Skelett des Graphen, welches alle Knoten mit minimalen Kosten (Kantengewichte) verbindet.

Ausgangssituation für den Algorithmus ist ein Graph G = (V , E) mit Knoten V und Kanten E. Weiterhin müssen die Kanten mit positiven, ganzzahligen Gewichten w ver+ sehen sein: w ∶ E → R . Minimale Spannbäume können dazu verwendet werden, ein möglichst preiswertes (bezogen auf die Verbindungen der Knoten) Netzwerk aufzubauen, in dem alle Teilnehmer verbunden sind. Eine wichtige Anwendung ist die Vermeidung von redundanten Pfaden in Computernetzwerken. Durch redundante Pfade können in manchen Netzwerkprotokollen Inkonsistenzen auftreten. Nähere Informationen dazu finden sich unter dem Begriff Spanning Tree Protocol, z. B. unter (Kasparick, 2014). Ein weiteres Beispiel ist das Brettspiel des Jahres 2004 „Zug um Zug“. Hier versuchen mehrere Mitspieler gemeinsam ein optimales Netzwerk für den Bahnverkehr aufzubauen. Im Kern entspricht dieses Vorgehen dem Aufbau eines minimalen Spannbaums. Wie kann ein solcher minimaler Spannbaum gefunden werden?

9.3.1 Algorithmus von Kruskal Joseph Kruskal, ein US-amerikanischer Mathematiker und Statistiker, beschreibt seinen 1956 gefunden Algorithmus für minimale Spannbäume selbst wie folgt: Führe den folgenden Schritt so oft wie möglich aus: Wähle unter den noch nicht ausgewählten Kanten von G (dem Graphen) die kürzeste Kante, die mit den schon gewählten Kanten keinen Kreis bildet. (Wikipedia, 2017a)

Abbildung 9.4 zeigt einen ungerichteten Graphen auf dem wir Kruskals Algorithmus nachvollziehen wollen. Wir wählen, aufsteigend nach dem jeweiligen Kantengewicht, die günstigsten Kanten aus. Die ausgewählten Kanten werden in die Menge MSP eingefügt. Die erste Kante, die wir auswählen, ist die Kante (f , g). Anschließend wählen wir die Kante (a, c) aus, da diese neben den Kanten (f , u) und (d, e) über das nächste, geringste Kantengewicht verfügt. Unser Algorithmus wählt bei gleichen Kantengewichten die Kante aus, deren Startknoten im Alphabet zuerst kommt. Nach zwei ausgewählten Kanten ist MSP = ((f , g), (a, c)). Wir fahren mit dem Hinzufügen von neuen Kanten fort, bis alle Knoten im minimalen Spannbaum erreicht werden können:

102 | 9 Graphen 11 a

2 3

4

c

5

10

b

4 d

3 2

f

e

2 1 8

5

u

g 7

Abb. 9.4: Beispielgraph für minimale Spannbäume

11 a

2 3 b

4

c 10

5 d

3 2

4 f

e

2 1 8

5

u

g 7

Abb. 9.5: Minimaler Spannbaum, gefunden über Kruskals Algorithmus

MSP = ((f , g), (a, c), (d, e), (f , u), (a, b), (d, f ), . . .) Bei der Auswahl der nächsten Kante, entweder (b, c) oder (d, u), beide mit dem Kantengewicht 4, würden Kreise entstehen, sodass diese Kanten nicht für MSP ausgewählt werden. Die nächste Kante die zu MSP hinzugefügt wird, ist die Kante (c, d): MSP = ((f , g)), (a, c), (d, e), (f , u), (a, b), (d, f ), (c, d)) Alle nachfolgenden Kanten würden zu weiteren Kreisen führen. Alle Knoten sind durch MSP erreichbar. Der Algorithmus kommt zum Ende. Den minimalen Spannbaum, der durch MSP beschrieben ist, zeigt Abbildung 9.5. Kruskals Algorithmus ist ein einfaches und leicht nachzuvollziehendes Verfahren zur Bestimmung minimaler Spannbäume. Ein Nachteil bei der praktischen Verwendung ist allerdings, dass während des Aufbaus des minimalen Spannbaums disjunkte Spannbäume entstehen können. In unserem Beispiel ist dies bereits der Fall nach Hinzufügen der Kante (a, c), welche keine Verbindung zur vorher ausgewählten Kante (f , g) in MSP hat. Das Problem der disjunkten Teilbäume löst der Algorithmus von Prim.

9.4 Kürzeste Wege

|

103

9.3.2 Algorithmus von Prim Im Gegensatz zu Kruskals Algorithmus wird beim Algorithmus von Prim ein bestehender minimaler Spannbaum schrittweise mit einer möglichst günstigen Kante erweitert. So ist der entstehende minimale Spannbaum stets zusammenhängend. Der Algorithmus wurde bereits 1930 von Vojtěch Jarník, einem tschechischen Mathematiker, entwickelt. 1957 wurde der Algorithmus von Robert C. Prim und 1959 von Edsger W. Dijkstra weiterentwickelt. Ausgehend vom Graphen in Abbildung 9.4 und einem frei gewählten Startknoten a, entwickelt sich der minimale Spannbaum wie folgt, wobei immer die günstigste Kante, welche MSP erweitert, hinzugefügt wird: MSP = ((a, c), (a, b), (c, d), (c, e), (d, f ), (f , g), (f , u)) Im Ergebnis unterscheidet sich der gefundene minimale Spannbaum nicht vom Spannbaum, der durch den Algorithmus von Kruskal gefunden wurde. Allerdings entstehen auf dem Weg der Entwicklung keine disjunkten Teilbäume. Beide Algorithmen zum Finden von minimalen Spannbäumen folgen dem GreedyPrinzip. Greedy-Algorithmen bauen eine einmal gefundene Lösung schrittweise aus. Sie wählen jeweils die Erweiterung, welche in der aktuellen, lokalen Situation den größten Gewinn verspricht. Der Gewinn wird im Allgemeinen über eine Bewertungsfunktion bestimmt. Bei minimalen Spannbäumen werden günstige Kanten durch die Bewertungsfunktion als lukrativ bewertet. Greedy-Algorithmen sind schnell, finden jedoch nicht immer das optimale Ergebnis. Ein weiteres Beispiel für einen GreedyAlgorithmus ist der Dijkstra-Algorithmus zum Finden von kürzesten Wegen in Graphen.

9.4 Kürzeste Wege Das als Dijkstra-Algorithmus bekannte Verfahren wurde 1959 von Edsger W. Dijkstra beschrieben (Dijkstra, 1959). Das Verfahren findet zu einem gegebenen Ausgangsknoten die jeweils kürzesten Pfade zu anderen Knoten in einem gerichteten, kantengewichteten Graphen. Der Algorithmus sucht, ausgehend vom Ausgangsknoten bzw. dem aktuell untersuchten Knoten u, nach der günstigsten Kante (Verbindung) zu weiteren Knoten (Greedy-Verfahren). Das Ergebnis des Verfahrens sind Pfade mit der geringsten Summe der Kantengewichte w i , ausgehend vom Ausgangsknoten, zu allen weiteren Knoten des Graphen. Der Algorithmus von Dijkstra hat vielfältige Anwendungen rund um die Wegfindung. Beispielsweise können in Computerspielen die virtuellen Welten als Graph modelliert werden. Nicht-Spieler-Charakter im Spiel können mittels des Algorithmus von Dijkstra ihre kürzesten Wege durch die Spielewelt planen. Weiterhin wird der Algo-

104 | 9 Graphen rithmus in vielfältigen Navigationsaufgaben wie z. B. dem Routing von Werkstücken in einer Fabrik eingesetzt.

F

10

B

2 3

5

A

1

C

9

2

D

6 4

E

3

Abb. 9.6: Beispielgraph für Algorithmus von Dijkstra

Zur Verdeutlichung des Vorgehens wollen wir den Graphen in Abbildung 9.6 verwenden. Ausgehend vom Ausgangsknoten A wenden wir Dijkstras Algorithmus an. Unser Vorgehen halten wir in Tabelle 9.5⁶ fest. Tab. 9.5: Vorgehen beim Dijkstra-Algorithmus

A D E B C F

B

C

D

E

F

10 über A 8 über D 8 über D 8 über D 8 über D 8 über D

∞ 14 über D 11 über E 9 über B 9 über B 9 über B

5 über A 5 über A 5 über A 5 über A 5 über A 5 über A

∞ 7 über D 7 über D 7 über D 7 über D 7 über D

∞ ∞ ∞ ∞ ∞ ∞

In der ersten Zeile sehen wir, dass der Ausgangsknoten A mit zwei Nachbarknoten B und D verbunden ist. Zu den verbleibenden Knoten ist keine Verbindung bekannt, deswegen ist dort ∞ eingetragen. Wenn Pfade bekannt sind, werden deren Kosten (Kosten 10 über Knoten B). über dem letzten Verbindungsknoten aufgetragen, z. B. 10 B Da diejenige Kante, die zu Knoten D führt, mit 5 < 10 günstiger ist als die Kante zu Knoten B, führen wir unseren Algorithmus am Knoten D weiter aus (zweite Zeile). In der zweiten Zeile können wir die kürzeste Verbindung zu Knoten B verbessern (über Knoten D mit Gesamtkosten 8) sowie neue Verbindungen zu den Knoten C und E feststellen. Als nächster noch nicht besuchter Knoten kann Knoten E in der dritten Zeile untersucht werden. Ausgehend von Knoten E stellen wir einen neuen, günstigeren Pfad zu Knoten C mit Kosten 11 fest und tragen diesen in die Tabelle ein. Alle

6 Das Vorgehen ist einem Video auf YouTube entlehnt. Das Video unter https://www.youtube.com/ watch?v=8Ls1RqHCOPw, Abruf: 18.07.2017, kann als weiteres Beispiel zum Verständnis des Vorgehens dienen.

9.4 Kürzeste Wege

| 105

anderen Werte werden übernommen. Der nächste noch nicht besuchte Knoten mit geringen Verbindungskosten ist Knoten B. In der vierten Zeile können wir über Knoten B abermals eine Vergünstigung des Pfades zu Knoten C mit Gesamtkosten von 9 eintragen. Alle weiteren Werte werden übernommen. In der fünften Zeile betrachten wir die Situation ausgehend von Knoten C. Es können keine weiteren Verbesserungen festgestellt werden, die Werte werden aus der letzten Zeile übernommen. Der Vollständigkeit halber betrachten wir in der letzten Zeile den Graphen ausgehend von Knoten F. Da Knoten F nicht mit dem restlichen Graphen verbunden ist, können wir keine neuen, kürzeren Pfade feststellen. Damit ist das Verfahren abgeschlossen. Die kürzesten Pfade, ausgehend von A, können nun anhand der Tabelle nachvollzogen werden. Dass der Knoten F disjunkt vom Graphen ist, zeigt auch der verbleibende Eintrag ∞ für die Pfadlänge zu Knoten F.

10 Schwere Probleme und Heuristiken Bei schweren Problemen der Informatik handelt es sich um Probleme, die über eine hohe Komplexität verfügen und somit schwer zu lösen sind. Die meisten dieser Probleme finden sich in einer Komplexitätsklasse, die als NP-vollständig beschrieben wird. Eines dieser Probleme ist beispielsweise die Berechnung einer Rundreise über ausgewählte Haltestellen im öffentlichen Personennahverkehr hinweg. NP-vollständige Probleme sind in polynomieller Zeit zu lösen, wenn der Algorithmus über einen Nicht-eterminismus verfügt. Der Nicht-Determinismus kann als allwissendes Orakel verstanden werden. Das Orakel weiß zu jeder Zeit, welche Entscheidung zur Lösung des Problems getroffen werden muss. Es entscheidet sich an einer Verzweigung immer zielführend, auch wenn für die Entscheidungsfindung kein Algorithmus bekannt ist. Rein formal ist die NP-Vollständigkeit nur für sogenannte Entscheidungsprobleme definiert. Da Optimierungsprobleme in Entscheidungsprobleme überführt (reduziert) werden können, kann man umgangssprachlich auch bei Optimierungsproblemen von einer NP-Vollständigkeit sprechen. Von schweren Problemen der Informatik spricht man daher, wenn vermutlich kein effizienter Algorithmus gefunden werden kann, der das Problem löst. Zumindest lässt sich für NP-vollständige (schwere) Probleme, unter Verwendung eines deterministischen Verfahrens, eine gültige Lösung in Polynomialzeit überprüfen. Dieser Sachverhalt spiegelt sich auch in einer der wichtigsten Fragen der Informatik wider, die sich auf den folgenden Ausdruck reduzieren lässt: P = NP ∨ P ≠ NP Entspricht die Klasse der Probleme, deren Lösung mittels eines deterministischen p Verfahrens in Polynomialzeit (𝒪(n ), kurz P) zu finden ist, der Klasse der Probleme, deren Lösung mittels eines nicht-deterministischen Verfahrens in Polynomialzeit (NP) lösbar ist? Aktuell gibt es noch keinen Nachweis für die These P = NP. Falls jemals ein Beweis für P = NP gefunden würde, hätte dies größte Auswirkungen auf die Datenverarbeitung, wie wir sie heute kennen. Beispielsweise müssten asymmetrische Kryptographie-Verfahren, die auf Einwegfunktionen¹ beruhen, ersetzt werden. Diese Eigenschaft der Einweg- bzw. Trapdoor-Funktionen wäre durch P = NP aufgehoben. Der Begriff der NP-Vollständigkeit wurde 1971 von Stephen A. Cook im Satz von Cook geprägt (Cook, 1971). Rabin Karp konnte im Jahr 1972, aufbauend auf den Ar-

1 Eine Einwegfunktion beschreibt hier ein mathematisches Verfahren (Funktion), welches in der einen Richtung leicht zu berechnen ist, in Umkehrrichtung hingegen (ohne Zusatzwissen, vergleichbar mit einer Trapdoor-Funktion) schwer zu berechnen ist. Beispielsweise ist die Multiplikation zweier Primzahlen bzw. ganzer Zahlen einfach. Die Umkehrung, das Finden der entsprechenden Primfaktoren ist beliebig schwer. https://doi.org/10.1515/9783110496253-011

10.1 Problem des Handlungsreisenden

|

107

beiten von Cook, 21 Probleme klassifizieren und identifizieren, die ebenfalls NPvollständig sind (Karp, 1972). Unter diesen Problemen sind das Problem des Handlungsreisenden, als spezielles Hamiltonkreis-Problem, ebenso wie das KnappsackProblem zu finden.

10.1 Problem des Handlungsreisenden Das Problem des Handlungsreisenden oder englisch Travelling Salesman Problem (TSP) ist ein klassisches Optimierungsproblem. Durch einer Anzahl miteinander verbundener Städte muss eine optimale Rundreise gefunden werden, auf der alle Städte besucht werden und deren Route wiederum bei der Ausgangsstadt endet. Formal kann das Problem des Handlungsreisenden als Optimierungsproblem auf einem gerichteten Graphen mit Kantengewichtungen beschrieben werden. Obwohl das Problem auch auf schwach vernetzten Graphen beschrieben ist, wird oft angenommen, dass es sich um einen voll vernetzten Graphen handelt. Zwischen jedem Knoten (Stadt) des Graphen existieren Kanten zu jedem weiteren Knoten (Stadt). Die hohe Komplexität des TSP ergibt sich aus der großen Anzahl von Möglichkeiten eine Rundreise zu gestalten. In jedem Schritt stehen dem Algorithmus als nächsten Knoten all die Knoten zur Verfügung, die er noch nicht besucht hat. Die Anzahl der möglichen Touren berechnet sich zu (n − 1)!. Die Anzahl der möglichen Touren ist über-exponentiell. Ein exaktes Lösungsverfahren, welches die kürzeste Rundreise findet, kann nur alle Kombinationsmöglichkeiten ausprobieren und die kürzeste Rundreise wählen. Das exakte Lösungsverfahren muss somit über-exponentiell viele Kombinationen ausprobieren und kann nicht als effizient bezeichnet werden. Bereits ab 50 Knoten ist das Ausprobieren aller Kombinationen nicht mehr zu Lebzeiten möglich. In Tabelle 10.1 sind die Entfernungen zwischen einigen deutschen Großstädten aufgetragen. Die Entfernungen sind der Entfernungstabelle für 40 deutsche GroßstädTab. 10.1: Entfernungstabelle deutscher Großstädte (Angaben in km)

Augsburg Berlin Hannover Karlsruhe München Ulm Würzburg

Augsburg – 593 600 221 61 83 243

Berlin 593 – 258 670 596 604 490

Hannover 600 258 – 500 647 536 369

Karlsruhe 221 670 500 – 270 160 195

München 61 596 647 270 – 124 294

Ulm 83 604 536 160 124 – 180

Würzburg 243 490 369 195 294 180 –

108 | 10 Schwere Probleme und Heuristiken te² entnommen. Den resultierenden Graphen zeigt Abbildung 10.1. Die räumliche Anordnung der Städte entspricht natürlich nicht den geographischen Gegebenheiten. Wie finden wir nun die optimale Rundreise durch die sieben deutschen Großstädte? 243 83

Augsburg

600

369

221

Hannover

593 258

500

195

Karlsruhe 270

670

647

180

536

Ulm 124

596

Berlin

Würzburg

160

294

München 604 490

61

Abb. 10.1: Graph aus Entfernungstabelle deutscher Großstädte (Kantengewichte in km)

10.1.1 Durch Ausprobieren (brute force) Der erste, naive Weg führt über das Ausprobieren aller möglichen Pfade durch den Graphen und der Auswahl des Pfades, mit der geringsten Entfernung. Nach ausgiebiger Betrachtung aller 7! = 5040 Möglichkeiten, finden wir exakt 14 Mal³ die optimale Rundreise mit der Länge von 1722 km. Eine dieser 14 möglichen kürzesten Rundreisen ist der Pfad TSP1 = (W u¨ rzburg, Karlsruhe, Ulm, Augsburg, M u¨ nchen, Berlin, Hannover) Die Überprüfung dieser Lösung kann in 𝒪(n) mit n = 7 nachvollzogen werden. Die manuelle Suche nach der optimalen Rundreise lässt sich durch die PythonImplementierung für die Brute-Force-Lösung des TSP in (Häberlein, 2012) abkürzen. Der geneigte Leser implementiert die Suche nach der kürzesten Rundreise als Übung.

2 Verfügbar unter http://www.auslandversicherungen.de/entfernungstabelle.html, Abruf: 19.07.2017. 3 14 Mal deswegen, weil es in unserem Beispiel eine optimale Rundreise gibt, die jeweils links- bzw. rechtsherum durchreist werden kann. Weiterhin wird diese Rundreise für jeden möglichen der sieben Anfangsknoten gefunden. Somit genau 2 ⋅ 7 = 14 Mal.

10.1 Problem des Handlungsreisenden

|

109

10.1.2 Nearest-Neighbour-Insertion Wie aus der bisherigen Betrachtung hervorgeht, kann ein Brute-Force-Vorgehen durch Ausprobieren aller Möglichkeiten nicht das geeignete Mittel sein. Ein naives Vorgehen könnte darin bestehen, ausgehend von einem Startknoten, jeweils die günstigste Verbindung zu einem noch nicht besuchten, benachbarten Knoten zu wählen. Dieses Verfahren ist auch als Nearest-Neighbour-Insertion-Heuristik bekannt. Es ist ein GreedyVerfahren, da lokal die bestmögliche Erweiterung zur Gesamtlösung gewählt wird. Wenn wir mit der Nearest-Neighbour-Insertion-Heuristik ab dem Startknoten Augsburg vorgehen, finden wir die folgende Rundreise: TSP2 = (Augsburg, M u¨ nchen, Ulm, Karlsruhe, W u¨ rzburg, Hannover, Berlin) Die Länge der Rundreise berechnet sich zu 61 km + 124 km + 160 km + 195 km + 369 km+258 km+593 km = 1760 km. Gegenüber 1722 km keine optimale Rundreise, trotzdem ist sie relativ kurz.

10.1.3 Nearest-Insertion-Heuristik Weitere Heuristiken gehen nicht Knoten für Knoten vor, sondern erweitern eine mögliche kurze, erste Rundreise mit zwei Städten, durch geeignete weitere Knoten. Bei der Nearest-Insertion-Heuristik wird zur bereits gefundenen Rundreise jeweils der nächste Knoten kostengünstigst in die Rundreise eingefügt. Dazu wird die zum hinzuzufügendenen Knoten nächstgelegene Kante aufgebrochen und über den hinzuzufügenden Knoten wieder geschlossen. Wenden wir das Verfahren, ausgehend vom einer mögliche ersten Rundreise (Augsburg, M u¨ nchen) an, können wir in einer ersten Erweiterung Ulm als kürzeste Erweiterung vornehmen. Ulm wird zwischen Augsburg und M u¨ nchen kostengünstigst eingefügt: TSP3,1 = (Augsburg, Ulm, M u¨ nchen) Der nächstliegende Knoten Karlsruhe kann zwischen Augsburg und Ulm kostengünstigst eingefügt werden: TSP3,2 = (Augsburg, Karlsruhe, Ulm, M u¨ nchen) Als nächster Knoten kann W u¨ rzburg zwischen Karlsruhe und Ulm eingefügt werden: TSP3,3 = (Augsburg, Karlsruhe, W u¨ rzburg, Ulm, M u¨ nchen) Als nächste Stadt fügen wir Hannover zwischen Karlsruhe und W u¨ rzburg zur Rundreise hinzu:

110 | 10 Schwere Probleme und Heuristiken TSP3,4 = (Augsburg, Karlsruhe, Hannover, W u¨ rzburg, Ulm, M u¨ nchen) Im letzten Schritt wird Berlin zwischen Hannover und W u¨ rzburg eingefügt und die Rundreise geschlossen: TSP3,5 = (Augsburg, Karlsruhe, Hannover, Berlin, W u¨ rzburg, Ulm, M u¨ nchen) Die Länge der resultierenden Rundreise lässt sich zu 221 km+500 km+258 km+ 490 km + 180 km + 124 km + 61 km = 1834 km berechnen. Ein guter Wert, aber nicht die optimale Rundreise.

10.1.4 Farthest-Insertion-Heuristik Eventuell führt ein zuerst paradox wirkender Ansatz weiter. Wir wollen nicht den nächstgelegenen Knoten einfügen, sondern den am weitesten von der Rundreise entfernten Knoten. Wir starten wieder bei einer kurzen Rundreise TSP4,1 = (Augsburg, M u¨ nchen). Die sich durch die Farthest-Insertion-Heuristik ergebenden Erweiterungen sind wie folgt:

TSP4,1

=

(Augsburg, M u¨ nchen)

TSP4,2

=

(Augsburg, Hannover, M u¨ nchen)

TSP4,3

=

(Augsburg, Hannover, Berlin, M u¨ nchen)

TSP4,4

=

(Augsburg, W u¨ rzburg, Hannover, Berlin, M u¨ nchen)

TSP4,5

=

(Augsburg, Karlsruhe, W u¨ rzburg, Hannover, Berlin, M u¨ nchen)

TSP4,6

=

(Augsburg, Ulm, Karlsruhe, W u¨ rzburg, Hannover, Berlin, M u¨ nchen)

Die geschlossene Rundreise zeigt eine Länge von 83 km + 160 km + 195 km + 369 km + 258 km + 596 km + 61 km = 1722 km auf. Diese Länge entspricht der Länge der optimalen Rundreise.

10.1.5 Random-Insertion-Heuristik Ebenso paradox, aber auch möglich, ist das kostengünstige Einfügen von zufälligen Knoten in die Rundreise.

10.1 Problem des Handlungsreisenden

| 111

Ausgehend von der Rundreise (Augsburg, M u¨ nchen) ergeben sich die zufälligen, kostengünstigen Erweiterungen wie folgt:

TSP5,1

=

(Augsburg, M u¨ nchen)

TSP5,2

=

(Augsburg, Hannover, M u¨ nchen)

TSP5,3

=

(Augsburg, W u¨ rzburg, Hannover, M u¨ nchen)

TSP5,4

=

(Augsburg, W u¨ rzburg, Hannover, Karlsruhe, M u¨ nchen)

TSP5,5

=

(Augsburg, W u¨ rzburg, Hannover, Karlsruhe, Ulm, M u¨ nchen)

TSP5,6

=

(Augsburg, W u¨ rzburg, Berlin, Hannover, Karlsruhe, Ulm, M u¨ nchen)

Die Länge der nun über zufällige Erweiterungen geschlossenen Rundreise ergibt sich zu 243 km + 490 km + 258 km + 500 km + 160 km + 124 km + 61 km = 1836 km. Ein für die zufällige Auswahl der Erweiterungen nicht allzu schlechter Wert. Zusammenfassend empfiehlt die Literatur das Farthest-Neighbour-InsertionVerfahren als nicht ganz so ungeeignet. Im Durchschnittsfall (average case) schneidet es sogar besser ab als das Nearest-Neighbour-Insertion-Verfahren. Der Vorteil rührt daher, dass die Nearest-Neighbour-Insertion-Heuristik zum Ende des Verfahrens, wenn nur noch wenige nicht besuchte Knoten verfügbar sind, längere Entfernungen in Kauf nehmen muss.

10.1.6 Minimaler-Spannbaum-Heuristik Ein weiteres Näherungsverfahren für das TSP-Problem ist eine Heuristik, die auf minimalen Spannbäumen aufbaut. Zunächst wird für den zu betrachtenden Graphen ein minimaler Spannbaum MST bestimmt. Anschließend wird jede Kante des MST verdoppelt. Ausgehend von einem beliebigen Startknoten wird nun ein Eulerkreis⁴ gebildet, der alle (nun verdoppelten) Kanten enthält. Bereits besuchte Knoten, und die Kanten dorthin, werden durch direkte Verbindungskanten ersetzt, soweit es sich nicht um den Start/End-Knoten handelt. Nach Anwendung der bekannten MST-Verfahren aus Abschnitt 9.3 ergibt sich der minimale Spannbaum, wie in Abbildung 10.2 gezeigt. Die Kanten des MST wer-

4 Als Eulerkreis oder Eulertour wird in der Graphentheorie ein Zyklus (Rundreise) in einem Graphen bezeichnet, der jede Kante des Graphen genau einmal enthält. Der Name geht auf das vom Mathematiker Leonard Euler 1736 gelöste „Königsberger Brücken-Problem“ zurück. Auf eine sehr unterhaltsame Reise in die Graphentheorie und auch zum Königsberger Brücken-Problem nimmt uns (Gritzmann and Brandenberg, 2005) mit.

112 | 10 Schwere Probleme und Heuristiken 243 83

Augsburg

600

369

221

Hannover

593 258

500

195

Karlsruhe 270

670

647

180

536

Ulm 124

596

Berlin

Würzburg

160

294

München 604 490

61

Abb. 10.2: Minimaler Spannbaum für deutsche Großstädte (Kantengewichte in km)

den verdoppelt und der entstehende Eulerkreis wird gesucht, wobei doppelt besuchte Knoten kurzgeschlossen werden. Die Abfolge der Suche des Eulerkreises ist wie folgt: Augsburg, M u¨ nchen, Augsburg (zu überspringen, kurzschließen zu Ulm), W u¨ rzburg, Ulm (zu überspringen, kurzschließen zu Karlsruhe), Hannover, Karlsruhe und W u¨ rzburg (beide überspringen, kurzschließen zu Berlin). Somit ist die entstehende Rundreise, ausgehend vom Ausgangsknoten Augsburg: TSP6 = (Augsburg, M u¨ nchen, Ulm, W u¨ rzburg, Karlsruhe, Hannover, Berlin) Diese gefundene Rundreise hat eine Länge von 61 km + 124 km + 180 km + 195 km + 500 km + 258 km + 593 km = 1911 km.

10.1.7 Tourverschmelzungsheuristik Eine weitere Heuristik für das TSP ist die sogenannte Tourverschmelzung oder auch Savings-Algorithmus. Bei diesem Verfahren werden, ausgehend von einem Startknoten, Stichtouren zu allen anderen Knoten geplant. Anschließend werden diese Stichtouren so miteinander verschmolzen, dass die größte Wegersparnis erfolgt. Das Vorgehen wird in Abbildung 10.3 verdeutlicht. Ausgehend von Knoten v sind bereits erweiterte/verschmolzene Stichtouren t1 zu x (und w) und t2 zu u (und y) vorhanden. Diese beiden Stichtouren können zu einer resultierenden Stichtour verschmolzen werden. Die Kanten (v, u) und (v, x) werden entfernt, da sie durch die Tourverschmelzungskante (u, x) unter Einsparung von Kantengewichten ersetzt werden.

10.1 Problem des Handlungsreisenden

| 113

u Stichtour von v nach u

tour t1

Verschmelzung von t1 und t2

v Stichtour von v nach x

w

x tour t2 y

Abb. 10.3: Vorgehen bei Tourverschmelzungen

Augsburg 593 Berlin

593

600

Hannover

600

221

221

61 61

Karlsruhe

83

München

83

243

Ulm

243

Würzburg

Abb. 10.4: Tourverschmelzungen zu deutschen Großstädten (Angaben in km)

Wenden wir den Tourverschmelzungsalgorithmus auf unsere Rundreise zu deutschen Großstädten an, entstehen, ausgehend vom Startknoten Augsburg, die Stichtouren wie in Abbildung 10.4 dargestellt.

Augsburg 539 Berlin

221

221 61

Karlsruhe

61

83 83

München

Ulm

243

243 Würzburg

258 Hannover

Abb. 10.5: Zustand nach der ersten Tourverschmelzung (Angaben in km)

600

114 | 10 Schwere Probleme und Heuristiken Eine erste Tourverschmelzung mit maximaler Ersparnis verschmilzt die Stichtouren zu Berlin und Hannover, die Einsparung beträgt 593 km + 600 km − 258 km = 935 km, wie in Abbildung 10.5 gezeigt. Die Ersatzkanten, die durch eine Tourverschmelzung hinzukommen sind jeweils gestrichelt eingetragen. Die zweite Tourverschmelzung verschmilzt die Stichtouren zu Berlin, Hannover mit der Stichtour zu W u¨ rzburg. Die Einsparung beträgt 600 km + 243 km − 369 km = 474 km, wie in Abbildung 10.6 gezeigt.

Augsburg

593 221

Berlin

221 61 61

Karlsruhe

83

München

83

Ulm

258

243

Hannover

369

Würzburg

Abb. 10.6: Zustand nach der zweiten Tourverschmelzung (Angaben in km)

Die dritte Tourverschmelzung verschmilzt die Stichtouren zu Karlsruhe mit W u¨ rzburg, Hannover, Berlin, wobei die Richtung der Tour umgedreht wird. Die Einsparung beträgt 243 km + 221 km − 195 km = 269 km, wie in Abbildung 10.7 gezeigt. Die vierte Tourverschmelzung verschmilzt die Stichtouren zu Karlsruhe, W u¨ rzburg, Hannover, Berlin mit Ulm, wobei die Richtung der Tour umgedreht wird. Die Einsparung beträgt 221 km+83 km−160 km = 144 km, wie in Abbildung 10.8 gezeigt. Die letzte Tourverschmelzung verschmilzt die Stichtouren zu M u¨ nchen mit Berlin, Hannover, W u¨ rzburg, Karlsruhe, Ulm. Die Einsparung beträgt 593 km+61 km− 596 km = 58 km, wie in Abbildung 10.9 gezeigt. Die resultierende Rundreise hat eine Gesamtlänge von 1722 km und entspricht somit einer optimalen Rundreise. Eine Implementierung in Python kann ebenfalls in (Häberlein, 2012) gefunden werden. Es ist ratsam, die Implementierung durch Ausga-

10.1 Problem des Handlungsreisenden

|

115

Hannover 258 Berlin 593 Augsburg 221 61 Karlsruhe

61

München

369

83 83 Ulm

195 Würzburg

Abb. 10.7: Zustand nach der dritten Tourverschmelzung (Angaben in km)

ben anzureichern bzw. mit einem Debugger Schritt für Schritt durchzugehen, um die Feinheiten des Algorithmus zu verstehen.

116 | 10 Schwere Probleme und Heuristiken

Berlin

Berlin

258

258 Hannover

Hannover 369

369

Würzburg

Würzburg

195

593

195

Karlsruhe

Karlsruhe

160

160 Ulm

Ulm 83

83

Augsburg 61

596

61

München

Abb. 10.8: Zustand nach der vierten Tourverschmelzung (Angaben in km)

Augsburg 61 München

Abb. 10.9: Zustand nach der letzten Tourverschmelzung (Angaben in km)

10.2 Rucksackproblem Das Rucksackproblem oder englisch Knapsack-Problem ist ein weiteres Problem aus der Liste der 21 von Rabin Karp identifizierten NP-vollständigen Probleme (Karp, 1972). Aus einer Menge von Objekten, die jeweils über ein Gewicht oder Volumen und einen Wert verfügen, soll eine Untermenge ausgewählt werden, die in einen gewichts- oder volumenbeschränkten Rucksack untergebracht werden kann. Es handelt sich somit um ein Optimierungsproblem der Kombinatorik, dessen optimale Lösung nur durch Ausprobieren aller Möglichkeiten gefunden werden kann. Formal steht ein Rucksack

10.2 Rucksackproblem

| 117

mit einem zupackbaren Höchstgewicht T zur Verfügung. Die Gegenstände verfügen jeweils über ein Gewicht w i und einen Wert v i . Vorgehen zur Lösung Ein erstes intuitives Vorgehen zur Lösung des Rucksackproblems besteht in der Auswahl der Gegenstände, wahlweise nach: 1. dem Gesamtprofit V = ∑ v j der in den Rucksack gepackten Gegenstände 2. dem Gesamtgewicht W = ∑ w j mit W ≤ T 3. der Profitdichte bzw. dem Profitabilitätsindex pi i = wv i unter Berücksichtigung des i Maximalgewichts T Als Beispiel nehmen wir den begeisterten Retrocomputer-Sammler Hans Franke, den Organisator des Vintage Computer Festival Europa, dem VCFe⁵. Hans befindet sich gerade auf dem Flohmarkt des VCFe. Er hat zum Transport seiner käuflich zu erwerbenden Schätze leider nur einen Umzugskarton mit einer Maximalkapazität von 10 kg dabei (T = 10 kg). In die engere Auswahl historischer Computer und Gerätschaften haben es die Geräte in Tabelle 10.2 geschafft. Hans wählt nun seine Geräte, die er kaufen und mitnehmen möchte, nach dem Gesamtprofit (1) aus. Er sortiert die Gegenstände absteigend nach ihrem Wert und füllt seinen Umzugskarton wie in der Tabelle 10.3 gezeigt. Als ersten Gegenstand wählt Hans den Commodore-PET-Rechner aus. Als zweiten Gegenstand müsste Hans die Sun Ultra5 Workstation mitnehmen, leider passt diese nicht mehr in seinen Umzugskarton (Gewicht der Sun 5 kg gegenüber Restkapazität von 3 kg) und er muss zum nächst geringwertigen Gegenstand, dem Commodore Amiga 500 greifen. Der CommodoreMonitor 1084 passt, als dritte Auswahl, gerade noch so in seinen Umzugskarton, das Gesamtgewicht von T = 10 kg ist erreicht, er hat mit diesem Vorgehen einen Gesamtprofit von 365 € erreichen können. Als nächstes versucht Hans seinen Profit dadurch zu optimieren, indem er die Gegenstände dem Gesamtgewicht nach mitnimmt (Tabelle 10.4). Hans startet mit den Gegenständen mit dem geringsten Gewicht und arbeitet sich dem Gewicht nach vor. Nachdem er, als letzten Gegenstand, den Commodore-Monitor 1084 in seinen Umzugskarton gepackt hat, verbleiben noch 0,3 kg Restkapazität bei einem Gesamtprofit von 245 €. In seinem letzten Versuch füllt Hans seinen Umzugskarton nach der Profitdichte der einzelnen Gegenstände (3). Sein Ergebnis zeigt die Tabelle 10.5. Zunächst entscheidet sich Hans, absteigend nach der Profitdichte, für den Mephisto-Schachcomputer, den Commodore Amiga 500, den Commodore PET und den Epson HX20. Es ver-

5 „Ziel des Vintage Computer Festivals ist es den Erhalt und die Pflege historischer Computer und anderer (E)DV Gerätschaften zu fördern, das Interesse an überflüssiger Hard- und Software zu wecken und vor allem den Spaß daran auszuleben.“ Quelle: http://www.vcfe.org/, Abruf: 21.07.2017.

118 | 10 Schwere Probleme und Heuristiken Tab. 10.2: Historische Computer und Geräte des VCFe-Flohmarkt (Wert und Gewichtangaben sind frei gewählt) Nummer 1 2 3 4 5 6 7 8 9 10

Bezeichnung HP-12C-Taschenrechner Mephisto-Schachcomputer Epson HX20 Commodore Amiga 500 Commodore-Monitor 1084 Commodore PET Commodore Floppy 1541 Amstrad CPC 6128 Sun Ultra 5 Workstation Computerbücher

Wert in €

Gewicht in kg

Profitdichte

20 45 25 60 55 250 30 35 80 10

0,2 0,5 1 1 3 6 2 4 5 2

10 90 25 60 18,33 41,67 15 8,75 16 5

Tab. 10.3: Auswahl der Einkäufe nur nach Profit oder Wert Nummer 6 4 5

Bezeichnung Commodore PET Commodore Amiga 500 Commodore-Monitor 1084 Gesamtprofit

Wert in €

Gewicht in kg

Restkapazität in kg

250 60 55 365

6 1 3

4 3 0

Wert in €

Gewicht in kg

Restkapazität in kg

20 45 25 60 30 10 55 245

0,2 0,5 1 1 2 2 3

9,8 9,3 8,3 7,3 5,3 3,3 0,3

Tab. 10.4: Auswahl der Einkäufe nur nach Gewicht Nummer 1 2 3 4 7 10 5

Bezeichnung HP-12C-Taschenrechner Mephisto-Schachcomputer Epson HX20 Commodore Amiga 500 Commodore Floppy 1541 Computerbücher Commodore-Monitor 1084 Gesamtprofit

Tab. 10.5: Auswahl der Einkäufe nach der Profitdichte

Nummer 2 4 6 3 1

Bezeichnung

Wert in €

Gewicht in kg

Profitdichte

Restkapazität in kg

Mephisto-Schachcomputer Commodore Amiga 500 Commodore PET Epson HX20 HP-12C-Taschenrechner Gesamtprofit

45 60 250 25 20 400

0,5 1 6 1 0,2

90 60 41,67 25 10

9,5 8,5 2,5 1,5 1,3

10.2 Rucksackproblem

| 119

Tab. 10.6: Optimale Auswahl der Einkäufe

Nummer 7 6 4 2 1

Bezeichnung

Wert in €

Gewicht in kg

Profitdichte

Restkapazität in kg

Commodore Floppy 1541 Commodore PET Commodore Amiga 500 Mephisto-Schachcomputer HP-12C-Taschenrechner Gesamtprofit

30 250 60 45 20 405

2 6 1 0,5 0,2

15 41,67 60 90 10

8 2 1 0,5 0,3

bleibt eine Restkapazität des Umzugskartons von 1,5 kg. Für den Commodore-Monitor 1084, die Sun Ultra 5 Workstation und die Commodore Floppy 1541 ist nicht mehr ausreichend Platz im Umzugskarton. Somit nimmt Hans als letztes den HP-12CTaschenrechner mit. Nun findet Hans keine weiteren Gegenstände für seinen Einkauf. Trotz der verbleibenden Restkapazität von 1,3 kg im Umzugskarton, hat Hans 400 € Gesamtprofit erreichen können. Zu Hause angekommen stellt sich Hans die Frage: „Hätte ich meinen Einkauf noch wertvoller gestalten können?“ Wie kann er sich sicher sein? Bei einer Gesamtanzahl 10 von zehn Gegenständen hätte Hans 2 = 1024 Kombinationen durchprobieren müssen um die optimale Zusammenstellung für seinen Einkauf zu finden. Hans zerbricht sich den Kopf, versucht die optimale Kombination zu finden und kommt auf die Zusammenstellung in der Tabelle 10.6. Gibt es nun ein Vorgehen, welches uns noch näher an den optimalen Einkauf mit einem Profit von 405 € herankommen lässt, als die bereits verwendeten GreedyHeuristiken bzw. ohne alle Kombinationen ausprobieren zu müssen? Branch-and-Bound Die Antwort auf die Frage gibt eine in der Optimierung von Unternehmensabläufen gebräuchliche Heuristik, die Branch-and-Bound-Heuristik oder auch „Verzweigung und Schranke“ oder „Verzweigung und Begrenzen.“ Die Branch-and-Bound-Heuristik dient entweder der Gewinnmaximierung oder der Gewichtsminimierung, somit der Lösung eines Optimierungsproblems. Das Verfahren schlägt vor, die möglichen Entscheidungen in Form eines binären Entscheidungsbaums aufzuteilen. Jede Kante des Baumes entspricht einer Entscheidung einen Gegenstand mitzunehmen oder diesen nicht mitzunehmen. Da der binäre Entscheidungsbaum für das VCFe-Beispiel mit zehn Gegenständen eine Tiefe von zehn aufweisen würde, somit zu umfangreich würde, um das Konzept von Branch-and-Bound zu verdeutlichen, beschränken wir uns im Folgenden auf ein einfacheres Beispiel mit den Gegenständen x1 bis x4 aus der Tabelle 10.7.

!x4 x4

!x3

!x4

x4

x3

!x2

!x4

x4

!x3

x2

x3

!x4

!x1

x4

Start x1

!x4 x4

!x3

!x2

x3

!x4

nach Schritt 1: mit x1

x4

x2

x4

x3

nach Schritt 4: mit x1 und x2 ohne x3 und mit x4

!x4

nach Schritt 3: mit x1 und x2 und ohne x3

!x3

nach Schritt 2: mit x1 und x2

!x4

x4

120 | 10 Schwere Probleme und Heuristiken

Abb. 10.10: Binärer Entscheidungsbaum für Branch-and-Bound

10.2 Rucksackproblem

| 121

Tab. 10.7: Vereinfachtes Beispiel für Branch-and-Bound Gegenstand

x1

x2

x3

x4

Profit v i Gewicht w i Profitdichte

10 2 5

10 4 2,5

12 6 2

18 9 2

vi wi

Den binären Entscheidungsbaum für Branch-and-Bound zeigt Abbildung 10.10. Ausgehend vom Wurzelknoten zweigen wir in jedem Knoten nach links ab, wenn wir das Element x1 bis x4 nicht mitnehmen (notiert mit !x n ) bzw. nach rechts ab wenn wir das Element mitnehmen. Die 16 Blätter des Baumes zeigen die möglichen Endkonfigurationen die aus der Auswahl von vier Gegenständen entstehen. Die jeweilige Konfiguration kann an den Kanten, welche zu diesem Blatt führen, abgelesen werden. Das Beispiel verdeutlicht, wie umfangreich der binäre Entscheidungsbaum wäre, wenn wir das VCFe-Beispiel herangezogen hätten. Das Aufbauen des binären Suchbaums und der Verzweigungen wird mit Branch beschrieben. Das Bound in Branch-and-Bound verdeutlicht nun die Kunst, Zweige im Entscheidungsbaum nicht weiter zu verfolgen, wenn der Ausbau der aktuellen Konfiguration nicht weiter erfolgversprechend ist. Wie können wir nun die Entscheidung treffen, einen Zweig nicht weiter zu verfolgen? Wir führen zwei Metriken ein, die uns entscheiden helfen, die Suche an einer Position zu begrenzen (bound). Wir führen einen upper bound UB und einen lower bound LB ein. Der upper bound beschreibt die theoretische Obergrenze, die wir an Profit bekämen, wenn wir den Rucksack mit weiteren (auch abgeschnittenen oder zerteilten) Teilen vollpacken. Der lower bound beschreibt eine untere Schranke dadurch, dass wir die aktuelle Konfiguration weiterentwickeln bis eine Grenze erreicht ist. Wir packen so lange Gegenstände ein, bis kein weiterer Gegenstand mehr in den Rucksack hinein passt. Hier gehen wir davon aus, dass wir Gegenstände nicht teilen können. Weiterhin führen wir die Größe Restkapazität RK des Rucksacks ein. Der Rucksack in diesem Beispiel hat eine maximale Kapazität von T = 15. Den erreichten Gesamtwert führen wir mit GP ein. Schritt 1 Im Wurzelknoten des Entscheidungsbaums können wir folgende Werte berechnen: RK = 15 GP = 0 LB = v1 + v2 + v3 ⇒ LB = 10 + 10 + 12 = 32 18 v4 ) = 38 UB = LB + RK ⋅ w ⇒ UB = 32 + (15 − (2 + 4 + 6)) ⋅ 9 4

122 | 10 Schwere Probleme und Heuristiken Wenn wir nun wissen wollen, ob es lukrativ ist x1 mitzunehmen oder nicht, müssen wir für beide Fälle LB und UB bestimmen. Ohne x1 : RK = 15 GP = 0 LB = v2 + v3 ⇒ LB = 22 18 UB = LB + v4 (teilweise) ⇒ UB = 22 + (15 − (4 + 6)) ⋅ ) = 32 9 und mit x1 : RK = 15 − 2 = 13 GP = 10 LB = v1 + v2 + v3 ⇒ LB = 32 18 UB = LB + v4 (teilweise) ⇒ UB = 32 + (15 − (2 + 4 + 6)) ⋅ ) = 38 9 LB und UB sind höher, wenn wir x1 mitnehmen, somit entscheiden wir uns x1 mitzunehmen und bekommen nach Schritt 1 eine neue Ausgangssituation für den nächsten Schritt mit RK = 13, GB = 10, LB = 32 und UB = 38. Schritt 2 Mit x1 im Rucksack wollen wir entscheiden, ob wir x2 dazu packen. Ohne x2 : RK = 13 GB = 10 LB = v1 + v3 ⇒ LB = 10 + 12 = 22 UB = LB + v4 (teilweise) ⇒ UB = 22 + ((15 − 8) ⋅ 2) = 36 Und mit x2 : RK = 13 − w2 ⇒ RK = 13 − 9 = 4 GP = v1 + v2 ⇒ GP = 10 + 10 = 20 LB = v1 + v2 + v3 ⇒ LB = 10 + 10 + 12 = 32 UB = LB + RK ⋅ v4 ⇒ UB = 32 + (15 − 13) ⋅ 2 = 38 Wiederum sprechen LB und UB dafür, x2 mitzunehmen. Wir packen x2 mit in den Rucksack und beginnen mit Schritt 3.

10.2 Rucksackproblem

| 123

Schritt 3 Die Ausgangssituation ist nun RK = 4, GP = 20, LB = 32 sowie UB = 38. Wir wollen nun entscheiden, ob wir x3 mitnehmen oder nicht. Ohne x3 bekommen wir:

RK = 4 GP = 20 LB = v1 + v2 + v4 ⇒ LB = 10 + 10 + 18 = 38 UB = v1 + v2 + v4 (teilweise) ⇒ 18 UB = 20 + (15 − (2 + 4) ⋅ ) = 20 + 9 ⋅ 2 = 38 9 Mit x3 bekommen wir:

RK = 3 GP = 32 LB = v1 + v2 + v3 ⇒ LB = 10 + 10 + 12 = 32 UB = v1 + v2 + v3 + v4 (teilweise) ⇒ 18 ) = 32 + 3 ⋅ 2 = 38 UB = 32 + (15 − (2 + 4 + 6) ⋅ 9

Wir sehen: Wenn wir x3 nicht mitnehmen, entspricht LB = UB dem maximal möglichen Wert. Im Falle, dass wir x3 mitnehmen folgt LB = 32. Wir entscheiden uns dafür, x3 nicht mitzunehmen. Im letzten Schritt müssen wir nun entscheiden, ob wir x4 mitnehmen oder nicht. Schritt 4 Die Ausgangssituation nach Schritt 3 ist RK = 4, GP = 20, LB = 38, UB = 38. Für den Fall, dass wir x4 nicht mitnehmen bekommen wir:

RK = 4 GP = 20 LB = 38 UB = 38

Wenn wir x4 mitnehmen, bekommen wir:

124 | 10 Schwere Probleme und Heuristiken

RK = 4 GP = v1 + v2 + v4 ⇒ GP = 38 LB = 38 UB = 38

Das Vorgehen bei Branch-and-Bound hat gezeigt, wie durch die beiden Heuristiken lower bound LB und upper bound UB eine optimale Füllung des Rucksacks mit x1 , x2 , ohne x3 und mit x4 erreicht werden konnte.

11 Zusammenfassung und Ausblick Mit der Betrachtung schwerer Probleme in der Informatik endet die Einführung in die Grundlagen der Informatik. In den letzten Kaptiteln haben wir uns hauptsächlich mit Algorithmen und Datenstrukturen beschäftigt, einem wichtigen Kerngebiet der Informatik. Über die Grundlagen der theoretischen Informatik mit einem Blick auf die formalen Sprachen und die Automatentheorie wurde ein Einblick in den mathematisch/theoretischen Unterbau der Informatik vermittelt. Zahlreiche Ideen und Computersysteme basieren auf diesem Unterbau, wie im Kapitel über die technische Informatik mit dem historischen Hintergrund und den aktuellen Entwicklungen in der Informatik dargestellt wurde. Mit den Kapiteln über Algorithmen und Datenstrukturen haben wir uns mit einer Konstante in der Informatik beschäftigt. Viele der Überlegungen, Untersuchungen, Konzepte und Umsetzungen aus diesem Kapitel spielen sowohl auf historischen Rechenmaschinen als auch auf aktuellen Computersystemen eine maßgebliche Rolle. Die vorgestellten Beschreibungsverfahren von Algorithmen sind außerdem ein wichtiges Werkzeug in der menschlichen Kommunikation in der Informatik. Die vorgestellten Wege zu Umsetzung (Implementierung) von Algorithmen und die Analyse der Algorithmen und ihrer Umsetzung nehmen einen Großteil der praktischen Arbeit in der Informatik ein, wie es auch im nachfolgenden Teilband zur Programmierung ausführlicher dargestellt wird. Bäume und Graphen als exemplarische Datenstrukturen stellen wichtige Organisationsmittel für Daten und Informationen in der modernen Informatik dar. Viele Verfahren zur Datenanalyse, beispielsweise von Big Data¹, basieren auf der Darstellung der zu untersuchenden Information in Form eines Graphen und der Untersuchung des resultierenden Graphen. Die moderne Informatik ist auch ohne den Einsatz von Hashing-Verfahren nicht mehr denkbar. Sie bilden die Grundlage effizienter Zugriffsund Verschlüsselungsverfahren, ohne die zahlreiche Anwendungen der modernen Informationsverarbeitung undenkbar wären. Perspektivisch haben wir uns auch mit der Lösung schwerer Probleme der Informatik mittels Heuristiken auseinander gesetzt. Hier bekamen wir einen kleinen Einblick in den Umgang mit hoher Komplexität, einer der größten Herausforderungen der modernen Informatik. Bei der Lösung dieser schweren Probleme, mit auf Turingmaschinen basierten Rechnern, stößt die Informatik regelmäßig an die Grenzen des technisch Machbaren.

1 Als Big Data werden nicht nur große Datenmengen bezeichnet, sondern auch die Verarbeitung von Daten die nicht zwingend streng strukturiert vorliegen (z. B. natürlichsprachliche Inhalte im Internet) und ebenfalls Daten, die mit hoher Frequenz verarbeitet werden müssen (z. B. Daten die im Large Hadron Collider (Teilchenbeschleuniger am CERN) entstehen). https://doi.org/10.1515/9783110496253-012

126 | 11 Zusammenfassung und Ausblick Neben den Literaturempfehlungen im Anschluss (Kapitel 12), soll hier noch ein kurzer Ausblick in interessante Fragestellungen gegeben werden, mit denen sich Informatiker aktuell auseinandersetzen. Eine sehr aktuelle Forschungsrichtung der angewandten Informatik besteht in der Entwicklung intelligenter autonomer Systeme. Mehr und mehr Entscheidungen, die bisher von Menschen getroffen wurden, sollen durch maschinelle Verfahren unterstützt werden. Neben dem automatisierten Fahren im Straßenverkehr, kommen solche Entscheidungsunterstützungssysteme auch in der Industrie 4.0 oder in den Kognitionswissenschaften zum Einsatz. In der Industrieautomatisierung der Industrie 4.0 werten maschinelle Verfahren Daten, die beispielsweise in Fertigungsanlagen entstehen, aus, bereiten diese auf und helfen dabei normale Betriebszustände von Fehlerzuständen in der Produktion zu unterscheiden. In den Kognitionswissenschaften werden menschliche Gehirnströme durch maschinelle Verfahren analysiert. Es wird versucht menschliche Affekte (Gemütsregungen) zu erkennen und zu interpretieren. In den vorgestellten Anwendungen spielen intelligente, autonom entscheidende Software-Einheiten, sogenannte Software-Agenten, sowie Verfahren der Mustererkennung und des maschinellen Lernens eine tragende Rolle. Einen guten Überblick über die Theorie und praktische Umsetzung intelligenter Software-Agenten gibt (Jennings and Wooldridge, 1998); eine zeitgemäße und gute Einführung in das maschinelle Lernen mit Python findet sich in (Géron, 2017). Erste Versuche in der Analyse von Gehirnströmen können beispielsweise mit dem NeuroSky Brainwave Starter Kit² sowie dem OpenBCI³ gemacht werden. Mit diesem Ausblick endet das Informatik-Kapitel, die vorgestellten Themen können in den nachfolgenden Literaturempfehlungen vertieft werden. Herzlich willkommen in der interessanten und weiten Welt der Informatik!

2 Details unter https://store.neurosky.com/pages/mindwave, Abruf: 12.08.2018. 3 Details unter http://openbci.com/, Abruf: 12.08.2018.

12 Lektüreempfehlungen Fischer, Peter und Hofer, Peter (2010): Lexikon der Informatik, 15., überarb. Aufl. 2011 Aufl. Berlin: Springer. Im „Lexikon der Informatik“ von Peter Fischer und Peter Hofer können viele Begriffe der Informatik, die auch in diesem Kapitel verwendet werden, nachgeschlagen werden. Eine kurze und prägnante Beschreibung unterstützt das Verständnis und den Überblick über die Teilgebiete der Informatik. Schneider, Uwe und Werner, Dieter (2012): Taschenbuch der Informatik. 7. Aufl. München: Carl Hanser. Das „Taschenbuch der Informatik“ von Uwe Schneider gibt eine weitere kompakte und kompetente Einführung in die Kerngebiete der Informatik. Ähnlich wie in diesem Kapitel kann ein erster Überblick über die vorgestellten Themen gewonnen werden. Bei Bedarf finden sich ausreichend Verweise auf weitere Literatur um das Wissen zu vertiefen und zu erweitern. Rechenberg, Peter und Pomberger, Gustav (2006): Informatik-Handbuch. 4., aktualisierte und erweiterte Aufl. München: Carl Hanser. Auf mehr als 1 000 Seiten stellt das „Informatik-Handbuch“ von Peter Rechenberg und Gustav Pomberger viele Teilgebiete der Informatik in gut verständlicher Weise dar. Bereits in der vierten Auflage stellt das Informatik-Handbuch ein sehr gutes Nachschlagewerk für Praktiker und Medienwissenschaftler dar. Rechenberg, Peter (2000): Was ist Informatik? Eine allgemeinverständliche Einführung. 3., überarbeitete und erweiterte Aufl. München: Carl Hanser. Ebenfalls von Peter Rechenberg liegt diese, vielleicht für Studenten der Medienwissenschaft sehr gut als Einstieg geeignete Lektüre vor. Der Autor stellt darin alle Bereiche der Informatik systematisch vor, vertieft einiges hier nur kursorisch dargestelltes und erklärt komplizierte Sachverhalte mit Beispielen (in Pseudocode) und Grafiken. Hervorzuheben ist dabei das Schlusskapitel, das sich auch den „philosophischen“ Fragen, die die Informatik aufwirft, widmet (Ethik, Ästhetik, Technikfolgen usw.) Knuth, Donald E. (2011): The Art of Computer Programming. Volumes 1-4. 3rd edition. Addison Wesley. Das Standardwerk zu Algorithmen und Datenstrukturen, quasi das Statussymbol eines guten Informatikers, ist das vierbändige Werk „The Art of Computer Programming“ von Donald E. Knuth. Hier finden sich zahlreiche Standardalgorithmen und umfangreiche Details zu ihrer Analyse und Implementierung. Hoffmann, Dirk W. (2012): Grenzen der Mathematik: Eine Reise durch die Kerngebiete der mathematischen Logik. 2 Aufl. Heidelberg: Springer Spektrum. In seinem Werk „Grenzen der Mathematik“ stellt Dirk Hoffmann den Überlappungsbereich zwischen Mathematik und theoretischer Informatik spannend und gut verständhttps://doi.org/10.1515/9783110496253-013

128 | 12 Lektüreempfehlungen lich dar. Das Buch ermöglicht einen unterhaltsamen Ausflug in dieses Grenzgebiet im Sinne von Star Treks „Where no man has gone before“. Dewdney, A. K. (2011): Der Turing Omnibus. Eine Reise durch die Informatik mit 66 Stationen. Berlin/Heidelberg: Springer. Der „Turing Omnibus“ nimmt den Leser auf eine wunderschöne Rundreise durch die Informatik und Mathematik mit. Zahlreiche Themen aus diesem Kapitel sowie aus weiterführenden Bereichen werden auf unterhaltsame und kurzweilige Weise erörtert. Für Informatik-Einsteiger und auch für „alte Hasen“ geeignet. Guttag, John V. (2016): Introduction to Computation and Programming Using Python. 2. Aufl. Cambridge (Massachusetts): The MIT Press. John V. Guttag gibt in „Introduction to Computation and Programming Using Python“ eine schöne Einführung in Algorithmen und deren Implementierung mit Python. Zahlreiche Algorithmen aus dem Bereich Data Science zum Verständnis und zur Modellierung größerer Datenmengen geben einen Ausblick in aktuelle Fragestellungen der Informatik. Devadas, Srini (2017): Programming for the Puzzled: Learn to Program While Solving Puzzles. Cambridge (Massachusetts): The MIT Press. Unterhaltsame Herausforderungen zum Sammeln von Programmiererfahrung gibt Srini Devadas in „Programming for the Puzzled“. Zahlreiche logische Puzzle werden vorgestellt, deren algorithmische Lösung und Umsetzung in Python laden zum eigenständigen Ausprobieren und Weiterentwickeln ein.

Literatur Balzert, H. (2008): Java: der Einstieg in die Programmierung: Strukturiert und prozedural programmieren, Dortmund, W3l. Bauer, F. L. und Deutsches Museum (2004): Informatik : Führer durch die Ausstellung / Deutsches Museum, München, EOS-Druck St. Ottilien. Brodie, L. (1987): Starting Forth: Introduction to the FORTH Language and Operating System for Beginners and Professionals, zweite Aufl., Englewood Cliffs, N.J, Prentice-Hall. Claus, V. und Schwill, A. (2006): Duden Informatik A – Z: Fachlexikon für Studium, Ausbildung und Beruf, vierte Aufl., Mannheim, Bibliographisches Institut. Cook, S. A. (1971): The complexity of theorem-proving procedures, in Proceedings of the Third Annual ACM Symposium on Theory of Computing, ACM, New York, NY, 151–158. Dijkstra, E. W. (1959): A Note on Two Problems in Connexion with Graphs, Numerische Mathematik 1, 269–271. Eirund, H., Müller, B. und Schreiber, G. (2000): Formale Beschreibungsverfahren der Informatik. Ein Arbeitsbuch für die Praxis, Stuttgart, B.G. Teubner Verlag. Erk, K. (2009): Theoretische Informatik: Eine umfassende Einführung, dritte Aufl., Berlin, Springer. Géron, A. (2017): Hands-On Machine Learning with Scikit-Learn and TensorFlow, Sebastopol, CA, O’Reilly Media. Gritzmann, P. und Brandenberg, R. (2005): Das Geheimnis des kürzesten Weges: Ein mathematisches Abenteuer, dritte Aufl., Berlin, Springer. Häberlein, T. (2012): Praktische Algorithmik mit Python, München, Oldenbourg. Hoare, C. A. R. (1962): Quicksort, The Computer Journal 5(1), 10–16. Hoffmann, D. W. (2012): Grenzen der Mathematik: Eine Reise durch die Kerngebiete der mathematischen Logik, zweite Aufl., Heidelberg, Springer Spektrum. Isernhagen, R. und Helmke, H. (2004): Softwaretechnik in C und C++ – Kompendium: Modulare, objektorientierte und generische Programmierung, vierte Aufl., München; Wien, Carl Hanser Verlag. Jennings, N. R. und Wooldridge, M. J., Hrsg. (1998): Agent technology: foundations, applications, and markets, Springer. Jouppi, N. (2017): In-datacenter performance analysis of a tensor processing unit, ACM SIGARCH Computer Architecture News – ISCA’17 45(2), 1–12. Kantel, J. (2010): Lernt programmieren, sonst werdet ihr programmiert! über die Emanzipation von der Software-Industrie. (https://www.deutschlandfunkkultur.de/lernt-programmieren-sonstwerdet-ihr-programmiert.1005.de.html?dram:article_id=159157 – Abruf: 23.09.2018). Karp, R. (1972): Reducibility Among Combinatorial Problems, in R. Miller und J. Thatcher, Hrsg., Complexity of Computer Computations, Plenum Press, 85–103. Kasparick, H. (2014): Wie organisiert Spanning Tree ein Ethernet-Netzwerk? Der Baum im Netzwerk, ADMIN-Magazin. (http://www.admin-magazin.de/Das-Heft/2014/03/Wie-organisiert-Spanni ng-Tree-ein-Ethernet-Netzwerk – Abruf: 10.07.2018). Kaufmann, W. J. und Smarr, L. L. (1993): Supercomputing and the Transformation of Science, New York, Scientific American Library. Kittler, F., Dotzler, B. und Turing, A. (1987): Intelligence Service. Schriften, Berlin, Brinkmann u. Bose. Kröhling, A. (2017): Digitalisierung – Technik für eine nachhaltige Gesellschaft?, in CSR und Digitalisierung, Management-Reihe Corporate Social Responsibility, Springer Gabler, Berlin, Heidelberg, 23–49. Peled, D. (2001): Software Reliability Methods, Texts in Computer Science, New York, SpringerVerlag. https://doi.org/10.1515/9783110496253-014

130 | 12 Literatur Schröder, H.-D. (2006): Digitalisierung, in Medien von A biz Z, VS Verlag für Sozialwissenschaften, 95–97. Segars, S. (2011): ARM processor evolution: Bringing high performance to mobile devices, in 2011 IEEE Hot Chips 23 Symposium (HCS), 1–37. Shannon, C. E. (1948): A mathematical theory of communication, The Bell System Technical Journal 27(3), 379–423. Stevens, M., Bursztein, E., Karpman, P., Albertini, A., Markov, Y., Petit-Bianco, A. und Baisse, C. (2017): Announcing the first SHA1 collision, Google Online Security Blog. (https://security.g oogleblog.com/2017/02/announcing-first-sha1-collision.html – Abruf: 23.09.2018). Turing, A. M. (1936): On computable numbers with an application to the Entscheidungsproblem, Proceedings of the London Mathematical Society, 2 42(1), 230–265. Weilkiens, T. (2014): Systems Engineering mit SysML/UML: Anforderungen, Analyse, Architektur, dritte Aufl., dpunkt.verlag. Wikipedia (2017a): Algorithmus von Kruskal. (https://de.wikipedia.org/w/index.php?title=Algorithm us_von_Kruskal&oldid=167224256 – Abruf: 23.09.2018). Wikipedia (2017b): Informatik. (https://de.wikipedia.org/w/index.php?title=Informatik&oldid=1633 96944 – Abruf: 23.09.2018). Wikiquote (2017): Edsger W. Dijkstra. (https://en.wikiquote.org/wiki/Edsger_W._Dijkstra – Abruf: 23.09.2018). Zaks, R. (1982): Programmierung des Z80, Düsseldorf, Sybex. Zaks, R. (1984): Programmierung des 6502, Düsseldorf, Sybex. Zoppke, T. (2004): Simulating the ENIAC as a Java Applet. (http://zuse-z1.zib.de/simulations/eniac/ doc/eniac_simulation_thesis.pdf – Abruf: 23.09.2018).

|

Teil II: Programmieren für Medienwissenschaftler (Stefan Höltgen & Johannes Maibaum)

1 Einleitung Stefan Höltgen und Johannes Maibaum „Du sollst nicht nicht programmieren können“¹, lautete Ende der 1990er-Jahre eines der „Zehn Gebote der Medienwissenschaft“. Angesichts aktuell vernehmbarer Rufe nach einem Schulfach für Computerprogrammierung scheint diese Aufforderung gehört worden zu sein. Allerdings besitzt die Kenntnis von Programmiersprachen für Medienwissenschaftler eine andere, erweiterte Relevanz. Hier geht es nicht allein darum, Anschlussfähigkeit an eine Kulturtechnik zu erlangen, die vielleicht als Ausgangsbasis für einen Informatik-Leistungskurs, später vielleicht sogar ein Informatik-Studium oder gar eine Karriere als Programmierer bieten soll. Vielmehr soll die Computerprogrammierung aus der Sicht der Medienwissenschaft: 1. einen symbolischen Zugang zum Computer als realer Maschine bieten, 2. eine Lesekompetenz für formale Sprachen (und damit gleichzeitig eine Möglichkeit Programmiersprachen in ihrer Genealogie, Struktur und kulturellen Relevanz mit anderen formalen und natürlichen Sprachen zu vergleichen) vermitteln, 3. eine Möglichkeit zur Verfügung stellen, um medientechnische und -theoretische Fragestellungen zu „implementieren“ und operativ als Simulationen und Reenactments zu studieren, 4. und eine notwendige Brücke zwischen kultur-/geisteswissenschaftlichen Diskursen und informatischen und anderen technischen Disziplinen schlagen helfen. Dadurch, dass kontemporäre Medientechnik heute zumeist computerbasiert („digitalisiert“, eigentlich aber eher „algorithmisiert“) ist, stellen die Kenntnis und das Verständnis von Computerprogrammierung ein zentrales Element medientechnischen Wissens dar. Ein interdisziplinärer Blick auf Programmiersprachen und Computerprogrammierung, der sowohl die technischen Prozesse als auch deren epistemologische Implikationen in den Blick nimmt, ermöglicht eine medienwissenschaftliche „Vermittlung“ zwischen den oft als getrennt wahrgenommenen Sphären der Kultur- und Technikwissenschaften: Beide wenden gleichermaßen Medientechnologien an, um zu forschen, zu lehren und zu publizieren. Medientechnologien schreiben sich damit in diese Prozesse ein. Daher kann medienwissenschaftliches Wissen beiden Wissenschaftskulturen auch Mittel an die Hand geben, die „medientechnischen Aprioris“ (Ernst 2012:302) ihrer Arbeiten mitzu(be)denken. Hierzu sollten Medienwissenschaftler technisch ‚auf Augenhöhe‘ mit beiden Seiten diskutieren können. Im folgenden Kapitel werden Einführungen in vier ganz unterschiedliche Programmiersprachen angeboten. Die Wahl der Sprachen führt dabei auch einen Ausschnitt aus der Genealogie der Programmiersprachen vor: (Lehr)Assembler-Sprachen

1 http://post.in-mind.de/pipermail/rohrpost/2005-February/007800.html (Abruf: 22.05.2018) https://doi.org/10.1515/9783110496253-015

134 | 1 Einleitung dienten, als eine Vorlage für die Entwicklung von BASIC, von dem wiederum bestimmte Elemente in Python übernommen wurden. Bei den möglichen Gemeinsamkeiten sollen allerdings die sowohl historischen als auch technologischen Unterschiede dieser Sprachen sollen dazu dienen, vier Anwendungsmöglichkeiten von Programmiersprachen für Medienwissenschaftler zu konkretisieren: Die Programmierung von Assembler soll einen Zugang zum Computer als Hardware und gleichermaßen Konkretisierung der Von-Neumann-Architektur und der Turingmaschine anbieten. Die Wahl des 6502-Assemblers ist dabei vor allem der Einfachheit (in Hinblick auf Befehlssatz und dessen Orthogonalität) sowie der Verbreitung dieser historischen CPU geschuldet. Der 1975 veröffentlichte Baustein ist auch heute noch (in einer aktuellen Version) erhältlich und dient deshalb auch als Grundlage für den in Band 4 dieser Lehrwerkreihe vorgestellten Selbstbaucomputer MOUSE. Auf MOUSE beziehungsweise den Emulator MOUSE2Go bezieht sich dann auch die Programmierfeinführung in Assembler. Die Programmiersprache BBC BASIC soll dazu dienen, die Mediengeschichte des Computers programmierend nachzuvollziehen und zugleich mit BASIC eine der populärsten historischen Programmierkulturen vorstellen. BASIC wurde 1964 als Programmiersprache für „Nicht-Informatiker“ entwickelt und hat in den folgenden drei Jahrzehnten eine unvergleichliche Popularität und Verbreitung als Schulsprache erfahren.² Das hier vorgestellte BBC BASIC ist eine moderne Variante, die immer noch weiterentwickelt wird, für zahlreiche historische und aktuelle Plattformen verfügbar ist und somit anbietet programmierend „historische Brücken“ zu schlagen. Dennis M. Ritchies Anfang der 1970er-Jahre publizierte Systemprogrammiersprache C soll zeigen, wie höhersprachliche Programmierparadigmen und -konzepte Algorithmen gänzlich anders darstellbar machen und zugleich, weil C eine „Sprache ‚mittlerer Ebene‘“ (Sommergut 1994:18) darstellt, maschinennah verständlich machen. Anders als Assembler (der quasi direkt in den Speicher assembliert wird) und BASIC (das zur Laufzeit mit einem Interpreter übersetzt wird), ist C eine Compiler-Sprache und führt damit auch diese Form der maschinellen „Übersetzung“ in den Diskurs ein. Die Möglichkeiten, aus C mit Hilfe des Compilers einen Assembler-Zwischencode zu erzeugen, ermöglichen zudem direkte Vergleiche der verschiedenen Übersetzungsstufen. Python schließlich soll, als eine heute sowohl in praktischen Anwendungen als auch als Ersatz für „Pseudocode“ vielfältig verwendete Programmiersprache mit niedriger Einstiegshürde, eine generelle Lesekompetenz für moderne, strukturierte und objektorientierte Sprachen vermitteln. Die hier im Band vertretenen Kybernetik- und

2 Die Lehre historischer Programmiersprachen bzw. Assemblersprachen für historische CPUs stellt zugleich eine retrodidaktische Reduktion dar. Die Einfachheit dieser Dialekte bietet auch Studenten technikferner Studiengänge einen Zugang zum Thema Programmieren. Darüber hinaus macht die Tatsache, dass sich BBC BASIC strukturieren lässt und 6502-Assembler einen vergleichsweise einfachen Einblick in die nach wie vor dominierende Von-Neumann-Architektur der Digitalcomputer gibt, beide Sprachen zu einem idealen Ausgangspunkt für Studien komplexerer Sprachen und Systeme.

1 Einleitung

| 135

Informatik-Teilbände verwenden Python zur Darstellung von Algorithmen und für Experimente. Die mögliche Objektorientierung in der Python-Programmierung führt ein modernes Programmierparadigma³ praktisch vor. Aufgrund ihrer unterschiedlichen Intentionen gehen die vier Kurzeinführungen methodisch auch ganz unterschiedlich an die jeweilige Sprache heran und stellen die für Medienwissenschaftler interessanten Aspekte in den Fokus. Gemein ist den Kurzeinführungen allerdings, dass sie in keiner Weise erschöpfend sein können; dazu bietet ihnen das Kapitel einen zu kleinen Raum. Sie können und sollen allerdings auch gar kein systematisch aufgebautes Lehrwerk ersetzen, sondern ein solches unter den genannten Perspektiven ergänzen. Für das systematische Studium der vier Sprachen geeignete Lehrwerke werden in abschießenden Lektürelisten vorgeschlagen. Dass ein Lehrwerk über Programmiersprachen auch Programmcode in abgedruckter Form enthält, ist selbstverständlich. Die Programmlistings im folgenden Kapitel sollten als Möglichkeit der Code-Lektüre genutzt werden: Wie kann ein menschlicher Leser einen formalsprachlich notierten Text lesend nachvollziehen? Welche „Hermeneutik“ nimmt er dabei in Anspruch? Allerdings sind die abgedruckten Codes nur in zweiter Hinsicht für den menschlichen Leser bestimmt; vielmehr sollen die Computer sie „verstehen“. Hierzu müssen sie vom Buch in die Rechner übertragen werden. Das geschieht am besten durch Abtippen (was aufgrund der Kürze der Programmtexte ein zumutbarer Vorgang sein sollte⁴), denn beim Abtippen verändert sich die Sichtweise auf die Codes noch einmal. Hierbei kann der Versuch unternommen werden über die Rolle des Menschen zwischen den Medien Buch/Papier und Computer zu reflektieren. Dem methodischen Ziel der Lehrbuchreihe folgend, sowohl Lehrwerk für Seminare und Übungen sein zu können⁵, als auch Begleittext für autonomes und autodidaktisches Lernen, wird der für das Lernen von Programmiersprachen sowieso gültige Rat „learning bei doing“ empfohlen: Modifizieren Sie die Programmtexte und experimentieren Sie mit ihnen! Vorschläge hierfür finden sich zum Teil unterhalb der Experiment-Blöcke. Um Ihnen den Einstieg zu erleichtern, werden leicht zugängliche Quellen für Tutorials, Nachschlage- und Lehrwerke benannt. Die Hardware, auf die sich die Programmier-Experimente stützten, ist in Form günstiger SinglebaordComputer (insb. Raspberry Pi und Arduino) verfügbar. Eine Besonderheit stellt hier das Assembler-Kapitel dar, denn es stellt die Programmierung eines selbst zu bauenden Lerncomputers⁶ vor. Wo dieser (noch) nicht vorliegt, kann eine Emulation desselben für Arduino-Computer genutzt werden.

3 Das Ziel dieser Einführung bleibt trotzdem die (medien)wissenschaftliche Reflexion von Programmierung und Programmiersprachen; unser Kapitel kann und soll keine systematische Programmierausbildung ersetzen. 4 Um diesen Prozess allerdings nicht zu stark zu oktroyieren, werden die Programmtexte dort, wo es möglich ist, mit ihren Quellen verlinkt und/oder als Downloads (www.degruyter.com) angeboten. 5 Hierzu finden sich Vorschläge für Kursgestaltungen auf www.degruyter.com. 6 Die Entwicklung dieses Systems wird in Band 4 der Lehrbuchreihe vorgestellt.

2 Assembler Stefan Höltgen

2.1 Einführung Der Computer als Werkzeug ist ganz wesentlich darauf angewiesen, dass er seine komplexen Funktionen verbirgt und dem Nutzer Schnittstellen bietet, die auf sein (anthropomorphes) Maß zugeschnitten sind (vgl. Weiser 1991). Betrachtet man die Geschichte des Digitalcomputers, so lässt sich ein Vektor in Richtung „Nutzerfreundlichkeit“ darin nachzeichnen. Dieser wachsenden Nutzerfreundlichkeit auf der Oberfläche der Schnittstellen steht jedoch eine wachsende Komplexität auf den darunter liegenden Ebenen gegenüber: Um etwa gestengesteuerte grafische User-Interfaces, Multitasking und Multimedia anbieten zu können, bedarf es hochspezialisierter Mikroelektronik, großer Mengen verfügbaren Speichers und Taktraten im Gigahertz-Bereich. Welche Arbeiten der Computer als Apparat (Krämer 1988:8 f.) dabei ausführt, bleibt für den Nutzer so lange unsichtbar, bis er sich auf die Ebene computerisierter Verarbeitung selbst hinab begibt. Die Fragen, wie man eine Computerfunktion auf ein menschliches Zeitmaß reduziert (sodass der Nutzer sie wahrnehmen kann), wie sich Interaktion zwischen Rechner und Anwender überhaupt bewerkstelligen lässt oder welche Möglichkeiten programmiererischer Flexibilität auf der Ebene der Maschinensprache noch vorhanden sind, soll das folgende Unterkapitel zur Assembler-Programmierung beantworten. Im Teilband „Logik für Medienwissenschaftler“ (vgl. Band 1, Kap. I) wurde die Frage aufgeworfen, warum Computer rechnen können.¹ Dass Rechnen viel mehr bedeutet als arithmetische Operationen auf Zahlen anzuwenden, hat die theoretische Informatik (vgl. Kap. I.1) gezeigt. Die technische Informatik (vgl. Kap. I.2) hat erläutert, wie Digitalcomputer aufgebaut sind, um diesen Zweck (alles Berechenbare berechnen zu können) zu erfüllen. Die formalen Beschreibungen der Logik und der Alphabete (vgl. Kapitel I.3.1) sind dem realen Computer allerdings fremd. Als implementierte (Mikro)Elektronik „versteht“ er ausschließlich zeitdiskrete Signale in Form von elektrischer Spannungen. Die Schaltungslogik (vgl. Band I, Kap. I.6) hat gezeigt, wie diese Signale mithilfe spezifischer digitaler Bauteile manipuliert werden können; die Arithmetisch-Logische Einheit (ALU) wurde dabei als das komplexeste digitale Bauteil vorgestellt. In ihr finden die logischen und arithmetischen Operationen statt, mit

1 Das folgende Kapitel bezieht die Informationen des Logik-Teilbandes, insbesondere des dortigen Abschnitts „Logik in Maschinensprache“ (Band 1, Kap. I.7) mit ein und kann zur Vorbereitung vorab gelesen werden. https://doi.org/10.1515/9783110496253-016

2.1 Einführung

| 137

deren Hilfe Computer zu ihren Funktionen fähig sind. An diesem Punkt setzt nun das folgende Kapitel über Assembler-Programmierung ein. „Computer verstehen nur Nullen und Einsen“, heißt es landläufig, wenn die Diskrepanz zwischen den einfachen binären Zuständen der Digital-Mikroelektronik und der daraus erwachsenden Emergenz an Computerfunktionen vor Augen geführt werden soll. An dieser Stelle muss aber bereits unterschieden werden, um welche Nullen und Einsen es sich handelt, denn Digitalcomputer nutzen binäre Signale sowohl für interne Steuerungsprozesse (diese hat der Logik-Teilband vorgestellt) als auch für die Kodierung von zu verarbeitenden Daten und nicht zuletzt auch von Befehlen und Funktionen. Je nachdem, auf welchen Leitungen eine Signalmenge wie z.B. 011011001 auftritt, kann damit eine interne Funktion ausgelöst werden, ein spezifischer Programmierbefehl gemeint sein oder die Zahl kann für ein konkretes Datum stehen. Die sogenannte Von-Neumann-Architektur (vgl. Kap. I.1.3) von Digitalcomputern verwaltet lediglich zwei Sorten von Signalen auf der Hardwareebene: Steuerungssignale und Datensignale. Damit letztere, weil sie aus demselben Speicher kommen, in tatsächliche Daten und Programmbefehle unterschieden werden können, müssen sie sowohl ein strenges Format einhalten als auch – soll es sich um Befehle, sogenannte Opcodes (operation codes) handeln – dem Computer bekannt sein. Alle verfügbaren Opcodes eines Computers sind in dessen Mikroprogrammspeicher hinterlegt. In diesem Mikroprogramm (micro code) ist die Maschinensprache quasi als HardwareLexikon realisiert; hier befindet sich die Grenze zwischen dem realen und dem symbolischen Zeichensystem des Computers. Und an dieser Stelle unterscheiden sich verschiedene Computer fundamental voneinander – je nachdem, welche Maschinensprache in ihre CPU integriert ist. Maschinensprache-Opcodes sind dabei wesentlich einfacher strukturiert als Befehle und Funktionen höherer Programmiersprachen. Und dennoch sind sie ebenso mächtig wie diese, denn jede Software, die auf einem Computer ausgeführt werden soll, muss in letzter Instanz in Maschinensprache – also in Programme mit diesen „einfachen“ Opcodes – übersetzt werden. Während höhere Programmiersprachen auf verschiedenen Kalkülen (vgl. Krämer 1988) basieren oder das Programmieren auf Grundlage unterschiedlicher Programmierparadigmen (vgl. Müller/Weichert 2013: 207 ff.) ermöglichen, um für ihn das Erstellen von Programmen „menschlicher“ zu gestalten, ist das hinter Maschinensprachen liegende Kalkül das sogenannte Maschinenkalkül und das vordergründige Paradigma das imperative Programmieren. Auf dieser Ebene zeigt sich der Digitalcomputer programmiersprachlich als das, was er von seiner Hardware ist: eine Maschine, die Befehle ausführt.

2.1.1 Assembler Die ersten Digitalcomputer wurden durch Verdrahtung ihrer einzelnen Funktionseinheiten programmiert. Programmieren hieß hier: die logischen Funktionen der Bauteile

138 | 2 Assembler so miteinander zu kombinieren, dass sie Algorithmen repräsentieren.² Mit der Möglichkeit, Computern Boole’sche Ausdrücke in Form von Nullen und Einsen einzugeben, war bereits ein Schritt zur Vereinfachung der Programmierarbeit getan – selbst, wenn diese Werte mit Kippschalterstellungen (vgl. Band 1, Kap. I.6.1.2) repräsentiert wurden. Die Hardware des Computers wurde auf diese Weise von der Software getrennt: Während erstere nun unverändert bleiben konnte, versetzte letztere, je nach Wunsch, den Computer in unterschiedliche Zustände. Von den „proto-symbolischen“ Maschinensprachen hin zu für den Programmierer vergleichsweise komfortabel nutzbaren Assembler-Sprachen³ war es historisch dann nur ein kleiner Schritt. Sogenannte Assemblierer⁴ übernahmen die Aufgabe, Opcodes und Daten, die in einfach zu merkenden Mnemonics (griech. mn¯emoniká – Gedächtnis) notiert wurden, in die für den Computer verständlichen binären Zustände zu übersetzen. Sie ermöglichten es so, Programme zu strukturieren und für (menschliche) Leser nachvollziehbarer zu gestalten. Überdies wurden sukzessive zusätzliche Funktionen in die Assemblierer integriert, die das Programmieren komfortabler gestalteten, ohne dafür die „Maschinenebene“ verlassen zu müssen. So ermöglichen beispielsweise Pseudo-Opcodes Sprungziele (die in Maschinensprache immer numerische Speicheradressen sein müssen, vgl. 2.2.4) als alphanumerische „Labels“ zu kennzeichnen, spezifische Speicheradressen für bestimmte Werte zu reservieren, (ähnlich wie Variablen) mit einem Namen zu versehen und im Programm zu nutzen, den Programmzähler (vgl. Kap. 2.2.3) zu manipulieren oder Daten im Programm als Byte-Wertetabellen zu hinterlegen. Die Hauptaufgabe von Assemblierern ist jedoch das Übersetzen von mnemonischen Assemblerprogrammen in Maschinensprache. Dieser Prozess findet – je nach Komplexität des Assembler-Dialekts (und der verwendeten Pseudo-Opcodes) – in mehreren Schritten statt: Zunächst werden symbolische Adressen (Variablen, Konstanten), Label etc. in reale Adressen übersetzt und dort Inhalte (etwa von Datentabellen) hinterlegt. Im zweiten Schritt werden die Mnemonics, Adressangaben und Daten in Maschinensprache übersetzt. Bei der Bearbeitung überprüfen die meisten Assemblierer die syntaktische Korrektheit von Programmen und ob Daten und Adressen in den korrekten Formaten und Intervallbereichen angegeben wurden. Tauchen hier keine Fehler auf, die zum Abbruch des Assemblier-Vorgangs führen, erzeugt der

2 Ein Beispiel hierfür ist die Programmierung des ENIAC, Mitte der 1940er-Jahre (vgl. Kapitel 1.3 und Goldstein & Goldstein 1973). 3 Der früheste Assembler entstand ab 1948 von Nathaniel Rochester für den IBM-701 (vgl. Rochester 1953). Zur Geschichte der Assembler-Programmierung: http://uva.ulb.ac.be/cit_courseware/asm/asm _1.htm (Abruf: 09.05.18) 4 In der Literatur wird der Begriff Assembler häufig sowohl für die Programmiersprache als auch für die Programme, die Assemblersprachen in Maschinensprachen übersetzen, benutzt. Um im Folgenden Missverständnisse zu vermeiden, wird für die Übersetzungsprogramme (nach DIN 44300) der Begriff „Assemblierer“ und für die Sprache selbst „Assembler“ verwendet.

2.1 Einführung

| 139

Assembler eine Binärdatei (binary), die entweder direkt im Speicher des Computers oder auf einem Datenträger als ausführbares Programm abgelegt wird. Fehler, die nicht zum Abbruch des Assembliervorgangs führen (semantische Fehler, Laufzeitfehler), sind in einer maschinennahen Sprache häufig schwieriger zu finden und zu entfernen als in höheren Programmiersprachen. Viele Entwicklungsumgebungen stellen hierfür Debugger zur Verfügung, mit denen Programmcode etwa schrittweise ausgeführt und getestet werden kann (single step) oder Programme an bestimmten Stellen angehalten werden können (durch Setzen von break points), um die Inhalte von Registern u.a. zu überprüfen.

2.1.2 Hardwarenahe Programmierung Bei der Assembler-Programmierung befindet sich der Programmierer – anders als bei Hochsprachen – im direkten Dialog mit der Computerhardware. Er muss ihre Funktionen und Idiosynkrasien für den Entwurf seines Programms kennen. Für Medienwissenschaftler ist die (konkrete) Kenntnis von Assemblerprogrammierung daher ein idealer Weg, um das Medium Computer in seinen Funktionen untersuchen und verstehen zu können. Hardwarenähe bedeutet allerdings noch mehr: Dadurch, dass keine weiteren Barrieren (wie Interpreter, Betriebssysteme etc.) zwischen dem Programm und der Computerhardware existieren, werden Assemblerprogramme besonders schnell abgearbeitet. Diese Geschwindigkeit muss vom Programmierer nicht selten antizipiert werden, etwa, wenn der Computer taktgenaue Operationen durchführen soll oder der Programmierer sein Programm für die Nutzung durch einen Anwender mit Warteschleifen (vgl. Kap. 2.5.1) „ausbremsen“ muss. Die Geschwindigkeit von Assemblerprogrammen rührt zu einem Teil auch daher, dass in dieser Sprache entwickelte Programme oft wesentlich kleinere ausführbare Dateien erzeugen als Programme in höheren Sprachen. Assemblerprogramme sind kompakter als funktionsgleiche Kompilate von hochsprachlichen Programmen, weil ihre Befehle nicht selbst wiederum kleine Maschinensprache-Routinen darstellen, sondern unmittelbar eine Hardware-Struktur des oben erwähnten Mikroprogramms aktivieren. Dieses Mikroprogramm gehört zu den Bestandteilen der CPU, die im Folgenden kurz vorgestellt werden.

2.1.3 Aufbau einer CPU Die Zentraleinheit eines Digitalcomputers (Central Processing Unit, CPU) befindet sich in modernen Mikrocomputern auf einem monolithischen Baustein – dem Mikroprozessor (oft mit μP oder uP abgekürzt). Solche Bausteine werden seit Anfang der

140 | 2 Assembler 1970er-Jahre produziert⁵ und haben seither wesentlich zur Vergünstigung und Verbreitung der Computertechnologie beigetragen. CPUs stellen das „Herzstück“ eines Mikrocomputers dar. Im Prinzip lässt sich eine CPU (abgesehen von der Spannungsversorgung und dem Taktgeber) ohne weitere Hardware betreiben (vgl. Band 4, Kap. II) – aus ihrer „Perspektive“ gehören alle an sie angeschlossenen Bausteine eines Computers (RAM, ROM, I/O-Bausteine etc.) bereits zur Peripherie. Abb. 2.1 zeigt den Aufbau der im Folgenden behandelten 8-Bit-CPU MOS 6502. Darauf gekennzeichnet sind die einzelnen Funktionseinheiten. Die markantesten Strukturen bilden:

Abb. 2.1: Die-Foto der 6502

5 Auch frühere Systemarchitekturen (Minicomputer, Mainframes) verfügten über eine CPU. Diese war jedoch auf mehrere Bausteine verteilt – im Extremfall als diskrete Schaltung (mit Relais, Röhren oder Transistoren) realisiert. Mit Erfindung der CPU „on a chip“ wurden die wesentlichen Teile der Zentraleinheit auf einem Baustein zusammengefasst: Rechenwerk (mit ALU), Steuerwerk, Mikroprogramm, Register und (bei modernen CPUs) weitere basale Funktionseinheiten.

2.1 Einführung

|

141

– das Mikroprogramm: fixierte Schaltnetze, die die Bestandteile der Opcodes repräsentieren – die Register: wenige Bit große interne Speicher, die zu verarbeitende Daten aufnehmen – die Arithmetisch-Logische Einheit (ALU): hier finden die Rechenoperationen statt – der Program Counter: das Befehlsregister; ein Speicher, der die Adresse des aktuellen Befehls vom laufenden Programm enthält – die Kontrolllogik: das Steuerwerk der CPU, in welchem deren verschiedene Funktionen koordiniert werden – die Busse: Verbindungsleitungen zwischen den genannten Funktionseinheiten Das Foto ist stark vergrößert. Der Siliciumchip ist 3,9 ⋅ 4,3 mm groß. Auf dieser Fläche befinden sich circa 3500 Transistoren, die alle genannten Funktionen realisieren. Im Vergleich zu modernen CPUs ist die erstmals 1975 erschienene 6502 noch sehr „weiträumig“ angelegt; heute werden auf wesentlich kleineren Flächen mehrere Milliarden Transistoren verbaut. Der Chip ist in einem Kunststoffgehäuse untergebracht, aus dem alle Leitungen als Pins ausgeführt sind. Abb. 2.2 zeigt den IC als DIP-Baustein und daneben (Abb. 2.3) dessen Pin-Belegungen.

Abb. 2.2: Die 6502 als integrierte Schaltung (IC)

Abb. 2.3: Belegung der einzelnen IC-Pins

Die CPU ist zwar der zentrale aber nur ein elektronischer Baustein, der für einen Computer benötigt wird. Bevor der MOUSE-Computer, in welchem diese CPU implementiert ist, vorgestellt wird, sollen die Funktionen der MOS 6502 beschrieben werden.

142 | 2 Assembler

Abb. 2.4: Funktionsdiagramm 6502

2.2 Funktionen Abb. 2.4 zeigt ein Funktionsdiagramm der CPU. Solche Diagramme empfehlen sich gerade für den Programmieranfänger stets im Blick zu behalten, um einen Überblick über die Abläufe in der CPU zu gewähren.

2.2.1 Die Busse Die einzelnen Funktionseinheiten werden durch drei verschiedenen Busse verbunden. Der Datenbus der 6502 verbindet die ALU mit den drei Registern (s.u.) und ist 8 Bit breit – kann also Werte zwischen 000000002 (010 ) und 111111112 (25510 ) transportieren. Auf dem Datenbus werden die Daten für die Berechnung und Speicherung transportiert; er führt an 8 Leitungen aus der CPU (vgl. Abb. 2.3: D0-D7) hinaus zum RAMSpeicher und zu den I/O-Bausteinen. Damit die CPU die korrekte Adresse für das Lesen und Schreiben der Daten benutzen kann, muss diese ebenfalls intern generiert und auf dem Adressbus transportiert werden (vgl. Abb. 2.3: A0-A15). Dieser Bus ist 16 Bit breit, 16 kann also Werte von 0 bis 2 -1 (65535) transportieren und damit einen Speicher von 64 Kilobyte adressieren. Der (im Funktionsdiagramm nicht aufgeführte) Steuerungsbus transportiert innerhalb der CPU die Signale, die einzelne Funktionen aktivieren (vgl. Band 1, Kap. I.6.4). Da er für den Programmierer nicht erreichbar ist, spielt seine Funktion im Folgenden keine Rolle.

2.2 Funktionen

| 143

2.2.2 Die Arithmetisch-Logische Einheit (ALU) Die Arithmetisch-Logische Einheit der 6502 hat zwei 8 Bit breite Eingänge und einen 8 Bit breiten Ausgang. Einer ihrer Eingänge ist fest mit dem Akkumulator (A-Register, s.u.) verbunden. Der andere Eingang liegt am Datenbus und kann daher Daten aus den anderen Registern oder dem RAM-Speicher in die ALU transportieren. In der ALU werden alle logischen und arithmetischen Opcodes ausgeführt und auf die Daten angewendet. Der Ausgang der ALU ist sowohl mit dem Akkumulator als auch mit Adressbus verbunden, denn in der ALU finden auch Adressberechnungen statt.

2.2.3 Die Register Register sind CPU-interne Flip-Flop-Speicher und dienen der schnellen Verarbeitung von Daten. In ihnen werden Werte zwischengespeichert, die aus dem RAM oder den anderen Registern kommen oder dorthin geschrieben werden sollen. Die meisten Mikroprozessoren verfügen über mehrere und unterschiedlich große Register für verschiedene Aufgaben. Die 6502 besitzt „nur“ sechs Register, von denen dem Programmierer drei (A, X, Y) für die Datenverarbeitung zur Verfügung stehen und sehr vielseitig einsetzbar sind.⁶ Die anderen drei Register (PCL/H, SP und P) speichern Adressen und Statusinformationen: – Der Akkumulator (Akku) ist 8 Bit groß, direkt mit der ALU verbunden und nimmt deren Ergebnisausgaben auf. Viele Opcodes beziehen sich implizit auf Inhalte des Akkumulators. – Das X-Register und das Y-Register sind zwei ebenfalls 8 Bit große Indexregister, die sowohl als Datenspeicher als auch als Register genutzt werden, welche Werte enthalten, mit denen Adressen arithmetisch manipuliert werden können (daher der Begriff „Index“ im Namen). – Der Program Counter (PCL/PCH) ist ein 16 Bit großes Register, das die RAM-Adresse des aktuell zu verarbeitenden Befehls oder Datums enthält. Der Program Counter kann durch Sprungbefehle, Adress-Arithmetik (in X und Y) sowie durch PseudoOpcodes manipuliert werden, um das Programm an einer gewünschten Stelle fortzusetzen. Andernfalls wird er nach der Ausführung eines jeden Befehls auf die nächste Adresse des Programms inkrementiert. – Der Stack Pointer (SP) ist ein 8 bit großes Register, dem ein 9. Bit mit dem Wert 1 vorgeschaltet ist, sodass die 8 Bits die Adressen innerhalb der ersten RAM-Page (s. u.) enthalten. Dieser RAM-Bereich ist ein Stapelspeicher (vgl. Band 1, Kap. II.5.2.2), der von bestimmten Stack-Opcodes genutzt wird.

6 Die Tatsache, dass die meisten Opcodes der 6502 für alle Register und Adressierungsarten zur Verfügung stehen, ist ein Maß für die hohe Orthogonalität der CPU.

144 | 2 Assembler – Das Statusregister (P) ist 8 Bit groß und enthält Status-Bits (Flags), die bestimmte Zustände nach der letzten Operation der CPU enthalten. Diese Bits können z.B. bei Verzweigungsbefehlen als Bedingungen abgefragt werden. Das P-Register kann durch bestimmte Opcodes manipuliert werden. (Seine Belegung zeigt Tabelle 2.1.) Tab. 2.1: Das Statusregister (P) der 6502 7 Negativ (N)

6 Overflow (V)

5 1

4 Break (B)

3 Decimal (D)

2 Interrupt (I)

1 Zero (Z)

0 Carry (C)

2.2.4 Zahlensysteme: Dual, Dezimal, Hexadezimal Als Exkurs sei an dieser Stelle eine Lektion über die in Assembler nutzbaren Zahlensysteme eingeschoben. Sie basiert auf der Kenntnis des Dualzahlensystems (Band 1, Kap. I.5) und stellt eine Erweiterung dessen dar.⁷ Die 6502 kann Daten und Adressen im dezimalen und hexadezimalen System entgegennehmen. Daten im hexadezimalen System sind durch ein vorangestelltes $-Zeichen (Präfix) erkennbar. Einige Assemblierer erlauben zudem die Werteübergabe im Dualzahl-Format.⁸ Das Hexadezimal-Zahlenformat (kurz Hex-Format genannt und mit einem tiefgestellten HEX oder einer 16 im Index markiert) hat sich insbesondere bei der Programmierung maschinennaher Sprachen als sehr nützlich erweisen. Das liegt vor allem daran, dass Speicher von Mikrocomputern in „8er-Einheiten“ organisiert sind: 8 Bit sind 1 Byte; 1024 Byte (2 ⋅ 8 ⋅ 8 ⋅ 8 Bit) sind ein Kilobyte usw. Die Bussysteme sind diesen sogenannten Wortbreiten angepasst, weshalb von 4-, 8-, 16-, 32- oder 64-Bit-Computern gesprochen wird. Wie der Name bereits andeutet, nutzt das Hexadezimalsystem 16 Ziffern (vgl. Tabelle 2.2). Die Affinität zwischen Dual- und Hexadezimalzahlen bei Digitalcomputern zeigt sich im Übergang von einer Hexadezimal-Stelle zur nächsten: Die ersten 16 Ziffern (0F) füllen ein Halbbyte bzw. Nibble (4 Bit). Ab der Zahl 16 findet ein Übergang ins zweite Halbbyte statt. Zweistellige Hexadezimalzahlen lassen sich also leicht als Dualzahlen kodieren, indem jede Hex-Ziffer als Halbbyte kodiert wird. Diese Übersetzbarkeit kommt insbesondere der Adressrechnung zugute. Die 16 Bit großen Adressen verteilen sich auf die Hex-Zahlen 000016 –FFFF16 . Jede der vier Hex-Ziffern einer solchen Adresse ist als ein Dual-Nibble notierbar. Eine Adresse wie E09416 lässt sich damit wie in Tabelle 2.3 dual darstellen. 7 Aus Platz- und Relevanzgründen werden Oktalzahlen hier nicht diskutiert. Das Oktalzahlen-System (zur Basis 8) ist insbesondere in Minicomputer-Systemen genutzt worden und findet sich auch noch bei schalterprogrammierbaren Mikrocomputern wie dem Altair 8800 (vgl. Coy 1988:80 ff.). 8 Der unten vorgestellte Assemblierer des MOUSE-Computers nimmt ausschließlich Hexadezimalzahlen entgegen, weswegen das $-Präfix bei ihm optional ist.

2.2 Funktionen

| 145

Tab. 2.2: Dezimal – Dual – Hexadezimal

Tab. 2.3: Nibble-Darstellung einer Adresse

Dezimal 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ... 31 32 ... 254 255

hexadezimal dual

Dual 0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111 0001 0000 ... 0001 1111 0010 0000 ... 1111 1110 1111 1111

Hexadezimal 0 1 2 3 4 5 6 7 8 9 A B C D E F 10 ... 1F 20 ... FE FF

E 1110

0 0000

9 1001

4 0100

Die Umrechnung vom Dezimal- ins Hexadezimal-System erfolgt durch Multiplikation der Hex-Ziffern mit der Basis 16: Beispiel: E09416 E 0 9 4

+ 0 + 14 + 224 + 3593

• • • •

16 16 16 16

= 14 = 224 = 3593 = 57492

E09416 = 5749210

Die Umrechnung vom dezimalen ins hexadezimale Zahlensystem kann auf dem Vergleich des Stellenwertsystems mittels Modulo-Rechnung (vgl. Band 1, Kap. I.5.2) erfolgen:

146 | 2 Assembler Beispiel: 5749210 57492 3593 224 14

: : : :

16 16 16 16

= 3593 = 224 = 14 = 0

Rest Rest Rest Rest

4 9 0 14 (hexadeizmal: E)

5749210 = E09416

2.2.5 Adressen und Speicher Damit die CPU mit der „Außenwelt“ kommunizieren kann, benötigt sie spezifische Informationen, wohin Daten geschrieben und woher sie gelesen werden sollen. Diese Informationen heißen Adressen und beziehen sich auf 1 Byte große Zellen innerhalb des Adressraums (zur technischen Realisierung vgl. Band 1, Kap. II.5.2). Die MultiplexerBausteine (vgl. Abb. 2.4 sowie Band 1, Kap. I.6.4) verknüpfen hierzu die 8-Bit-Inhalte des Program Counters zu einer 16-Bit-Zahl, die als Adresse an den Adressbus weitergeben wird. Diese Verknüpfung erfolgt nach dem Prinzip: Highbyte (PCH) ⋅ 256 + Lowbyte (PCL) = Adresse. Wie auch andere CPUs organisiert die 6502 den an ihr angeschlossenen Speicher (z.B. RAM) in unterschiedliche Bereiche: – 000016 –00FF16 – hier liegt die sogenannte Zeropage.⁹ Sie kann mit besonders kompakten Opcodes (die die bezogene Adresse in Form einer 1 Byte großen Adress-Information enthält, die komplett aus dem unteren Adressregister bezogen wird) angesteuert werden. In der Zeropage werden vom Programmierer häufig Variablen-Werte und sogenannte Pointer bzw. Vektoren (zwei aufeinander folgende Speicherinhalte, die auf andere Adressen verweisen) hinterlegt. – 010016 –01FF16 – die Page 1 wird von der 6502 als Processor Stack benutzt. In ihr werden beispielsweise Registerinhalte gesichert (vgl. 2.4.3). Sie sollte daher nicht für Daten oder Programmcode benutzt werden, weil diese entweder die Inhalte des Stacks überschreiben oder bei Aufruf von Stack-Opcodes selbst überschrieben werden. Der Stack wird von oben nach unten gefüllt: Das erste Element liegt in 01FF16 , das letzte Element in 010016 . Die Stack-Befehle greifen nach dem Lastin-first-out-Prinzip (LiFo) auf den Stack zu. Der Stack Pointer wird von der CPU automatisch verwaltet und verweist stets auf die nächste freie Stack-Speicherzelle. Zeigt der Stackpointer auf die Adresse (01)0016 , so wird er auf FF gesetzt und er-

9 Der Speicher von 6502-Systemen ist in sogenannte „Pages“ von 256 Byte Größe unterteilt. Diese Einteilung erleichterte die Adressgenerierung und lässt sich aus den Hexadezimal-Werten leicht ablesen.

2.2 Funktionen

| 147

neut (von oben herab) beschrieben, wobei alte Stackinhalte überschrieben werden. – 020016 –FFF916 : Dieser circa 65000 Byte große RAM-Bereich¹⁰ kann vom Programmierer im Prinzip für seine Anwendungen und Daten genutzt werden. (Einzig das systemspezifische I/O-Mapping kann Teile davon „verdecken“ – siehe unten.) – FFFA16 –FFFF16 : Diese Adressen werden bei den unterschiedlichen Interrupts angesteuert. Sie enthalten die Pointer, welche auf Speicherbereiche verweisen, die bei Interrupts angesteuert werden sollen.

2.2.6 Memory-mapped I/O und ROM Wie bereits geschrieben, kann die 6502-CPU nur über ihren Adress- und Datenbus mit der Peripherie kommunizieren. Während über den Datenbus die zu verarbeitenden Befehle und Daten bidirektional übermittelt werden, werden über den Adressbus ausschließlich Adressen ausgegeben, die bestimmte Speicherzellen im RAM adressieren, in denen die Befehle und Daten enthalten sind. Wie ist diese CPU nun in der Lage mit anderer Peripherie (Tastatur, Monitor, Drucker, ...) zu kommunizieren? Hierfür wird bei der 6502 das sogenannte Memory-Mapped-I/O-Verfahren eingesetzt. Dabei werden bestimmte RAM-Adressbereiche „überdeckt“ (mapped) und können nicht mehr als Speicher genutzt werden. Anstelle dessen werden Schreib/Lese-Vorgänge, die an diese Adressen gerichtet sind, an die jeweiligen I/O-Bausteine weitergeleitet. Für 6502-Computer-Architekturen gibt es unterschiedliche solcher Bausteine, die für serielle oder parallele Kommunikation genutzt werden können. In der hier vorgestellten Rechnerarchitektur findet der Baustein Motorola 6850¹¹ Einsatz, der die serielle Kommunikation zwischen dem 6502-Computer und dem angeschlossenen Terminal-Computer verwaltet. Dieser Baustein ist auf die RAM-Adresse 800016 „gemappt“. Der MOUSE-Computer bringt einige Programme auf einem ROM-Baustein mit, die direkt nach dem Start des Computers zur Verfügung stehen. Diese Software besteht aus separaten Maschinensprache-Programmen, die ebenfalls Speicheradressen benötigen, um angesteuert werden und interne Daten verarbeiten zu können. Die wichtigsten Software-Komponenten stellen das I/O-System MIOS und das Betriebssystem M-OS dar. Von letzterem aus wird der Assemblierer (der ebenfalls ein Programm ist)

10 Dass die 6502 maximal 64 Kilobyte RAM adressieren kann, bedeutet nicht, dass immer so viel Speicher angeschlossen sein muss. Im System, das in diesem Kapitel beschrieben wird, ist ein 32 Kilobyte großer sRAM-Baustein integriert, der über die Adressen 000016 –7FFF16 angesprochen wird. Die Adressen 800016 –FFFF16 werden vom 8 Kilobyte großen ROM belegt oder sind unbelegt. 11 http://www.classiccmp.org/dunfield/r/6850.pdf (Abruf: 17.09.2017)

148 | 2 Assembler sowie alle anderen Programme aufgerufen.¹² Um diese Programme oder Teile von ihnen ansteuern zu können, muss lediglich zu einer ROM-Adresse in diesem Bereich gesprungen werden.

2.2.7 Adressierungsarten Die Methoden, mit denen die CPU und namentlich die Opcodes auf die Register und RAM-Speicher zugreifen, werden als Adressierungsarten bezeichnet. Eine möglichst große Vielfalt an Adressierungsarten ist ein Ausweis für die Qualität eines Mikroprozessors und ermöglicht es komfortabler zu programmieren und kompakteren Code zu erzeugen.¹³ Die 6502 verfügt über neun Adressierungsarten, deren Kenntnis Voraussetzung für die effektive Programmierung in Assembler darstellt. Daher sollen sie im folgenden detailliert vorgestellt werden. Implizite Adressierung Bei der impliziten Adressierung ist das bezogene Register im Opcode enthalten. Beispiel: INX = Erhöhe den im X-Register gespeicherten Wert um 1 (das Register ist implizit im Opcode enthalten) Von Akkumulator-Adressierung spricht man, wenn sich bei der impliziten Adressierung sowohl die Quelle als auch das Ziel auf den Akkumulator beziehen. Beispiel: ASL (Ohne Angabe einer Adresse: Schiebe die Bits des im Akkumulator enthaltenen Wertes um eine Position nach links) Unmittelbare Adressierung Dem Register wird ein Wert unmittelbar übergeben. Als Marker hierfür dient das Präfix Raute (#). (Achtung: Wird die Raute vergessen, interpretiert der Assembler den angegebenen Wert als Adresse!) Beispiel: LDX #$F7 = Lade den Wert F716 in das Register X. Absolute Adressierung Die Operation wird auf eine RAM-Adresse angewendet, die als Absolutwert übergeben wird. Der Adresswert muss eine 16-Bit-Zahl sein. Beispiel: STA $17FF = Speichere den Inhalt des Akkumulators in die RAM-Adresse 17FF16 . 12 Eine Übersicht über die Funktionen des Betriebssystems befindet sich auf dem Webserver des Verlags: www.degruyter.com. 13 Aber selbst, wenn nur wenige Möglichkeiten der Adressierung von Speicherinhalten zur Verfügung stehen – wie bei der Turing-Maschine (vgl. Kap. I-1.2.2) – , lassen sich mit einem Computer dennoch alle berechenbaren Probleme berechnen.

2.2 Funktionen

| 149

Relative Adressierung Eine Verzweigungsoperation (branch) erfolgt zu einer RAM-Adresse, deren Abstand relativ zum Programmcounter¹⁴ übergeben wird. Dieser Abstand (Offset) wird als 8-BitZahl übergeben. Bei Rückwärtssprüngen muss der Offset im Zweierkomplement (vgl. Band 1, Kap. I.5.4) angegeben werden: – $00-$7f als positiver Offset, also von 0 bis 127 [0-7F16 ] (Vorwärtssprung) – $80-$ff als negativer Offset, also von -128 bis -1 [8016 –FF16 ] (Rückwärtssprung) Beispiele: BEQ $3B = Spring vorwärts zur Adresse, die sich aus der Addition Program Counter +3B16 ergibt. BNE $A2 = Spring rückwärts zur Adresse, die sich aus der Subtraktion Program Counter+ A216 (A2 ist eine negative Zahl in Zweierkomplementdarstellung) ergibt. Mittels relativer Adressierung lässt sich Programmcode sehr flexibel in unterschiedlichen Speicherbereichen unterbringen. Dies kann sinnvoll sein, wenn er häufiger modifiziert oder verschoben wird (und sich deshalb fixe Adressen oft ändern könnten) oder falls noch weitere Programme in den Speicher geladen werden sollen. Zeropage-Adressierung Die Operation bezieht sich auf eine Adresse der Zeropage (siehe oben). Beispiel: LDX $27 = Lade den Inhalt der Zeropage-Adresse (00)2716 in das Register X. (Achtung: Zeropage-Adressierung und unmittelbare Adressierung unterscheiden sich nur durch die Angabe der Raute #, die leicht vergessen werden kann!) Indizierte Adressierung Mit indizierter Adressierung lässt sich Speicher im Programm flexibel verwalten. Dies ist zum Beispiel sinnvoll, wenn bestimmte größere Speicherblöcke bearbeitet oder Sprungziele auf Basis vorheriger Berechnungen angepasst werden sollen. Der bezogenen (Basis-)Adresse wird hierzu ein Indexwert (Offset) aus dem Register X oder Y hinzuaddiert (vgl. Abb. 2.5). Beispiel: LDA $27B3,X = Lade den Inhalt der Adresse, die sich aus der Summe 27B316 und dem Inhalt des Registers X ergibt, in den Akkumulator.

14 Auch ein relativer Sprung erhöht den Program Counter um 2 Byte, daher sind es effektiv -126 bis +129 Adressen, die von dort aus angesprungen werden können.

150 | 2 Assembler

Abb. 2.5: Indizierte Adressierung – LDA 27B3,X (für X=5) überträgt den Wert xx aus 27B8 in den Akkumulator

Abb. 2.6: Indirekte Adressierung: Der Adresswert aabb wird aus den Adressen FFFE und FFFF geladen und als Sprungziel auf den Program Counter gelegt.

Indirekte Adressierung Hierbei wird die Adresse indirekt übergeben, indem deren Lowbyte-Anteil aus der angegebenen Adresse ausgelesen wird. Ihr Highbyte-Anteil befindet sich in der darauffolgenden Adresse und wird automatisch ergänzt (vgl. 2.6).¹⁵ Beispiel: JMP ($FFFE) = Spring zur Adresse, die sich wie folgt ermittelt: In Adresse FFFE16 steht der Lowbyte-Anteil des Sprungziels. In Adresse FFFF16 steht der Highbyte-Anteil des Sprungziels. (Das Sprungziel berechnet sich aus dem Inhalt von FFFE16 + 256 ⋅ dem Inhalt von FFFA16 .) Indirekte X-indizierte Zeropage-Adressierung Bei dieser Adressierungsart wird der Inhalt einer Zeropage-Adresse als Lowbyte und der Inhalt der ihr nachfolgenden Zernage-Adresse als Highbyte genutzt. Zusätzlich zu der so ermittelten Adresse wird der Inhalt des Indexregisters X addiert. Das Ergebnis aus ([LB+X]+256 ⋅ [HB+X]) ergibt das Sprungziel (vgl. 2.7 li.). Beispiel: LDA ($1B,X) = Lade den Inhalt der RAM-Adresse, die sich aus der Zeropage-Adresse 1B + X (Lowbyte) und 1C + X (Highbyte) ergibt, in das Register A.

15 Diese Lese-Reihenfolge von (zuerst) Lowbyte- und (danach) Highbyte-Anteil einer Adresse wird Little Endian genannt. Einige Prozessoren verfahren genau anders herum (Big Endian, u.a. 6800 und 68000 von Motorola). Bei der 6502 zeigt sich hier ein Hardware-Fehler: Ein indirekter Sprung JMP($40FF) ermittelt das Sprungziel nicht (wie es korrekt wäre) aus den Adressen 40FF16 und 410016 , sondern aus den Adressen 40FF16 und 400016 . Dieser Design-Flaw wurde im 65C02 (der im MOUSEComputer verbaut wurde) behoben.

2.3 Der Befehlssatz der 6502

| 151

Abb. 2.7: Indirekte indizierte Zeropage-Adressierung – vorindiziert (li.) und nachindiziert (re.)

Indirekte Y-nachindizierte Zeropage-Adressierung Bei Verwendung des Y-Registers für die indirekte indizierte Zeropage-Adressierung ergibt sich eine veränderte Arithmetik: Hier wird zuerst die RAM-Adresse aus der angegebenen Zeropage-Adresse (Lowbyte) und der ihr nachfolgenden Adresse (Highbyte) ermittelt und erst dann zu der daraus gebildeten 16-Bit-Adresse der Inhalt des Y-Registers addiert (vgl. Abb. 2.7): (LB+256 ⋅ HB)+Y. Beispiel: LDA ($2B),Y = Inhalt von 2B und 2C ergeben die Adresse, zu der der Inhalt von Y addiert wird. Zwei Hinweise seien an dieser Stelle gegeben: Die beiden indirekten (und) indizierten Zeropage-Adressierungen unterscheiden sich durch die Verwendung des Indexregisters (entweder X oder Y) sowie durch das Setzen der Klammer (Angabe des Indexregisters innerhalb oder außerhalb der Klammer). Bei indizierten ZeropageAdressierungen kann die Adresse $FF zur Page 1 übersprungen werden. LDA ($FF),Y (für beispielsweise Y=2) lädt dann jedoch nicht den Inhalt von Page-1-Adresse (01)0116 , sondern den von Zeropage-Adresse (00)0116 in das Register A (Überlauf).

2.3 Der Befehlssatz der 6502 Die 6502-CPU verfügt über maximal 256 mögliche Opcodes.¹⁶ Implementiert sind davon 151; 105 sind ungenutzt.¹⁷ Der Befehlssatz lässt sich funktional wie folgt differenzieren: – Lade-, Transfer- und Speicherbefehle (LDA, TYA, STX, ...) – Arithmetische Befehle (ADC, DEC, INX, ...)

16 Neben der Datenbus-Breite und der Registergröße ist dies das dritte Merkmal des „echten“ 8-BitProzessors. Andere 8-Bit-CPUs, wie Zilogs Z80, verfügen über 16-Bit-Register und (mittels Präfix erweiterte) umfangreichere Befehlssätze. 17 Von diesen ungenutzten Opcodes sind einige sogenannte „illegale Opcodes“, die aufgerufen werden können und Funktionen realisieren, jedoch von den Ingenieuren nicht intendiert waren. Spätere Varianten der 6502 (CMOS 65C02) sperren den Zugriff auf diese Opcodes. Im vorliegenden System ist solch eine CMOS-Variante des Prozessors verbaut. Diese verfügt über 212 „legale“ Opcodes. (Vgl. http://www.pagetable.com/?p=39),Abruf:16.05.2018)

152 | 2 Assembler Tab. 2.4: ADC Daten/Adresse – Dual-Format: 011xxx01 xxx

Opcode

Adressierung

Größe (Byte)

Taktzyklen

000 001 010 011 100 101 110 111

6116 6516 6916 6D16 7116 7516 7916 7D16

(indirekt, X) Zeropage Unmittelbar Absolut (indirekt,Y) Zeropage,X Absolut,Y Absolut,X

2 2 2 3 2 2 3 3

6 3 2 4 5 4 4 4

– – – – –

Logische und Bit-Befehle (CMP, EOR, LOL, BIT, ...) Verzweigungs- Sprung- und Rücksprungbefehle (BEQ, BMI, JMP, JSR, RTS, ...) Stack-Befehle (PHP, PHA, ...) Status-Register-Operationen (CLC, SEC, SEI, ...) sonstige (NOP, BRK)

Aufgrund des hier zur Verfügung stehenden Raumes kann keine detaillierte Diskussion des Befehlssatzes erfolgen – diese wird sowohl durch die vielfältig existierende Literatur (z.B. Zaks 1986:95-175 und 343-384) als auch durch die offiziellen Datenblätter der Prozessorhersteller (vgl. MOS 1975) vorgenommen. Für die AssemblerProgrammierung sollte eine solche Quelle als Referenz- und Nachschlagewerk verwendet werden. Anstelle dessen findet sich auf der folgenden Seite eine Tabelle (vgl. Abb. 2.8), in der die Opcodes ihren Hexadezimal-Werten zugewiesen sind. In Programmen verbraucht jeder Opcode der 6502-CPU 1 Byte Speicher, wozu ggf. noch 1 oder 2 Byte für seine Daten/Argumente hinzukommt. Seine Ausführungszeiten (gemessen in Taktzyklen) unterscheiden sind jedoch zum Beispiel¹⁸ abhängig von der gewählten Adressierungsart. In wie vielen Taktzyklen ein Befehl abgearbeitet wird (wie viele Takte er „verbraucht“), ist der Befehlsbeschreibung als Information ebenso beigegeben, wie, welche Status-Bits durch ihn verändert werden (können). Ebenso geben die meisten Übersichten an, welchen Hexadezimal- und Dualzahlenwert ein Opcode besitzt. Aus letzterem lässt sich z.B. zeigen, wie bezogene Register in die Mikroprogramm-Struktur des Befehls implementiert sind. Dies zeigt Tabelle 2.4 am Beispiel des ADC-Opcodes (Add with Carry, vgl. Zaks 1986:107 f.).

18 Zaks (1987:51-57 und 65-87) bietet eine sehr detaillierte und lesenswerte Beschreibung der internen Prozesse der Z80-CPU bei der Abarbeitung von Befehlen.

2.3 Der Befehlssatz der 6502

|

153

Abb. 2.8: Die 65C02-Opcodes. Legende: LB = Lowbyte des Opcodes; HB = Highbyte des Opcodes; * = 6502-Opcodes mit neuen Adressierungsarten; • = Neue Opcodes; a = Akkumulator; A = Akkumulator-Adressierung; zp = Zeropage; r = relative Adressangabe; s = Stack; x = Indexregister X; y = Indexregister Y; i = implizite Adressierung; () = indirekte Adressierung; # = absoluter Wert

154 | 2 Assembler

Abb. 2.9: Der MOUSE-Computer

2.4 Der MOUSE-Computer Zur Programmierung in Assembler wird hier der Selbstbau-Computer (dessen Konstruktion in Band 4, Teilband II vorgestellt wird) MOUSE¹⁹ (vgl. Abb. 2.9) verwendet. Für diejenigen, die über keinen „realen“ MOUSE-Computer verfügen, existiert die Emulation MOUSE2Go²⁰ desselben für Arduino-Computer. Ungeachtet der medienwissenschaftlichen Brisanz der Unterscheidung von realer Hardware und ihrer Software-Emulation werden beide Systeme im Folgenden synonym behandelt.

2.4.1 Aufbau MOUSE verfügt über eine W65C02-CPU der Firma Western Design Center²¹ (mit 1,8432 Megahertz getaktet). Die Grundausführung besitzt 32 Kilobyte RAM und ein 8 Kilobyte großes ROM²². Als I/O-Baustein verwendet der Computer einen Motorola M6850 ACIA (Asynchronous Communications Interface Adapter).²³

19 https://github.com/mkeller0815/MOUSE (Abruf: 16.05.2018) 20 https://mkeller0815.github.io/MOUSE2Go/ (Abruf: 16.05.2018) 21 http://www.westerndesigncenter.com/wdc/documentation/w65c02s.pdf (Abruf: 16.05.2018) 22 Hierbei handelt es sich um ein EEPROM (Electronical Erasable Read Only Memory, vgl Band 1, Kap. II.5.2.4), dessen Inhalte mithilfe einer besonderen Software modifiziert werden können – etwa, um die darauf befindlichen Programme zu aktualisieren oder weitere darauf zu installieren. 23 http://www.classiccmp.org/dunfield/r/6850.pdf (Abruf: 16.05.2018)

2.4 Der MOUSE-Computer

| 155

Tab. 2.5: Memory Map von MOUSE Start

Ende

000016 010016 020016 800016 E00016 FFFA16

00FF16 01FF16 7FFF16 800116 FFF916 FFFF16

Funktion Zeropage (wird teilweise der Software im ROM benutzt) Stack frei nutzbarer RAM-Speicher (32255 Byte) I/O ROM (8 Kilobyte) Interrupt- und Reset-Sprungvektoren

2.4.2 Speicherorganisation Die Memory Map des MOUSE-Computers stellt Tabelle 2.5 im Groben dar. Der Computer führt nach dem Start/Reset das Betriebssystem M-OS aus, indem der Reset-Vektor (FFFC16 und FFFD16 ) angesprungen wird. Für die Programmierung benötigen wir dieses sowie das Programm „Assembler“. Die von M-OS, MIOS und Assembler genutzten Speicherbereiche der Zeropage (0016 –0F16 ) und des Adressraums zwischen 020016 und 03FF16 sollten für selbst geschriebene Programme mit Vorsicht genutzt werden, da deren Inhalte durch das Betriebssystem und andere Programme überschrieben werden könnten. Da aber immer nur ein Programm aktiv ist und auf diese Speicherbereiche zugreift, sind Abstürze durch Nutzung dieser Speicherbereiche nicht möglich.

2.4.3 Besondere Adressen im ROM Die im MOUSE implementierten Programme sind selbst in Maschinensprache geschrieben und enthalten Routinen, die auch vom Assembler-Programmierer genutzt werden können. Hierzu hat der Autor Einsprungadressen (Jump Tables) im ROM²⁴ abgelegt, in denen die Adressen solcher Routinen hinterlegt sind. Während sich – aufgrund von Weiterentwicklungen der Programme – die absoluten Adressen der Routinen ändern können, bleiben die Jump-Table-Adressen, in denen die jeweiligen Startadressen dieser Routinen hinterlegt sind, unverändert. Daher sollten diese – und nicht die absoluten Adressen der Routinen selbst – mit dem Befehl JSR (Jump To Subroutine) angesprungen werden. Ein Jump-Table-Eintrag beginnt immer mit dem Opcode für JMP (4C16 ) und nachfolgende zwei Bytes für den Highbyte- und LowbyteAnteil der anzuspringenden Adresse. Einige dieser Routinen sind im Folgenden aufgeführt:

24 https://github.com/mkeller0815/MOUSE/blob/master/Source/M-OS/labelmap.txt 16.05.2018)

(Abruf:

156 | 2 Assembler – $E000: gibt einen String aus, dessen Startadresse in den Adressen $0000 (LB) und $0001 (HB) hinterlegt ist. Die Ausgabe wird mit „0“ gestoppt. – $E003: gibt Zeichen aus (der ASCII-Code des Zeichens befindet sich im Akkumulator). – $E006: liest ein Zeichen ein (der ASCII-Code des Zeichens befindet sich danach im Akkumulator). – $E00C: Gibt den Inhalt des Akkumulators als 8-Bit Dualzahl aus. – $E00F: Gibt den Inhalt des Akkumulators als zweistellige Hexadezimalzahl aus. – $E012: Gibt den Inhalt des Akkumulators als einstellige Hexadezimalziffer aus. – $E094: Rücksprung in das Betriebssystem. Der Sprungvektor liegt an der Adresse $FFFC. Selbstgeschriebene Programme sollten mit JPM($FFFC) enden, damit der MOUSE-Computer nicht abstürzt. Experiment II.1: Betriebssystem-Routine nutzen 1 2 3

0400 LDA #$41 ; ASCII-Wert von 'A' in Akkumulator 0402 JSR $E003 ; Akkumulatorinhalt als Character ausgeben 0405 JMP ($FFFC) ; Ende (Ruecksprung ins Betriebssystem)

Nach²⁵ der Eingabe des Programms kann es mit „g 0400“ vom M-OS aus gestartet werden. Dann wird ein „A“ auf dem Bildschirm ausgegeben. Die Nutzung fertiger Routinen aus dem Betriebssystem wird von „Bare Metal Codern“ (Programmierer, die ihren Code komplett selbst entwickeln) oft kritisiert: Hierdurch würden Programme unverständlich und unsicher, die verwendeten Routinen besäßen häufig einen Overhead an nicht benötigten Funktionen und das grundsätzliche Verständnis für die Funktionsweise (im Beispiel etwa die Kommunikation der CPU mit dem seriellen I/O-Baustein) bliebe aus. Die Nutzung von fremden CodeBestandteilen kann andererseits jedoch die Programmentwicklung (gerade bei Programmieranfängern) vereinfachen und der Analyse²⁶, Kürzung und Optimierung der genutzten Routinen für eigene Zwecke steht nichts im Wege. Programmieren in Form von Hacken fremden Codes ist eine adäquate Rezeptionsform und -praxis von Code.

25 Bitte lesen Sie vor der Eingabe zuerst die Angaben zu den Besonderheiten des Assemblierers auf der nächsten Seite! 26 Hierfür stellt MOUSE einen Disassembler zur Verfügung, der im Speicher befindlichen, ausführbaren Code als mnemonischen Assembler-Code auf dem Bildschirm ausgibt. Er kann mit „d aaaa“ (aaaa=Startadresse) von M-OS aus aufgerufen werden.

2.5 Programmierung

|

157

Abb. 2.10: Startbild des Assemblierers

2.5 Programmierung Zur Programmierung des MOUSE-Computers in Assembler kann der dort eingebaute Assemblierer genutzt werden. Dieser verfügt zwar über nur wenige Funktionen, vereinfacht die Programmierung aber dadurch, dass er direkt im Speicher des Computers arbeitet.²⁷ Er wird vom M-OS aus aufgerufen mit dem Befehl a [ADRESSE] ADRESSE ist ein konkreter vierstelliger Hexadezimal-Zahlenwert, der die Startadresse des zu schreibenden Assembler-Programms übergibt. Diese muss im frei nutzbaren RAM (siehe Kap. 2.4.2) liegen. Danach meldet sich der Assemblierer wie in Abb. 2.10 zu sehen. Nun kann das Programm eingegeben werden. Der Assemblierer ermittelt automatisch die Byte-Länge der gerade eingegebenen Anweisung und berechnet daraus bei Drücken von „Return“ die nächste Adresse des Programms.

27 Andere Assemblierer (wie zum Beispiel der für die 6502 oft genutzte DASM. http://dasm-dillon.sou rceforge.net/, Abruf: 16.05.2018) übersetzen Textdateien mit Assembler-Code in Maschinensprache. Solche Assembler bieten einen großen Funktionsumfang und zahlreiche Pseudo-Opcodes. Für größere Projekte sollte daher auf diese Entwicklungsumgebungen zurückgegriffen werden. Wie damit entwickelte Programme auf den MOUSE-Computer übertragen werden, beschreibt die Anleitung unter www.degruyter.com. Eine Auswahl an Assemblierern listet die Seite 6502.org (http://6502.org/tools/a sm/, Abruf: 13.09.2017).

158 | 2 Assembler Folgende Besonderheiten sind bei der Nutzung des eingebauten Assemblierers zu berücksichtigen: – Der Assemblierer unterstützt keine Pseudo-Opcodes. – Kommentare können ebenfalls nicht mit eingegeben werden. (In den hier diskutierten Programmbeispielen dienen sie allein der Information des Lesers und können nicht mit eingetippt werden.) – Wie auch das M-OS unterstützt der Assemblierer weder die Pfeil- noch die Backspaceoder Delete-Tasten. Falsche Angaben können nur korrigiert werden, indem man den Assemblierer beendet (siehe unten) und mit a ADRESSE (des falschen Befehls) noch einmal startet und den Code erneut korrekt eingibt. – Der Assemblierer prüft die syntaktische Richtigkeit des Codes während der Eingabe und unterbricht ggf. mit einer Fehlermeldung. – Relative Adressen für Branch-Befehle können entweder als Zweierkomplement oder als absolute Adresse angegeben werden. (Letzteres stellt eine Besonderheit dieses Assemblierers dar und wird von anderen Entwicklungssystemen ggf. nicht unterstützt.) Nach Eingabe der letzten Programmzeile (und Drücken der Return-Taste) kann der Assemblierer durch Drücken von „Escape“ beendet werden. Zur Überprüfung lässt sich das eingegebene Programm auf zwei Arten aus dem Speicher auslesen und darstellen: 1. Durch Eingabe von o ADRESSE1 ADRESSE2 kann der Speicherinhalt von ADRESSE1 bis ADRESSE2 in Form von Hexadezimalzahlen ausgegeben werden. (Bei Eingabe von s ADRESSE wird nur der Inhalt von ADRESSE angezeigt. Diese Funktion ist besonders nützlich, um vom Programm veränderte Speicherinhalte zu testen.) 2. Durch Eingabe von d ADRESSE wird der Speicher ab ADRESSE disassembliert und in Form von Adressen und mnemonischem Assemblercode ausgegeben. (Diese Ausgabe kann durch Drücken von „Escape“ abgebrochen werden.) g ADRESSE startet das Programm schließlich (wobei ADRESSE die Startadresse des Programms sein muss).

2.5.1 Warteschleifen Assemblersprachen werden vor allem dort eingesetzt, wo zeitkritische Prozesse ablaufen. Insbesondere zu Beginn des Mikrocomputer-Zeitalters, als die CPU viele Aufgaben noch allein übernehmen musste (neben den Berechnungsaufgaben zum Beispiel die Video- und Audio-Ausgabe sowie das I/O-Handling), war genaues Timing wichtig, um einen für den Nutzer flüssigen Programmablauf zu gewährleisten. Die taktgenaue Programmierung ging bei einigen Systemen (wie der Computerspielkonsole VCS von Atari) sogar so weit, dass die CPU die Spielalgorithmen nur dann abarbeiten konnte, wenn der Kathodenstrahl der angeschlossenen Fernsehbildröhre gerade abgeschal-

2.5 Programmierung

|

159

tet war, während er vom rechten zum linken Bildschirmrand zurücklief. Dies geschah (bei US-amerikanischen Fernsehern) 60 mal pro Sekunde für wenige Millisekunden. Dann hatte die CPU 76 Takte Zeit, Programmcode auszuführen, bevor sie sich wieder um die Grafikausgabe der nächsten Bildzeile „kümmern“ musste (vgl. Bogost/Montfort 2009:27-30). Damit der Programmierer Grafiken auf den Bildschirm bringen und „nebenher“ seine übrigen Algorithmen einplanen konnte, musste er also genau berechnen, wie viele Takte seine Programmteile verbrauchen. Die Konstruktion von Warteschleifen kehrt das Prinzip der Ermittlung der Zeitkomplexität eines Algorithmus’ (vgl. Kap. I.4.1.5) um: Hier soll ein Algorithmus eine definierte Zeit lang laufen (und eben nicht so zeiteffizient wie möglich sein). Das folgende Experiment soll zeigen, wie man mit dem MOUSE-Computer eine zeitgenaue Warteschleife von einer Sekunde Länge programmiert. Dabei ist wichtig zu wissen, mit welcher Frequenz die CPU getaktet²⁸ ist und wie viele Taktzyklen die Befehle der Pausen-Routine verbrauchen. Diese wird für gewöhnlich als (Warte)Schleife angelegt. Am Beginn steht die Berechnung der zu wartenden Taktzyklen: 1,8432 Megahertz sind 1.843.200 Hertz – also Schwingungen pro Sekunde. Pro Schwingung wird ein Takt erzeugt, welcher damit 0,543 Mikrosekunden dauert. Für eine Warteschleife von 1 Sekunde Dauer gilt es also 1.843.200 Takte zu „verbrauchen“. Experiment II.2: Warteschleife 1 2 3 4 5 6 7 8 9

0400 LDX #$FF 0402 LDY #$FF 0404 DEY 0421 BNE $ED 0423 DEX 0429 BNE $E3 042B JMP ($FFFC)

; ; ; ; ; ; ; ; ;

Aeussere Schleife (2) Innere Schleife (2) inneren Schleifenzaehler -1 (2) 12 Byte Platz für NOPs (je 2) Sprung zurueck nach 0404, solange nicht Null (3 oder 2) aeusseren Schleifenzaehler -1 (2) 5 Byte Platz für NOPs (je 2) Sprung zurueck nach 0402, solange nicht Null (3 oder 2) Ende

Der Zeitverbrauch der Routine ergibt sich aus der Rechnung in Tabelle 2.6. 326.148 Takte benötigen circa 0,177 Sekunden, um abgearbeitet zu werden.²⁹ Um die benötigte Wartezeit zu erreichen, könnte die Schleife mehrfach (6 mal) durchlaufen oder in die innere oder äußere Schleife zusätzliche Opcodes eingebaut werden. Für letzteres vorgesehen ist der Befehl NOP (No Operation), der nichts anderes tut als 2 Taktzyklen zu verbrauchen. Ein NOP in die innere Schleife eingebracht, führt dazu, dass 130.050

28 Hier zeigt sich einer der bedeutsamsten Unterschiede zwischen Original-Hardware und ihrer Emulation. Die MOUSE-CPU ist mit 1,8432 MHz getaktet; die der MOUSE2Go-Emulation mit 1 MHz (wenn sie auf einem Arduino mit 16 MHz ausgeführt wird). 29 Der langsamere Emulator benötigt circa 0,33 Sekunden, um die Warteschleife einmal abzuarbeiten.

160 | 2 Assembler zusätzliche Takte (0,24 Sekunden) anfallen; durch das Einfügen von 12 NOPs³⁰ in die innere Schleife wäre damit das Ziel einer eine Sekunde andauernden Warteschleife erreicht. Tab. 2.6: Berechnung der Taktzyklen des Warteschleifen-Programms Programmteil

Adressen

Taktzyklen

Anmerkung

Initialisierung Innere Schleife Äußere Schleife Summe

040016 –040316 040416 –042316 040216 –042A16

4 324.870 1.274 326.148

255 ⋅ ((254 ⋅ 5)+1 ⋅ 4) (254 ⋅ 5)+ ⋅ 4

2.5.2 Selbstmodifizierender Code Von-Neumann-Architekturen benutzen sowohl für Daten als auch für Programme denselben Speicher (vgl. Kap. I.1.3.1.1). Daher muss der Programmierer – etwa bei der Angabe von Sprungzielen – genau wissen, welche Adresse er ansteuert. Verweist er auf Daten/Argumente anstatt auf einen Opcode, so interpretiert die CPU diese fälschlicherweise als Programmanweisung, was zu Fehlern und in den meisten Fällen zum Absturz des Computers führt. Eine andere hiermit zusammenhängende Schwierigkeit ist der Speicherschutz (vgl. Kittler 1993:220), der auf der Ebene der Maschinensprache nicht mehr vom Betriebssystem gewährt wird. Mit Assembler-Programmen ist es möglich, in jeden Teil des frei verfügbaren RAM-Speichers zu schreiben – also sogar in die Bereiche, in denen das Programm abgelegt ist, das diesen Schreibvorgang vornimmt. Dies kann dazu benutzt werden, selbstmodifizierenden Code zu generieren. Experiment II.3: Selbstmodifizierender Code 1 2 3 4 5 6 7 8 9 10 11

0400 0401 0403 0405 0408 040A 040D 040F 0412 0414 0417

CLC LDA ADC JSR LDX STX LDX STX LDX STX JMP

#$F0 #$01 $E00F #$38 $0400 $#0F $0402 $#E9 $0403 ($FFFC)

; ; ; ; ; ; ; ; ;

F0+01 Sprung zur M-OS-Routine 'Ausgabe' Opcode SEC ... ... in $0400 schreiben Datum 0F ... ... in $0402 schreiben Opcode SBC ... ... in $0403 schreiben Ende

30 Hierfür können auch andere Operationen mit bis zu 7 Taktzyklen Länge (etwa Stack-Operationen) verwendet werden, um die Schleife kompakter zu gestalten.

2.5 Programmierung

| 161

Nach Ablauf des Programms wird zunächst das Additionsergebnis F016 +0116 =F116 ausgeben und dann ins M-OS zurückgekehrt. Startet man das Programm ein zweites mal, ändert sich die Ausgabe zu 0D16 . Aufklärung über den Grund dieser Veränderung gibt das Disassembly des Speicherinhalts mit d 0400: Statt CLC steht nun SEC in Adresse 0400, statt des Operanden F016 findet sich nun 0F16 in Adresse 040116 und statt des Befehls ADC der Befehl SBC in Adresse 040216 . Diese drei Änderungen werden in den Programmzeilen 040816 –041616 generiert, in dem die dort hinterlegten Daten 3816 (Opcode für CLC) , 0F16 und E916 (Opcode für SBC) an die Stellen des Speichers geschrieben werden, an denen bereits Programmteile stehen. Aus der Addition F016 +0116 =F116 ist so die Subtraktion 0F16 –0116 =0E16 geworden. (Aus dem CLC in 040016 wurde ein SEC, damit die Subtraktion ein korrektes Ergebnis liefert.)

2.5.3 Interrupt Handling Die Geschwindigkeit, mit der Computer arbeiten, ermöglicht es erst, viele Prozesse scheinbar parallel ablaufen zu lassen. In Wirklichkeit werden Prozesse von einer CPU grundsätzlich nacheinander abgearbeitet. Dass der Eindruck von Parallelität (und deshalb von Multitasking) entstehen kann, liegt daran, dass die Arbeit der CPU an einem Prozess regelmäßig unterbrochen wird, um kurzfristig eine andere Aufgabe zu erledigen. Während man zum Beispiel einen Text in einem Textverarbeitungsprogramm eingibt, lässt das Betriebssystem die Uhrzeit weiterlaufen, prüft die Bewegungen der Maus usw. Gerade der letztgenannte Prozess gehört aber zu denjenigen, die nicht anlasslos ständig abgearbeitet werden müssen, sondern nur dann, wenn die Maus tatsächlich bewegt wurde. I/O-Bausteine, die die Signaleingänge der Computerschnittstellen verarbeiten, senden der CPU hierzu sogenannte Interrupt-Signale (Unterbrechungen), die den Prozessor zum kurzfristigen Unterbrechen der gerade durchgeführten Arbeit veranlassen, eine bestimmte (vom Programmierer zuvor definierte) Stelle im Programm anzuspringen, die dortigen Anweisungen auszuführen und danach wieder zur vorherigen Aufgabe zurückzukehren. Erst durch den Einsatz von Interrupts sind Computer überhaupt in der Lage als interaktive Medien zu fungieren, welche Eingaben verwalten und verarbeiten können. Die 6502 lässt drei unterschiedliche Interrupts zu (vgl. Tabelle 2.7). NMI und IRQ besitzen eigene Leitungen, die von außen in die CPU führen (siehe Abb. 2.3 li.). Liegt an ihnen ein Interrupt-Signal an³¹, so lösen sie einen Prozess aus,

31 Der Oberstrich über NMI und IRQ bedeutet, dass diese Leitungen „active low“ sind, also dort immer eine Spannung anliegt, die abfällt, wenn ein Interrupt vorliegt. Dies verhindert, dass ein irrtümlich anliegendes Spannungssignal einen Interrupt auslöst.

162 | 2 Assembler Tab. 2.7: Interrupt-Arten des 6502 Interrupt

Adressen

NMI IRQ BRK

$FFFA / $FFFB $FFFE / $FFFF $FFFE / $FFFF

Anmerkungen Nicht maskierbarer Interrupt Maskierbarer Interrupt Ein Software-Interrupt, der durch den Opcode BRK ausgelöst werden kann (setzt Break-Flag im Statusregister auf 1).

der das laufende Programm unterbricht und aus den in Tabelle 2.7 genannten Vektoradressen die Adressinformationen entnimmt, an welcher Stelle sich die sogenannte Interrupt Service Routine (ISR) befindet. Diese wird angesprungen und der darin befindliche Code abgearbeitet. Im MOUSE-Computer³² wird noch ein kleiner Umweg eingebaut: Hier steht an den NMI-/IRQ-Adressen ein Verweis auf folgende RAM-Adressen: $7FFC/$7FFD: Soft-NMI-Vektor $7FFE/$7FFF: Soft-IRQ-Vektor Zum Programmieren eigener Interrupt-Routinen können diese beiden Adressen verwendet werden. In ihnen können dann die Informationen darüber abgelegt werden, wo sich die ISR befinden. Mit dem Befehl RTI am Ende einer ISR wird die vorherige Programmausführung dann wieder fortgesetzt, bis ein neues Interrupt-Signal anliegt. Neben den hardwareseitig erzeugten Interrupts lässt sich mit BRK auch ein Software-Interrupt auslösen. Dieser nutzt die selben Sprungvektoren wie IRQ, lässt sich von diesem aber dadurch unterscheiden, dass das Break-Flag im Statusregister auf 1 gesetzt wird. Maskierbare Interrupts wie IRQ und BRK lassen sich ignorieren (maskieren), indem das Interrupt-Flag im Statusregister mit dem Befehl SEI auf 1 gesetzt wird. Setzt man es mit CLI auf 0, so sind diese Interrupts wieder zugelassen. Weil für den Programmierer nicht absehbar ist, wann ein Interrupt ausgelöst wird, gilt es am Beginn der ISR die Registerstände zu sichern. Hierzu wird bevorzugt der Software-Stack verwendet und es existiert eine Anzahl von Stack-Operationen, die Registerinhalte auf den Stack schreiben und (am Ende der ISR) wieder zurück in die Register laden (vgl. Kapitel 2.3). Die Arbeit mit Interrupts stellt überdies erhöhte Anforderungen an die Programmier- und Hardwarekenntnisse. Eine Konsultation der Sekundärliteratur (vgl. Zaks 1986:225 ff. sowie Zaks 1983:5 ff., 213 ff. und Zaks 1984:157 ff.) ist deshalb ratsam. Das nachfolgende Experiment zeigt, wie man das IRQ-Signal nutzen kann, um eine Schleife zu verlassen und ein Unterprogramm abzuarbeiten:

32 Die hier beschriebenen Verfahren und Programme beziehen sich auf den MOUSE2Go-Emulator. Das Interrupt-Handling des MOUSE-Computers wird in Band 4 dieser Lehrbuchreiche beschrieben.

2.5 Programmierung

|

163

Experiment II.4: Interrupts 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

0200 0202 0205 0207 020A 020C 020F 0211 0300 0301 0400 0401 0403 0406 0407 0408 0409 040B 040E 040F

LDA STA LDA STA LDA STA LDA STA SEI JMP PHA LDA JSR PLA RTI PHA LDA JSR PLA RTI

#$04 $7FFC #$00 $7FFD #$04 $7FFE #$08 $7FFF

; ; ; ; ; ; ; ; ;

Hinterlege Highbyte ... ... des NMI-Spungvektors Hinterlege Lowbyte ... ... des NMI-Spungvektors Hinterlege Highbyte ... ... des IRQ-Spungvektors Hinterlege Lowbyte ... des IRQ-Sprungvektors IRQ wird ermoeglicht

$0301 #$41 $e003

; ISR NMI ; 'A' ... ; ... ausgeben

#$42 $e003

; ; ; ;

Ende ISR ISR IRQ 'B' ... ... ausgeben

; Ende ISR

Das Programm ist in drei Teile unterteilt: Adressen $0200-$0213: Hier werden die Sprungvektoren in den Adressen hinterlegt, die bei einem Interrupt aufgerufen werden. Adressen $0300-$0303: Hier ist das „Hauptprogramm“: Aktivierung des IRQ und eine Endlosschleife. Adressen $0400-$040F: Hier finden sich die Interrupt Service Routinen. Nach dem Start des Programms geschieht „augenscheinlich“ gar nichts. Das Programm hängt in der Endlosschleife des Hauptteils. Sobald ein Interrupt ausgelöst wird, wird diese Schleife jedoch kurzfristig verlassen und die entsprechende Serviceroutine angelaufen: Wurde ein NMI ausgelöst, so wird ein „A“ auf dem Bildschirm ausgegeben; wurde ein IRQ ausgelöst, so wird ein „B“ ausgegeben. Danach wird aus der ISR ins Hauptprogramm zurückgesprungen. Das Auslösen der Interrupts wird durch externe Signale ermöglicht: Beim Arduino werden hierfür mittels Drahtbrücken die Ports von NMI oder IRQ und der Masseleitung kurzgeschlossen (vgl. Abb. 2.11). Dadurch fällt die Spannung am betreffenden Interrupt-Anschluss ab (vgl. Fußnote 31) und löst das Interruptsignal aus. Um Interrupts beim (nicht-emulierten) MOUSE-Computer auszulösen, kann man die CPU-Pins

164 | 2 Assembler

Abb. 2.11: Arduino mit den markierten Ports für NMI-, IRQ-Interrupt und Masseleitung

für IRQ und NMI, die auf auf dem Expansionheader des Boards liegen, einfach gegen GND schalten und das identische Verhalten auslösen.

2.6 Assemblercode lesen Mithilfe des Disassemblers ist es möglich sich auch den Code des Betriebssystems und der im ROM vorhandenen Programme anzeigen zu lassen, um ihn zu lesen. Solche „Lektüren“ haben den konkreten Nutzen, dass man auf diese Weise implementierte Algorithmen für die Entwicklung eigenen Codes studieren oder diese vom eigenen Code aus aufrufen kann. Aber auch für medienwissenschaftliche Fragestellungen ist die Lektüre von Assembler-Code nicht uninteressant, zeigt sich auf dieser Ebene doch erst wirklich, welche Anweisungen die Hardware ausführt, um bestimmte Funktionen zu realisieren. Programme können auf diese Weise in ihren (nicht selten auch verborgenen) Details³³ erforscht werden.

33 Ein Beispiel hierfür ist die Analyse des Bundes-Trojaner-Programms durch den Chaos Computer Club (http://www.zeit.de/digital/datenschutz/2011-10/ccc-bundestrojaner-onlinedurchsuchu ng/komplettansicht, Abruf: 13.09.2017), bei dem der disassemblierte Code sogar in der Presse veröffentlicht wurde (http://www.faz.net/aktuell/chaos-computer-club-der-deutsche-staatstrojaner-wurd e-geknackt-11486538.html, Abruf: 13.09.2017).

2.6 Assemblercode lesen

| 165

Die Lektüre von Assembler setzt allerdings andere Voraussetzungen an den Leser als die hochsprachlicher Programme. Zunächst ist eine Kenntnis der Hardware – insbesondere der CPU – nötig. Die Peripherie-Bausteine und die Speicherarchitektur müssen ebenfalls bekannt sein. Um einen Algorithmus zu verstehen, muss das Programm lesend nachvollzogen – im Prinzip also „im Kopf ausgeführt“ werden.³⁴ Mit Hilfsmitteln (Papier und Stift) lässt sich der Code visuell strukturieren – etwa, indem Sprünge als Strichverbindungen zwischen Adressen dargestellt oder sich ändernde Registerinhalte und aktuelle Status notiert werden. Das Kommentieren der einzelnen Programmteile bringt schrittweise Klarheit in dessen Aufbau und Funktionsweise. Der so nachvollzogene Algorithmus kann schließlich in ein „verständlicheres“ Diagramm (zum Beispiel ein Flussdiagramm) übertragen werden. Studieren Sie diese Möglichkeit, indem Sie Programmbestandteile des MOUSEROMs disassemblieren – etwa Routinen aus dem Betriebssystem. Hier empfehlen sich beispielsweise die Routinen der oben (Kapitel 2.4.3) aufgelisteten Funktionen. Eine Übersicht über die Vektor-Adressen und damit der Speicherorte dieser Funktionen finden Sie in der Dokumentation des MOUSE-Computers.³⁵ Ein Beispiel für einen solchen Algorithmus stellt die Funktion „bin8out“ (zur Darstellung einer Hexziffer im Binärformat) dar. Ihr Einsprungvektor befindet sich bei E00C16 bis E00E16 . Geben Sie im Monitorprogramm s e00c ein. Es wird 4c angezeigt. Das ist der Opcode für JMP (denn von dieser Einsprungadresse soll ja zur eigentlichen Routine gesprungen werden). Danach (nach Eingabe von s e00d und s e00e) folgen die Adressinformationen als zwei 8 Bit große Werte: fc16 und 6316 . Aus diesen beiden Angaben lässt sich die Startadresse von „bin8out“ (nach der Form Highbyte ⋅ 256 + Lowbyte) ersehen: fc6316 . Sie kennen nun die Startadresse des Programmteils; es fehlt nur noch dessen Endadresse. Beim Disassemblieren fremden Codes sind beide Adressen zumeist nicht bekannt und ergeben sich erst während der Übersetzung und Analyse der Speicherinhalte. Da es sich bei der zu untersuchenden Routine um ein Unterprogramm des Monitorprogramms handelt, gibt der RTS-Befehl einen guten Indikator für das Ende dieser Routine. Dieser Befehl findet sich in Adresse fc7516 . Ein Disassembly des RAMBereichs ab fc6316 (nach Eingabe von d fc63) zeigt folgendes Resultat: ... $fc63 $fc65 $fc66 $fc68

$a2 $08 $18 $a0 $30 $0a

LDX CLC LDY ASL

#$08 #$30 A

34 Unversehens findet sich der Leser von Assemblerprogrammen also im Zustand einer „Papiermaschine“ (Turing 1987:85). 35 Vgl. https://github.com/mkeller0815/MOUSE2Go/blob/master/M-OS-6502/labelmap.txt (Abruf: 16.05.2018) Nicht nur aus Platzgründen, sondern auch, weil sich die realen ROM-Adressen dieser Programme in neueren Revisionen der MOUSE-Software ändern, kann hier keine konkrete Code-Analyse erfolgen.

166 | 2 Assembler $fc69 $fc6b $fc6c $fc6d $fc6e $fc71 $fc72 $fc73 $fc75 ...

$90 $01 BCC $c8 INY $48 PHA $98 TYA $20 $c7 $fc JSR $68 PLA $ca DEX $d0 $f0 BNE $60 RTS

$fc6c

$fcc7

$fc65

Da das Betriebssystem des MOUSE-Computers³⁶ „open source“ ist, lässt sich das Analyse-Ergebnis mit dem Sourcecode vergleichen. Hierbei zeigt sich sehr deutlich, dass Disassembly und Sourcecode nicht dasselbe sind. Während ersterer unkommentiert, unstrukturiert und damit zunächst kryptisch ist, zeigt letzterer die Arbeit des Programmierers mit samt den Lektüre-Hilfestellungen. In der Datei MIOS_kernal.asm³⁷ findet sich der Sourcecode zu obigem Speicherauszug. Vergleichen Sie, ob Ihre Interpretation des selbst disassemblierten Codes mit der des Sourcecodes deckungsgleich ist und versuchen Sie die Unterschiede zu erklären: Sourcecode: bin8out 1 u_bin8out: 2 ldx #$08 ; counter for 8 bit 3 _loop: clc ; clear carry flag 4 ldy #0 5 asl ; shift byte by one position 6 bcc _p0 7 iny 8 _p0: pha ; save A 9 tya ; 10 jsr k_wchr 11 pla ; get A back 12 dex ; decrement counter 13 bne _loop 14 rts ; return

36 Im Folgenden werden die Codes des MOUSE2Go-Emulators diskutiert, die sich insofern von denen des MOUSE-Computers unterscheiden, als dass sie in 6502-Assembler (und nicht in 65C02-Assembler) vorliegen. 37 https://github.com/mkeller0815/MOUSE2Go/blob/master/M-OS-6502/MIOS_kernel.asm (Abruf: 16.05.2018)

2.7 Schluss |

167

2.7 Schluss Obwohl jeder Mikroprozessor-Typ seinen eigenen Assembler-Dialekt besitzt, ähneln diese Dialekte einander sehr. Unterschiede bestehen zumeist im Befehlsumfang, der möglichen Wortbreite und den Taktraten. Jedes durch Mikroprozessor gesteuerte System lässt sich im Prinzip in Assembler programmieren.³⁸ Das vorangegangene Kapitel kann daher mehrere Zwecke erfüllen: Zunächst ermöglicht es, die Programmierung des 6502 als Beispiel für eine hardwarenahe Auseinandersetzung mit Computern zu nutzen. Zahlreiche Prozesse digitaler Medien finden auf dieser Ebene ihre medientechnische Realisierung. Daneben kann das Erlernen eines leichten Assemblers (wie der 6502-Assembler) als Ausgangspunkt für die Beschäftigung mit komplexeren und moderneren Hardware-Architekturen dienen. Schließlich bietet die Kenntnis von Assemblersprachen die Möglichkeit, die Algorithmen jeder Software auf der symbolischen Ebene nachvollziehbar zu machen. Jedes Programm im RAM-Speicher eines Computers kann disassembliert werden, womit seine Codes lesbar werden – selbst dann, wenn der Sourcecode (der in Assembler oder einer Hochsprache vorliegt) unbekannt ist. Die Kenntnis von Assemblersprachen ist somit auch eine Ermächtigung von Wissen über Computerprozesse. Das vorangegangene Kapitel kann für solch eine Beschäftigung den Ausgangspunkt bilden; eine Verbreiterung und Vertiefung der Kenntnisse ist dafür jedoch notwendig. Insbesondere aber muss eine Programmiersprache programmiert werden, um gelernt zu werden – dies gilt umso mehr für Assembler, weil die Programme eng an die Hardware-Funktionen des Systems gekoppelt sind. Aufgrund des begrenzten Raumes kann hier keine vertiefende Einführung oder Analyse von Codes stattfinden. Auf der Webseite des DeGruyter-Verlags sind daher weitere Beispiele und Aufgaben hinterlegt. Zudem werden Ihnen im Anhang dieses Kapitels Empfehlungen für die vertiefende Lektüre zum Thema angeboten.

2.8 Lektüreempfehlungen Zaks, Rodnay (1986): Programmierung des 6502 (mit 65C02). 9. Auflage. Düsseldorf: Sybex. Rodnay Zaks hat zu allen einschlägigen 8-Bit-Prozessoren Programmierhandbücher verfasst, die zum großen Teil auch in die deutsche Sprache übersetzt wurden. Das vorliegende 6502-Handbuch ist das erste von dreien, die sich mit dieser Architektur beschäftigen (Nachfolgebände behandeln fortgeschrittene Programmierung und An-

38 Das Blackboxing erweckt allerdings oft den Eindruck nicht bis auf diese Ebene vordringen zu können. Hacker-Szenen, die beispielsweise Mikrocontroller in Haushaltsgeräten umprogrammieren, bieten allerdings Zugänge zu fast jedem System an.

168 | 2 Assembler wendungen; auf Englisch liegt zusätzlich ein Buch über Spieleprogrammierung des 6502 von ihm vor). Der Autor stellt den Aufbau und die Arbeitsweise der CPU minutiös vor, bevor er sich dem Befehlssatz des 6502 (und in neueren Auflagen auch des 65C02) widmet. In der zweiten Hälfte werden Algorithmen für arithmetische und I/OAufgaben diskutiert. 6502.org. The 6502 Microprocessor Ressource. http://6502.org/ (Abruf: 17.12.2017) Die Internetseite 6502.org ist die erste Anlaufstelle bei der Suche nach Anleitung, Literatur und Programmbeispielen. Die dort vorgestellten vor allem englischen Bücher können als PDF-Dateien heruntergeladen werden und bieten reichhaltiges Material für eigene Beschäftigungen mit der Maschinensprache. visual6502. Visual Transistor-level Simulation of the 6502 CPU and other chips! http: //visual6502.org/ (Abruf: 17.12.2017) Die Mitstreiter dieser Internetseite haben sich der Erhaltung und Erforschung historischer Large-Scale-Integration-Bausteine verschrieben. Hierzu werden die Bausteine gesammelt, geöffnet, fotografiert, dokumentiert und am Ende des Prozesses online emuliert. Der 6502 nimmt darunter eine Sonderstellung ein (wie die URL andeutet). Für diesen Mikroprozessor liegt ausführliche Dokumentation in einem Wiki und eine Javascript-Emulation vor. Mit letzterer kann man die internen Prozesse der (emulierten) CPU beim Abarbeiten von Code beobachten. Oxyron: 6502/6510/8500/8502 Opcode matrix. http://www.oxyron.de/html/opcodes02 .html (Abruf: 17.12.2017) Hier wird eine knappe und systematisch geordnete Befehlsübersicht für die 6502-CPU angeboten. Andrew John Jacobs: Instruction Reference. http://www.obelisk.me.uk/6502/ref erence .html (Abruf: 17.12.2017) Diese Seite bietet eine Online-Referenz zum 6502-Assembler. Zusammen mit der Oxyron-Seite bildet sie ein gutes Werkzeug während der Programmierung. Michael Steil: pagetable.com. Some Assembly Required. http://www.pagetable.com/ (Abruf: 17.12.2017) Michael Steil betreibt dieses computerarchäologische orientierte Weblog. Wie kaum ein anderer hat Steil die internen Prozesse des Commodore 64 analysiert und beschrieben. Auf seiner Webseite pagetable finden sich zahlreiche Beiträge zur Geschichte des 6502 und seiner Implementierungen. C64-Wiki. http://www.c64-wiki.de/ (Abruf: 17.12.2017) Das C64-Wiki ist die zentrale Anlaufstelle für Informationssuchende um Commodores Heimcomputer. Hier werden auch alle Assembler-Befehle des 6502 mit eigenen Einträgen und Programmbeispielen niedrigschwellig beschrieben.

3 BASIC Stefan Höltgen Die Programmiersprache BASIC gehört zu denjenigen Hochsprachen mit der vielfältigsten Kulturgeschichte. BASIC wurde im Mai 1964 am Dartmouth College (Hanover, New Hampshire, USA) publiziert. Seine Erfinder, Thomas E. Kurtz und John G. Kemeny, beabsichtigten damit, eine Bildungslücke zwischen den naturwissenschaftlichtechnischen Studiengängen und den Gesellschafts-/Kulturwissenschaften zu schließen: Existierte für erstere zu diesem Zeitpunkt bereits eine Vielzahl von Programmiersprachen für unterschiedlichste Anwendungsmöglichkeiten, so stellte die programmiererische Auseinandersetzung mit Computern für letztere noch eine oft unüberwindliche Hürde dar. Dies lag zum einen daran, dass die existierenden Programmiersprachen hohe Voraussetzungen (in Mathematik, Technik, Computerwissenschaften) für ihre Benutzung hatten. Zum anderen verfügten Sprachen wie Fortran, COBOL oder Assembler nicht über Möglichkeiten und Funktionen, die sie für Geistes- und Kulturwissenschaftler interessant machten. BASIC sollte diesen Umständen Abhilfe schaffen. Kurtz und Kemeny hatten zuvor Erfahrung mit dem Entwurf von Lehrsprachen gesammelt und diese in BASIC einfließen lassen. Ihre Sprache basiert auf damals populären Sprachen wie Algol 60 und Fortran und enthielt Konzepte von AssemblerSprachen, die eigens für die studentische Ausbildung angepasst wurden. Dass BASIC über die nächsten drei Jahrzehnte eine beispiellose Entwicklung durchmachte, die zu ungezählten Dialekten für unterschiedlichste Systeme führte, lag zunächst daran, dass die Entwickler BASIC als „Freeware“ publizierten. Deshalb zog die einfach zu erlernende Sprache recht bald nach ihrer Veröffentlichung Computerfirmen an, die ihren vergleichsweise günstigen Rechnern (die zu dieser Zeit eine durch technische Entwicklungen bedingte radikale Verkleinerung in Größe und Kosten erfahren hatten) eine Programmiersprache mitgeben wollten. So implementierten Firmen wie Hewlett Packard, DEC und andere ab Ende der 1960er-Jahre speziell auf ihre Systeme angepasste BASIC-Compiler und -Interpreter. Mitte der 1970er-Jahre, als dann Mikrocomputer den Weg in private Haushalte fanden, war BASIC (auch dank der Initiative einiger Hobbyisten) längst die Anfängersprache der Wahl und diente dazu die Kleincomputer als ideale Lehrsysteme zu vermarkten. In Fachkreisen (der Informatik) war BASIC allerdings nie sehr populär, weil die radikalen Vereinfachungen und vor allem das von ihr nahegelegte maschinennahe Programmierparadigma die Errungenschaften strukturierten Programmierens und schulgültiger Algorithmen-Entwicklungen unterliefen. Manche Informatiker gingen in ihrer Kritik sogar so weit, dass sie Programmierern, die Kontakt zu BASIC gehabt hatten, attestierten: „It is practically impossible to teach good programming to students that have had a prior exposure to BASIC: as potential programmers they are mentally mutilated beyond hope of regeneration.“ (Dijkstra 1982) https://doi.org/10.1515/9783110496253-017

170 | 3 BASIC BASIC konnte sich in den 1980er-Jahren dennoch auch als Lehrsprache eine zeitlang selbst gegen didaktisch ausgefeiltere Sprachen (wie Pascal oder Logo) durchsetzen, weil Schulen häufig Homecomputer als Lehrplattformen benutzten, die BASIC in ihren ROMs mitbrachten und so die zusätzliche Anschaffung anderer Programmiersprachen überflüssig erscheinen ließen. Hinzu kam, dass BASIC von vielen Schülern bereits programmiert wurde, weil eben jene Homecomputer auch bei den Kindern und Jugendlichen zu Hause standen und zum autodidaktischen Programmierenlernen einluden. Über die fünf Jahrzehnte seines Bestehens hinweg hat BASIC sein „Gesicht“ deutlich gewandelt. Von der „reinen Lehre“, die Kemeny und Kurtz zu Beginn formuliert hatten (vgl. Höltgen/Ernst 2013/14:16 und Kurtz 2009:82 f.), wich die Implementierung auf unterschiedlichen Systemen ab: Hardware-spezifische Funktionen (etwa für Grafik- und Soundanwendungen sowie für die Integration oder den Aufruf von Maschinensprache-Routinen in BASIC-Programmen) kamen hinzu. Die ohnehin lockeren Strukturierungsvorschriften (z.B. nur ein Befehl pro Programmzeile, obligatorisches LET für die Variableninitialisierung u.a.) wurden noch weiter aufgeweicht und der Befehlsvorrat einiger Dialekte überstieg an Zahl und Komplexität ein Maß, dass die Anfänge von BASIC als bloße Lehrsprache vergessen ließ. Angesichts dieser Entwicklung halfen nicht einmal die in der ersten Hälfte der 1980er-Jahre einsetzenden Bemühungen um Standardisierung (ISO/IEC 6373:1984 und Cook 1980) und die Abkehr von Zeilennummern und GOTO-Anweisungen, um auf diese Weise strukturiertes Programmieren zu „erzwingen“. Heute existiert BASIC immer noch – einerseits in den überaus produktiven Retrocomputing-Szenen (deren technik-historische Leistung im Folgenden als operative Computerarchäologie aufgerufen wird¹), andererseits in Form unterschiedlicher aktueller Dialekte für moderne Systeme. Hier ist es vor allem das ab 1991 von Microsoft entwickelte „Visual BASIC“, das als Sprache für die Entwicklung von Macroscripts innerhalb anderer Programme (etwa dem Office-Paket) nach wie vor Anwendung findet. Darüber hinaus werden aber auch noch alte Dialekte gepflegt, erweitert und auf neue Hardware-Plattformen portiert. Hierzu zählt der im folgende vorgestellte Dialekt „BBC BASIC“.

3.1 BBC BASIC BBC BASIC wurde im Jahr 1981 von Sophie Wilson, einer Ingenieurin der britischen Firma Acorn, für den 8-Bit-Homecomputer BBC Micro² entwickelt. Der Name von Pro-

1 Vgl. https://www.youtube.com/watch?v=ThlLeZGsEOo (Abruf: 16.05.2018) 2 Eine Online-Emulation des BBC Micro samt BBC BASIC findet sich hier: https://bbc.godbolt.org/ (Abruf: 16.05.2018)

3.1 BBC BASIC

| 171

Abb. 3.1: Der Homecomputer BBC Micro (Acorn)

grammiersprachendialekt und Computer geht auf eine Ausschreibung der britischen Sendeanstalt BBC (British Broadcasting Company) zurück, die zu dieser Zeit ein umfangreiches „Computer Literacy Project“ lancierte, wozu neben der Produktion einer Schulfernsehserie („The Computer Programme“) auch eine Aufforderung an britische Technologieunternehmen ging, einen für Lehrzwecke geeigneten Computer zu entwerfen. Unter den zahlreichen Einreichungen gewann das System der Firma Acorn – es bot die besten Grundvoraussetzungen, um im Unterricht eingesetzt zu werden, war vielfältig erweiterbar und brachte einen eigenen³, neu entwickelten BASIC-Dialekt mit, der optimal auf die Hardware zugeschnitten war. Der BBC Micro (Abb. 3.1) und mit ihm das BBC BASIC wurden die Computerlehrumgebungen für britische Schulen. (vgl. Gazzard 2016:19–44). Die Firma Acorn implementierte BBC BASIC aber nicht nur im BBC Micro und in ihren nachfolgenden Archimedes-Computern, sondern lizenzierte auch Fremdfirmen⁴ diesen BASIC-Dialekt zu verwenden. So entwickelte sich das BBC BASIC ab Mitte der 1980er-Jahre in Großbritannien zu einem Quasi-Standard, der durch beson-

3 Nicht wenige Computer-Plattformen variierten bereits vorhandene BASIC-Dialekte. Noch öfter wurden allerdings Dialekte lizenziert, die durch Dritthersteller (z.B. Microsoft BASIC) entwickelt wurden. Die Ähnlichkeiten der BASIC-Dialekte sind ebenso beachtenswert wie ihre Unterschiede. Eine Sprachgeschichte, die dies untersucht, wäre noch zu entwickeln. 4 Hierzu zählen zum Beispiel die Firmen Tatung (mit den Einstein-Computern) oder Amstrad (die BBC BASIC in ihren portablem NC-100-, NC-150 und NC-200-Computern unterbrachte).

172 | 3 BASIC dere Initiativen bis heute als Dialekt für zahlreiche Plattformen⁵ angeboten wurde. Zu diesen gehört auch der Experimentier-Computer Raspberry Pi, dessen Prozessor auf einem Entwurf der Firma ARM Ltd. – der Nachfolgefirma von Acorn (vgl. Mohr 2014:157–163) – basiert. Die weiter unten vorgestellten Programme wurden auf dieser Plattform entwickelt und/oder getestet. Da hierbei so wenig wie möglich auf Hardware-Spezifikationen zugegriffen wurde, sind sie ohne (oder nur mit geringen) Anpassungen auch auf andere Systeme mit BBC BASIC portierbar. Das folgende Kapitel stellt aus Platzgründen keine Programmierlehre im klassischen Sinn dar⁶, sondern will versuchen BASIC im Allgemeinen und BBC BASIC im Besonderen als eine Sprache vorzustellen, die einen bedeutenden Einfluss auf historische Programmierkulturen hatte. Neben der Kulturgeschichte der Sprache bilden die Mediengeschichte jener Computer, die die Sprache implementierten, und die Archäologie der BASIC-Programmierung einen weiteren Fokus des Kapitels. BASIC wird hier deshalb vor allem über ausgewählte Programme vorgestellt, die zum Analysieren und Experimentieren einladen sollen. Die Vermittlung von BASIC für Medienwissenschaftler erfüllt mithin also weniger den Zweck eine Programmiersprache für den Praxisbedarf⁷ zu erlernen, als dass sie vielmehr als eine Hands-on-Archäologie verstanden wird, mit der die Geschichte einer Programmiersprache programmierend erarbeitet, hinterfragt, ergänzt und aktualisiert werden kann.

3.2 Eigenschaften der Sprache BBC BASIC kann auf dem vorliegenden System sowohl interpretiert als auch kompiliert ausgeführt werden. (Der Unterschied zwischen beiden Arbeitsweisen wird in Kap. 3.2.1 erläutert.) Für erste Experimente bietet sich der Interpreter an, weil hier Eingaben direkt verarbeitet und Ergebnisse sofort nach dem Drücken der Return-Taste angezeigt werden. Viele Befehle und Funktionen von BASIC lassen sich allerdings nur in Programmen verwenden (oder sinnvoll nutzen). Daher wird die Diskussion von BASIC-

5 Vgl. http://mdfs.net/Software/BBCBasic/ (Abruf: 16.05.2018) 6 Thomas E. Kurtz empfiehlt: „An einem Kurs teilzunehmen, ist eigentlich ziemliche Zeitverschwendung. [...] Neue Sprachen lernt man, indem man die Anleitung liest.“ (Kurtz 2009:93) Und: „Einfache Coding-Aufgaben und ein leichter Zugriff auf einfach zu nutzende Implementierungen sind erforderlich, ebenso viele Beispiele.“ (Ebd.:82) Dieser Idee folgt das vorliegende Kapitel; zusätzlich bieten wir auf www.degruyter.de ein Semesterprogramm zum Lehren und Lernen der Sprache und empfehlen ebenfalls die Konsultation des Manuals (siehe Lektüreempfehlungen). 7 Hierfür kann (eingeschränkt) die in diesem Kapitel vorgestellt Sprache Python verwendet werden. Für BBC BASIC wie auch für die anderen hier aspektierten Sprachen bildet das vorliegende Buch jedoch allein die medienwissenschaftliche Grundlage. Die Programmierung selbst wird in der am Ende vorgestellten, weiterführenden Literatur vorgestellt und kann in den Supplementen zum Buch auf der Webseite www.degruyter.com heruntergeladen werden.

3.2 Eigenschaften der Sprache

| 173

Programmen den Hauptteil des Kapitels einnehmen. Zunächst sollen die Struktur, der Befehls- und Funktionsvorrat von BBC BASIC überblicksartig vorgestellt werden.

3.2.1 Die Struktur von BASIC-Programmen In den BASIC-Dialekten der ersten zwei Jahrzehnte werden BASIC-Programme auf Basis von Zeilennummern programmiert. Diese Nummern bilden zugleich das Strukturelement der Programme als auch Label, die mithilfe von GOTO-Befehlen angesprungen werden können. Erinnert letzteres an Programmiersprachen wie Fortran, so ist ersteres ein Ausweis für BASIC als maschinennahe Sprache: Während in Assembler die Befehle an jeweils einer Adresse situiert sind, bilden die Zeilennummern in BASIC ebenfalls Adressen im Programm. Diese Struktur hat BASIC von Didaktikern den Vorwurf eingebracht problemfern und maschinennah (vgl. Arbeitskreis Schulsprache 1976:C5) zu sein, besitzt jedoch den epistemologischen Mehrwert, dass hier Programme in einer Hochsprache nach dem Paradigma einer Maschinensprache entworfen werden können. Experiment II.5: BBC-BASIC-Programm mit Zeilennummern 1 2 3

10 CLS 20 PRINT "Hallo Welt!" 30 GOTO 20

Die Abarbeitung von BASIC-Programmen erfolgt – sofern sie interpretiert sind – strikt nach aufsteigenden Zeilennummern (vgl. Experiment 1). Diese ermöglichen auch die „adressgenaue“ Diskussion von Programmstellen und erleichtern deren Editieren selbst dann, wenn keine Editor-Funktionen vorhanden sind: Eine fehlerhafte Zeile kann einfach noch einmal neu geschrieben werden. Wird BASIC ohne Zeilennummern programmiert, so geschieht dies zumeist in einem spezifischen Editor (Integrated Development Environment, IDE) und die Programme werden vor dem Ablauf in Maschinensprache übersetzt (kompiliert) und nicht zur Laufzeit ausgeführt (interpretiert). Experiment II.6: BBC-BASIC-Programm ohne Zeilennummern 1 2 3

(Start) PRINT "Hallo Welt!" GOTO Start

174 | 3 BASIC

Der Interpreter kann direkt über eine Eingabe-Shell genutzt werden, in der nicht nur die Programme eingegeben, sondern auch bestimmte Befehle direkt ausgeführt werden können. Experiment II.7: BBC-BASIC-Programm ohne Zeilennummern in der Shell 1

REPEAT:PRINT "Hallo Welt!":UNTIL TRUE=FALSE

3.2.2 Befehle Befehle – sowohl Programmierbefehle als auch Befehle zur Programmsteuerung – werden in BASIC als Verben im Imperativ eingegeben: RUN, LOAD, GOTO, DRAW usw. Dass für diese Befehle von Beginn an englisches Vokabular genutzt wurde, sollte ihre leichte Erlernbarkeit und Merkbarkeit unterstützen (vgl. Höltgen/Ernst 2013/14:14). Wie alle turingvollständigen Programmiersprachen (vgl. Kap. I.1.2.2) verfügt BASIC dabei auch über Befehle, die den Programmablauf steuern (Schleifen mit FOR-TO-NEXT-, WHILE-ENDWHILE) und mit und ohne Bedingungen Verzweigungen im Programm ermöglichen (IF-THEN, CASE). Zur Steuerung, zum Laden und Speichern sowie zur Anzeige und zum Editieren von BASIC-Programmen dienen Befehle, die bereits Komponenten von Betriebssystemen darstellen. In den meisten frühen Homecomputern war BASIC deshalb zugleich auch das Betriebssystem. Für Ein- und Ausgabe von Text sowie Grafik- und Soundausgaben existiert eine große Anzahl von Befehlen mit vielfältigen Parametern. Einige Befehle sollen das strukturierte Programmieren erleichtern, indem sie den Aufruf und die Abarbeitung von Unterprogrammen regeln (GOSUB, RETURN) oder Funktionen deklarieren (DEF FN, DEF PROC). Mit ihnen ist es möglich, BASIC-Programme auch ohne Zeilennummern und GOTO-Befehl zu entwickeln.

3.2.3 Funktionen und Daten, Variablen und Konstanten BBC BASIC ist reich an Funktionen für mathematische Anwendungen und Zeichenkettenbehandlung. Diese Funktionen werden zumeist als Mnemonics (SIN(), STR$(), FN() usw.) angegeben, bei denen die Werte in Klammern übergeben werden. Bei der Verwendung einer Funktion ist der durch sie zu verarbeitende Datentyp entscheidend. BASIC kennt in seiner ursprünglichen Form nur zwei Datentypen: Zahlen (reelle Zahlen) und Zeichenketten (Strings). Variablennamen für Zahlen können frei gewählt werden, müssen aber mit einem Buchstaben beginnen (A7=33) und dürfen keine Schlüsselwörter der Sprache sein oder enthalten (GOTO=13 ist nicht erlaubt); Zeichenketten-

3.2 Eigenschaften der Sprache

| 175

Variablennamen müssen zusätzlich mit einem Dollar-Zeichen ($) enden (A$="Hallo"); ihre Werte werden in doppelten Anführungszeichen übergeben. Variablen müssen in BASIC nicht definiert werden. Möglichkeiten der Definition von Datentypen gibt es in BBC BASIC dennoch. Hierbei kann bestimmt werden, ob eine Zahlenvariable als Integer-, Fließkommazahl mit variabler Größe, Boole’scher Ausdruck oder anderes verwendet werden soll. Auf diese Weise lassen sich zum Beispiel Ausgaben formatieren, Programme beschleunigen oder Speicherplatz sparen (da zum Beispiel nicht mehr jede nummerische Variable als reelle Fließkommazahl behandelt werden muss). Alle Variablen können zudem dimensioniert werden – also als Arrays⁸ behandelt werden. Hierzu muss zunächst die Dimensionsgröße mit DIM() definiert werden, wodurch ein Speicherbereich für das Array reserviert wird. Darüber hinaus ermöglicht BBC BASIC durch das Kapseln von Variablen (mittels LOCAL) innerhalb bestimmter Prozeduren und Funktionen sogar in Ansätzen das Programmieren nach dem objektorientierten Paradigma. Einige Standardwerte und Systeminformationen sind in Form von Konstanten abrufbar. Dazu gehört die Kreiszahl PI. Informationen über die systeminterne Uhrzeit (TIME, TIME$) sowie über Speichergrenzen (HIMEM, LOMEM) und andere Informationen über den Speicher (PAGE, PTR) sind als Pseudo-Variablen abrufund manipulierbar. Darüber hinaus existieren Variablen, die über die Position und Eigenschaften des Text- und des Grafik-Cursors informieren (POS, VPOS, POINT, TINT) sowie über angeschlossene Steuerungsgeräte wie Maus und Joystick (ADVAL, MOUSE). System-Variablen, die bestimmte Steuerungswerte enthalten, können zusätzlich abgefragt werden.⁹

3.2.4 BBC BASIC und Assembler BASIC wurde ab den 1970er-Jahren häufig zur Programmierung in Maschinensprache genutzt. Hierzu wurden sogenannte BASIC-Loader verwendet, die AssemblerProgramme und Daten in den Speicher schrieben und mithilfe besonderer BASICBefehle starteten. Die Opcodes und Daten für die Maschinensprache-Programme wurden dabei zumeist als Dezimal- oder Hexadezimal-Zahlenkolonnen in DATA-Zeilen hinterlegt. In der Hauptroutine wurde diese Datenbank dann mittels einer Schleife mit READ ausgelesen und mit dem POKE-Befehl in den Speicher geschrieben. Dieses Verfahren war oft deshalb nötig, weil BASIC auf 8-Bit-Mikrocomputern eine relativ langsam arbeitende Programmiersprache war. Zeitkritische Operationen (I/O-Routinen oder

8 Ein Array (engl. Datenfeld) ist eine mehrdimensionale Variable. In BASIC (und anderen Sprachen) können Variablen nicht nur eindimensional definiert (z.B. A=7), sondern auch indexiert werden (z.B. A(1)=7:A(2)=13:A(3)=-7. Dies macht eine Verarbeitung der Arrays in Schleifen möglich. (Zum Umgang mit Arrays in C vgl. Kapitel 4.10.3) 9 http://www.bbcbasic.co.uk/bbcwin/manual/bbcwin2.html#systemvars (Abruf: 16.05.2018).

176 | 3 BASIC Sound- und Grafik-Ausgaben) wurden daher in der ungleich schneller arbeitenden Maschinensprache kodiert. Der BBC-Micro-Computer basiert auf einem solchen 8-Bit-Mikroprozessor, der MOS 6502 (vgl. Kap. 3.1). In das BBC BASIC sind Befehle wie SYS, CALL und die Funktion USR() implementiert, um Maschinenspracheprogramme aufzurufen. Die Sprache bietet jedoch noch eine wesentlich komfortablere Möglichkeit, Maschinensprache von BASIC aus zu programmieren – einen sogenannten Inline-Assembler: Durch Setzen einer geöffneten eckigen Klammern ([) allein in eine BASIC-Programmzeile wird dem Interpreter/Compiler das Signal gegeben, dass die nachfolgenden Programmzeilen Assembler-Mnemonics enthalten und so interpretiert werden müssen. Um zurück zur BASIC-Verarbeitung zu gelangen, muss in der Zeile nach dem letzten AssemblerOpcode eine geschlossene eckige Klammer (]) gesetzt werden. Experiment II.8: Inline-Assembler 1 2 3 4 5

10 20 30 40 50

CLS [ NOP ; dies ist ein Assembler-Mnemonic ] END

Das obige Programm führt in seinem Assembler-Teil lediglich ein NOP (No Operation) aus. Hier kann das Thema der Assembler-Programmierung nicht vertieft werden, zumal sich die Assembler-Sprache des im Raspberry Pi implementierten ARM-Prozessors signifikant von der der MOS 6502 unterscheidet. Interessierte seien an dieser Stelle auf die Sekundärliteratur zum ARM-Assembler verwiesen.¹⁰

3.3 Programmieren in BASIC Die Beschäftigung mit BASIC ist dazu geeignet die Geschichte der Programmierung, die Theorie der Algorithmen und die Kulturtechnik des Hackings als Re-enactment nachzuvollziehen. Das folgende Kapitel verfährt dabei so, dass ausgewählte einschlägige Algorithmen der BASIC-Geschichte (3.3.1), Standard-Algorithmen (3.3.2) und schließlich Programme zu spezifischen computerarchäologischen Aspekten (3.3.3) in BBC BASIC vorgestellt werden. Danach erfolgt eine grobe Funktionsbeschreibung des jeweiligen Programms und dann Vorschläge zur vertiefenden Analyse und Modifikation.

10 Beispielsweise http://bob.cs.sonoma.edu/IntroCompOrg-Rpi/intro-co-rpi.html sowie http://ww w.peter-cockerell.net/aalp/html/ch-4.html (beide Abruf: 16.05.2018)

3.3 Programmieren in BASIC

| 177

Dieser Top-Down-Zugang zum Erlernen einer Programmiersprache entspricht dem Modell des reverse engineering, bei dem eine Black Box in ihren Funktionen sukzessive durchdrungen wird. En passant ergeben sich auf diese Weise auch Kenntnisse in der BASIC-Programmierung. Die hier vorgestellten Programme sollten am besten händisch abgetippt werden. Damit wird nicht nur eine historische Technik des Homecomputer-Zeitalters nachvollzogen, sondern dies ermöglicht auch ein hermeneutisches Durchdringen des Codes beim Lesen/Abtippen und forciert somit den BASIC-(Selbst-)Lernprozess.

3.3.1 Historische BASIC-Algorithmen Dadurch, dass BASIC über drei Jahrzehnte hinweg von Hobbyisten programmiert wurde, die sich über Zeitschriften, Bücher und den Austausch von Datenträgern gegenseitig mit ihrem Wissen und ihren Programmen versorgt haben, ist der Fundus an historischen Sourcecodes nahezu unerschöpflich – und gleichermaßen vom Vergessen und Verfall bedroht, denn eine historische Aufarbeitung der Diskursmonumente des Heimcomputer-Zeitalters hat bislang nicht stattgefunden. Im Folgenden werden einige der bekannteren Programme der BASIC-Geschichte nebst ihren historischen Entstehungskontexten vorgestellt. Das erste BASIC-Programm Experiment II.9: Erstes BASIC-Programm 1 2 3 4 5 6 7 8 9 10 11 12 13

10 15 20 30 37 42 55 60 65 70 80 85 90

READ A1, A2, A3, A4 LET D=A1*A4-A3*A2 IF D=0 THEN 65 READ B1, B2 LET X1=(B1*A4-B2*A2)/D LET X2=(A1*B2-A3*B1)/D PRINT X1, X2 GOTO 30 PRINT "NO UNIQUE SOLUTION" DATA 1, 2,4 DATA 2, -7,5 DATA 1, 3, 4, -7 END

Das obige Programm ist das erste Beispielprogramm aus dem Manual des DartmouthBASIC vom 1. Oktober 1964 (Dartmouth College Computer Center 1964:3); es gilt als das erste BASIC-Programm überhaupt. Mit ihm soll ein lineares Gleichungssystem

178 | 3 BASIC mit zwei Unbekannten (X1 und X2) gelöst werden. Markant an dem Sourcecode ist dreierlei: 1. deutet die auffällig ungleichmäßige Zeilennummerierung darauf hin, dass das Programm mehrfach be-/überarbeitet wurde. Die Zeilennummerierung ist mithin ein Indiz für den Entstehungsprozess. 2. enthält das Programm trotzdem noch einen Fehler: Dadurch, dass in Zeile 60 fortlaufend zurück zur Zeile 30 gesprungen wird, aber spätestens nach dem fünften Rücksprung keine weiteren Wertepaare mehr in den DATA-Zeilen zu lesen sind, entsteht ein „Out of Data“-Error. 3. weist die Werteübergabe mittels DATA und READ darauf hin, dass dieser frühe BASIC-Dialekt noch nicht interaktiv war; Befehle für die User-Eingabe fehlen noch, daher müssen programmintern zu verarbeitende Daten im Programmcode selbst abgelegt werden. Versuchen Sie, das obige Programm zu Debuggen, sodass der unter 2. genannte Fehler nicht mehr auftritt. Versuchen Sie dann das Programm in BBC BASIC so zu ändern, dass die Wertepaare vom Nutzer eingegeben werden können. Zahlensystem-Konverter BBC BASIC bietet die Möglichkeit Zahlenwerte in verschiedenen Basis-Systemen anzugeben. Neben dem Dezimal-System können auch das duale und das hexadezimale Zahlensystem verwendet werden. Hierzu müssen Variablen nur entsprechend deklariert werden: Ein „&“ als Präfix ermöglicht die Übergabe eines hexadzimalen Wertes (a=&7B), ein vorangestelltes „%“ die Übergabe von Dualzahlen (b=%10101101). Bei Aufruf der Variablen (im Direktmodus mit PRINT a,b) werden diese Variablenwerte dann in das Dezimalsystem konvertiert und angezeigt. Diese automatische Umrechnung stellte BASIC nicht immer zur Verfügung. Kleine Programme (Tools), die zwischen den Zahlensystemen konvertierten, erleichterten Programmierern daher die Arbeit. Das folgende Beispiel (zit. n. Höltgen 2014:9) in Dartmouth-BASIC wandelt eine Dual- in eine Dezimalzahl um: Experiment II.10: Code Bumming 1 2 3 4 5 6 7

1 2 3 4 5 6 7

FOR I=0 TO 7 READ A LET B=B+EXP((7-I)*LOG(2))*A NEXT I PRINT B DATA 0,1,0,1,0,1,0,1 END

3.3 Programmieren in BASIC

| 179

Das obige Programm wurde als Einsendung eines Hacking-Wettbewerbes in einer aktuellen Computerzeitschrift (anlässlich des 50. „Geburtstags“ der Programmiersprache BASIC) abgedruckt. Aufgabe war es, eine Konvertierungsroutine nach den SyntaxVorgaben von Dartmouth-BASIC zu entwickeln, die die Aufgabe mit möglichst wenig Code löst. Solche „Bumming Contests“ besitzen eine lange Tradition in der Geschichte der Hacker-Szenen (vgl. Levy 1984:31 f.), stellen sie doch die Fertigkeiten der Programmierer auf eine besondere Probe. Hierbei entstehen oft unkonventionelle Lösungen, die sehr häufig nicht nur den „guten Stil“ einer Programmiersprache unterlaufen, sondern zeitweise auch Lücken im System nutzten, um Speicherplatz zu sparen (vgl. Saukas/Digital Prawn 2014:16 f.). Versuchen Sie einmal selbst diese Idee am oben zitierten Code in ein Programm umzusetzen und verknappen Sie die Konvertierungsroutine soweit wie es Ihnen möglich ist. Dafür müssen nicht notwendigerweise mathematische Funktionen wie in Zeile 3 verwendet werden. Conway’s Game of Life Zur Frage, wie sich beliebige Systeme mit Computern simulieren lassen, wird bereits seit Beginn des Computerzeitalters geforscht. John von Neumann (1951), Konrad Zuse (1969), BASIC-Miterfinder John G. Kemeny (1955) und andere Computerpioniere haben die Idee verfolgt, hierfür sogenannte Zellularautomaten zu verwenden: Kleinste virtuelle „Zellen“, die sich auf Basis definierter Regelsysteme entwickeln (oder verschwinden), sind in der Lage als Emergenzprozess zeitdiskrete Prozesse zu simulieren. Ausgehend von diesen Überlegungen hat sich Anfang der 1970er-Jahre ein regelrechter Run auf Zellularautomaten entwickelt, nachdem der britische Mathematiker John H. Conway sein „Game of Life“ entwickelt hatte: Ein Spiel, bei dem der Computer solche grafisch dargestellten Zellverbünde schrittweise verändert – auf Basis folgender Regeln: – Hat eine lebendige Zelle weniger als zwei Nachbarn, stirbt sie in der nächsten Generation an Vereinsamung. – Hat eine lebendige Zelle drei oder mehr Nachbarn, stirbt sie an Überbevölkerung. – Hat eine tote Zelle drei lebende Nachbarn, so wird sie in der nächsten Generation wiedergeboren. – Aus diesen Regeln folgt zusätzlich, dass eine Zelle mit zwei Nachbarn keine Statusveränderung erfährt. Das Spiel wird auf einem zweidimensionalen Raster gespielt. Die in der obigen Liste erwähnten Nachbarschaften beziehen sich immer auf ein Feld darin und betreffen die es umgebenden acht Nachbarfelder. Das Spiel kann im Prinzip unendlich lang laufen. Es sind drei „Endzustände“ möglich: 1. alle Zellen werden ausgelöscht. 2. Es entsteht

180 | 3 BASIC eine Situation der Stasis (in der sich Zellen nicht mehr verändern oder Zellmuster endlos oszillieren). 3. Es entsteht eine Situation permanenten Wechsels, ohne jemals Endzustand 1 oder 2 zu erreichen. (Ein 4. Fall, bei dem alle Zellen auf dem Feld leben, ist aufgrund der Regeln ausgeschlossen.) Ein Programm, das diese Regeln implementiert, könnte folgendermaßen aussehen: Experiment II.11: Conway’s Game of Life 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

5 REM GAME OF LIFE IN BASIC 10 CLS 20 DIM S(11,11):DIM A(11,11):OFF 30 GOSUB 500 40 GOSUB 900 50 GOSUB 600 60 GOSUB 700 80 GOTO 40 500 REM FELD FUELLEN 510 FOR I=1 TO 25 520 X=RND(10):Y=RND(10) 530 S(X,Y)=1:A(X,Y)=1 540 NEXT I 550 RETURN 600 REM ARBEIT->SPIEL 610 FOR Y=1 TO 10 620 FOR X=1 TO 10 630 S(X,Y)=A(X,Y) 640 NEXT X 650 NEXT Y 660 RETURN 700 REM SPIELREGEL ANWENDEN 710 FOR Y=1 TO 10 720 FOR X=1 TO 10 730 Q=S(X,Y-1)+S(X-1,Y-1)+S(X-1,Y)+S(X-1,Y+1)+ S(X,Y+1)+S(X+1,Y+1)+S(X+1,Y)+S(X+1,Y-1) 740 IF S(X,Y)=0 AND Q=0 THEN GOTO 860 750 IF X=1 AND Y=1 THEN Q=S(2,1)+S(2,2)+S(1,2):GOTO 830 760 IF X=1 AND Y=10 THEN Q=S(1,9)+S(2,9)+S(2,10):GOTO 830 770 IF X=10 AND Y=1 THEN Q=S(9,1)+S(9,2)+S(10,2):GOTO 830 780 IF X=10 AND Y=10 THEN Q=S(9,9)+S(10,9)+S(9,10):GOTO 830 790 IF X=1 AND (Y>1 AND Y1 AND Y1 AND X1 AND X++++[>++>+++>+++>+>+[. >>---.+++++++..+++.>.+.>++.+++." PROCbrainfuck(bf$) END DEF PROCbrainfuck(b$)

22 Für einige Sprachen, wie zum Beispiel LISP, wurde der Compiler in der Sprache entwickelt, die er kompilieren soll. Der BBC-BASIC-Editor BBCEdit von Andy Parkes ist ebenfalls als BBC-BASICProgramm verfasst, das in Echtzeit interpretiert wird. Die Implikationen einer solchen Selbstbezüglichkeit von Ausgangs- und Zielsprache ermöglichen interessante sprachwissenschaftliche und "philosophische Untersuchungen. 23 https://esolangs.org/wiki/Brainfuck (Abruf: 16.05.2018) 24 https://rosettacode.org/wiki/Execute_Brain****#BBC_BASIC (Abruf: 16.05.2018)

3.3 Programmieren in BASIC

| 199

7 LOCAL B%, K%, M%, P% 8 DIM M% LOCAL 65535 9 B% = 1 : REM pointer to string 10 K% = 0 : REM bracket counter 11 P% = 0 : REM pointer to memory 12 FOR B% = 1 TO LEN(b$) 13 CASE MID$(b$,B%,1) OF 14 WHEN "+": M%?P% += 1 15 WHEN "-": M%?P% -= 1 16 WHEN ">": P% += 1 17 WHEN "1: regeln.append(z[z.index(':')+1:].split(',')) def schritt(band, regeln, kopf, zustand): # Interpreter: if regeln[zustand][band[kopf]].find('E') > -1: return band, kopf, zustand symbol=-1 if regeln[zustand][band[kopf]].find('S') > -1: symbol=1 elif regeln[zustand][band[kopf]].find('L') > -1: symbol=0 dk=0 if regeln[zustand][band[kopf]].find('-') > -1: dk=-1 elif regeln[zustand][band[kopf]].find('+') > -1: dk=1 nzust=int(''.join(c for c in regeln[zustand][band[kopf]] if c.isdigit())) if symbol>-1: band[kopf]=symbol kopf+=dk zustand=nzust return band, kopf, zustand pygame.init() screen = pygame.display.set_mode((800, 50)) pygame.display.set_caption('Demonstration einer Turingmachine') band = [0] * 40 band[15:17]=1,1 zustand=kopf=kopf=0 clock = pygame.time.Clock() run = True

while run: clock.tick(3) for event in pygame.event.get(): if event.type == pygame.KEYDOWN: if event.key == pygame.K_ESCAPE: pygame.display.quit() run = False if event.type == pygame.QUIT: pygame.display.quit() run = False screen.fill((255, 255, 255)) band, kopf, zustand = schritt(band, regeln, kopf, zustand) pygame.draw.polygon(screen, (204, 0, 0), [[kopf*20+4, 10], [kopf*20+14, 10], [kopf*20+9, 20]]) 61 x=0

314 | 2 Determinismus und Determinierbarkeit 62 63 64

for c in band: pygame.draw.rect(screen, (0, 0, 0), (x*20+3, 28, 13, 13), 3) pygame.draw.rect(screen, (255*int(not c), 255*int(not c), 255*int(not c)), (x*20+3, 28, 13, 13)) 65 x+=1 66 pygame.display.flip() 67 pygame.display.quit()

Abb. 2.7: Die Turingmaschine bei der Arbeit Hodges (2012:99) beschreibt ein weiteres Programm, welches zwei Zahlen (zwei durch ein nichtmarkiertes Feld separierte Gruppen konsekutiv markierter Felder) addiert. Das von Hodges beschriebene Programm findet sich, übersetzt in die hier beschriebene Notation, in Listing 2.3. Zwei in der von Hodges beschriebenen Weise kodierte Zahlen, in diesem Fall eine Vier und eine Fünf, können mit der Zeile in Listing 2.4 (anstelle der Zeile 42 in Listing 2.2) auf das Band geschrieben werden.

Listing 2.3: Addition mit der Turingmaschine

Listing 2.4: Band-Markierungen zum Addieren

3 4 5 6 7 8

42 band[15:25] = 1,1,1,1,0,1,1,1,1,1

programm = ''' 0:+0,+1 1:S+2,+1 2:-3,+2 3:E,L3 '''

Versuchen Sie über die beiden obigen Beispiele hinaus auch eigene einfache Programme für die Turingmaschine zu schreiben und ausführen zu lassen. Bei Bedarf kann hierfür die Länge des Bandes mit der Länge der Liste band verändert werden (oben in Zeile 41). Ein Band mit 55 Feldern erhalten Sie beispielsweise mit band = [0] * 55. Die Fensterbreite des Programms können Sie verändern, indem Sie die Zahl 800 (Breite in Pixel) in Zeile 38 anpassen.

Während es sich bei der Turingmaschine um eine theoretische Zustandsmaschine handelt, deren symbolverarbeitende Operationen lediglich durch abstrakte Regeln definiert werden, sind technische Geräte wie Schreibmaschinen und Computer konkrete physikalische Vorrichtungen. Folglich sind ihre Operationen verschiedenen Imperfektionen, Verschleiß sowie störenden Einflüssen ausgesetzt. Die Gewährleistung von Determinierbarkeit unter diesen Bedingungen erfordert das Etablieren klarer und nachhaltig verlässlicher Zustände und daher das Ausräumen von Ambiguitäten zwischen diesen Zuständen. Im Fall digitaler Systeme ist dies die zuverlässige Unterscheidung der Zustände 1 und 0, aufgrund derer die Digitaltechnik – unter anderem – als „diskret“ beschrieben wird.

2.4 Programmierbare Abläufe: die Turingmaschine

|

315

Begriffsklärung: das „Diskrete“ in der Digitaltechnik Das Digitale wird gemeinhin als „diskret“ charakterisiert. Dies kann sich beziehen auf: 1. die Unstetigkeit digitaler Signale (in ihrer idealisierten Sicht), also auf die klare Trennung von 1 und 0 bzw. von anderen auf den Symbolen 1 und 0 basierenden Repräsentationen. Dieser Umstand kann präziser mit dem Wort Signal-diskret (siehe Band 1, Abschnitt II.4.2.6) beschrieben werden. 2. den schrittweisen Takt digitaler Computer, infolge dessen zwischen zwei konsekutiven Takten kein definierter Zustand auswertbar und keine fraktionalen Zeiteinheiten vorzufinden sind. Dieser Umstand kann präziser mit dem Wort Zeit-diskret (siehe Band 1, Abschnitt II.4.2.6) beschrieben werden. 3. die auch bei analogen Repräsentationen anzutreffende Trennung von Repräsentiertem und Repräsentation, also beispielsweise zwischen einem logischen Zustand und dem ihn repräsentierenden physikalischen Zustand oder zwischen Territorien und den sie repräsentierenden Landkarten („A map is not the territory.“ Korzybski 1995:58).

Die in Experiment III.2 besprochenen Beispielprogramme (Verdopplung und Addition) stellen ganze positive Zahlen als Gruppen konsekutiv markierter Felder dar. Andere Kodierungen sind ebenfalls möglich. So kann beispielsweise das binäre Zahlensystem verwendet werden. Um in diesem Fall mehrere Zahlen voneinander unterscheiden zu können, bietet es sich an, eine begrenzte Anzahl konsekutiver binärer Symbole für die Darstellung jeweils einer Zahl vorzusehen. So können mit Gruppen von je acht binären Symbolen (einem sogenannten Byte) jeweils ganze positive Zahlen zwischen 0 und 255 dargestellt werden. Alternativ kann hierbei das erste Bit zur Kodierung des Vorzeichens verwendet werden, sodass Werte im Zahlenraum von -128 bis 127 dargestellt werden können (siehe Band 1, Unterkapitel I.5.4). Darüber hinaus ist es möglich, Bytemuster mit alphanumerischen und anderen (mathematischen, orthografischen usw.) Zeichen zu assoziieren, um auch diese repräsentieren zu können. Die Strategie ist in der Tat weit verbreitet, auf der Turingmaschine jedoch schwieriger zu verarbeiten als die in Experiment III.2 verwendeten Gruppen konsekutiv markierter Felder. Bei der binären Kodierung umfangreicher Symbolvorräte basiert die verlässliche Unterscheidung von Symbolen letztlich wiederum auf der in Unterkapitel 2.3 diskutierten verlässlichen Unterscheidung einzelner binärer Zustände. Einzelne Regeln der Turingmaschine folgen dem Format des sogenannten bedingten Sprungs („Wenn ..., dann ..., sonst ...“), also einer Instruktion, die es gestattet, Programmabläufe abhängig von gegebenen Bedingungen zu steuern. Die Möglichkeit bedingter Sprünge ist eine grundsätzliche Eigenschaft heutiger digitaler Computer und eine Grundvoraussetzung für digitale kybernetische Systeme im Sinne der auf Seite 301 angebotenen Definition der Kybernetik. Ähnlich wie sich umfangreiche Symbolvorräte auf der Basis von Gruppen binärer Zustände kodieren lassen, können Sprünge in Programmabläufen durch Gruppen elementarer Zustände bedingt sein. Listing 2.3 ließe sich beispielsweise dahingehend erweitern, dass nach erfolgter Addition das zweite Feld rechts neben der Summe markiert wird, wenn die Summe eine gerade Zahl

316 | 2 Determinismus und Determinierbarkeit ist. Hierbei konstituieren mehrere elementare Zustände und darauf basierende Sprünge innerhalb eines verzweigenden Programmablaufs („Wenn ein markiertes Feld vorgefunden wird, dann ..., sonst ...“) gemeinsam die Bedingung für eine übergeordnete Bedingung („Wenn die Zahl gerade ist, ...“). Derselbe logische Zustand kann mehrfach in Gruppen physikalischer Zustände gespeichert, übermittelt oder verarbeitet werden. Da man mit Redundanz (siehe Band 1, Unterkapitel II.4.5) dieser Art begrenzte Verlässlichkeiten physikalischer Träger kompensieren und sich der idealen Determinierbarkeit logischer Formalismen annähern kann, ist diese Strategie oft in missionskritischen digitalen Technologien anzutreffen. Bei der parallelen Verarbeitung derselben Signale durch mehrfach implementierte digitale Subsysteme etwa können Abweichungen zwischen den jeweiligen Ergebnissen zur Erkennung und Korrektur von Fehlern herangezogen werden. Ein Beispiel ist der Saturn Launch Vehicle Digital Computer (LVDC) der NASA Mondrakete Saturn V. Der Arbeitsspeicher des LVDC basierte auf Ferritkernen, deren magnetische Ausrichtung, wie bereits erwähnt, ebenfalls die bistabile HystereseCharakteristik aufweist (siehe Band 1, Abschnitt II.5.3.1). Trotz der damit erreichten beachtlichen Zuverlässigkeit erfüllte der Computer die für bemannte Flüge geltenden Zuverlässigkeitsanforderungen nur mit zweifach ausgeführtem Arbeitsspeicher sowie dreifach redundanter Ausführung aller weiteren Baugruppen auf sieben Ebenen (Bilstein 1996:250). Für jedes Auslesen eines Maschinenzustands wurden die Zustände aller drei jeweils relevanten Baugruppen ausgelesen und bei möglichen Abweichungen das Resultat nach dem Mehrheitsprinzip ermittelt.

2.5 Deterministische Mechanismen: die Triviale Maschine Eine definierende Eigenschaft der Turingmaschine ist die Determinierbarkeit, mit der sie bei gleichen Regeln und gleichen Markierungen auf dem Band immer verlässlich zu demselben Ergebnis gelangt. Anders gesagt: Bei gleichen Startbedingungen führt ein gegebener Input immer zum selben (somit vorhersehbaren) Output. Diese Eigenschaft des Gedankenexperiments Turingmaschine ist zuvor bereits in mechanischen Geräten wie eben der Schreibmaschine weitgehend erreicht worden. Auch bei der Schreibmaschine zeigt sich eine hohe Verlässlichkeit und Vorhersehbarkeit bezüglich der Korrespondenz zwischen akzeptierten Inputs und den daraufhin produzierten Outputs. Dabei ist es im Prinzip irrelevant, dass die Input-Symbole der Schreibmaschine weitestgehend identisch sind mit den durch sie ausgelösten Output-Symbolen, dass also beispielsweise beim Anschlag der Taste A auch ein A geschrieben wird. Man könnte im Grunde die Tasten auf der Input-Seite oder die Typen auf der Output-Seite jeweils willkürlich untereinander austauschen. Danach wären die Output-Symbole zwar nicht mehr identisch mit den sie auslösenden Input-Symbolen, doch die Korrespondenz zwischen Input-Symbolen und Output-Symbolen wäre weiterhin sehr verlässlich. Auf denselben Input folgt immer derselbe Output. Basierend auf Beobachtun-

2.5 Deterministische Mechanismen: die Triviale Maschine

| 317

gen der Input-Output-Operationen der Maschine lässt sich folglich mit hoher Wahrscheinlichkeit vorhersagen, welche Output-Symbole welchen Input-Symbolen folgen werden. Die Maschine ist determinierbar. Es ist uns selbstverständlich, regelmäßig und direkt nacheinander auftretende Phänomene in kausalen Zusammenhängen zu sehen, zu verstehen und folglich zu erwarten. Die Erkenntnis, dass B wiederholt auf A folgt, lässt uns beim Auftreten weiterer As weitere Bs erwarten. Wir ziehen Muster dieser Art in Betracht, wenn wir unsere Umwelt hinsichtlich unserer Wünsche, Bedürfnisse und Abneigungen navigieren und manipulieren. Jedoch weist unsere Umwelt keinen kausalen Mechanismus an sich auf. Unserem Erkennen verschiedenster chemischer, physikalischer, biologischer, psychologischer und anderer kausaler Beziehungen liegt kein ersichtliches gemeinsames Bindeglied zwischen Ursache und Wirkung zugrunde. Zwischen Blitz und Donner, zwischen Einsamkeit und Traurigkeit und zwischen Spannung und Strom finden wir keinen verbindenden Sachverhalt und kein allgemeines Prinzip außer unserem eigenen Erkennen zusammentreffender Ereignisse. So erscheint die Bindung zwischen Ursache und Wirkung weniger als ein extern gegebenes Prinzip denn als eine interne Zuschreibung. Wie in Unterkapitel 2.1 erwähnt, erleben wir diese Zuschreibungen nichtsdestotrotz als weithin praktikabel. Zuschreibungen kausaler Verlässlichkeit lassen sich oft nur dann aufrechterhalten, wenn die jeweils beobachteten Prozesse von störenden Einwirkungen isoliert werden. So lässt sich die der Schreibmaschine zugeschriebene Verlässlichkeit, mit der etwa die Betätigung der Taste A (Input) immer zur Markierung des Zeichens A (Output) führt, nur dann aufrechterhalten, wenn die Maschine voll funktionstüchtig ist und ihren normalen Arbeitsbedingungen unterliegt. Ohne Farbband und Schreibpapier oder in einen Block Eis eingefroren verhält sich die Maschine anders. Dementsprechend setzen Zuschreibungen kausaler Verlässlichkeit insbesondere in der empirischen Wissenschaft „ansonsten gleiche Bedingungen“ (auf Lateinisch: ceteris paribus) voraus. Die hier beschriebene triadische Struktur (Input + Maschine → Output) unterliegt unseren Zuschreibungen kausaler Determiniertheit mindestens seit der griechischen Antike und Aristoteles’ Beschreibung syllogistischer (Band 1, Unterkapitel I.1.2) Strukturen in logischem Schließen (Untersatz + Obersatz → Schluss). Sie dient uns als Blaupause kausaler Wirkungszusammenhänge in praktisch allen Bereichen rationalen Denkens und Handelns (siehe Tabelle 2.1). Bateson erklärt, dass diese triadische Struktur unser eigenes Verständnis kausaler Wirkungszusammenhänge reflektiert und nicht die damit beschriebenen beobachtbaren Beziehungen an sich. Er demonstriert dies mit einer Gegenüberstellung zweier Syllogismen.

318 | 2 Determinismus und Determinierbarkeit Tab. 2.1: Triadische Struktur kausaler Wirkungszusammenhänge (Pörksen 1998:57) x

f

y

Input unabhängige Variable Ursache Untersatz Reiz Motiv Ziel ...

Operation Funktion Naturgesetz Obersatz Organismus Charakter System ...

Output abhängige Variable Wirkung Schluss Reaktion Tat Verhalten ...

Der Syllogismus in Barbara⁴ ist der erste von 24 validen syllogistischen Modi. Er beschreibt im Obersatz eine Eigenschaft der Mitglieder einer Kategorie. Im Untersatz identifiziert er ein Mitglied dieser Kategorie. Hieraus wird geschlossen, dass das Mitglied die genannte Eigenschaft der Mitglieder der Kategorie teilt. Der Syllogismus in Gras folgt scheinbar demselben Muster, missachtet jedoch gemeinhin übliche Kategorisierungen. Bateson argumentiert, dass der Syllogismus in Gras lebende Systeme besser repräsentiert als die Logik des Syllogismus in Barbara mit seinen strikten Unterscheidungen zwischen Mitglied und Kategorie – Unterscheidungen, die, so Bateson, zwar in Sprache auftreten, aber nicht in der natürlichen Welt (Roffman 2008:250). Syllogismus in Barbara

Syllogismus in Gras

Menschen sind sterblich Sokrates ist ein Mensch Sokrates ist sterblich

Gras ist sterblich Menschen sind sterblich Menschen sind Gras

Von Foerster formalisiert die triadische Struktur kausalen Denkens mit einem Gedankenexperiment in der Form einer Input-Output-Maschine (siehe Abbildung 2.8), der sogenannten Trivialen Maschine (TM). Diese Maschine übersetzt Input-Symbole in jeweils zugeordnete Output-Symbole. Hierbei haben aufeinanderfolgende Operationen keinen Einfluss aufeinander. Beobachter können die TM analytisch determinieren (von Foerster 1993:357), also kausale Beziehungen zwischen Inputs und korrespondierenden Outputs etablieren und diese in einer Wertetabelle (siehe Tabelle 2.2) – analog zu Wahrheitstabellen der Aussagenlogik (Band 1, Teilband I) – beschreiben. Solche Tabellen wiederum erlauben verlässliche Vorhersagen weiterer Outputs auf der Basis jeweils vorangehender Inputs. Dies kann in Experiment III.3 geprüft werden.

4 Die Benennung von Syllogismen folgt einer Konvention, nach der Obersätze, Untersätze und Schlüsse in vier Typen A, E, O, I kategorisiert und mit mnemonischen Namen entsprechend den jeweiligen Sequenzen benannt werden. Als erster dieser Modi, A-A-A, wird „Barbara“ besonders oft zitiert.

| 319

2.5 Deterministische Mechanismen: die Triviale Maschine

Experiment III.3: Triviale Maschine Listing 2.5 implementiert eine Triviale Maschine (von Foerster 2003b:309–311). Nach dem Programmstart wird zunächst der gewünschte Umfang des Symbolvorrats sowohl für mögliche Inputs als auch für mögliche Outputs abgefragt und dann eine jeweils zufällige Zuordnung von Inputs und Outputs festgelegt. Diese bleibt bis zum Abbruch des Programms mit ! erhalten. Ermitteln Sie durch Beobachtung die Zuordnung von Inputs und Outputs, notieren Sie diese in einer Wertetabelle. Stellen Sie nun auf der Basis der Wertetabelle Vorhersagen an und überzeugen Sie sich von deren Verlässlichkeit. x A B C D

y B C D A

Tab. 2.2: Wertetabelle: determinierbares Verhalten einer Trivialen Maschine

x

f

y

Abb. 2.8: Triviale Maschine mit der Funktion y = f (x)

Listing 2.5: Triviale Maschine (trivial-machine_DE.py) 1 2 3 4 5 6 7 8 9 10 11 12 13

import random import copy # Umfang des Symbolvorrats (sowohl für Inputs als auch für Outputs) abfragen sv=0 while sv26: sv= int(input("Umfang des Symbolvorrats (2..26)? ")) srain=list(map(chr, range(97, 97+sv))) # Input-Array generieren sraout=copy.copy(srain) # vorläufiges Output-Array zu erstellen random.shuffle(sraout) # Output-Array durchmischen print("Akzeptable Inputs und mögliche Outputs: ["+srain[0]+".."+srain[len(srain)-1]+"]")

14 15 inp='' 16 while True: 17 print("Die Triviale Maschine ist bereit.") 18 inp=input("Input (!=Ende)? ") 19 if inp!='': 20 if inp=="!": break 21 if inp in srain: 22 print("Output: " +sraout[srain.index(inp)]) 23 else: 24 print("Inakzeptables Input-Symbol.") 25 print("TM Ende.")

320 | 2 Determinismus und Determinierbarkeit Mit der Trivialen Maschine richtet von Foerster einen kritischen Blick auf das in modernen Kulturen verbreitete Streben nach determinierbarer Kontrolle nicht nur technischer, sondern auch sozialer Prozesse (von Foerster 2006:12–13). In diesem Sinne folgen nicht nur Computer, Logikgatter und die allermeisten technischen Geräte, sondern auch Vertragspartner, Experten, Bürokraten und erfolgreiche Schulkinder dem Prinzip der Trivialen Maschine. Von Foerster hinterfragt insbesondere Bildungseinrichtungen, in denen Lernende „trivialisiert“ werden, bis sie auf Fragen verlässlich mit den erwarteten – also bereits bekannten – Antworten reagieren (Segal 1986:106; Pruckner 2002:16:39–18:33; von Foerster 2006:12–13). Er verweist auf die Diskrepanz zwischen der Erwartung determinierbaren menschlichen Verhaltens einerseits und dem überwiegenden menschlichen Selbstverständnis als spontan und nicht-trivial andererseits (von Foerster und Schmidt 1993:360). Hierbei ist von Foerster nicht daran gelegen, den Menschen durch den Vergleich mit einer „Maschine“ auf mechanistisches Verhalten zu reduzieren. Vielmehr stellt er seiner Trivialen Maschine eine Nicht-Triviale Maschine gegenüber: ein einfacher Mechanismus, der die Möglichkeit deterministischer Vorhersagbarkeit grundsätzlich infrage stellt (Pörksen 1998:57–58). Mehr hierzu später. Mit diskreten Trennungen logischer und physikalischer Zustände, endlichen Symbolvorräten, redundanten Repräsentationen und Fehlerkorrekturen und weiteren Strategien lässt sich bei physikalischen Geräten ein hoher Grad an Zuverlässigkeit erreichen. Hieraus ergibt sich unter anderem die weitestgehend verlust- und fehlerfreie Kopier- und Reproduzierbarkeit digitaler Signale im Gegensatz zur unweigerlich verlustbehafteten Verarbeitung analoger Signale. So erweckt der Umgang mit digitalen Medien in aller Regel den Eindruck idealer Determinierbarkeit. Letztlich lässt sich die ideale Determinierbarkeit logischer Formalismen physikalisch jedoch nicht vollkommen umsetzen; lediglich eine Annäherung ist möglich. Kausale Verlässlichkeit ist nicht auf eine generelle naturgesetzliche Notwendigkeit, sondern lediglich auf wiederholte Beobachtung zurückzuführen. Allerdings ist zu bezweifeln, dass kausale Beziehungen generell im Sinne eines unidirektionalen Erkenntnisprozesses vorgefunden und daraufhin schlicht im Vertrauen auf die Wirkungszusammenhänge verinnerlicht werden. Die Annahme, zuvor verlässliche Umstände blieben notwendigerweise weiterhin verlässlich, ist irrig (und wird in der Rhetorik folglich als logischer Trugschluss – das sogenannte Traditionsargument – erkannt). Vielmehr deutet die Rolle von Maschinen in Implementationen determinierbarer Wirkungszusammenhänge und beim Veranschaulichen kausaler Prinzipien auf etwas anderes hin: dass wir nämlich kausale Verlässlichkeit auch technisch manipulierend etablieren und aufrechterhalten, sie also auch durch Willensakte externalisieren. Ein einfaches Beispiel ist die zweckgerichtete Abschirmung störender Einflüsse. So erscheint das Etablieren verlässlicher Ursache-Wirkungs-Zusammenhänge an sich als wechselseitig-kausaler Austausch zwischen internen und externen Prozessen, zwischen Verstehen und Handeln. Wechselseitige Wirkungszusammenhänge dieser Art sollen im folgenden Kapitel näher betrachtet werden.

3 Zirkuläre Kausalität 3.1 A beeinflusst B und B beeinflusst A Neben dem zu Beginn von Kapitel 2 besprochenen Conundrum zwischen Willensfreiheit und Determinismus stellt uns Kontrolle in selbstregulierenden Systemen wie der Watt’schen Dampfmaschine und dem Thermostat vor weitere philosophische Herausforderungen. Eine solche Herausforderung zeigt sich, wenngleich nicht auf den ersten Blick, in typischen Beschreibungen selbstregulierender Systeme wie der folgenden, einem Jugendlexikon (Braun 2008:637) entnommenen Beschreibung des Thermostats: Ein Bimetallstreifen schaltet bei zu großer Erwärmung das Heizelement aus und nach genügender Abkühlung wieder ein.

Hinter dieser durchaus zutreffenden und zunächst unverfänglich erscheinenden Charakterisierung verbirgt sich eine in modernen Kulturen vorherrschende selektive Wahrnehmung mit weitreichenden Konsequenzen. Die Beschreibung impliziert durch partielle Auslassung ein lediglich lineares Kontrollverhältnis. Der Bimetallschalter kontrolliert das Heizelement: „A kontrolliert B“. In dieser, für die Kybernetik erster Ordnung typischen Sichtweise befindet sich der Bimetallschalter auf der kontrollierenden Seite und das Heizelement auf der kontrollierten Seite eines linear-kausalen Kontrollverhältnisses. Diese Sichtweise erklärt die Ursache für Zustandsänderungen des Heizelements. Jedoch ist die selbstregulierende Oszillation des Thermostats dem Umstand geschuldet, dass auch der Bimetallschalter seine Zustände wechselt. Was bewirkt das Ein- und Ausschalten des Bimetallschalters? Es ist das Heizelement, das seinerseits mit der von ihm produzierten Hitze den Bimetallschalter kontrolliert. So kontrollieren sich beide Elemente gegenseitig in einer wechselseitigen, also zirkulär-kausalen Beziehung: „A kontrolliert B und B kontrolliert A“. Dieser Aspekt des Kontrollverhältnisses wird in der obigen Charakterisierung verschwiegen. Eine kleine Gruppe späterer Kybernetiker machte es sich Anfang der 1940er-Jahre zur Aufgabe, der einseitigen Sicht eine umfassendere Theorie gegenüberzustellen. Damals erforschte Arturo Rosenblueth an der Harvard University chemische Aspekte der Homöostase (Cannon 1932:24), also der in den Unterkapiteln 1.5 und 1.6 bereits angesprochenen zirkulär-kausalen Prozesse, durch die Organismen ihre Umgebungen anpassen, um somit wiederum ihre eigene Stabilität zu gewährleisten. Währenddessen begann er gemeinsam mit Norbert Wiener und Julian Bigelow eine abstrakte Theorie der Zielorientierung – der sogenannten Teleologie – zu formulieren. Wiener und Bigelow arbeiteten zu der Zeit am wenige Kilometer entfernten MIT an einer Herausforderung in der Luftabwehr, die in Kapitel 4 näher betrachtet wird. Es gelang der Gruppe, den bis dahin vornehmlich in der Philosophie behandelten Begriff der Teleologie auf die Prinzipien von Feedback und zirkulärer Kausalität https://doi.org/10.1515/9783110496253-022

322 | 3 Zirkuläre Kausalität zurückzuführen: „[T]he behavior of some machines and some reactions of living organisms involve a continuous feed-back from the goal that modifies and guides the behaving object.“ (Rosenblueth et al. 1943:20) Hieraus ergaben sich neue Herausforderungen. Zum einen waren die Begriffe Ziel und Zweck zu erklären. Anstatt diese Begriffe jedoch, wie in akademischer Rhetorik gemeinhin üblich, durch objektive Definitionen handhabbar zu machen, vermied die Gruppe objektive Formalismen und verwies darauf, dass das Identifizieren von Zielen und Zwecken Gegenstand subjektiver Interpretation sei (Rosenblueth et al. 1943:18–19)¹. Zum anderen zeichnete sich ab, dass die Berücksichtigung zirkulärer Kausalität den Hauptströmungen abendländischer Philosophie und Logik widerspricht. Zirkuläres Schließen fehlt in keiner Sammlung logischer Trugschlüsse (Engel 1980:54) und dass zirkuläre Argumente, einmal als solche identifiziert, zu verwerfen sind, ist vielerorts eine Selbstverständlichkeit. Die sich in der Arbeit der drei Forscher abzeichnende Berücksichtigung subjektiver Beobachtung und zirkulärer Kausalität sollte sich als Beginn einer bis heute andauernden kybernetischen Kampagne gegen akademische Orthodoxien herausstellen. Bevor im weiteren Verlauf dieses Teilbandes auf die Berücksichtigung subjektiver Beobachtung eingegangen wird, soll hier zunächst der Widerstand gegen die Berücksichtigung zirkulärer Kausalität betrachtet werden.

3.2 Logische Paradoxien Zirkuläre Kausalität ist, wie bereits anhand der Beispiele der Watt’schen Dampfmaschine (hohe Drehzahl → Ventilschließung → Verlangsamung → Ventilöffnung usw.) und des Thermostats (niedrige Temperatur → Heizelement ein → Erwärmung → Heizelement aus usw.) demonstriert wurde, sowohl nachvollziehbar als auch vielerorts anzutreffen. Doch der Widerstand gegen die Berücksichtigung zirkulärer Kausalität beruht weniger auf Problemen ihrer Verständlichkeit oder der Möglichkeit ihrer technischen Umsetzung. Vielmehr ist er in theoretischen und kulturellen Implikationen ihrer Beschreibung begründet, denn sie korrespondiert direkt mit einer in der modernen, westlichen Kultur geächteten logischen Figur, der Paradoxie. Als Musterbeispiele dieser Figur bereiten die sogenannte Lügner-Paradoxie (die Aussage „Ich bin ein Lügner.“) und deren Variation, die sogenannte Paradoxie des Epimenides („Epimenides der Kreter sagte: Alle Kreter sind Lügner.“) Philosophen seit dem antiken Griechenland Kopfzerbrechen. Offensichtlich sind diese Aussagen wahr, wenn sie falsch sind, und falsch, wenn sie wahr sind. Folglich sind sie unklare Aussagen und im Kontext der Aussagenlogik wenig hilfreich. Daher besteht der seit der grie-

1 Beer (2002:217) erklärt später: „the purpose of a system is what it does“, und priorisiert damit Prozess gegenüber der Beschreibung und Attribuierung von Intentionen.

3.2 Logische Paradoxien

|

323

chischen Antike übliche Umgang mit Paradoxien darin, zirkuläre Strukturen schlicht zu vermeiden (siehe Band 1, Unterkapitel I.1.3). Nichtsdestotrotz wurden seither auch zahlreiche Versuche unternommen, Paradoxien logisch handhabbar zu machen. Einen dieser Versuche unternahm der britische Philosoph und Mathematiker Bertrand Russell zu Beginn des 20. Jahrhunderts. Im Jahr 1901 fand Russell ein Paradox in der von dem deutschen Philosophen und Mathematiker Gottlob Frege entwickelten Mengenlehre. Diese nahm an, dass die Definition jeder Menge eine Abgrenzung zweier Mengen darstellt, nämlich der Menge der in ihr enthaltenen Elemente einerseits und deren Komplement, also die Menge aller davon abgegrenzten Elemente andererseits (die Definition der Menge der Lebewesen zum Beispiel grenzt diese von der Menge des Nicht-Lebendigen ab). Weiterhin nahm Freges Mengenlehre an, dass Mengen hierarchisch in verschachtelte Untermengen gegliedert seien (die Menge der Pflanzen beispielsweise ist eine Untermenge der Menge der Lebewesen). Nun impliziert die hierarchische Gliederung der Mengen die Existenz einer übergeordneten Menge aller Mengen. Wenn diese allerdings eine Abgrenzung von einer anderen Menge darstellt, dann gehört diese andere, abgegrenzte Menge, da sie ja eine Menge ist, in die Menge aller Mengen!² Inspiriert unter anderem von Freges Mengenlehre und der von ihm darin entdeckten Paradoxie unternahm Russell gemeinsam mit Alfred North Whitehead den Versuch, die Gesamtheit mathematischer Wahrheiten in einem umfangreichen Grundlagenwerk mit dem Titel Principia Mathematica (Whitehead und Russell 1910–1913) darzustellen. Der umfassende Anspruch dieses Projekts erforderte eine Lösung des Paradoxie-Problems. Russell widmete dieser Herausforderung mehrere Jahre, bis er 1905 schließlich erfolglos aufgab und laut Segal (1986:39–41) erklärte: „The solution to the paradox is simple – I WON’T ALLOW IT. I FORBID IT. A set cannot be considered as one of its own elements!“ (Russell 1967:222–229) Paradoxien und zirkuläres Schließen blieben weiterhin Tabus in abendländischem Denken. Kybernetische Denker sind jedoch wenig geneigt, sich Form und Umfang ihrer Betrachtungen von den Grenzen des formell Beschreibbaren diktieren zu lassen. Wiener weist darauf hin, dass Maschinen keine prinzipiellen Schwierigkeiten mit paradoxen Instruktionen haben und in diesem Fall schlicht oszillieren (Wiener 1963:126). Bateson zitiert Wiener mit den Worten: „if you present the Epimenides paradox to a computer, the answer will come out YES ... NO ... YES ... NO ... until the computer runs out of ink or energy or encounters some other ceiling.“ (Bateson 1979:107) Er versichert, Computer würden sich unter diesen Umständen keineswegs spontan in Luft auflösen (Bateson 1972:281). Experiment III.4 lädt dazu ein, dies zu prüfen.

2 Die Figur der sich selbst enthaltenden Menge entspricht der Form der sogenannten Klein’schen Flasche, einer dreidimensionalen Entsprechung des Möbiusbandes. Richards’ (2016:48) Definition auf Seite 301 spielt auf diese Form an und verweist auf die Anwendbarkeit der Kybernetik auf sich selbst.

324 | 3 Zirkuläre Kausalität

Experiment III.4: Paradoxon des Epimenides Das folgende Skript implementiert die klassische Lügner-Paradoxie in Python. Seine Ausführung führt in eine Endlos-Schleife, die mit der Tastenkombination ctrl + c abgebrochen werden kann. Listing 3.1: Lügner-Paradoxie (liars-paradox_DE.py) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

def auswertung(aussage): if aussage == "Ich bin ein Lügner.": aussage=aussage.replace('ein', 'kein') return aussage if aussage == "Ich bin kein Lügner.": aussage=aussage.replace('kein', 'ein') return aussage aussage="Ich bin ein Lügner." vorherige_aussage="" while not vorherige_aussage == aussage: vorherige_aussage=aussage aussage=auswertung(aussage) print(aussage)

Bei seiner Ausführung tritt das Skript in Listing 3.1 in eine endlose Oszillation zwischen zwei Zuständen ein und gibt dabei abwechselnd die Sätze „Ich bin ein Lügner.“ und „Ich bin kein Lügner.“ aus. Es kommt weder zu einer Fehlermeldung noch zu technischen Problemen, noch löst sich der Computer spontan in Luft auf. Es stellt sich somit die Frage: Wenn ein Computer die Lügner-Paradoxie problemlos bearbeiten kann (und Dampfmaschinen und Thermostate sich selbst regulieren können), warum bereiten Paradoxien Mathematikern und Logikern Probleme? Worin besteht der Unterschied zwischen Computern und selbstregulierenden Mechanismen einerseits und selbst-invertierenden Strukturen in der Aussagenlogik andererseits?

Von Foerster stellt fest, dass Computer Paradoxien nicht nur problemlos verarbeiten können, sondern in ihrer Funktionsweise mitunter ihrerseits auf zyklisch selbstinvertierenden Prozessen beruhen. Bevor digitale Computer mittels schwingender Quarzkristalle getaktet wurden, folgten sie den Oszillationen bistabiler Flip-FlopSchwingkreise (Band 1, Unterkapitel I.6.4), einem elektronischen Äquivalent paradoxer Aussagen. Trotz ihrer verbreiteten Reputation als „logische“ Input-OutputMaschinen folgten frühe Computer somit ironischerweise einem paradoxen Herzschlag (Grössing 2005:BAL7.MP3, 30:25).

3.3 Geburtsurkunde der Kybernetik Rosenblueth, Wiener und Bigelow entwickelten ihre Ideen ungeachtet akademischer Orthodoxien und ließen sich dabei weder vom subjektiven Charakter der Begriffe Ziel und Zweck noch vom zirkulär-kausalen Charakter der Selbstregulierung aufhalten. Als

3.4 Reflexivität

| 325

Rosenblueth die Gelegenheit bekam, den handverlesenen Teilnehmern eines Seminars im Mai 1942 die Arbeitsergebnisse seiner Gruppe zu präsentieren, löste er damit eine Sensation aus (Kline 2015:40). Bei dem Treffen handelte es sich um das von Frank Fremont-Smith, dem damaligen medizinischen Direktor der Josiah Macy Jr. Stiftung (siehe Unterkapitel 1.5) organisierte Cerebral Inhibition Meeting in New York. Unter den Teilnehmern waren neben Fremont-Smith und Rosenblueth auch der Neurophysiologe Warren McCulloch sowie die Anthropologen Margaret Mead und Gregory Bateson.³ Die Seminarteilnehmer erkannten, dass zirkuläre Kausalität und Feedback nicht länger ignoriert werden konnten. Sie wurden das zentrale Thema der Macy-Konferenzen, die zwischen 1946 und 1953 in New York veranstaltet wurden, nachdem der Zweite Weltkrieg zwischenzeitlich andere Prioritäten diktierte. Einige Monate nach dem Cerebral Inhibition Meeting publizierten Rosenblueth, Wiener und Bigelow (1943) ihre Ergebnisse in einem Artikel, der bereits im darauffolgenden Jahrzehnt als „Geburtsurkunde der Kybernetik“ bezeichnet werden sollte (de Latil 1957:8). Binnen weniger Jahre sollte die Kybernetik zu einer dominierenden Wissenschaft avancieren. Doch die kybernetische Anfechtung philosophischer Orthodoxien entging zunächst selbst Anhängern der neuen Disziplin und für einige Jahrzehnte galt die Kybernetik vornehmlich als Methodik für gerichtete technische Kontrolle. In dieser Form nahm sie Mitte des vergangenen Jahrhunderts zwischenzeitlich den Status eines prototypischen Paradigmas für das Verstehen und das Angehen von Herausforderungen in vielen Bereichen des Lebens ein. Seit der Etablierung der Kybernetik zweiter Ordnung in den 1970er-Jahren ist die Tragweite zirkulär-kausaler Beziehungen stärker anerkannt. Es verbreitet sich die Erkenntnis, dass viele unserer Herausforderungen durch Reflexivität charakterisiert sind und dass sie sich somit linearer Kausalität und gerichteter, zweckorientierter Kontrolle entziehen.

3.4 Reflexivität Inputs und Outputs reflexiver Herausforderungen bedingen sich gegenseitig. Derartige Konstellationen sind in vielen Kontexten anzutreffen.⁴ Messungen verändern das Gemessene. Der Stückpreis beeinflusst die Absatzmenge, während die Absatzmenge den Stückpreis beeinflusst. Zu viel Nähe erstickt Beziehungen. Das Ersetzen menschlicher Arbeitskraft durch automatisierte Systeme kann dazu führen, dass Menschen automatisierte Vorgänge weniger beherrschen und somit ein erhöhter Bedarf an menschlicher Arbeitskraft entsteht (Bessen 2016). Diese „Paradoxie der Automatisierung“ und das Ersticken von Beziehungen durch zu viel Nähe sind Beispiele für den

3 Mead berichtete später, sie habe sich während des Treffens einen Zahn abgebrochen, dies in ihrer Aufregung über Rosenblueths Präsentation aber erst nach dem Treffen bemerkt (Mead 1968:1). 4 Siehe Hegels (1989:145) Herr-Knecht-Dialektik.

326 | 3 Zirkuläre Kausalität sogenannten Kobra-Effekt. Dieser Effekt beschreibt Handlungen, die ungewollt zum Gegenteil ihrer erhofften Konsequenzen führen. Er geht auf eine Anekdote zurück, die sich im kolonialen Indien zugetragen haben soll: Um eine Kobraplage einzudämmen, schrieben die Kolonialherren ein Kopfgeld für getötete Kobras aus. Angeblich wurde dies als Geschäftsmodell erkannt und führte zur industriellen Zucht von Kobras.⁵ Wie in Experiment III.5 demonstriert wird, erfordert die Auseinandersetzung mit reflexiven Herausforderungen andere Strategien als die Bearbeitung linearer Probleme.

Experiment III.5: Reflexivität Dieses Experiment lädt zur Bearbeitung einer linearen und einer reflexiven Aufgabe (von Foerster 2003b:269; 2006:215–216) ein. Ersetzen Sie in den folgenden beiden Sätzen die drei Punkte „...“ jeweils mit einem Zahlwort, sodass wahre Aussagen entstehen: 1. Das Wort „System“ hat ... Buchstaben. 2. Dieser Satz hat ... Buchstaben. Weder Leerzeichen noch Interpunktionszeichen sind als Buchstaben zu zählen. Das Experiment lässt sich auch in anderen natürlichen Sprachen (z. B. Englisch: This sentence has ... letters.) bearbeiten und hat in unterschiedlichen Sprachen eine unterschiedliche Anzahl korrekter Lösungen. Falls Sie die zweite Aufgabe in Python lösen möchten, bietet sich Listing 3.2 zur Generierung von Zahlwörtern an. Es produziert die Liste numerale mit den deutschen Zahlwörtern zwischen null und neunundneunzig. In Zeile 3 können durch Veränderung der Sprachkennung de andere Sprachen ausgewählt werden, etwa en, fr, ru. Listing 3.2: Deutsche Zahlwörter (numerals_DE.py) 1 2 3

from num2words import num2words numerale=[] for i in range(0,100): numerale.append(num2words(i, lang='de'))

Es zeigt sich, dass Lösungen des zweiten Satzes nicht auf geradem Wege berechnet werden können. Vielmehr müssen durch Versuch und Irrtum oder durch systematisches Testen zunächst Lösungskandidaten produziert und diese wiederum daraufhin geprüft werden, ob sich ein Gleichgewicht zwischen Input und Output bzw. zwischen Form und Inhalt einstellt.

5 Eine Variante des Kobra-Effekts im Kontext digital vernetzter Medien ist der sogenannte StreisandEffekt: Hierbei führt der Versuch, Inhalte zu verbergen, zu verstärkter Aufmerksamkeit für diese Inhalte (Kirwan-Taylor 2008). Der Name dieses Effekts beruht auf einem Versuch der Sängerin Barbra Streisand im Jahr 2003, eine Online-Abbildung ihres Anwesens in einer Luftbild-Studie zur kalifornischen Küstenerosion auf rechtlichem Wege zu verhindern. Vor dem Einreichen der später abgewiesenen Klage wurde die Abbildung lediglich sechsmal heruntergeladen, davon zweimal von Streisands Anwälten. Im darauffolgenden Monat wurde die Website über 420 000 Mal besucht (Rogers 2003).

3.5 Widerstand gegenüber zirkulärer Kausalität

|

327

3.5 Widerstand gegenüber zirkulärer Kausalität Jenseits der Kybernetik dominiert weiterhin die Tendenz, zirkulär-kausale Beziehungen entweder zu ignorieren oder sie, wie im Fall der auf Seite 321 zitierten Beschreibung des Thermostats in einem Jugendlexikon, in Teilbeziehungen zu zerlegen und die resultierenden Fragmente dann als linear-kausal zu behandeln. Diese Tendenz ist selbst im näheren Umkreis der Kybernetik anzutreffen. In der KI-Forschung unternahm Minsky mit einer Sammlung aus 270 Essays den Versuch, intelligentes Verhalten auf nicht-intelligente Operationen zu reduzieren. Einer der Essays behandelt zirkuläre Kausalität. Darin betont Minsky zunächst die Omnipräsenz zirkulär-kausaler Beziehungen, erklärt aber umgehend, dass sich alle kausalen Strukturen gleichsam als lineare Ketten abbilden und daher einheitlich als solche behandeln ließen. Im letzten Satz seines Essays räumt Minsky (1985:48) schließlich ein, dass hierbei oft wichtige Interaktionen und Abhängigkeiten außer Acht gelassen werden müssen. Gründe für das Ablehnen, das Ignorieren und das Zerlegen zirkulär-kausaler Beziehungen sind vielfältig (Fischer, 2015). Oft sind sie pragmatischer Natur. Trotz der in Experiment III.4 demonstrierten Umsetzbarkeit selbst-negierender Instruktionen in Computerprogrammen ist die Verarbeitung zyklischer Datenstrukturen aus der Perspektive von Programmierern oft sowohl rechenintensiv als auch umständlich. Dies liegt unter anderem daran, dass Verkettungen mit zyklischen Strukturen endlose Pfade enthalten. Ohne das Ergreifen geeigneter Maßnahmen führt das Durchsuchen solcher Strukturen zu Endlosschleifen (Lutz 2013:560–561). Daher tendiert man aus praktischen Gründen oft dazu, Datenstrukturen apriorisch auf lineare und hierarchische Verknüpfungen zu beschränken (Lutz 2013:310– 311). Auch in betrieblichem und institutionellem Management führen zyklische Beziehungen zwischen Personen und Arbeitsgruppen oft zu Unklarheiten, etwa bezüglich Autorität, Verantwortung und Belohnung. Obgleich organische und egalitäre Beziehungen Vorteile im Hinblick auf Betriebsklima und organisatorische Beweglichkeit bieten, werden sie daher häufig zugunsten hierarchischer Strukturen vermieden. Neben pragmatischen Motivationen wird unsere Sicht kausaler Beziehungen auch von Tendenzen unseres Denkens und unserer Wahrnehmung sowie von deren kulturellen Prägungen beeinflusst. So bestimmt zum Beispiel die Beschaffenheit unserer Sinnesorgane und unserer Nervensysteme die Grenzen unserer Wahrnehmung, während unsere Intentionen und Erwartungen die Aufmerksamkeit ausrichten. Unsere Nutzung etwa des Thermostats richtet sich, ungeachtet seiner zirkulär-kausalen Selbstregulierung, auf die Anpassung der Temperatur. Auf dieser Ebene lässt sich die Funktion des Thermostats durchaus als linear-kausal beschreiben (Betätigung des Thermostats → Anpassung der Temperatur). Weiterhin kann unser Blick auf Regelkreise von unterschiedlichen Signalstärken in unterschiedlichen Teilbeziehungen der jeweiligen Regelkreise beeinflusst werden. Auch dies wird am Beispiel des Thermostats ersichtlich. Hier konsumieren die Zu-

328 | 3 Zirkuläre Kausalität standsänderungen des Bimetallschalters ungleich weniger Energie als die Zustandsänderungen des Heizelements. Darüber hinaus erscheinen Signale in Regelkreisen nur selten symmetrisch bezüglich ihrer Beschaffenheit. So erscheint der elektrische Signalpfad vom Bimetallschalter zum Heizelement im Thermostat wesentlich gerichteter und direkter als der ungerichtete, verlustbehaftete, stochastischen Prinzipien folgende Signalpfad vom Heizelement zum Bimetallschalter. Aus kybernetischer Sicht sind absolute Stärken und Beschaffenheiten von Signalen nicht von Interesse, solange diese von den jeweiligen signalverarbeitenden Elementen erfasst werden. Aus der Sicht jener, die Thermostate nutzen, steht jedoch die gerichtete Umwandlung von elektrischer in thermische Energie im Vordergrund. Zirkulär-kausale Beziehungen werden neben pragmatischen und kognitiven Gründen schließlich auch – wie im Fall der kategorischen Verbannung von Paradoxien und zirkulärem Schließen seit der griechischen Antike – aufgrund formeller Gründe ignoriert oder zerlegt. Diese formellen Gründe erweisen sich als besonders beharrlich und langlebig. Experiment III.4 warf die Frage auf: Worin besteht der Unterschied zwischen selbstnegierenden Prozessen und Computerprogrammen einerseits und paradoxen Aussagen andererseits? Warum tolerieren technische Systeme zirkuläre Kausalität, während formelle Logik Paradoxien nicht toleriert? Dies ist darin begründet, dass selbstregulierende physikalische Systeme einerseits und formelle Logik andererseits unterschiedlichen Zwecken dienen. Der Zweck selbstregulierender Systeme ist die Bewerkstelligung von Anpassungsprozessen unter fluktuierenden Bedingungen. Der Zweck der Aussagenlogik ist das Erreichen endgültiger Aussagen: „es geht um das Schlussfolgern an sich“ (Ulmann 2015:4). Wie das deutsche „schließen“ und das englische „to conclude“ nahelegen, sind logische Aussagen beweiskräftig und schlüssig, wenn sie abschließend feststehen. Mit anderen Worten: Die Operationen selbstregulierender Systeme (Thermostate, regulierte Dampfmaschinen etc.) sind prozessbasiert. Sie breiten sich in der Zeit aus. Das Erreichen endgültiger, statischer Zustände ist hier abträglich. Formelle logische Systeme hingegen produzieren statische, schlüssige Ergebnisse. Sie sind zielorientiert und an sich atemporal (Bateson 1979:117)⁶. Hier sind sich selbst invertierende Aussagen und anhaltende Oszillationen zwischen mehreren Zuständen nachteilig. 6 Der Unterschied zwischen Ziel- und Prozessorientierung hat Konsequenzen für das Verständnis anderer Begriffe, etwa dem der Äquivalenz in der Maschinentheorie. Hier gelten Maschinen als äquivalent, wenn sich ihre jeweiligen Zustände vollständig aufeinander abbilden lassen (Hermes 1961:37). Auf Seite 289 wurde in diesem Sinne die Äquivalenz vernetzter McCulloch-Pitts-Neuronen mit der Turingmaschine erwähnt. Aus prozessorientierter, beobachterbasierter Sicht bedarf dies einer Differenzierung. Eine Spieluhr, die eine Komposition in drei Minuten abspielt, und ein Pianola, das eine Notenrolle mit derselben Komposition in vier Minuten abspielt, beispielsweise sind aus maschinentheoretischer Sicht äquivalent, da sich ihre Zustände aufeinander abbilden lassen und da beide dasselbe Ergebnis (das Ende des Stücks) erreichen. Aus der Sicht prozessorientierter Beobachter hingegen erscheint ihre Äquivalenz fraglich.

3.5 Widerstand gegenüber zirkulärer Kausalität

|

329

Während zirkuläre Kausalität außerhalb der Kybernetik oft abgelehnt wird, werden in der Kybernetik sowohl die lineare als auch die zirkuläre Kausalität herangezogen. So kritisiert die Kybernetik zwar übermäßiges Vertrauen auf lineare Kausalität in vielen Kontexten, sie lehnt lineare Kausalität an sich aber nicht kategorisch ab. Aus ihrer Sicht haben beide kausalen Modelle ihre Berechtigung – entsprechend den jeweiligen Prioritäten, etwa bezüglich Ziel- bzw. Prozessorientierung. Mit ihrer beschreibenden Agenda sind empirische Wissenschaft und formelle Logik zielorientiert („Essen führt zu Sättigung.“). Hier findet lineare Kausalität ihre Berechtigung. Kybernetik ist prozessorientiert („Hunger gibt Anreiz zu Essen und Sättigung und erhält die Möglichkeit, auch morgen wieder Hunger verspüren zu können.“). Hier hat zirkuläre Kausalität ihre Berechtigung. Aus kybernetischer Sicht drohen Anwendungen linearer Kausalität die jeweils betrachteten Beziehungen unangemessen zu trivialisieren. Ironischerweise erscheint der naturwissenschaftliche Betrieb trotz seiner weitreichenden Fixierung auf lineare Kausalität aus kybernetischer Sicht als inhärent zirkulär. Dies beschränkt sich keineswegs auf gelegentliche Akzeptanzen zirkulär-kausaler Sachverhalte wie etwa die biologische Betrachtung des Austauschs von Sauerstoff und Kohlendioxid zwischen Tieren und Pflanzen oder symbiotischer und koevolutionärer Beziehungen zwischen verschiedenen Spezies. Auf grundlegenderer Ebene lässt sich der wissenschaftliche Prozess selbst als zirkuläre Folge sich gegenseitig hervorbringender Phasen mit stabilisierenden oder destabilisierenden Eigenschaften beschreiben (Kuhn 1962). Darüber hinaus beruht der naturwissenschaftliche Betrieb insgesamt auf einem impliziten zirkulär-kausalen Weltbild. Er konzeptionalisiert das Universum als geschlossenes System, innerhalb dessen er beobachtbare Phänomene ausschließlich auf andere beobachtbare Phänomene zurückführt und Erklärungen auf der Basis übernatürlicher Ursachen ablehnt⁷. Diese Zirkularität spiegelt sich in den Interdependenzen der Definitionen in wissenschaftlichen Wörterbücher wider (von Foerster 2003b:308), wie das folgende Beispiel zeigt (Barnhart 1986:383, 385; meine Unterstreichungen). mass, n. Physics. a measure of the quantity of matter a body contains [...] matter, n. Physics. anything which has mass and can exist ordinarily as a solid, liquid or gas [...]

7 Ähnlich der Paradoxie in Freges Mengenlehre wirft das Verständnis des Universums als kausal geschlossenes System die Frage auf: Wo ist die Ursache des Universums an sich zu suchen, wenn alle Ursachen innerhalb des Universums zu finden sind? Aristoteles postulierte als Antwort auf Fragen dieser Art den „unbewegten Beweger“.

4 Zwischen Wirk- und Zweckursachen 4.1 Das Vorhalteproblem der Luftabwehr Rosenblueth und Wiener erkannten den enormen Bedarf nach experimenteller Forschung, der mit der Tragweite ihrer Erkenntnisse einherging. Sie planten hierfür die Gründung eines neuen, interdisziplinären Instituts (Wiener 1948:8). Zunächst stand jedoch der Zweite Weltkrieg im Vordergrund und Wiener wollte praktische Beiträge leisten (Galison 1994:228). Gegen Ende des Ersten Weltkriegs hatte er sich am Aberdeen Proving Ground, einer Forschungs- und Entwicklungseinrichtung der United States Army, Herausforderungen konventioneller Artillerie gewidmet (Conway und Siegelman 2005:42–43). Nun, während des Zweiten Weltkriegs, nahm er sich am MIT gemeinsam mit Bigelow der Automatisierung der Flugabwehr an. Angesichts Wieners unverblümt ablehnender Einstellung zu Gewalt und Unterdrückung überrascht es wenig, dass sein Beitrag zu den Kriegsanstrengungen defensiver Natur war. Die besondere Herausforderung der Flugabwehr bestand darin, dass Projektile mit Geschwindigkeiten um 300 m/s etwa 28 Sekunden benötigen, um die typische Flughöhe angreifender Flugzeuge von 8 500 m zu erreichen. In dieser Zeit legt ein Flugzeug mit einer Geschwindigkeit von 320 km/h etwa 2,5 km zurück, was korrektes Zielen deutlich erschwert, insbesondere bei nicht-geradlinigen Flugbahnen angreifender Flugzeuge. Um Treffer zu erzielen, gilt es demnach die Flugbahnen sowohl des Flugzeugs als auch des Projektils vorherzusagen und in der Zielführung zu berücksichtigen¹, um dementsprechend vor angreifende Flugzeuge zu zielen. Um dieses sogenannte „Vorhalteproblem“ zu lösen, sollte Wieners Flugabwehrsystem angreifende Flugzeuge wiederholt mittels Radar lokalisieren, ihre Flugbahnen auf Basis der gewonnenen Koordinaten-Zeitserien mit statistischen Methoden interpolieren und die zu erwartenden bevorstehenden Flugbahnen extrapolieren. Unter Berücksichtigung zu erwartender Flugzeiten von Projektilen sollte das System Geschütze automatisch auf erfolgversprechende Koordinaten vor angreifende Flugzeuge richten und feuern. Ein Prototyp des Systems, den Wiener und Kollegen am MIT entwickelten – ein analoger Einzweck-Computer – zeigte für kürzere Zeitspannen eine erstaunlich hohe Treffsicherheit. Für die in der Luftabwehr realistisch zu erwartenden Projektilflugzeiten bot das System jedoch keine deutliche Verbesserung gegenüber bereits verfügbaren Systemen. Es wurde daher weder in Serie gefertigt noch in Kampfhandlungen eingesetzt (Conway und Siegelman 2005:120–124; Dyson 2012:110–113). Nichtsdestotrotz prägten das System und die ihm zugrunde liegenden Methoden fortan kybernetische Technologien und damit zahlreiche Aspekte täglichen Lebens weltweit. Die von Wiener entwickelten Methoden der Interpolation und Extrapolati-

1 Wiener und Kollegen (1943:20) bezeichneten dies als „Vorhersage zweiter Ordnung“. https://doi.org/10.1515/9783110496253-023

4.1 Das Vorhalteproblem der Luftabwehr

| 331

on von Zeitserien sind ein Meilenstein der Mathematik. Wiener beschrieb sie in einem 120-seitigen Manuskript mit dem komplizierten Titel The Extrapolation, Interpolation and Smoothing of Stationary Time Series (Wiener 1949)². Es wurde während des Zweiten Weltkriegs unter strenger Geheimhaltung an eine kleine Gruppe von Ingenieuren und Wissenschaftlern verteilt. Mit Referenz auf den hellgelben Einband des Manuskripts und die darin enthaltene furchteinflößende Mathematik bezeichneten die Mitglieder dieser Gruppe das Manuskript bald als „Gelbe Gefahr“ („Yellow Peril“). Es ist heute sowohl unter diesem als auch unter seinem originalen Namen bekannt und frei verfügbar. Die darin besprochenen Methoden sind seither weiterentwickelt worden und stehen als Standardbibliotheken in zahlreichen Programmiersprachen zur Verfügung. In dem folgenden Experiment III.6 können Sie einen einfachen zweidimensionalen „Luftabwehr-Prediktor“ implementieren und damit experimentieren. Experiment III.6: Einfacher „Luftabwehr-Prediktor“ Dieses Experiment erlaubt die Untersuchung eines einfachen, zweidimensionalen, auf mathematischer Extrapolation basierenden Prediktors. Das Programm in Listing 4.1 öffnet ein senkrecht geteiltes Fenster, in dem per Maus oder Trackpad von links nach rechts Kurven gezeichnet werden können (siehe Abbildung 4.1). Diese werden nach Überschreiten der vertikalen Trennungslinie interpoliert und Prognosen des extrapolierten weiteren Verlaufs durch eine Reihe von Punkten angezeigt.

x

x

x

x

Abb. 4.1: Benutzung des einfachen „Luftabwehr-Prediktors“

Listing 4.1: Einfacher „Luftabwehr-Prediktor“ (simple-anti-aircraft-predictor_DE.py) 1 2 3

import pygame from sys import exit from numpy import *

2 Shannon (Blackman et al. 1946) und Kolmogorov (1941) arbeiteten zeitnah an ähnlichen Aufgaben.

332 | 4 Zwischen Wirk- und Zweckursachen 4 5 class Plane: 6 def __init__(self): 7 self.breite = 800; self.hoehe = 600 8 pygame.init() 9 self.screen = pygame.display.set_mode((self.breite, self.hoehe)) 10 self.screen.fill((255, 255, 255)) 11 self.mouse_pos = pygame.mouse.get_pos() 12 pygame.display.set_caption('Einfacher Wiener-Prediktor') 13 self.draw_color = (0,0,0) 14 pygame.draw.line(self.screen, (0,0,0), [600,0], [600,600], 1) 15 pygame.display.update() 16 17 def event_loop(self): 18 running = True 19 drawing = False 20 old = [-999,-999] 21 x = []; y = [] 22 while running: 23 for event in pygame.event.get(): 24 if event.type == pygame.QUIT: 25 running=False 26 exit() 27 if event.type == pygame.MOUSEBUTTONDOWN: 28 if old==[-999,-999]: 29 self.screen.fill((255, 255, 255)) 30 pygame.draw.line(self.screen,(0,0,0),[600,0],[600,600], 1) 31 pygame.display.update() 32 old=pygame.mouse.get_pos() 33 flag=0 34 drawing = True 35 if event.type == pygame.MOUSEBUTTONUP: 36 drawing = False 37 old = [-999,-999] 38 x = []; y = [] 39 if drawing: 40 if pygame.mouse.get_pos()[0]599: 44 extrap = polyfit(x, y, 2) 45 for n in [605, 650, 700, 750, 795]: 46 pygame.draw.circle(self.screen, (255,0,0), (n, int(polyval(extrap, n))), 5) 47 flag = 1 48 if old != [-999,-999]: 49 pygame.draw.line(self.screen, (0,0,0), old, pygame.mouse.get_pos(), 2) 50 old = pygame.mouse.get_pos()

4.1 Das Vorhalteproblem der Luftabwehr

|

333

51 pygame.display.update() 52 53 if __name__ == '__main__': 54 p = Plane() 55 p.event_loop() Die Funktion polyfit() in Zeile 44 führt eine Kurvenanpassung auf der Basis der Listen x und y durch. Sie basiert im Gegensatz zu dem von Wiener entwickelten statistischen Ansatz auf der „Methode der kleinsten Quadrate“ (Blackman et al. 1946:78–79) und gibt eine Liste mit den Koeffizienten des ermittelten Polynoms zurück. Mit dem dritten Parameter (im obigen Skript: 2) wird in polyfit() der Grad des zu ermittelnden Polynoms spezifiziert. Das Ersetzen dieses Wertes mit anderen ganzzahligen Werten {1, 3, 4, 5, 6} verändert dementsprechend die Charakteristik der Extrapolationen. Durch das Experimentieren mit unterschiedlichen polynomen Graden lassen sich unterschiedliche Kurvencharakteristika erzielen. Hierbei stellt sich mit fortschreitendem Abstand zwischen der beobachteten Kurve zu den extrapolierten Werten stets eine sinkende Treffsicherheit ein. Die Auswahl polynomer Grade entspricht hierbei letztlich subjektiven Vorhersagen bezüglich der Charakteristika erwarteter Flugbahnen.

Obgleich es in der Entwicklung der Kybernetik früh eine Schlüsselrolle einnimmt, basierte Wieners Flugabwehrsystem nicht auf dem hier zentralen Feedback-Prinzip. Vielmehr handelte es sich im engeren Sinne, wie in der folgenden Begriffsklärung erläutert wird, um ein sogenanntes Feedforward-System.

Begriffsklärung: Steuerung, Feedback und Feedforward Vor allem im Ingenieurwesen werden drei Kategorien zweckgerichteter Anpassungen unterschieden: 1. Steuerung: Anpassungen werden vorgenommen und Effekte somit herbeigeführt, ohne diese zu prüfen. Beispiel: Einschalten einer aktiven CPU-Kühlung beim Hochfahren eines Computers. 2. Regulierung mit Feedback: Anpassungen werden vorgenommen und Effekte somit herbeigeführt. Diese Effekte werden beobachtet und Ergebnisse dieser Beobachtungen zum anpassenden Element zurückgeführt (Feedback), um dort weitere Anpassungen zu beeinflussen. Beispiel: Die CPU eines Computers ist mit einem Temperatursensor ausgestattet. Steigt die CPU-Temperatur über einen bestimmten Punkt, wird die aktive CPU-Kühlung eingeschaltet. Sinkt die Temperatur unter einen bestimmten Punkt, wird die Kühlung abgeschaltet. 3. Feedforward-basierte Regulierung: Das anpassende Element ist mit einem Modell der seinerseits herbeizuführenden Effekte ausgestattet. Es kann somit zielgerichtet Effekte herbeiführen und regulieren, ohne dass die Beobachtung resultierender Effekte erforderlich ist. Beispiel: Die Aufgaben eines Computers sowie deren jeweilige Rechendauer und -last sind bekannt. Zu Beginn der Bearbeitung einer Aufgabe wird die aktive CPU-Kühlung entsprechend der erwarteten Hitzeentwicklung und Rechendauer in Gang gesetzt. Mit Feedback- und Feedforward-basierten Regulierungen gehen spezifische Vor- und Nachteile einher. So ist Feedback-basierte Regelung robust gegenüber unvorhergesehenen Einflüssen (im Fall der CPUKühlung beispielsweise Schwankungen der Umgebungstemperatur). Feedforward-basierte Regelung hingegen kann Effekten schnell entgegentreten.

334 | 4 Zwischen Wirk- und Zweckursachen

4.2 Vorhersage auf der Basis von Beobachtung Im Sinne des Feedforward-Prinzips sollte das von Wiener und Kollegen entwickelte Flugabwehrsystem Vorhersagen zum weiteren Verlauf beobachteter Flugbahnen an motorisierte Geschütze weiterleiten. Kursanpassungen aufsteigender Projektile, wie sie bei späteren, gelenkten Flugkörpern möglich wurden, waren nicht vorgesehen. Stattdessen sollten die Flugbahnen angreifender Flugzeuge fortlaufend beobachtet, darauf basierend neue Vorhersagen berechnet und neue Schüsse dementsprechend ausgerichtet werden. Das System analysierte rückblickend bereits Gegebenes und folgerte daraus vorausschauend, was passieren sollte. Damit schlug es eine automatisierte Brücke zwischen der rückblickenden Beschreibung im Sinne Aristoteles’ effizienter Kausalität (Wirkursachen: „wegen ...“) und antizipierender Zweckorientierung im Sinne Aristoteles’ finaler Kausalität (Zweckursachen: „um zu ...“)³. Entsprechend der auf Seite 301 angebotenen Definition beruht der zentrale Interessensgegenstand der technischen Kybernetik, der zweckgerichtete Anpassungsprozess, generell auf diesem Brückenschlag. Er folgt der Annahme, dass bezweckte zukünftige Ereignisse auf der Basis gegebener Bedingungen vorhergesagt und bewerkstelligt werden können. Somit geht Zweckursächlichkeit notwendigerweise mit Vorhersage einher. Unsere Möglichkeiten kausaler Vorhersagen haben sich mit „informationsverarbeitenden“ Technologien wie dem Flugabwehrsystem Wieners dramatisch entwickelt. Da Technologien dieser Art zunächst selten und kostspielig waren, mitunter militärischer Geheimhaltung unterlagen und ihre mathematischen Prinzipien nicht ohne Weiteres generell zugänglich waren, drang diese Entwicklung nur langsam in das öffentliche Bewusstsein. Die US-amerikanische Öffentlichkeit bekam im Jahr 1952 einen ersten Eindruck der Möglichkeiten computergestützter statistischer Vorhersage. Als Werbeaktion der Firma Remington Rand wurde in der CBS-Live-Fernsehübertragung am Präsidentschaftswahlabend ein Computer eingesetzt. Der von J. Presper Eckert und John Mauchly entwickelte UNIVAC I sollte eine Vorhersage des Wahlausgangs demonstrieren. Mauchly entwarf für diesen Zweck gemeinsam mit dem Mathematiker Max Woodbury ein statistisches Vorhersageprogramm auf der Basis ihrer Analyse früherer Wahlverläufe. Meinungsumfragen hatten uneinheitliche Ergebnisse ermittelt. Danach konnte es sowohl zu einer verheerenden Niederlage des Amtsinhabers Eisenhower als auch zu einem engen Kopf-an-Kopf-Rennen zwischen Eisenhower und seinem Herausforderer Stevenson kommen. Als am frühen Abend Auszählungen erster Wahlkreise mit bislang weniger als 3,4 Mio. Stimmen verkündet und von UNIVAC verarbeitet wurden, sagte der Computer Eisenhower überwältigende Gewinnchancen von 100:1 und einen deutlichen Sieg voraus. CBS-News-Manager lehnten es ab, diese scheinbar abstruse Vorhersage zu verkünden. Stattdessen wurde erklärt, UNIVAC habe Eisenhower Gewinnchancen von 8:7 vorausgesagt. Anschließend erkannte Woodbury,

3 Siehe von Glasersfeld (1987:42–49) und von Foerster (2003b:298).

4.2 Vorhersage auf der Basis von Beobachtung

| 335

dass fehlerhafte Daten verarbeitet worden waren, korrigierte sie und ließ den Computer eine neue Vorhersage berechnen. Eisenhowers Gewinnchancen lagen auch nach der Korrektur weiterhin bei 100:1. Nach Abschluss der Stimmauszählung erwies sich, dass die Vorhersage des Computers weniger als 1 % vom endgültigen Wahlausgang abgewichen war. Die CBS-Journalisten erklärten kleinlaut, dass UNIVAC bereits Stunden zuvor eine akkurate Vorhersage errechnet hatte. Die Öffentlichkeit reagierte begeistert und seither sind Computerprognosen ein fester Bestandteil der Wahlberichterstattung in Massenmedien (Randy 2008). Seit den Zeiten UNIVACs haben sich die Dynamiken demokratischer Prozesse jedoch gewandelt. Demokratien tendierten lange Zeit zur Ausbildung zweier konkurrierender politischer Lager und, zumindest in der Abwesenheit überwältigender Ereignisse, zu Oszillationen dazwischen (Lowell 1898). Koalitionsbildungen zur Sicherung parlamentarischer Mehrheiten, Sperrklauseln und andere Mechanismen gaben dabei vielen demokratischen Systemen bistabile Hysterese-Charakteristika. Diese weichen jedoch vermehrt anderen, weniger vorhersagbaren Charakteristika und obgleich Vorhersageverfahren seit den 1950er-Jahren erheblich weiterentwickelt wurden, sind Wahlprognosen heute nicht immer verlässlich. Dies kann mit zirkulär-kausalen und reflexiven Dynamiken in (Selbst-)Beobachtung erklärt werden. Zirkuläre Kausalität kann sich einstellen, wenn nicht nur Wahlberechtigte ihre Repräsentanten, sondern auch Repräsentanten ihre Wählerschaften bestimmen – etwa durch die Instrumentalisierung statistischer Vorhersageverfahren. Es wäre denkbar, Standpunkte in Meinungsumfragen, sozialen Medien und Fokusgruppen zu erproben, Wahlkampftaktiken für unterschiedliche sozio-ökonomische Milieus anzupassen, Urnengänge zu erleichtern oder zu erschweren und diese Strategien auf der Basis statistischer Vorhersagen mit Wahlkreisreformen zu koordinieren (Norris 2015). Erkennen Wahlberechtigte nun, dass ökonomische und politische Machtstrukturen hierdurch bedingt konvergieren (Hasen 2016), während öffentliche Meinungen und politische Entscheidungen divergieren (Gilens und Page 2014:575), zeigen sie sich möglicherweise politikverdrossen, bleiben Wahlen fern oder nutzen ihr Stimmrecht zum bloßen Protest. Da zu erwarten ist, dass Wählende politische Fragen im eigenen Interesse entscheiden, wäre Wahlverhalten dieser Art augenscheinlich irrational. Wenn Wahlberechtigte vorhersagende Einflussnahmen auf ihr Verhalten jedoch als trivialisierend und somit als entmenschlichend erachten, dann sehen sie die Störung dieser Einflussnahmen möglicherweise rational im eigenen Interesse und priorisieren sie über explizite Wahlkampfthemen. So könnten kontrollierende Einflussnahmen und instrumentalisierte Vorhersageverfahren reflexiv zu kaum vorhersehbaren, möglicherweise gefährlichen Wahlergebnissen und als selbstzerstörende Prophezeiungen zu Destabilisierungen führen.

336 | 4 Zwischen Wirk- und Zweckursachen

4.3 Stabilität und Stabilisierung In vielen Bereichen des Lebens werden Stabilität und Determinierbarkeit auf technische Weise gewährleistet. Ein einfaches medientechnisches Beispiel ist die Verwendung von Stativen zum Zweck der Kamerastabilisierung in der Fotografie, etwa um bei längeren Belichtungszeiten das Verwackeln von Bildern zu vermeiden. Da gängige Stative ihre Funktion erfüllen, ohne aktiv Anpassungen vorzunehmen, spricht man diesem Fall von statischer Stabilität. Bei Film- und Videoaufnahmen hingegen sind oft Kamerabewegungen erforderlich. Um diese kontrolliert und gleichförmig zu gestalten, eignen sich mehrere technische Ansätze. Die sogenannte Steadicam (auch Schwebestativ genannt) ist ein tragbares Halterungssystem, das die Kamera über einen beweglichen Arm mit einer Weste verbindet, welche am Rumpf der bedienenden Person befestigt wird. Diese Person hat erwünschte Bewegungen der Kamera weitestgehend unter Kontrolle, während kleinere, etwa vom Gang der Person verursachte, oft unerwünschte Bewegungen durch die entkoppelnde Aufhängung des beweglichen Arms unter Ausnutzung der Massenträgheit von Monitor, Batterie und möglicher Zusatzgewichte „gefiltert“ werden. Neben der Massenträgheit kann zur Kamerastabilisierung auch die Drehimpulserhaltung genutzt werden, also die Tendenz rotierender Massen, sich um die Achse ihrer Rotation gegenüber Drehimpulsen in anderen Ebenen zu stabilisieren. Dieser Effekt hilft zum Beispiel bei der aufrechten Stabilisierung von fahrenden Zweirädern, da sich deren Räder mit steigender Rotationsgeschwindigkeit (und in Abhängigkeit von ihrer Masse) zunehmend seitlichen Kippbewegungen widersetzen. Abbildung 4.2 zeigt den amerikanischen Wissenschaftler Robert Goddard bei einer Demonstration dieses Effekts. Goddard trug zwischen 1915 und 1941 mit experimenteller Arbeit maßgeblich zur Entwicklung von Antriebs- und Steuerungssystemen für Raketen bei und war damit ein Wegbereiter der Raumfahrt.⁴ Die Abbildungen 4.2 und 4.4 wurden Goddards filmischer Dokumentation dieses Forschungsprogramms entnommen. In Abbildung 4.2 demonstriert Goddard die Drehimpulserhaltung. Er sitzt auf einem Drehschemel und hält ein von einem Assistenten in schnelle Rotation versetztes Rad in den Händen. Goddards Änderungen der Rotationsachse des Rades verursachen Gegenimpulse, die auf seinen Körper wirken und sich als Drehungen des Schemels auswirken. Das Phänomen kann zur sogenannten Kreiselstabilisierung von Kameras und anderer Gerätschaften genutzt werden, indem diese an schnell rotierende Massen montiert werden. Das Prinzip kam bei den Dreharbeiten für Wolfgang Petersens Film „Das Boot“ zum Einsatz. Der enge Nachbau des Inneren eines U-Boots stellte Kameramann Jost Vacano vor die Herausforderung, Kamerabewegungen entlang des engen Innenraums in

4 Zuvor erfand und patentierte er die erste Vakuumröhre zum Zweck der Signalverstärkung (Aitgen 1985:239; Band 1, Abschnitt I.6.1.2).

4.4 Dynamische Stabilität

|

337

Abb. 4.2: Goddard demonstriert die Drehimpulserhaltung. Ein Assistent versetzt das Rad in Rotation. Goddard ändert die Rotationsachse des Rades und der Gegenimpuls versetzt ihn auf seinem Drehschemel ohne äußere Krafteinwirkung in kontrollierte Drehbewegungen. Quelle: US National Archives. Identifier: 67881, local identifier: 342-USAF-28437

Laufgeschwindigkeit und durch enge Druckschotte hindurch zu kontrollieren. Hierfür stabilisierte er eine 35-mm-Arriflex-Kamera mit zwei Kenyon-Kreiselstabilisatoren. Mit der stabilisierten Kamera sowie mit Helm und Schutzpolstern ausgestattet – und mit Übung – gelangen Vocano jene Aufnahmen, die den Film auszeichnen: Aufnahmen ohne unnatürliches Wackeln, die den Eindruck schneller menschlicher Bewegung erwecken und eine klaustrophobische Atmosphäre schaffen (Hope-Jones 2006).

4.4 Dynamische Stabilität Die Achsenstabilität kreiselnder Massen kann zudem zur dynamischen Kamerastabilisierung genutzt werden. Hierfür wird ein Kreisel in einem schwenkbaren Rahmen drehbar aufgehängt. Da der rotierende Kreisel aufgrund der Drehimpulserhaltung auch bei wechselnder Ausrichtung des Rahmens achsenstabil bleibt, kann an der Winkeldifferenz zwischen Rahmen und Kreisel die Ausrichtung des Rahmens kontinuierlich gemessen werden. Abbildung 4.3 zeigt eine schematische Darstellung der als Gyroskop oder Kreiselinstrument bezeichneten Anordnung mit zwei ineinander verschachtelten, kardanisch aufgehängten Rahmen – sogenannten Gimbals. Das Gyroskop wurde bereits in den 1860er-Jahren von Robert Whitehead entwickelt und kam zunächst in der Kursstabilisierung des sogenannten WhiteheadTorpedos zum Einsatz. Jahrzehnte bevor der Begriff des negativen Feedbacks gebräuchlich wurde, wurden hierbei Abweichungen von intendierten Ausrichtungen von Torpedos gemessen und durch die Anpassung der Ausrichtungen von Seiten- und Tiefenrudern kontinuierlich kompensiert. Goddard wandte dieses Verfahren an, um seine Raketen auf möglichst senkrechtem Kurs zu stabilisieren und um so maximale Flughöhen zu erreichen. Abbildung 4.4 zeigt Goddard bei der Demonstration eines

338 | 4 Zwischen Wirk- und Zweckursachen

Abb. 4.3: Schematische Darstellung eines Drei-Achsen-Gyroskops

Abb. 4.4: Goddard demonstriert ein Drei-Achsen-Gyroskop. Quelle: US National Archives. Identifier: 67881, local identifier: 342-USAF-28437

Gyroskops. Seine Raketen korrigierten ihren Kurs, indem gyroskopisch gemessene Abweichungen von der intendierten senkrechten Ausrichtung proportionale Ablenkungen des Raketen-Antriebsstrahls mittels vier Strahlrudern auslösten. Sobald die gewünschte Ausrichtung erreicht war, wurde die Ablenkung des Antriebsstrahls beendet. Hierbei wurde der Ist-Zustand des Systems (Orientierung des Flugkörpers) mit Referenz auf einen Soll-Zustand (gyroskopisch stabilisierter Vektor) angepasst. Dies ist eine von zwei unterschiedlichen Formen der Regulierung. Werden die Signalleitungen zwischen Gyroskop und Antriebsablenkung vertauscht (was sowohl Goddard als auch anderen mitunter passierte), so führt dies nicht zur kontinuierlichen Minimierung, sondern zur kontinuierlichen Verstärkung von Kursabweichungen. So konfigurierte Raketen fliegen in einer engen Kurve und schlagen nach kurzer Reise neben ihren Starttürmen ein. Begriffsklärung: Negatives und positives Feedback Differenzen zwischen Ist- und Soll-Zuständen können nicht nur reduziert, sondern auch verstärkt werden. Somit ergeben sich zwei Formen von Feedback und Anpassung (Rosenblueth et al. 1943:19): 1. Negatives Feedback: Abweichungen des Ist-Zustandes vom Soll-Zustand werden als „Fehler“ (englisch: error) erkannt und minimiert. Beispiele für negative Feedbackprozesse sind: Homöostase, Preisbildung durch Angebot und Nachfrage, Fliehkraft-basierte Drehzahlregulierung in der Dampfmaschine, Kurskorrekturen in Fahrzeugen (Schiffe, Raketen etc.). Negative Feedbacksysteme haben gemein, dass sie Ziele verfolgen oder Zustände aufrechterhalten. 2. Positives Feedback: Differenzen zwischen Ist-Zustand und Soll-Zustand werden verstärkt (Maruyama 1963). Ohne begrenzende oder dämpfende Maßnahmen eskalieren Prozesse dieser Art und können zu verheerenden Folgen für zugrunde liegende Systeme und ihre Kontexte führen. Daher werden sie auch als Teufelskreise oder Gewaltspiralen bezeichnet. Beispiele für positive Feedbackprozesse sind: elektroakustische Rückkopplungen (pfeifende Lautsprecher), Wettrüsten, Bevölkerungsexplosionen und Profitmaximierung.

4.4 Dynamische Stabilität

|

339

Mit miniaturisierten Gyroskopen ausgestattete Smartphones und Tablets erlauben die praktische Demonstration der beiden Arten von Feedback. Eine solche Demonstration ist auf der diesen Beitrag begleitenden Webseite unter https://www.degruyter.com verlinkt. Öffnen dieses Links mit einem Smartphone oder Tablet lädt die schematische Darstellung einer Rakete mit einem Gyroskop (senkrechter Pfeil) und einem Gimbal-gelagerten Antrieb (Abbildung 4.5). Rotieren Sie Ihr Gerät in der Hand und beobachten Sie die in Abbildung 4.6 dargestellten Formen der regulierten Anpassung. Durch Antippen des Plus- bzw. Minussymbols kann zwischen positivem und negativem Feedback umgeschaltet werden. Negatives Feedback reduziert Abweichungen vom senkrechten Pfad der Rakete. Die Begriffe positives und negatives Feedback werden auch verwendet, um anspornende oder entmutigende Rückmeldungen zu beschreiben. Diese Verwendung erscheint nicht immer konsistent mit der Verwendung im Sinne der Minimierung bzw. Verstärkung von Abweichungen – etwa wenn KursHalten (negatives Feedback) ermutigt wird (positives Feedback). Grund hierfür sind unterschiedliche Betrachtungsreichweiten und unterschiedliche Systemgrenzen aus den Perspektiven verschiedener Beobachter (mehr hierzu in Unterkapitel 6.1).

Abb. 4.5: Feedback-Demonstration

Abb. 4.6: Positives (links), negatives Feedback (rechts)

Während man Goddards Forschung in seiner Heimat weitgehend ignorierte und bisweilen verhöhnte (NYT 1920; 1969), wurde sie in Europa aufmerksam verfolgt und im nationalsozialistischen Deutschland rüstungstechnisch angewandt. Die Lenkbombe Fritz X wurde nach Abwurf ferngesteuert und dabei in einer Ebene mittels Gyroskop durch negatives Feedback stabilisiert. Bei der Zielführung des Marschflugkörpers Fieseler Fi 103 „V1“ kamen verschiedene Verfahren zum Einsatz.

340 | 4 Zwischen Wirk- und Zweckursachen In einem dieser Verfahren diente ein Gyroskop mittels negativen Feedback zur seitlichen Stabilisierung. Andere Zielführungsparameter wurden hierbei ebenfalls durch negatives Feedback bestimmt, indem in Serie gefeuerte Flugkörper im Flug Niederfrequenzsignale sendeten, die von Peilstationen verfolgt wurden, um nachfolgende Flugkörper genauer auf ihre intendierten Ziele auszurichten. Auf der englischen Seite wurden die „V1“ von Feedbacksystemen aus US-amerikanischer Herstellung erwartet und weitgehend außer Gefecht gesetzt. Es waren nicht die von Wiener erfolglos geplanten automatisierten Luftabwehrgeschütze. Es waren neue Flakgranaten mit Funk-Näherungszündern, die im Flug explodierten, wenn sie per Funk die Nähe angreifender Flugkörper erkannten, und motorisierte SCR-584 Radarstationen, die mittels negativen Feedback herannahende Flugkörper kontinuierlich orteten und ihnen folgten (Rid 2016:39–42). Im Nachfolger der „V1“, der Rakete Aggregat 4 „V2“, wurden sowohl Antrieb als auch Steuerung auf Goddards Forschungen aufbauend entwickelt. Die Zielführung erfolgte mithilfe von zwei Gyroskopen und negativem Feedback. Bei der Bombardierung Londons mit dieser Waffe gelang es England, positives Feedback in die Zielführung einzubringen, indem Doppelagenten Einschlagsmeldungen mit verzerrten Ortsangaben an die deutsche Seite kommunizierten. Infolgedessen wurden nachfolgende Raketen von ihren intendierten dicht besiedelten Zielen weg und auf bewaldete, wenig besiedelte Orte hin ausgerichtet. Man geht davon aus, dass dies Tausende Menschenleben gerettet hat (Macintyre 2007:262–267). Seither hat sich die dynamische Flugstabilisierung auf der Basis negativen Feedbacks weiterentwickelt. Sensoren wurden miniaturisiert und Microcontroller können komplizierte Echtzeitberechnungen anstellen. Damit bieten als Quadrocopter ausgeführte Kameradrohnen zuvor nicht verfügbare Möglichkeiten der Kameraführung und -stabilisation. Vom Boden aus per Funk ferngesteuert sind sie leichter, kostengünstiger und wendiger als andere Fluggeräte. Um Piloten weitestgehende Kontrolle über die Führung einer Drohnenkamera zu geben, muss die Drohne einerseits empfangene Kontrollsignale ausführen. Andererseits muss sie aber auch andere, unerwünschte Einflüsse auf Orientierung und Position (vornehmlich Windbewegungen) ermitteln und kontinuierlich computergestützt durch negatives Feedback kompensieren (man spricht vom „Ausregeln“). Zu diesem Zweck enthält das Fluggerät ein Inertialnavigationssystem bestehend aus Gyroskopen (Orientierungssensoren) und Akzelerometern (Beschleunigungssensoren) sowie einem Microcontroller. Durch die getrennte Geschwindigkeitskontrolle der Rotoren kontrolliert der Microcontroller die Bewegungen der Drohne. Dabei erfasst er mithilfe des Inertialnavigationssystems fortlaufend unintendierte Bewegungen und regelt diese aus, während er empfangene Kontrollsignale in die entsprechenden intendierten Bewegungen umsetzt. Somit sind beispielsweise auch bei Windbewegungen stationäre Kamerapositionen ohne Bodenkontakt möglich.

5 Ausgangspunkt Subjekt 5.1 Eine kritische Annäherung an „Information“ Was genau ist der essenzielle Gegenstand kybernetischen Interesses in diesen Prozessen? Was genau „füttern“ Feedforward und Feedback vor und zurück? Wiener war einer der ersten Wissenschaftler, die überlegten, ob sich diese Fragen auf der Basis naturwissenschaftlicher Theorien – etwa mit physikalischen Wechselspielen von Materie und Energie in Raum und Zeit – beantworten ließen. Ebenso war Wiener unter den Ersten (insbesondere westlich des Atlantiks), die zwischen den Weltkriegen einen qualitativen Unterschied wahrnahmen zwischen den starken Strömen in bereits damals weit verbreiteten elektrischen Anlagen und den schwachen Strömen, die gerade erst begannen in neuen Entwicklungen zum Tragen zu kommen (Conway und Siegelman 2005:65). Im heutigen Sprachgebrauch ist dies der Unterschied zwischen elektrischen und elektronischen Systemen. Wiener sah, dass die Ströme, mit denen elektronische Systeme kontrolliert werden, beliebig gering sein mögen – solange sie ihre Signalwirkung erbringen. Des Weiteren erkannte er, dass es sich mit elektromagnetischen Feldstärken in der Radiokommunikation ebenso verhielt. Wiener (1948:132) folgerte daraus, dass Kommunikation und Kontrolle weniger durch den Austausch von Materie und Energie charakterisiert seien, und postulierte als neue Größe die Information: Information is information, not matter or energy. No materialism which does not admit this can survive at the present day.

Der erste dieser beiden Sätze gab für nichts Geringeres Anstoß als für ein neues Zeitalter, eine neue Gesellschaft und eine neue Wirtschaft. Dennoch sollte der Informationsbegriff, wie im Folgenden demonstriert wird, mit der Zeit auch auf Zweifel stoßen. Östlich des Eisernen Vorhangs trug der zweite Satz zunächst zur kategorischen Ablehnung der Kybernetik bei, da er sich nicht mit den Grundsätzen der marxistischen materialistischen Dialektik vereinbaren ließ und diese somit infrage stellte (Levien et al. 1964:27–29; Gerovitch 2002:127; Peters 2016:39; Band 1, Kapitel II.2). Seit sich Wiener in seinem Buch Cybernetics (Wiener 1948) neben dem Begriff der Kontrolle auch jenem der Kommunikation widmete und darin der Information eine wichtige Rolle zuschrieb, werden die Kybernetik und die Informationstheorie generell als eng verwandte Disziplinen verstanden. Während die Kybernetik erster Ordnung und die Informationstheorie in der Tat oft in ähnlichen Kontexten herangezogen werden, steht die Kybernetik zweiter Ordnung sowohl der Informationstheorie an sich als auch der These einer inhaltlichen Verwandtschaft beider Felder verhalten gegenüber. Auf die Informationstheorie wird in einer Vielzahl medienwissenschaftlicher und medientechnischer Studien zurückgegriffen. Sie wurde von Claude Shannon ebenfalls am

https://doi.org/10.1515/9783110496253-024

342 | 5 Ausgangspunkt Subjekt MIT entwickelt und basiert auf seiner generellen Kommunikationstheorie (Shannon 1948). Eine frühe Verwandtschaft von Informationstheorie und Kybernetik besteht insofern, als Shannon bei der Entwicklung der Informationstheorie laut Wieners Biografen (Conway und Siegelman 2005:125–126) Einzelunterricht von Wiener in Anspruch nahm (Kline 2015:31), der bereits vor dem Zweiten Weltkrieg statistische Methoden zur Signalverarbeitung entwickelte (Conway und Siegelman 2005:66). Während Shannon diese Zusammenarbeit in seiner mathematischen Kommunikationstheorie umsetzte, arbeitete Wiener an seinem Buch Cybernetics. Beide Texte wurden im Jahr 1948 publiziert. Der Kern der Shannon’schen Kommunikationstheorie ist das in Abbildung 5.1 dargestellte generelle Kommunikationsmodell.

information source

transmitter

signal

received signal

noise source

receiver

destination

Abb. 5.1: Shannons (1948:381) Schema eines generellen Kommunikationssystems

Kommunikation erfolgt gemäß diesem Modell zwischen einer Informationsquelle (information source) und einem Bestimmungsort (destination). Die Informationsquelle wählt aus einer begrenzten Menge möglicher Botschaften eine Botschaft (signal) aus, welche von einem Sender (transmitter) durch einen Kanal übertragen und auf Seiten des Bestimmungsorts von einem Empfänger (receiver) empfangen wird. Auf dem Kanal ist das Signal Störquellen (noise source) ausgesetzt, sodass der Empfänger von einer Verzerrung der ursprünglichen Botschaft auszugehen hat und eventuell restaurierende Maßnahmen ergreifen muss. Das Restaurieren verzerrt ankommender Botschaften kann vom Sender unterstützt werden, indem Botschaften redundant kodiert werden, das heißt dass Wiederholungen in die Botschaft kodiert werden. Bei diesem Vorgehen wird also eine reduzierte Fehlerrate zum Preis längerer Botschaften erreicht (siehe Band 1, Abschnitt II.4.5.3). Die Shannon’sche Kommunikationstheorie ist in der Darstellung ihres Geltungsbereichs nicht eindeutig. Einerseits klammert Shannon (1948) Fragen der Bedeutung explizit aus (1948:379) und legt somit eine rein technische Behandlung von Kommunikation nahe. Auch erklärt er, dass mit dem Begriff „Kommunikationssystem“ Systeme des in Abbildung 5.1 dargestellten Typs gemeint sind (1948:380). Somit verweist der Begriff auf eine Menge (technischer) Systeme in einer übergeordneten Menge (auch nichttechnischer) Systeme, sodass von einem partiellen Geltungsanspruch für eine Untermenge technischer Systeme ausgegangen werden sollte. Andererseits lässt die Formulierung „generelles Kommunikationssystem“ auf einen weiten Geltungsanspruch und Anwendbarkeit auf jedwede Kommunikation schließen. In der Tat wird die Theorie oft

5.1 Eine kritische Annäherung an „Information“

| 343

über die Grenzen technischer Anliegen hinaus auch auf sowohl individuelle als auch soziale menschliche Kommunikation angewandt. Die häufig vorausgesetzte generelle Anwendbarkeit des obigen Modells soll mit dem folgenden Experiment III.7 untersucht werden. Experiment III.7: Kommunikationsversuch Bei der Ausführung des Skripts in Listing 5.1 gibt Ihr Computer für etwa drei Minuten Töne von sich und wird somit, entsprechend dem in Abbildung 5.1 dargestellten Shannon’schen Kommunikationsmodell, zur Quelle auditiver Information (vergewissern Sie sich zunächst, dass die Audio-Ausgabe gewährleistet ist). Sie befinden sich zuhörend in der Position des empfangenden Zielorts der gesendeten Botschaft. Was ist deren Inhalt? Dekodieren Sie! Wenn Ihre Wahrnehmung der Botschaft nicht von Störquellen überdeckt oder verzerrt wird, sollte, sofern das obige Modell tatsächlich generell anwendbar ist, Ihrer Dekodierung der Botschaft nichts im Weg stehen. Enthält die Botschaft dekodierbare Information? Oder handelt es sich hierbei an sich schlicht um eine Störquelle? Listing 5.1: Kommunikationsversuch (communication-attempt_DE.py) 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

import pygame, time from array import array pygame.mixer.pre_init(44100, -16, 1, 1024); pygame.init() class Ton(pygame.mixer.Sound): def __init__(self, frq): self.frq = frq pygame.mixer.Sound.__init__(self, self.synthese()) def synthese(self): p = int(round(pygame.mixer.get_init()[0]/self.frq)) sampels = array("h", [0] * p) amp = 2 ** (abs(pygame.mixer.get_init()[1])-1)-1 for t in range(p): sampels[t] = amp if t < p / 2 else -amp return sampels muster=[680, 80, 20498, 8741, 38229, 21056, 0, 1, 32768, 3328, 26, 0, 21504, 248, 0, 6, 7265, 34816, 12826, 12678, 48891, 61312, 0, 4096, 1024, 0, 8192, 4032, 496, 0, 6241, 50720, 8200, 26723, 39675, 61374, 0, 64, 49168, 384, 131, 63, 1543, 49164, 16, 2052, 4144, 4120, 24640, 3139, 1, 38912, 12556, 390, 1028, 2052, 4120, 1088, 12296, 32800, 8320, 32896, 32774, 192, 12292, 30080, 2056, 16, 31744, 8564, 46596, 58622, 57793, 47106, 33714, 1287, 58378, 3080, 13824, 0, 56, 8192, 29973, 21728, 2720, 20, 15, 32768, 32704, 896, 57356, 96, 13313, 24780, 1633, 5140, 16932, 18560, 17680, 132, 8193, 64, 148, 121, 62704] l = Ton(frq=261) # c' m = Ton(frq=392) # g' h = Ton(frq=523) # c'' seq=''

344 | 5 Ausgangspunkt Subjekt 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44

intbin = lambda x, n: format(x,'b').zfill(n) for n in muster: seq+=intbin(n, 16) m.play(-1); time.sleep(15); m.stop() curr=-1; accu=0; n=0 for t in seq: if n= n - 1: c = c + 1 break else: if k > k_max: k_max = k i = i + 1

3 Die Funktion lz_complexity() in den Zeilen 6 bis 26 in Skript 5.3 basiert auf einem Flussdiagramm in Kaspar und Schuster (1987:843, Fig. 1).

350 | 5 Ausgangspunkt Subjekt 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

if i == l: c = c + 1; l = l + k_max if l + 1 > n: break else: i = 0; k = 1; k_max = 1 else: k = 1 return c pillenzahl = 100 vorpillen = [] for i in range(0,pillenzahl): farbe = bool(random.getrandbits(1)) pille = 'x' if i < pillenzahl/2 else 'o' if farbe == 0: pille = pille.upper() vorpillen.append(pille) shake=u'SCHÜTTELN!'#.decode('utf-8') vorfarben = vorformen = nachfarben = nachformen = '' nachpillen = list(vorpillen) random.shuffle(nachpillen) print(' vor nach\n') for i in range(0,pillenzahl): print(vorpillen[i]+' ', end = '') if (i % 10) == 9: print(' '+shake[int(i/10)]+' ', end = '') for j in range(0,10): print(nachpillen[int(i/10)*10+j]+' ', end = '') if nachpillen[int(i/10)*10+j]=='O' or nachpillen[int(i/10)*10+j]=='o': nachfarben+='1' else: nachfarben+='0' if nachpillen[int(i/10)*10+j]=='o' or nachpillen[int(i/10)*10+j]=='x': nachformen+='1' else: nachformen+='0' print() vorfarben+='1' if vorpillen[i] == 'O' or vorpillen[i] == 'o' else '0' vorformen+='1' if vorpillen[i] == 'o' or vorpillen[i] == 'x' else '0'

print('\n'+u'\u0394'+' Komplexität der Farb-Verteilung:',lz_complexity(nachfarben)-lz_complexity(vorfarben)) 61 print(u'\u0394'+' Komplexität der Form-Verteilung:',lz_complexity(nachformen)-lz_complexity(vorformen),'\n')

5.1 Eine kritische Annäherung an „Information“

|

351

∆ Komplexität nach Schütteln

20

Farbe Form

15

10

5

0

-5

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

Gläser mit Pillen

Abb. 5.5: Differenzen der Komplexität von Farb- und Form-Verteilungen von 25 Gläsern mit Pillen nach dem Schütteln

Nun mag der Einwand vorgebracht werden, dass Äpfel mit Birnen verglichen würden. Schließlich handelt es sich bei Shannons und ähnlichen Komplexitätsmaßen um wohldefinierte mathematische Prozeduren für die Auswertung von Verteilungen abstrakter, purer Symbole, welche als einziges Attribut ihren jeweiligen symbolischen Wert besitzen. Pillen als physische Objekte hingegen weisen mehrere Attribute auf wie Form, Farbe, Gewicht, Geschmack etc. und eröffnen damit Interpretationsspielräume in menschlicher Betrachtung, die, so könnte man argumentieren, in der formellen Verarbeitung von Symbolsequenzen nicht bestünden. Diesem Einwand sei hier in zweifacher Hinsicht entgegengetreten. Zum einen erlauben abstrakte Symbole durchaus divergierende Interpretationen. Von Foerster (2003b:202) demonstriert dies mit den beiden folgenden Symbolsequenzen und der Feststellung, Sequenz B sei ebenso „schön“ geordnet wie Sequenz A: A: 1, 2, 3, 4, 5, 6, 7, 8, 9 B: 8, 5, 4, 9, 1, 7, 6, 3, 2 In der Tat weist Sequenz B insofern eine ebenso aufsteigende Ordnung auf wie Sequenz A, als sie der alphabetischen Ordnung der jeweiligen englischen Zahlwörter folgt. Hierin zeigt sich, dass auch Betrachtungen reiner Symbole Spielräume für divergierende Interpretationen zulassen. Zum anderen sind diese Interpretationsspielräume nicht nur Beobachtern aus Fleisch und Blut vorbehalten. Die maschinelle Verarbeitung von Symbolsequenzen folgt den Entscheidungen und Interpretationen derer, die sie implementieren. Dies kann mit Vorfällen illustriert werden, die sich bei der NASA und in ähnlicher Form auch in anderen Kontexten ereignet haben.

352 | 5 Ausgangspunkt Subjekt Im Juni 1985 sollte während der Mission STS-51-G des NASA Space Shuttles Discovery ein vom US-Verteidigungsministerium im Rahmen der Strategic Defense Initiative (SDI) in Auftrag gegebenes Zielfolge-Experiment durchgeführt werden. Ein von der Erdoberfläche gesendeter Laser sollte von einem im Fenster der DiscoveryEinstiegsluke installierten handgroßen Reflektor zurück zur Erde reflektiert werden. Als sich das Shuttle bei seiner 37. Erdumrundung Hawaii näherte, richtete das auf dem Berg Haleakala¯ auf der hawaiianischen Insel Maui gelegene Air Force Maui Optical and Supercomputing Observatorium einen blinkenden, blaugrünen, vier Watt schwachen Laserstrahl in den Himmel. Vier redundante und ein unabhängiger Flugcomputer vom Typ IBM AP-101 fungierten als Autopilot an Bord des Shuttles und steuerten dessen ¯ ausrichten sollte. Antriebssystem, das nun den Reflektor auf den Gipfel Haleakalas Stattdessen richteten sie den Spiegel jedoch hinaus ins leere All. Die Höhe des Observatoriums auf dem Berg Haleakala¯ wurde mit dem Wert 9 994 in der Einheit Fuß (feet) programmiert, während der auf den IBM AP-101 ausgeführte Code Längenmaße generell in nautischen Meilen interpretierte. So richtete der Autopilot den Reflektor auf einen imaginären Berggipfel mit einer Höhe von 9 994 nautischen Meilen aus, einen Punkt tief im All. Zwei Tage später wurde das Experiment wiederholt – diesmal mit Erfolg. Im September 1999 führte eine ähnliche Verwechslung der Einheiten Pfund (pounds) und Newton zum Absturz der NASA-Raumsonde Mars Climate Orbiter. Der Direktor des zuständigen Jet Propulsion Laboratory, Edward C. Stone, kommentierte den Vorfall mit den Worten (Pollack 1999): The real issue is not that the data was wrong, [t]he real issue is that our process did not realize there was this discrepancy and correct for it.

Ähnlich dem Austausch von Schlüsseln in der Kryptologie erfordert also jedwede Kommunikation den vorausgehenden Abgleich allseitig verwendeter interpretativer Mittel. Die in den obigen NASA-Beispielen kommunizierten Zahlen wurden falsch gedeutet, da die Maßeinheiten im Ursprungskontext und im Kontext der Anwendung unterschiedlich interpretiert wurden. Doch selbst mit vereinbarten Maßeinheiten können unterschiedliche Beobachter angesichts desselben zu messenden Gegenstandes unterschiedliche Messergebnisse erzielen, wenn sie in ihren Messungen unterschiedliche Methoden oder Werkzeuge anwenden. Richardson (1961:169–170) stellt fest, dass benachbarte Länder mitunter verschiedene Angaben über die Längen ihrer gemeinsamen Grenzen machen. So habe die Länge der portugiesisch-spanischen Grenze im Jahr 1938 aus spanischer Sicht 987 km und aus portugiesischer Sicht 1 214 km betragen. Eine Ursache hierfür ist die sogenannte Küstenlinien-Paradoxie: Aufgrund ihrer „fraktalen“ Form, mit Landschaftsmerkmalen unterschiedlicher Größenordnungen, hängen die Längenmessungen territorialer Umrisse wesentlich von den dabei verwendeten Schrittweiten ab.

5.2 Konstruierende Wahrnehmung

| 353

So offenbart sich Kommunikation nicht als „Übermittlung von Information“, sondern als Exposition und Rezeption von Signalen, also von Mustern – Verteilungen von Materie und Energie in Raum und Zeit. Bedeutungstragend sind diese Muster an sich nicht.⁴ Von Foerster (2006:5) bezeichnet sie als „potenzielle Information“. Bedeutung ergibt sich erst aus ihrer Interpretation, was den vorausgehenden Abgleich interpretativer Mittel voraussetzt. Da dieser Abgleich wiederum nur kommunikativ zu bewerkstelligen ist, führt das Vorhaben in einen endlosen Regress, den wir durch wiederholte Versuche gemeinsamen Handelns und Verstehens bewältigen. Von Foerster (2006:47) fasst zusammen: „Die Welt enthält keine Information.“ Ob und wie diese Muster auch nach Abgleich interpretativer Mittel seitens „Empfangender“ interpretiert werden, entzieht sich weitestgehend sowohl dem Einblick als auch der Einflussnahme anderer – „Sendender“ inbegriffen. Von Foerster beschreibt dies mit seinem hermeneutischen Prinzip (von Foerster und Pörksen 2013:72): Der Hörer, nicht der Sprecher, bestimmt die Bedeutung einer Aussage.

Diese Feststellung bezieht sich nicht nur auf das Hören im engeren Sinne, sondern auf jedwede Wahrnehmung kommunizierter Muster. Hierbei kommt Differenz zum Tragen – laut Ashby (1956:9) das fundamentalste Konzept der Kybernetik. Die in der Wahrnehmung von Differenz relevanten Schwellen und Kriterien unterliegen individuellen Physiologien, Einstellungen und Erfahrungen. Bateson (1972:271) charakterisiert Information dementsprechend aus der Perspektive subjektiver Beobachter als „the difference that makes a difference“ – ein Verständnis von Information, das im Gegensatz zu dem Shannons keinen Anspruch auf einen messbaren, objektiv gegebenen Inhalt erhebt. Hierin zeigt sich eine kybernetische Skepsis gegenüber der Idee mentaler Repräsentation einer objektiv wahrnehmbaren Realität. Diese Skepsis kann mit einem Blick auf unser Nervensystem untermauert werden.

5.2 Konstruierende Wahrnehmung Es ist weithin bekannt, dass unsere Wahrnehmung physiologischen Grenzen unterliegt, etwa hinsichtlich der Spektren sichtbarer Farben, hörbarer Frequenzen oder der Schwellen, unter denen wir keine Nuancen wahrnehmen. Auch ist bekannt, dass sich diese sensorischen Unterschiede in vielen Fällen auf physiologische Unterschiede beispielsweise zwischen Spezies, Individuen oder unterschiedlichen Lebensabschnitten derselben Individuen zurückführen lassen. Die Unvollständigkeit unserer Sensorik lässt sich unter bestimmten Bedingungen direkt erfahrbar machen. Zu diesem Zweck soll uns das Experiment III.9 den „blinden Fleck“ buchstäblich vor Augen führen.

4 Diese Erkenntnis zieht weiterhin das Konzept „vermittelbaren“ Wissens und das darauf basierende Verständnis von Bildung analog zu Banküberweisungen (Freire 2005:71–86) in Zweifel.

354 | 5 Ausgangspunkt Subjekt

Experiment III.9: Blinder Fleck Dieses Experiment (von Foerster 1984:4–5) demonstriert am Beispiel des sogenannten blinden Flecks die Unvollständigkeit unserer Wahrnehmung, deren Kompensation sowie unsere weitgehende Unbewusstheit dieser Umstände. Halten Sie die folgende Grafik in Armlänge vor sich. Schließen Sie Ihr linkes Auge und fixieren Sie mit dem rechten Auge den Stern. Der schwarz gefüllte Kreis erscheint nun in Ihrem peripheren Sichtfeld. Bewegen Sie nun die Grafik auf ihr rechtes Auge zu, ohne den Stern aus dem Auge zu verlieren. Bei einer bestimmten Entfernung vor Ihrem Gesicht wird in Ihrem peripheren Sichtfeld der schwarze Kreis verschwinden, während der anvisierte Stern klar sichtbar bleibt.





Das Verschwinden des schwarzen Kreises lässt sich mit der Anatomie des Auges erklären (siehe Abbildung 5.6). Auf der Rückwand des Auges treffen Projektionen auf die Netzhaut, deren visuelle Rezeptoren optische Reize in neurale Signale umsetzen. An der Stelle, an der außen der Sehnerv austritt, befinden sich im Inneren des Auges keine visuellen Rezeptoren. Während der fixierte Stern auf die Netzhaut projiziert wird, trifft die Projektion des Kreises bei einem bestimmten Abstand (und somit in einem bestimmten Winkel) auf diese Stelle, den „blinden Fleck“. Da sich an dieser Stelle keine visuellen Rezeptoren befinden, wird der dorthin projizierte Kreis nicht wahrgenommen.

«

Abb. 5.6: Horizontaler Schnitt des rechten Auges mit Projektion von Stern und Kreis

Bemerkenswerterweise nehmen wir trotz dieser partiellen Blindheit kein „Loch“ in der Mitte unseres Sichtfeldes wahr. Von Foerster (2006:26) beschreibt diesen Umstand mit seinem Prinzip der Doppelten Blindheit: Wir sehen nicht, daß wir nicht sehen.

Dieses Prinzip gilt für andere Sinne gleichermaßen. Neben der Unvollständigkeit unserer Wahrnehmung entzieht sich uns auch das aktive Zutun des Nervensystems zur Wahrnehmung. So ist das (gesunde) Nervensystem offenbar in der Lage, visuelle Wahrnehmungen am blinden Fleck unbemerkt zu „interpolieren“. Ganz ähnlich verhält es sich mit unserer Farbwahrnehmung. Die menschliche Netzhaut enthält zwei Sorten visueller Rezeptoren – die helligkeitswahrnehmenden Stäbchen und die

5.2 Konstruierende Wahrnehmung

|

355

farbwahrnehmenden Zäpfchen. Die Konzentration Letzterer ist in den zentraleren Regionen der Netzhaut hoch und nimmt nach außen hin ab. So ist davon auszugehen, dass wir auf physiologischer Ebene keine periphere Farbwahrnehmung haben. Allerdings erleben wir gesundes Sehen als gleichmäßig farbig. Allem Anschein nach ist das Nervensystem kreativ und färbt das periphere Sichtfeld ein. Hierfür gibt es physiologische Indizien. Maturana und Varela (1987:162–163) stellen fest, dass die Mehrheit der von den Netzhäuten kommenden Nervenfasern zunächst in die sogenannten seitlichen Kniehöcker⁵ führen, von wo aus weitere Verbindungen in den visuellen Kortex bestehen. Jedoch trägt die Sehbahn nur etwa 20 % zu den mit dem seitlichen Kniehöcker verbundenen Nervenfasern bei. 80 % des Inputs des seitlichen Kniehöckers kommen von anderen Teilen des Nervensystems. So ist nicht davon auszugehen, dass die visuelle Wahrnehmung lediglich von Stimulationen seitens der Netzhaut determiniert wird und der seitliche Kniehöcker dabei die bloße Rolle einer Relaisstation spielt. Die Mehrheit der unsere visuelle Wahrnehmung ausmachenden Signale wird offenbar von anderen Teilen des Nervensystems hervorgebracht, sodass Stimulationen seitens der Netzhaut eine quantitativ untergeordnete Rolle spielen. Von Foerster (2006:38–40) macht eine ähnliche Beobachtung auf der Ebene des gesamten Nervensystems. Er stellt fest, dass Signalpfade zwischen verbundenen Neuronen durch den sogenannten synaptischen Spalt unterbrochen sind, dessen veränderliches chemisches Milieu sowohl inhibitorisch als auch exzitatorisch auf die Signalübertragung zwischen Neuronen wirken kann. Da das menschliche Nervensystem lediglich einige 100 Millionen sensorische Rezeptoren, aber etwa 10 000 Milliarden synaptische Spalte aufweist, so von Foerster, sind wir um ein Vielfaches empfindlicher gegenüber Veränderungen unserer inneren Umwelt als gegenüber Veränderungen in unserer äußeren Umwelt. Weiterhin stellt von Foerster (2006:31–33) fest, dass in den Nervensystemen von Säugetieren sogenannte internuntiale Neuronen bzw. Interneuronen auftreten, die zwei oder mehrere Neuronen verbinden (auf diese Weise bilden sie auch neuronale Erregungskreise). Abbildung 5.7 illustriert die Verbindung zwischen einem sensorischen und einem motorischen Neuron durch ein Interneuron. Das entweder inhibitorische oder exzitatorische Verhalten eines Interneurons wird unter anderem von dessen eignem vergangenem Verhalten beeinflusst.⁶

5 Die seitlichen Kniehöcker sind Teile des Metathalamus im Zwischenhirn von Säugetieren. 6 Bei ihren Input-Output-Operationen können Interneuronen also „Erinnerungen“ ablegen und in Betracht ziehen – ähnlich etwa einer Person bei der Benutzung eines Abakus. Dementsprechend argumentiert von Foerster (2006:33), dass das In-Erscheinung-Treten von Interneuronen das Element des Rechnens in das Reich der Lebewesen eingeführt und entsprechenden Organismen somit eine Vielfalt nicht-trivialer Verhaltensweisen ermöglicht habe. Von Foersters (2006:39) Postulat der Kognitiven Homöostase besagt: „Das Nervensystem ist so organisiert (bzw. organisiert sich selbst so), daß es eine stabile Realität errechnet.“

356 | 5 Ausgangspunkt Subjekt

Abb. 5.7: Sensorisches (oben), internuntiales (Mitte) und motorisches (unten) Neuron. Basierend auf von Foerster (2006:32, Bild 9)

Abb. 5.8: Elektrisches „Feuern“ eines Berührungsrezeptors bei kontinuierlicher schwacher (oben), moderater (Mitte) und starker (unten) Stimulation. Basierend auf von Foerster (2006:34, Bild 11)

Die Betrachtung des Formats neuronaler Signale gibt weiteren Aufschluss über die Verfahrensweise unseres Wahrnehmungsapparates. Das „Feuern“ von Rezeptorzellen kann beispielsweise mit Mikrosonden in der Hörbahn erfasst, verstärkt und visualisiert werden. Hierbei haben diese Signale in Form kurzer elektrochemischer Entladungen stets eine Amplitude von etwa einem Zehntel Volt. Mit steigender Intensität der jeweiligen Stimulation steigt die Frequenz dieser Impulse. Auf physiologischer Ebene kommunizieren Neuronen also lediglich Quantitäten, die im Fall externer Stimulationen mit Körperstellen assoziiert sind. Von Foerster spricht vom „Prinzip der undifferenzierten Kodierung“ (von Foerster 2006:29): Die Reaktion einer Nervenzelle enkodiert nicht die physikalischen Merkmale des Agens, das ihre Reaktion verursacht. Es wird lediglich das „so viel“ an diesem Punkt meines Körpers enkodiert, nicht aber das „was“.

Die physikalischen Qualitäten unserer Stimuli, die wir als Farben, Gerüche, Geschmäcker usw. wahrnehmen, werden folglich nicht in der Aktivität der Neuronen kodiert. Vielmehr ist davon auszugehen, dass das Nervensystem selbst die Vielfalt wahrgenommener Qualitäten erzeugt. Das Zutun des Nervensystems in der Wahrnehmung ist keineswegs auf physiologische Grenzen und unwillkürliche neuronale Aktivitäten beschränkt. Es lässt sich

5.2 Konstruierende Wahrnehmung

| 357

mitunter bewusst lenken und dieses Lenken lässt sich, wie das folgende Experiment III.10 zeigt, demonstrieren. Experiment III.10: Oszillierendes Schachbrett Dieses Experiment (basierend auf Uribe 1991) lädt dazu ein, das Verständnis von Beobachtung als passivem „Empfangen“ von „Information“ kritisch zu prüfen. Es zeigt, dass wir unsere Beobachtungen aktiv beeinflussen können. Das folgende Skript öffnet ein Fenster, in dem ein Schachbrettmuster aus schwarzen und weißen Feldern dreimal pro Sekunde binär oszilliert. Listing 5.4: Schachbrett-Oszillator (chess-board-oscillator_DE.py) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19

import numpy as np import matplotlib.pyplot as plt import matplotlib.animation as animation def update(data, grid): for x in range(16): for y in range(16): grid[x,y]=np.logical_not(grid[x,y]) mat.set_data(grid) return [mat] grid = np.kron([[1, 0] * 8, [0, 1] * 8] * 8, np.ones((1, 1))) animation.rcParams["toolbar"] = "None" fig, ax = plt.subplots() fig.canvas.set_window_title("Binär oszillierendes Schachbrett") mat = ax.matshow(grid, cmap="Greys", interpolation="nearest") ax.axis("off") ani = animation.FuncAnimation(fig, update, fargs=(grid, ), interval=300) plt.show()

Richten Sie Ihre Aufmerksamkeit auf die Mitte des oszillierenden Musters. Es entsteht der Eindruck, die Felder befänden sich in Bewegung. Dabei ist die Bewegungsrichtung unter Ihrer Kontrolle. Entscheiden Sie, ob sich die Felder nach oben, nach unten, nach links, nach rechts oder in einer der vier diagonalen Richtungen bewegen, und sie werden Ihren Entscheidungen folgen. Die subjektiv wahrgenommene Bewegungsrichtung ändert sich, ohne dass es einen Grund gäbe, dies dem beobachteten Phänomen zuzuschreiben. Was sich verändert, ist lediglich die in diesem Beispiel willkürlich kontrollierbare Betrachtungsweise.

Willkürliche Einflussnahmen auf die eigene Wahrnehmung lassen sich auch bei der Betrachtung technischer Medien demonstrieren. Abbildung 5.9 zeigt sowohl den bereits erwähnten chinesischen Abakus als auch einen Rechenschieber. Der Abakus gilt, da seine Perlen in diskreten Schritten gezählt werden, gemeinhin als digital. Der Rechenschieber hingegen gilt, da an ihm Proportionen entlang kontinuierlicher Skalen gemessen werden, als analog (Kämmerer in Ulmann, 2010:2). Jeder Stab des Abakus repräsentiert eine Dezimalstelle, mit der niederwertigsten Stelle rechts. In den oberen Gruppen aus je zwei Perlen repräsentiert jede Perle eine

358 | 5 Ausgangspunkt Subjekt

Abb. 5.9: Chinesischer Abakus und Rechenschieber

Fünf. In den unteren Gruppen aus je fünf Perlen repräsentiert jede Perle eine Eins. Folglich stellt der Abakus in Abbildung 5.9 die Zahl 1 964 dar. Anstatt den Rechenschieber und seine beweglichen Teile, die Zunge und den Läufer, zu benutzen wie vorgesehen, sind Zweckentfremdungen möglich. So lassen sich beispielsweise mehrere Rechenschieber vertikal orientieren, um mehrere Dezimalstellen darzustellen, indem man mit den Läufern in gleichen Abständen 5er-Schritte markiert und mit den Zungen in gleichen Abständen 1er-Schritte markiert. Auf diese Weise lassen sich, wie in Abbildung 5.10 illustriert, Zahlen wie auf dem Abakus darstellen (wiederum die Zahl 1 964) und Berechnungen anstellen. Die soeben noch analogen Rechenschieber fungieren nun als Abakus und erscheinen digital.

Abb. 5.10: Rechenschieber als Abakus

Auch in der Arbeit Turings kommt die Beobachterabhängigkeit zum Tragen. Turing beschrieb zunächst die auf den Seiten 311 bis 314 besprochene Turingmaschine, deren eingebautes Programm Symbole auf einem Band manipuliert. Er beschrieb darauf aufbauend eine weitere hypothetische Maschine, die das Programm einer beliebigen anderen Turingmaschine, auf einem Band kodiert, einliest und diese andere Maschine dann simuliert (Turing 1936:241–246).

5.2 Konstruierende Wahrnehmung

| 359

Bossomaier und Green (1998:16) veranschaulichen diese als Universelle Turingmaschine (UTM) bezeichnete Variante mit dem Bild einer Turingmaschine mit zwei Bändern. Das erste Band enthält das (austauschbare) Programm einer zu simulierenden Turingmaschine, während das zweite Band dem der einfachen Turingmaschine entspricht. Im heutigen Sprachgebrauch enthält das erste Band das Programm und das zweite Band die Daten dieser universellen Maschine. Fänden nicht eingeweihte Beobachter eine solche Maschine im Betrieb vor, so wären sie nicht in der Lage zu erkennen, welches der beiden Bänder das Programm und welches die Daten enthält. Die Interpretation von Symbolen entweder als Programm oder als Daten⁷ liegt folglich in den Augen Beobachter⁸. Später, bei der Diskussion der Möglichkeit künstlicher Intelligenz definiert Turing (1950:433–434) Intelligenz mit seinem sogenannten Turing-Test. In diesem Test wird die „Intelligenz“ von Computerprogrammen getestet, indem eine Person (C) schriftlich sowohl mit einer anderen Person (A) als auch mit einem zu prüfenden Computerprogramm (B) kommuniziert. Sowohl (A) als auch (B) sind (C) unbekannt, befinden sich außer Sicht- und Hörweite und haben die Aufgabe, (A) davon zu überzeugen, dass sie menschlich sind. Gelingt es Person (C) nach eingehendem Austausch mit (A) und (B) nicht, deren Identitäten klar festzustellen, dann ist dies laut Turing ein Beleg für die Intelligenz des Computerprogramms (B).⁹ Der Test stellt also keine objektive Definition einer Eigenschaft von Programmen, sondern eine operative Definition dar, mit der diesbezügliche subjektive Urteile von Beobachtern eruiert werden können (Glanville 2009:397–398). Intelligenz ist folglich keine Qualität des Betrachteten, sondern vielmehr die Qualität eines Verhältnisses zwischen Beobachtern und Beobachtetem. Diese Erkenntnis kann auf beliebige vermeintliche Objekteigenschaften übertragen werden. Von Foerster (2006:5) argumentiert: „Obszönität“ ist keine Eigenschaft, die den Dingen selbst angehört, sondern eine Subjekt-ObjektBeziehung, denn wenn wir Herrn X ein Gemälde zeigen und er dieses obszön nennt, dann wissen wir eine Menge über Herrn X, aber sehr wenig über das Gemälde.

7 Dies ist generalisierbar auf die Unterscheidungen von Werkzeug und Material, Agens und Ressource, Prozess und Inhalt. 8 Ihre prinzipielle Austauschbarkeit ermöglicht, dass sich Programme und Daten in der VonNeumann-Architektur (die auf der Turingmaschine basierende, von John von Neumann entwickelte und heute vorherrschende Bauweise digitaler Computer) denselben Speicher teilen. 9 McCarthy, Minsky, Rochester und Shannon (1955) definieren KI ähnlich beobachterbasiert: „[T]he artificial intelligence problem is taken to be that of making a machine behave in ways that would be called intelligent if a human were so behaving.“ Simon (1985:8) qualifiziert Kreativität ganz ähnlich.

360 | 5 Ausgangspunkt Subjekt

5.3 Radikaler Konstruktivismus Wenn neuronale Signale unsere Wahrnehmung konstituieren, unsere Nervensysteme auf Stimulationen jedoch unvollständig, selektiv und aktiv Einfluss nehmend reagieren, und wenn neuronale Signale nicht die Qualität von Dingen, sondern lediglich die Intensität von Unterscheidungen kodieren, dann stellt sich die Frage: In welchem Verhältnis stehen unsere Wahrnehmungen zum Wahrgenommenen? Das Verhältnis von Wahrnehmung und Wahrgenommenem entzieht sich allerdings einem objektiven Vergleich, da jeder Versuch einer Gegenüberstellung letztlich nur innerhalb unserer Wahrnehmung unternommen werden kann. So gleicht unser epistemologischer Ausgangspunkt der Perspektive der Gefangenen in Platons Höhlengleichnis (von Foerster 2010a:54). Im Gegensatz zu den in der Höhle Festsitzenden haben wir jedoch keine Aussicht auf Befreiung durch Nicht-Gefangene, die uns aus der Subjektivität unserer Wahrnehmung herausführen könnten. Befreiung ist nur in der Höhle zu finden, etwa in der Erkenntnis, dass es keine Beobachtung ohne Beobachter gibt. Authentischere Bilder als die Schatten an den Höhlenwänden unseres Erlebens sind nicht zu erwarten. Stattdessen erweist sich nun die „objektive Realität“ vor der Höhle als Trugbild. Von Glasersfeld (1991:17) erklärt: „Objektivität ist die Illusion, daß Beobachtungen ohne einen Beobachter gemacht werden können.“ Von Foerster (2013) legt nach: „Wahrheit ist die Erfindung eines Lügners.“ Diese radikal-konstruktivistische Sichtweise widerspricht der Annahme des naiven Realismus, Wahrnehmung sei ein passiver Empfang von Information, die objektiv gegebene Dinge abbildet. Als eine alternative Sichtweise beschreibt der radikale Konstruktivismus Erkenntnis als einen fortwährenden, zirkulären Prozess, in dem wir handelnd und wahrnehmend mit der Welt in Beziehung stehen. Maturana (2002:15– 25) beschreibt Beziehungen dieser Art als strukturelle Kopplung. Hierbei ist Handeln eine Voraussetzung für Wahrnehmung und umgekehrt. Von Foerster (1993:52 erklärt: Der Sinn (oder die Bedeutung) der Signale des Sensoriums wird durch das Motorium bestimmt, und der Sinn (oder die Bedeutung) der Signale des Motoriums wird durch das Sensorium bestimmt.

In diesem zirkulären Austausch mit der Welt treffen wir Unterscheidungen, stellen Analogien her, entwickeln Handlungsschemata und konstruieren operationale Strukturen. Diese werden in weiteren Bezugnahmen zur Welt erhärtet oder infrage gestellt und revidiert. Von Glasersfeld entwickelte die radikal-konstruktivistische Erkenntnistheorie in Anlehnung an die Entwicklungspsychologie Jean Piagets. Dessen Konzept der Objektpermanenz, also das Erkennen der überdauernden Identität etwa von Gegenständen und Personen, basiert gleichsam auf wiederholtem sensomotorischem Engagement mit der Welt. Von Glasersfeld (1987:182) fasst zusammen:

5.3 Radikaler Konstruktivismus

|

361

a) Das aktive Subjekt organisiert sein sensomotorisches Erleben, indem es Handlungsschemata aufbaut und diejenigen beibehält, die zu Gleichgewicht führen oder es angesichts von Störungen erhalten. b) Durch Reflexion werden von den Handlungsschemata dann operationale Strukturen abstrahiert und externalisierten Gegenständen zugeschrieben. c) Nachdem diese operationalen Strukturen von dem sensomotorischen „Inhalt“, der ursprünglich zu ihrem Aufbau führte, abstrahiert worden sind, kann mit ihnen in einem Klima der Sicherheit operiert werden, und auf dieser Stufe liefern sie „logisch-mathematische Wahrheit“. d) Andererseits aber werden operationale Strukturen auf Gegenstände projiziert und somit „externalisiert“. Ihre fortdauernde Viabilität angesichts weiterer Erfahrung führt dann zum Glauben an ihre unabhängige „Existenz“ und mithin zum Glauben an ihre „objektive Wahrheit“.

So konstituieren individuell konstruierte Unterscheidungen, Analogien, Handlungsschemata und operationale Strukturen subjektive Realität. Das Verhältnis subjektiver Realitäten zur Welt unterliegt in dieser Sichtweise nicht dem Kriterium objektiver, prüfbarer Korrektheit, sondern dem der Korrespondenz und Gangbarkeit beziehungsweise der Viabilität. Ideen, Hypothesen, Theorien und Modelle sind viabel, „solange unsere Erfahrung erfolgreich in sie eingepaßt werden kann“ und „sie von der Erfahrung nicht kaputtgemacht werden“ (von Glasersfeld 1987:136–140). Dieser Viabilitätsbegriff weist Parallelen zur Evolutionstheorie auf (von Glasersfeld 1987:183) und ist, wie in Unterkapitel 5.4 gezeigt wird, auch in der Wissenschaftstheorie anwendbar. Die radikal-konstruktivistische Sicht des Erkenntnisprozesses gleicht der auf den Seiten 318 und 319 beschriebenen analytischen Determinierung der Trivialen Maschine (1993:357). Ähnlich der Unzugänglichkeit der „Welt an sich“ ist die Triviale Maschine opak und gestattet keinen Einblick in ihre Wirkungsweise. Vermutungen darüber lassen sich lediglich aus Beobachtungen ihrer Inputs und Outputs ableiten. In diesem Sinne sind auch die Welt und die Dinge in ihr Black Boxes, die nur durch Interaktion und Beobachtung ihrer Inputs und Outputs zu verstehen sind. Dementsprechend entwickelt Ashby (1956:110) in seiner Auseinandersetzung mit Maschinen die Black Box als Gegenstand jedweder epistemologischer Praxis: What is being suggested now is not that Black Boxes behave somewhat like real objects but that the real objects are in fact all Black Boxes, and that we have in fact been operating with Black Boxes all our lives.

Auf diesem Gedanken aufbauend entwickelt Glanville (1988) eine sowohl mit dem radikalen Konstruktivismus als auch mit der Kybernetik zweiter Ordnung konsistente Erkenntnistheorie. In dieser Theorie bezeichnet er das, was von Foerster (1993:357) als „analytisches Determinieren“ und von Glasersfeld (1987:154) als „Konstruktion permanenter Objekte“ beschreibt, als das „Weißen“ von Black Boxes. Da der Begriff der Black Box in verschiedenen Kontexten recht unterschiedlich verwendet wird, ist an dieser Stelle ein kurzer Exkurs angebracht.

362 | 5 Ausgangspunkt Subjekt

Begriffsklärung: Black Box Der Begriff der Black Box wird in unterschiedlichen Kontexten benutzt und bezeichnet verschiedenartige Systeme, deren Inneres nicht einsehbar ist: 1. Luftfahrt 1: In Flugzeugen kommen Vorrichtungen zum Einsatz, die ungewollte Vibrationen durch negatives Feedback kompensieren (Mindell 2008:34–35). Da diese Geräte selbstständig arbeiten und aus der Piloten-Perspektive „opak“ erscheinen, werden sie als black boxes bezeichnet. 2. Luftfahrt 2: Flugschreiber werden ebenfalls als black boxes bezeichnet. Diese robust ausgeführten Geräte werden an Bord von Flugzeugen mitgeführt und zeichnen dort fortlaufend technische Daten und Kommunikation auf, um nach einem eventuellen Unglück forensische Ermittlungen zu unterstützen. Ungeachtet ihrer Bezeichnung sind black boxes dieser Art meist leuchtend orange. 3. Systemtechnik: Technische Systeme verbergen komplexe interne Prozesse und machen diese über Schnittstellen zugänglich. Modulare Systeme werden oft lediglich durch diese Schnittstellen spezifiziert, ohne interne Mechanismen vorzuschreiben. Technische Systeme, deren Innenleben in diesem Sinne ignoriert werden darf oder soll, bezeichnet man ebenfalls als black boxes. 4. Behaviorismus: Die behavioristische Psychologie betrachtet Stimuli (Inputs) und Verhaltensweisen (Outputs) von Organismen und vermeidet die Beschreibung innerpsychischer Prozesse. In dieser Hinsicht betrachtet sie Organismen als black boxes. 5. Kybernetik 1: Ashby entwickelte 1954 eine „partiell beobachtbare Maschine“ und gab ihr den Namen Black Box (Ashby 1954b:4950–4953; siehe Abbildung 7.2 und Seite 403). 6. Kybernetik 2: In Anlehnung an Ashby beschreibt Glanville ein radikal-konstruktivistisches epistemologisches Konzept mit dem Namen black box. Da sich uns die Wirkungszusammenhänge beobachteter Gegenstände generell entziehen, so Glanville, konstruieren wir auf der Basis beobachteter Inputs und Outputs dieser Gegenstände hypothetische Erklärungsmodelle, mit denen wir ihr Verhalten erklären und vorhersagen. Glanville (2012a:179) beschreibt diesen Prozess als das „Weißen“ von black boxes. Glanvilles unterscheidet nicht zwischen Beobachtungsgegenständen und ihren Erklärungsmodellen, da uns lediglich die Erklärungsmodelle – die black boxes – zugänglich sind (Glanville 1988).

Trotz ihrer unterschiedlichen Wurzeln in der Piaget’schen Entwicklungspsychologie einerseits und in der Theorie abstrakter Maschinen andererseits gelangen der radikale Konstruktivismus und die Kybernetik zweiter Ordnung zu einer gemeinsamen Erkenntnistheorie. Glanville (2012b) diskutiert eine Liste von Kernideen des radikalen Konstruktivisten Glasersfeld (2007) und zeigt, dass diese Ideen gleichsam in der Kybernetik zweiter Ordnung zu finden sind. Er kommt zu dem Schluss, dass die beiden Felder zwei Seiten einer Medaille, wenn nicht gar identisch sind. Da der radikale Konstruktivismus den Erkenntnisprozess innerhalb des Beobachters verortet, der an eine letztlich unzugängliche Welt strukturell gekoppelt ist, lassen sich objektive Aussagen über „die Welt an sich“ nicht rechtfertigen und werden dementsprechend in beiden Feldern vermieden. Dies wird mitunter als Verneinung der Existenz einer beobachterunabhängigen Welt missverstanden und der radikalkonstruktivistischen Perspektive daher zu Unrecht Solipsismus unterstellt. Begriffsklärung: Radikaler Konstruktivismus und Solipsismus Der Solipsismus und der radikale Konstruktivismus vertreten zwei verschiedene subjektive Weltsichten. Dem Solipsismus zufolge ist nur die eigene Existenz gewiss. Andere Wahrnehmungen und Reali-

5.3 Radikaler Konstruktivismus

|

363

täten haben keine Existenz unabhängig von der eigenen Wahrnehmung. So kommt der Solipsismus zu dem Schluss, dass sie nicht existieren. Der radikale Konstruktivismus hingegen streitet die Möglichkeit einer beobachterunabhängigen Welt nicht ab. Da eine beobachterunabhängige Welt jedoch per definitionem nicht beobachtbar ist, verneint der radikale Konstruktivismus die Möglichkeit, Gewissheit über die beobachterunabhängige Welt zu erlangen. Der Solipsismus verneint den ontologischen Status der beobachterunabhängigen Welt. Der radikale Konstruktivismus verneint die Möglichkeit gerechtfertigter Aussagen über den ontologischen Status der beobachterunabhängigen Welt.

Auch ohne Gewissheit über die Natur der beobachterunabhängigen Welt finden wir handelnd und wahrnehmend Grund zu der Annahme, dass unser Wohlergehen von uns umgebenden Dynamiken beeinflusst wird, dass diese Dynamiken mitunter beschreibbar und antizipierbar sind und dass es sich empfiehlt, sie zu berücksichtigen: Auch radikale Konstruktivisten benutzen Sicherheitsgurte. Weiterhin befinden wir uns in strukturellen Kopplungen mit anderen und erkennen Gemeinsamkeiten. Diese Gemeinsamkeiten erweisen sich oft als viable Basis für das Entwickeln von Einvernehmen und gemeinsamer Werte. So erweist es sich auch ohne Einblick in die Wahrnehmung anderer und ohne Gewissheit über die beobachterunabhängige Welt oft als praktikabel und nützlich, gemeinsam so zu handeln und zu agieren, als ob wir dasselbe wahrnehmen und meinen würden (Glanville 2012a:105– 114, 387–402). Auch erweist es sich als praktikabel und zuträglich, im Austausch miteinander gemeinsame Standards und Regeln zu verhandeln und unser Miteinander daran auszurichten. Folglich ist es durchaus konsistent, gemeinsame Normen und Werte zu verhandeln und sich um deren kollektive Einhaltung zu bemühen sowie formelle Systeme mit Kategorien wie wahr und falsch zu entwickeln und anzuwenden, gleichzeitig aber die Möglichkeit objektiv wahrer Kenntnisse der beobachterunabhängigen Welt zu bestreiten. Dieses Arrangement empfiehlt sich auch, insofern als es oft gerade die Inanspruchnahme objektiver Wahrheiten ist, mit der das kollektive Verhandeln gemeinsamer Normen und Werte unterbunden oder infrage gestellt wird. So handelt es sich beim radikalen Konstruktivismus um einen epistemischen, jedoch nicht notwendigerweise um einen normativ-moralischen Relativismus. Dementsprechend funktioniert auch die alltägliche Verwendung des Begriffs Information – as abkürzende (Glanville 1996:455) Referenz auf vorverhandelte, als „geteilt“ erkannte, jedoch letztlich immer private Bedeutungen. Die Antwort auf die bei Shannon vermiedene Frage der Semantik findet sich in Prozessen der Resonanz, nicht in Prozessen der Übertragung. Von Glasersfeld veranschaulicht dies anhand der Bedeutungen des englischen Verbs to share in den Sätzen „We share a car.“ und „We share a bottle of wine.“. Er (von Glasersfeld 2005:7, 0:11–1:28) erklärt: Das Auto bleibt das gleiche, ob ich es verwende oder ob Sie es verwenden. Der Wein, den ich trinke, ist bestimmt nicht der, den Sie trinken, nicht? Und diese Zweideutigkeit ist sehr wichtig, denn in der Kommunikation ist man immer im Fall des Weins. Denn das, was Sie verstehen, ist immer aufgebaut aus Ihren Erlebnissen und nicht aus meinen, während das, was ich sage, [auf meinen Erlebnissen aufbaut].

364 | 5 Ausgangspunkt Subjekt

5.4 Empirisch-wissenschaftliche Methodik Mitte der 1970er-Jahre erhielt der damals junge Halbleiterhersteller Intel einen Millionenauftrag von AT&T zur Herstellung von Speicherchips für AT&T-Nebenstellenanlagen. Bei Intel hatte man sich zuvor entschieden, Speicher nicht auf der Basis bewährter Sperrschichttransistoren zu produzieren. Stattdessen wollte man auf die damals neue und besser miniaturisierbare MOS-Technologie zurückgreifen. Intelbestückte Nebenstellenanlagen erwiesen sich bald als absturzanfällig, da einzelne Bits in den MOS-Speichern zu spontanen Zustandsänderungen tendierten. Auf der Suche nach einer Erklärung entwickelten Intel-Ingenieure zahlreiche Hypothesen. Quellen zuvor beobachteter vergleichbarer Fehler – etwa systeminternes Rauschen („system noise“) oder offensichtliche Versäumnisse bei der klaren Trennung physikalischer Zustände (Unterkapitel 2.3 und Seite 315) – konnten schnell ausgeschlossen werden. Angesichts ausbleibender Fortschritte erwogen die Ingenieure auch weit hergeholte Hypothesen, zum Beispiel, dass Magnete in den Motoren elektrischer Bohnermaschinen die Speicherchips störten. Als auch die Höhenstrahlung in Verdacht geriet, zog man den mit der Teilchenphysik vertrauten Intel-Ingenieur Tim May hinzu. May konnte diese Hypothese schnell widerlegen. Die hohe Frequenz beobachteter Abstürze stand in keinem Verhältnis zur Intensität der Höhenstrahlung. Als May beim Baden in seinem hot tub weiter über das Rätsel nachgrübelte und sein Blick auf die Granitplatten in seinem Garten fiel, erfuhr er selbst einen intuitiven „bit-flip“ (Greenberg 2013:50–51). Die keramischen und gläsernen Gehäuse der Speicherchips bestanden aus natürlichen Materialien, deren Spurenanteile von Thorium und Uran Alphateilchen abstrahlen. Konnte dies die Probleme erklären? Da die Energie von Alphateilchen im Vergleich zur Ladung einzelner MOS-Speicherzellen durchaus signifikant ist, schien die Hypothese vielversprechend. Im Labor konnte May sie mit Messungen sowie der experimentellen Eliminierung und Abschirmung des Gehäusematerials bekräftigen. In Intels Speicherfertigung wurden daraufhin Kunststoffgehäuse eingeführt. Die resultierenden Produkte waren so überragend, dass die gesamte Halbleiterindustrie nachzog (May und Woods 1979; Greenberg 2013:49–52). May konnte sich dank seiner Intel-Aktien 1986 im Alter von 34 Jahren zur Ruhe setzen. Er wandte sich der Kryptologie zu und wurde 1992 Mitbegründer der Cypherpunks-Mailingliste, deren Mitglieder kryptologische Werkzeuge zum Schutz der Privatsphäre von Internet-Nutzern entwickelten (Greenberg 2013:81; Rid 2016:258–293). Mays Wandlung vom technisch-wissenschaftlichen Problemlöser zum Kryptologen lag nahe, folgt man dem Turing-Biografen Hodges (2012:205): [D]iscerning a pattern in the apparently patternless [is] essentially the work of the cryptanalyst, as of the scientist.

5.4 Empirisch-wissenschaftliche Methodik

| 365

May hatte ein Muster in der weitgehenden Übereinstimmung zwischen dem Verhalten von Alphateilchen einerseits und dem spontanen Auftreten von „bit-flips“ andererseits erkannt. Bemerkenswerterweise wurde aber niemals ein Alphateilchen direkt beim Kippen der Ladung einer Speicherzelle beobachtet. Mays Messungen wurden durch wissenschaftliche Instrumente vermittelt und die Tests mit Abschirmungen bekräftigten seine Hypothese lediglich mittels indirekter Indizien. May entdeckte kein Phänomen. Er konstruierte eine Erklärung. Er postulierte zwischen Input (etablierten Beschreibungen von Alphastrahlung) einerseits und Output (etablierten Beschreibungen von Speicherzuständen) andererseits ein drittes, transformierendes Element im Sinne der auf Seite 318 besprochenen triadischen (syllogistischen) Struktur kausaler Wirkungszusammenhänge. Er gelangte zu diesem Element, seiner Hypothese, auf letztlich kreativem Weg und schrieb ihm die gesuchte kausale Rolle zu. Zuvor Unerklärbares wurde in der Präsenz eines postulierten, kausal wirkenden Agens erklärbar¹⁰. Von Foerster (Dammbeck 2003:1:13:54– 1:14:20) erklärt dieses im wissenschaftlichen Betrieb verbreitete Vorgehen am Beispiel der Teilchenphysik: Sagen wir, da ist eine Lücke in meiner Theorie. Da kann ich nicht mehr drüberspringen. [Dann sag’ ich:] Da sind einfach neue Teilchen, die entweder grün, gelb [oder sonstwas sind und was die] alles machen. Die ersetzen das Loch in meiner Theorie. So behaupte ich: Jedes Teilchen [von dem] wir heute in der Physik lesen [...] ist die Antwort für eine Frage [...], die wir nicht beantworten können.

Angesichts ihres Anwendungswerts ist Mays Hypothese trotz ihres kreativen Ursprungs und auch ohne endgültige Gewissheit über den kausalen Zusammenhang zwischen Alphastrahlung und „bit-flips“ aber nicht haltlos. Sie avancierte im Zuge erfolgreicher Prüfungen und Anwendungen zur Theorie. Mays Experimente und Beobachtungen sind publiziert (May und Woods 1979), von anderen nachvollziehbar und somit offen gegenüber skeptischer Prüfung sowie möglicher Falsifikation und Ablösung durch haltbarere Theorien. Doch bietet weder diese noch irgendeine andere Theorie eine objektiv korrekte, sondern bestenfalls eine kritischen Diskursen ausgesetzte, zeitweilig akzeptierte Erklärung beschriebener Wirkungszusammenhänge. So erweist sich die Entwicklung wissenschaftlicher Theorien als sozialer Prozess (Kuhn 1962). In diesem Prozess ändern sich Theorien mit dem kulturellem Wandel, mit neuen Beobachtungen und mit der (Weiter-)Entwicklung anderer herangezogener Theorien. Fleck (1980) beschreibt diesen Prozess am Beispiel des zeitlichen Wandels der Syphilisdiagnostik. Theorien können sich als unhaltbar erweisen, selbst wenn sie zu erfolgreichen Anwendungen führen. Cowell (2013:361) beschreibt die Eindämmung eines Malaria10 In diesem Kontext ist Batesons (1972:48–69) „Metalog“ What Is an Instinct? zu empfehlen: http://www.paricenter.com/library/download/bateson.mp3 (Abruf: 10.07.2018). Ein Metalog ist laut Bateson (1972:12) eine Konversation, bei der Inhalt und Form übereinstimmen.

366 | 5 Ausgangspunkt Subjekt ausbruchs in Hongkonger Militärbaracken im Jahr 1848 durch die britische Militärführung. Damals führte man Malaria nicht auf Infektionen mit Parasiten, sondern auf verunreinigte Dünste, sogenanntes „Miasma“, zurück. Da statistische Analysen vermehrte Infektionen in der Nähe von Fenstern und Türen zeigten und diese Hypothese zu bestätigen schienen, ließ man umliegende Flächen reinigen und Fenster verplanken. Damit wurde dem Krankheitsausbruch erfolgreich Einhalt geboten – aus heutiger Sicht jedoch weniger durch das Aussperren von Miasma als durch das Fernhalten von Stechmücken. Plausibilität und Nutzwert von Theorien rechtfertigen folglich nicht die Proklamierung deren „Wahrheit“. Dementsprechend erklärt Popper, dass sich wissenschaftliche Theorien empirisch nicht verifizieren, sondern lediglich falsifizieren lassen (Popper 2005:66; Band 1, Unterkapitel I.1.3). So rechtfertigt etwa die konkrete Beobachtung ausschließlich schwarzer Raben nicht die generalisierende Theorie „Alle Raben sind schwarz“. Mit der konkreten Beobachtung eines weißen Rabens hingegen ist diese Theorie falsifiziert. Die Wissenschaft ist als sozialer Prozess keineswegs immun gegen unsere Tendenz, selbst dann an etablierten Erklärungsmustern festzuhalten, wenn dies angesichts widersprechender Beobachtungen nicht mehr zu rechtfertigen ist¹¹. Mitroff (1974) dokumentiert dies am Beispiel von NASA-Wissenschaftlern während des NASAMondprogramms. Anhänger einander widersprechender Theorien zur Entstehungsgeschichte des Mondes interpretierten die Beschaffenheit neu eintreffenden Mondgesteins als Bestätigung der jeweils eigenen Sicht und hielten weitgehend an ihren ursprünglichen Theorien fest. Theorien erweisen sich in der Terminologie von Glasersfelds (1987:184) als viabel, wenn sich daraus verlässliche Vorhersagen zuvor nicht beobachteter Ereignisse ableiten lassen. Hiermit schließt sich ein Kreis zwischen Beobachtung und Beschreibung. Der Kybernetiker Rosen (1999:159; 2012:72) illustriert diese zirkulär-kausale Struktur der empirisch-wissenschaftlichen Methode mit der in Abbildung 5.11 dargestellten sogenannten Modeling Relation.

N

F observation and measurement

11 Diese Tendenz wird in Experiment III.13 demonstriert.

inference

causation

prediction

Abb. 5.11: Modeling Relation (nach Rosen 1999:159; 2012:72)

5.4 Empirisch-wissenschaftliche Methodik

|

367

Sie zeigt ein „natürliches System“ N (Phänomen), ein „formelles System“ F (Beschreibung) sowie die Beziehung zwischen diesen beiden Systemen. N qualifiziert sich für diese Beziehung, indem es kausale Wirkungszusammenhänge erkennen lässt. F wird basierend auf Messungen und Beobachtungen von N postuliert und modelliert in N erkannte Wirkungszusammenhänge. F qualifiziert sich für diese Beziehung, indem es Inferenzen bezüglich der Wirkungszusammenhänge in N gestattet. Ermöglichen diese Inferenzen erfolgreiche Vorhersagen des Verhaltens von N, so erweist sich F als haltbar oder als nützlich. Unzutreffende Vorhersagen des Verhaltens von N auf der Basis aus F abgeleiteter Inferenzen falsifizieren F. In diesem Teilband sind zuvor an verschiedenen Stellen Unterschiede zwischen der Kybernetik zweiter Ordnung und empirisch-wissenschaftlicher Methodik herausgestellt worden. Für eine kritische Annäherung an den empirisch-wissenschaftlichen Ansatz aus kybernetischer Sicht soll an dieser Stelle eine zusammenfassende Bilanz dieser Unterschiede gezogen werden. Obwohl die Wissenschaft weitgehend auf lineare Kausalität besteht, zeigen sich aus der Perspektive der Kybernetik zweiter Ordnung verschiedene zirkulär-kausale Beziehungen im empirisch-wissenschaftlichen Betrieb. Rosens (1999:159; 2012:72) Modeling Relation zeigt den geschlossenen kausalen Kreislauf zwischen beobachteten natürlichen Systemen und beschreibenden formellen Systemen. Hinzu kommt die in Unterkapitel 3.4 besprochene Reflexivität, etwa zwischen Messungen und dem jeweils Gemessenen. So wirkt beispielsweise der am Glaskolben der Glühbirne in Abbildung 2.1 befestigte Bimetallschalter auch als Wärmesenke und beeinflusst somit die von ihm gemessene Temperatur des Glaskolbens. Indem übernatürliche Ursachen aus wissenschaftlichen Erklärungen ausgeschlossen werden, wird das Universum, wie in Unterkapitel 3.5 beschrieben, als geschlossenes System entworfen. In diesem geschlossenen System sind Phänomene kausal nur auf andere Phänomene innerhalb des Systems zurückzuführen und bedingen sich somit in letztlich zirkulär-kausalen Beziehungen gegenseitig. Weiterhin weisen die wissenschaftliche Entwicklung von Technologien und das spätere Heranziehen solcher Technologien in wissenschaftlichen Untersuchungen ein rekursives und somit ebenfalls zirkulär-kausales Verhältnis auf. MOS-Speicher zum Beispiel waren zunächst Gegenstand wissenschaftlicher Forschung und wurden Strahlenmessungen unterzogen (siehe oben). Seither kommen MOS-Speicher in wissenschaftlichen Forschungsinstrumenten wie etwa digitalen Strahlungsmessgeräten zum Einsatz. Rheinberger (2000:53) unterscheidet in diesem Sinne zwischen epistemischen Dingen (Forschungsgegenstände) und technischen Dingen (Forschungsinstrumente). Neben dem weitreichenden Insistieren auf linearer Kausalität erscheinen weitere Kriterien empirisch-wissenschaftlicher Forschung aus kybernetischer Perspektive anfechtbar. Die zuvor besprochene Beobachterabhängigkeit stellt beispielsweise die wissenschaftlichen Kriterien der Beobachtbarkeit und der Objektivität (und somit auch der Messbarkeit) infrage. Im weiteren Verlauf dieses Teilbandes wird darüber hinaus

368 | 5 Ausgangspunkt Subjekt den in Kapitel 2 besprochenen Konzepten Determinismus und Determinierbarkeit das Konzept der Nicht-Determinierbarkeit gegenübergestellt, welches Zweifel an den wissenschaftlichen Kriterien der Wiederholbarkeit und Verlässlichkeit aufwirft. Wie in Unterkapitel 3.5 dargestellt, steht darüber hinaus die kybernetische Prozessorientierung im Gegensatz zum zielorientierten Beschreiben in der formellen Logik und in der empirischen Wissenschaft. Der kybernetische Anspruch, Systeme in der Gesamtheit relevanter Einflüsse und Auswirkungen zu erfassen, steht des Weiteren dem Reduktionismus entgegen, also der insbesondere in den Naturwissenschaften anzutreffenden Strategie, komplizierte Forschungsgegenstände in handhabbare Stücke zu zerlegen (von Foerster 1993:337). In diesen Abweichungen zwischen der Kybernetik zweiter Ordnung einerseits und empirischer Wissenschaft andererseits zeigen sich unterschiedliche Grundannahmen beider Ansätze (Dent und Umpleby 1998). Während diese Unterschiede die Kybernetik aus Sicht mancher Wissenschaftler kategorisch disqualifiziert, rechtfertigen sie aus kybernetischer Sicht nicht die unbedingte Ablehnung empirisch-wissenschaftlicher Forschung. Aus kybernetischer Sicht stellt der empirisch-wissenschaftliche Betrieb eine begrenzte Untermenge der weiteren, übergeordneten Menge epistemischer Praktiken dar. Wie besprochen erweisen sich linear-kausale Beschreibungen, Vorhersagen und determinierende Einflussnahmen in vielen Fällen als durchaus praktikabel und nützlich. Mays Theorie beispielsweise führte die Halbleiterindustrie zu einer erfolgreichen Lösung ihres Problems. Insofern erscheint der empirisch-wissenschaftliche Ansatz nützlich und gerechtfertigt. Diese Praktikabilität ist jedoch keineswegs universal. Darüber hinaus wird sie durch Einschränkungen, Linearisierungen, Reduktionen und Kriterien erreicht, die den jeweiligen Phänomenen oft nur bedingt gerecht werden. So ist die bisherige Verlässlichkeit einer wissenschaftlichen Beschreibung kein Garant für ihre zukünftige Verlässlichkeit (Selby-Bigge 1888:89). Ebenso wenig rechtfertigt sie den Anspruch auf objektive Wahrheit. In diesem Sinne unterliegen die praktische Anwendung wissenschaftlicher Theorien einerseits und die gerechtfertigte Vertretung wissenschaftlicher Theorien andererseits unterschiedlichen Bewertungskriterien. Nicht alles, was verlässlich und praktikabel erscheint, erlaubt robuste formelle Beschreibung und umgekehrt. Empirischwissenschaftliche Forschung ist oft Heil bringend, unabdingbar und von unbestrittener Wichtigkeit. Dennoch bedarf sie eines kritischen Bewusstseins der eigenen Grenzen, Verfahrensweisen und Ziele und somit besonderer Umsicht bei der Anwendung auf lebende Systeme und die sie erhaltenden Ressourcen (was letztlich jedoch wiederum dem empirisch-wissenschaftlichen Ideal der Wertfreiheit widerspricht).

6 Systeme, Systemgrenzen und Wiedereintritt 6.1 Vom technischen zum ethischen Systembegriff Mit der Berücksichtigung der Beobachterabhängigkeit kam es im Lauf der vergangenen Jahrzehnte zu Verschiebungen und Differenzierungen in der Interpretation des systemischen Vokabulars. Dies betrifft insbesondere den Systembegriff selbst sowie den mit ihm eng verbundenen Begriff der Systemgrenze. So wurde die Frage „Was ist ein System?“ in verschiedenen Kontexten und zu verschiedenen Zeiten unterschiedlich beantwortet (Fischer und Richards 2017:37). Zu Definitionen von Systemen als objektiv existierende Entitäten traten Definitionen von Systemen als subjektive Konstrukte. Der Begründer der allgemeinen Systemtheorie von Bertalanffy (1968:33) definiert Systeme als „sets of elements standing in interaction“. Kauffman (1980:1) definiert den Begriff ähnlich als „a collection of parts which interact with each other to function as a whole“. Insbesondere in technisch geprägten Kontexten herrscht diese Definition bis heute vor. Sie erfuhr mehrere Differenzierungen, etwa im Hinblick auf Prozess- und Zielorientierung (Churchman 1971:42) und auf die Tendenz zur Selbsterhaltung (Maturana 1987:47). Weinbergs (2001:52) Definition des Systembegriffs als „a way of looking at the world“ berücksichtigt hingegen die Rolle subjektiver Beobachtung. Rosen (1999:86) führt aus: „[T]he partition between what is objective and what is not transmutes into the partition between a ‚system‘ and an observer“, und er fährt fort: „[W]here the partition between ‚system‘ and observer is drawn is entirely arbitrary.“ Der Komponist und Kybernetiker Herbert Brün schließlich arbeitet den konstruktivistischen Systembegriff der Kybernetik zweiter Ordnung klar heraus (Brün 2004b:82): A system is not something that exists objectively in space or time or anywhere. A system is the result of a look at a collection of stipulated elements. Stipulated in that I say which elements I will look at. Collection because I stipulate that these elements I have decided to look at are not yet ordered, and my look will decide on what I will put the emphasis and what I regard as not to be regarded entities.

Anstatt Systeme als objektiv anzutreffende Entitäten zu behandeln, tendieren Vertreter der Kybernetik zweiter Ordnung zu aktiven Formulierungen – etwa, dass betrachtende Systeme „erblicken“ im Sinne von „durch konstruierende Betrachtung erschaffen“: „To look a system.“ Sloan (1999:46) erklärt: I look a system whenever I look at a collection of elements and supply a framework for the relations between the elements that permit me to say that a change in the state of one of the elements is a change in the state of elements as a whole.

https://doi.org/10.1515/9783110496253-025

370 | 6 Systeme, Systemgrenzen und Wiedereintritt Das Verständnis von Systemen als objektiv gegebene physikalische Entitäten geht typischerweise einher mit dem Verständnis von Systemgrenzen als materielle Hüllen wie Häute, Schalen oder Fassaden. Hierbei bleiben Systeme ohne solche Hüllen wie etwa Wetter-, Bildungs-, Finanz-, Sternen- oder Zahlensysteme jedoch außer Acht. Im Gegensatz dazu werden Systemgrenzen aus konstruktivistischer Sicht und aus Sicht der Kybernetik zweiter Ordnung als immaterielle Projektionen verstanden – als Unterscheidungen der Beobachter zwischen denjenigen in Wechselbeziehungen stehenden Elementen, die relevant erscheinen, und denjenigen, die vernachlässigbar erscheinen oder unerkannt bleiben. In dieser Sicht werden Systemgrenzen nicht als vorgefundene Fakten, sondern als gedankliche Konstrukte verstanden. Manche Systeme handeln – oder werden behandelt – mit dem Ziel der Selbsterhaltung. Damit geht die Tendenz zum Schutz der eigenen Integrität einher, etwa durch die Ausbildung, Aneignung oder Installation physischer Hüllen. Diese Hüllen können mit jeweils durch Betrachtung konstruierten Systemgrenzen koinzidieren – zum Beispiel, wenn ein Organismus als System betrachtet wird und dessen Unterscheidung von seiner Umwelt entlang seiner Außenhaut verläuft. Nichtsdestotrotz handelt es sich hier um grundverschiedene Auffassungen von Systemgrenzen. Aus Sicht der Kybernetik zweiter Ordnung liegt die Identifikation von Systemen im sprichwörtlichen Auge des Betrachters. So mag es aus einer Perspektive sinnvoll erscheinen, beispielsweise ein Baby als ein System zu identifizieren, während es aus einer anderen Sicht sinnvoll erscheint, Mutter und Baby zusammen als ein System zu identifizieren. Das beobachterabhängige Systemverständnis kam bereits während der MacyKonferenzen zum Ausdruck — und stieß dort zunächst auf Vorbehalte. Bei dem Treffen im Jahr 1952 präsentierte Ashby ein von ihm entwickeltes, das „Gleichgewicht“ erhaltende Gerät, den sogenannten Homeostat, der wiederum aus vier identischen, sich gegenseitig dynamisch stabilisierenden Geräten bestand (Abbildung 6.1). Ashby beschrieb die Wechselbeziehungen im Homeostat analog zum Verhältnis zwischen Organismus und Umwelt. Man forderte eine Erklärung: Wo verlief die Grenze zwischen dem Homeostat und seiner Umwelt? Zwischen einem der vier Geräte und den drei anderen? Zwischen zwei von ihnen und den anderen beiden? Oder zwischen allen vieren und der sie bedienenden Person?¹ Ashby vermied es, eine Grenze zwischen seinem maschinell verkörperten Organismus und dessen Umwelt zu lokalisieren, und rief damit selbst im Epizentrum der Kybernetik Skepsis hervor (Pias 2003:595–619). Ashbys Präsentation warf Fragen auf, die aus Sicht der späteren Kybernetik zweiter Ordnung eher über Fragende und Antwortende Aufschluss geben als über den Gegenstand ihrer Beschreibungen. Die Frage etwa, ob Wasser Teil eines Organismus oder Teil seiner Umwelt sei (Pias 2003:593; Rid 2016:57), sowie entsprechende Antworten zugunsten entweder des Organismus oder der Umwelt spiegeln eher den Hang

1 Wechselbeziehungen zwischen möglichen Zuständen von Variablen in asymmetrischer Anzahl führten Ashby zur Formulierung des in Kapitel 7 besprochenen Begriffs der Varietät.

6.1 Vom technischen zum ethischen Systembegriff

| 371

zu gegenseitiger Ausschließlichkeit in westlichem Denken (tertium non datur; Band 1, Abschnitt I.2.1.4) als die Konstitution von Organismen und ihren Kontexten wider. Allem Anschein nach erkannte Ashby die Rolle von Beobachtern bei der Verortung von Systemgrenzen bereits damals. Zwei Jahre später machte Ashby (1954a:39) dies explizit und nahm Rosens obige Feststellung vorweg: As the organism and its environment are to be treated as a single system, the dividing line between “organism” and “environment” becomes partly conceptual, and to that extent arbitrary.

Die Beobachterabhängigkeit von Systemgrenzen ist unter anderem im Kontext vernetzter digitaler Medien von letztlich politischer Bedeutung. Die staatliche Erhebung biometrischer und anderer personenbezogener Daten, doxxing, das „Leaken“ von Dokumenten, die Zensur von Medieninhalten, die Vorratsdatenspeicherung und das Blockieren von Onlinediensten durch Firewalls sind nur einige Beispiele, bei denen einander widersprechende Verläufe systemischer Grenzen Einvernehmen und mehrheitlich gestützte Regulierungen erschweren. Hieran erweist sich, dass der Verlauf von Systemgrenzen zwar prinzipiell beliebig ist, unterschiedlich verortete Systemgrenzen im Bezug auf lebende Systeme aber nicht notwendigerweise gleichwertig oder gleichermaßen zu rechtfertigen sind. Folgt das „Erblicken“ von Systemgrenzen dem Ermessen relevanter, auf gemeinsame Ziele gerichteter Elemente, so legt dies letztlich technische Hierarchien von Ganzem und Teilen nahe, in denen Komponenten zwangsläufig ihren übergeordneten Konfigurationen dienen.

Abb. 6.1: W. Ross Ashbys (1954a:101) „Homeostat“. Reproduziert mit freundlicher Genehmigung der Hinterbliebenen W. Ross Ashbys und des Ross Ashby Digital Archive http://www.rossashby.info.

Auf biologische und soziale Systeme angewandt, suggeriert diese Priorisierung übergeordneter Systeme wie etwa „des Volkes“, „der Wirtschaft“ oder „der Umwelt“ die Rechtfertigung autoritärer Einflussnahme. Von Foerster (1977:104–105) lehnt diese Sicht ab und betont die Rolle übergeordneter biologischer und sozialer Systeme im Dienst ihrer konstituierenden Elemente. Neben dem Ermessen der Relevanz betrach-

372 | 6 Systeme, Systemgrenzen und Wiedereintritt teter Elemente und ihrer Ausrichtung auf gemeinsame Ziele betont von Foerster das Kriterium der Autonomie bei der Abgrenzung lebender Systeme (1977:105; 2006:40). Maturana und Varela (1987:48) erklären: [A] system is autonomous if it can specify its own laws, what is proper to it.

Die Präsenz eines Selbst und dessen Möglichkeit zur Selbstbestimmung entspricht einer von vier verschiedenen Positionierungen von Beobachtern relativ zu den Grenzen von Systemen und den bei der Anpassung dieser Systeme relevanten Referenzen (Glanville 1997a:141–142; 2012a:134–135): – Beobachter befindet sich außerhalb des Systems, blickt nach außen. – Beobachter befindet sich außerhalb des Systems, blickt nach innen. – Beobachter befindet sich im System, blickt nach außen. – Beobachter befindet sich im System, blickt nach innen. Aus diesen Positionierungen ergeben sich unterschiedliche praktische Möglichkeiten für zweckgerichtet anpassendes Handeln. Diese lassen sich illustrieren mit den Möglichkeiten zur Einflussnahme etwa auf den Kurs eines Flugzeugs aus dem Inneren des Cockpits einerseits oder vom Boden per Fernsteuerung andererseits oder mit den Möglichkeiten zur Einflussnahme auf ein Fußballspiel aus der Position eines Spielers auf dem Spielfeld einerseits und der eines Trainers am Spielfeldrand andererseits. Entlang dieser Unterscheidungen verläuft auch die kybernetische Unterscheidung zwischen Moral und Ethik (von Foerster 2008:66; 2003b:289). Von Foerster (Bröker und von Foerster 2007:14) beschreibt Moral als „Zwangsmaschine“, mittels derer anderen von außen vorgeschrieben wird, wie sie sich zu verhalten haben: „Du sollst ...!“, „Du sollst nicht ...!“ Hier glaubt A zu wissen, was für B das Beste ist, und instruiert B dementsprechend. Die Referenz für Anpassungen in A liegt außerhalb von A. So enthebt sie A von Eigenverantwortung und führt bei Anklage zur Nuremberg defense: Man habe lediglich Befehle ausgeführt! Im Fall der Ethik stabilisiert sich die Referenz für eigenes Handeln hingegen – gewissermaßen analog zu einem internen Gyroskop – im inneren und wird durch eigenes Handeln stabilisiert. In diesem Fall impliziert Selbstbestimmung Eigenverantwortung. Aus der Position Außenstehender kann nichts über interne Selbstreferenz gesagt werden (Glanville 2012a:134). Kybernetiker zweiter Ordnung bemühen sich daher, so zu handeln und zu sprechen, dass Ethik dabei implizit bleibt und nicht zum Moralisieren degeneriert (von Foerster 2003b:291; 2008:68–69; 1993:347–349; Wittgenstein 1963:6.42–6.422). Von Foerster (2002:26) bemerkt: Ich möchte lernen, meine Sprache so zu beherrschen, dass Ethik, ganz gleich, ob es um Politik, Wissenschaft, Poesie oder was auch immer geht, implizit bleibt und es mir gelingt, meine eigene Person stets als Bezugsquelle meiner jeweiligen Beobachtungen sichtbar zu machen.

6.2 Gedächtnis und Wiedereintritt

|

373

6.2 Gedächtnis und Wiedereintritt Von Foerster führte in den 1940er-Jahren eine Gedächtnisstudie (Pias 2003:98–121) durch, die nicht nur grundsätzliche kybernetische Prinzipien belegt, sondern von Foerster auch den Weg zu den Macy-Konferenzen und zu seiner akademischen Laufbahn in den USA ebnen sollte (von Foerster 2003b:v–vi; Ritschl 1987:25:06–37:56). Basis der Studie war der Datensatz eines Gedächtnisexperiments des empirischen Psychologen Hermann Ebbinghaus (1885). Er hatte Testpersonen erfundene, daher sinnlose Silben lernen lassen und sie anschließend in bestimmten Intervallen gebeten, möglichst viele dieser Silben aus dem Gedächtnis wiederzugeben. Dabei zeigte sich, wie zu erwarten, ein kontinuierlicher Rückgang der Anzahl durchschnittlich erinnerter Silben. Dieser Rückgang näherte sich einem geringen Durchschnitt verlässlich erinnerter Silben an. Von Foerster scheiterte zunächst bei seinen Versuchen, diesen Datenverlauf als exponentiellen Verfallsprozess zu modellieren, da Verfallsfunktionen gemeinhin gegen null konvergieren, während Ebbinghaus’ experimentell ermittelte Daten auf eine Annäherung an einen positiven Wert deuteten. Erfolg stellte sich ein, als von Foerster begann, das Erinnern von Silben als neue Lernvorgänge zu behandeln. Er nahm an, dass jede Silbe im Gedächtnis von mehreren „Trägern“ gespeichert wird und dass die Erinnerung einer Silbe möglich ist, solange mindestens ein Träger diese Silbe speichert. Weiterhin nahm er an, dass das Speichervermögen der Träger einem Zerfallsprozess unterliegt. Er erklärte dies mit physikalischen Zerfallsprozessen, denen das erinnernde neuronale Gewebe unterworfen ist. Während die Anzahl der Träger einer Silbe kontinuierlich abklinge, werde die Silbe mit jedem Wiedereintritt ins Gedächtnis, auch beim Erinnern und Wiedergeben, von einer neuen Gruppe von Trägern gespeichert. So verfestige sich die Speicherung erinnerter Silben, während nicht erinnerte Silben keine Verfestigung erfahren und in Vergessenheit geraten. Unter Berücksichtigung dieser Annahmen führte von Foersters Modell zu einem Datenverlauf, der Ebbinghaus’ Ergebnisse perfekt abbildete (von Foerster2003a:v–vi). Die Dynamik dieses Gedächtnismodells mit und ohne Berücksichtigung der verfestigenden Wirkung des Wiedereintritts sowie jeweils resultierende Datenverläufe können in Experiment III.11 untersucht werden. Experiment III.11: Gedächtnis und Wiedereintritt Dieses Experiment² demonstriert die verfestigende Wirkung des Wiedereintritts von Silben in das Gedächtnis anhand einer simulierten Testpopulation. Im Kopf des Programms wird festgelegt, dass 200 simulierte Testpersonen (Zeile 4) siebenmal um die Wiedergabe erinnerter Silben gebeten werden (Zeile 5). Jeder simulierten Testperson werden zunächst 100 Silben präsentiert (Zeile 5). In Zeile 6 kann mit True bzw. False die verfestigende Wirkung des Wiedereintritts beim Erinnern ein- bzw. ausgeschaltet werden. Das Programm visualisiert Ergebnisse als sogenannte „Vergessenskurve“ (siehe Abbildung 6.2).

2 Basierend auf von Foerster (2003a:v–vi)

374 | 6 Systeme, Systemgrenzen und Wiedereintritt Listing 6.1: Ebbinghaus’sche Vergessenskurve (Ebbinghaus-forgetting-curve_DE.py) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

import random, copy, pylab subjects = 200 # Anzahl simulierter Testpersonen recursions = 7 # Anzahl der rekursiven Wiedereintritte jedes Subjekts silben = 100 # Anzahl der Silben reentry_reinforces = False # Verfestigung bei Wiedereintritt ein/aus

AL=[] # Sammlung aller Zeitserien (1 per Subjekt) def silbenfabrik(sls): vokale = 'aeiou' konsonanten = 'bcdfghjklmnpqrstvwxyz' stack=[] for x in range(0, sls): # Set von Nonsense-Silben generieren while True: # keine doppelten Einträge generieren s = konsonanten[random.randint(0, len(konsonanten)-1)] + vokale[random.randint(0, len(vokale)-1)] + konsonanten[random.randint(0, len(konsonanten)-1)] 16 if not s in stack: break 17 stack.append(s) 18 return stack 19 20 V = silbenfabrik(silben) # Array zur Speicherung der Nonsense-Silben 21 22 def erinnern(N, c): 23 blankno = 0 24 for m in N: 25 if m == "*": blankno = blankno + 1 # Freie Träger ('*') zählen 26 k = 0 # Erinnerungen vergessen: 27 for m in N: 28 if random.random() > 0.42: N[k] = '*' 29 k += 1 30 k=0 # Erinnerungen festigen: 31 if reentry_reinforces: 32 for m in N: 33 if ('*' in N) and m != '*' and random.random() > 0.15: 34 N[N.index('*')] = m # Silbe in ersten freien Träger kopieren 35 k = k + 1 36 #print("Träger: " + str(N)) 37 # Anzahl behaltener Silben (leere Träger entfernt) speichern 38 out.append(len(set(filter(lambda a: a != '*', N)))) 39 c = c - 1 # herunterzählen 40 if c > 0: # Rekursion beenden? 41 erinnern(N, c) # rekursiver Wiedereintritt 42 else: 43 AL.append(out) # diese Zeitserie an die Sammlung AL anhängen 44 45 for p in range(0, subjects): # Ein Durchlauf pro Subjekt 46 out = [silben] # Unveränderte initiale Anzahl an Silben eintragen

6.2 Gedächtnis und Wiedereintritt

47 48 49 50 51 52 53 54 55 56 57 58 59 60

| 375

erinnern(copy.deepcopy(V), recursions) # Aufruf der Erinnerungsfunktion AV=[] # Array für Durchschnittswerte for r in range(0, recursions+1): b = 0 for p in range(0, subjects): b = b + AL[p][r] AV.append(b / subjects) pylab.plot(AV, c='lightgray') pylab.plot(AV, 'h', markersize=3.6, c='k') # Graph darstellen pylab.xlim(-0.2, recursions+0.2); pylab.ylim(-2, silben+2) pylab.title('Vergessenskurve') pylab.xlabel('Wiedereintritte'); pylab.ylabel('Silben') pylab.show()

Ist die verfestigende Wirkung des Wiedereintritts beim Erinnern abgeschaltet (Option False in Zeile 6), so stellt sich der in Abbildung 6.2 untere, gegen null konvergierende Zerfallsverlauf ein. Ist die verfestigende Wirkung des Wiedereintritts beim Erinnern hingegen eingeschaltet (Option True in Zeile 6), so stellt sich der obere, gegen einen positiven Wert konvergierende Verlauf ein. Dieser Verlauf entspricht den von Ebbinghaus erhobenen und durch von Foerster (Pias 2003:98–121) modellierten Datenverläufen.³ 100

Vergessenskurve ohne Wiedereintritt Vergessenskurve mit Wiedereintritt

erinnerte Silben

80 60 40 20 0

0

1

2

3 4 Wiedereintritte

5

6

7

Abb. 6.2: Vergessenskurven ohne und mit Wiedereintritt

3 Die Graphen in den Abbildungen 6.2 und 6.6 bis 6.11 werden in einigen Quellen (Pias 2003:99; Rashid 2014:21–33) stetig dargestellt. Dies erleichtert zwar einerseits ihre Lesbarkeit. Da aber andererseits die jeweiligen unabhängigen Variablen in diskreten Schritten fortschreiten, ist die diskrete Darstellung angemessener. Um beiden Kriterien gerecht zu werden, wurde hier die Darstellung separater Punkte auf kontinuierlichen helleren Graphen gewählt.

376 | 6 Systeme, Systemgrenzen und Wiedereintritt Jede Wiedergabe erinnerter Silben, so von Foerster, bringt ein erneutes Erlernen mit sich (Pias 2003:99). Betrachtet man diesen Vorgang als Wiedereintritt verbalisierter Erinnerungen in das Gedächtnis des sich selbst zuhörenden Individuums, so wird eine zirkuläre Geschlossenheit zwischen individuellem Output und Input ersichtlich. Jeder Wiedereintritt konstituiert eine neue Lernerfahrung und verfestigt Erinnertes. Menschen machen sich diesen Effekt zunutze, wenn sie Gedanken, die es für kurze Zeiträume zu erinnern gilt, fortlaufend wiederholen. Jenseits des menschlichen Gedächtnisses verfestigen sich wiedereintretende Signale auch in verschiedenen Digitalspeichern. Sowohl die in frühen digitalen Computern verbreiteten Laufzeitleitungen und Williamsröhren als auch heutiges dRAM sind an sich flüchtig. Ihr andauerndes Speichervermögen beruht auf regelmäßigem Auslesen und neuem Einschreiben (dem sogenannten refresh) ihrer Zustände, also auf Wiedereintritt (siehe Band 1, Abschnitt II.5.2.3).

6.3 Operative Geschlossenheit und Eigenform Von Foersters Erklärung der Ebbinghaus’schen Vergessenskurve verweist auf die in der Kybernetik und der Systemtheorie gängigen Begriffspaare der (Nicht-)Linearität sowie der systemischen Offenheit bzw. Geschlossenheit. Beide Begriffspaare werden oft undifferenziert und praktisch homonymisch verwendet. Da jeweils beschriebene Sachverhalte infolgedessen vermischt und verwechselt und insbesondere zirkuläre Kausalität und Wiedereintritt übergangen und verkannt werden, sollen diese Begriffspaare im Folgenden genauer differenziert werden.

Begriffsklärung: Systemische Offenheit und systemische Geschlossenheit Das Begriffspaar systemische Geschlossenheit und systemische Offenheit kann sich beziehen auf: 1. die Isolation (Geschlossenheit) bzw. Permeabilität (Offenheit) von Systemen und ihren Kanälen (siehe A in Abbildung 6.3) hinsichtlich des Ein- und Austretens von Materie und/oder Energie sowie folglich von „Information“ (also zeitlichen und/oder räumlichen Mustern in Materie und/oder Energie). Diese Verwendung des Begriffspaars hat ihren Ursprung in den Naturwissenschaften, insbesondere in der Thermodynamik. 2. die operative Geschlossenheit oder Offenheit (mitunter auch operationale Geschlossenheit und Offenheit). Das Vorhandensein (operative Geschlossenheit) bzw. die Abwesenheit zirkulärer Kanäle (siehe B in Abbildung 6.3), die den Wiedereintritt von Outputs als neue Inputs in die sie produzierenden Systeme ermöglichen, sodass diese sich auf sich selbst beziehen. Diese Verwendung des Begriffspaars ist insbesondere in den Systemwissenschaften und in der Kybernetik anzutreffen.

6.3 Operative Geschlossenheit und Eigenform

|

377

A

B A

Abb. 6.3: Zwei Interpretationen systemischer Geschlossenheit A: systemische Isolation B: operative Geschlossenheit

Im Fall lebender Systeme manifestiert sich operative Geschlossenheit in senso-artikulatorischen und sensomotorischen Schleifen des Handelns und Verstehens. Somit erweist sie sich über Gedächtnisleistungen hinaus als Voraussetzung epistemischer Prozesse. Hejl (?:116) erklärt, dass „operationale Geschlossenheit lebender Systeme als das Ordnungsprinzip verstanden werden kann, das Kognition zu einem konstruktivistischen Prozeß macht“. Diesem Ordnungsprinzip liegen die zentralen Anliegen dieses Teilbandes zugrunde: zirkuläre Kausalität, Beobachterabhängigkeit, NichtDeterminierbarkeit und Selbstorganisation.

Begriffsklärung: Linearität und (Nicht-)Linearität Die Unterscheidung zwischen Linearität und Nicht-Linearität kann sich beziehen auf: 1. das quantitative Verhältnis zwischen Inputs und Outputs transformierender Systeme. Der Begriff „linear“ beschreibt in diesem Fall Systeme, deren Outputs sich gegenüber ihren Inputs so verändern, dass sich bei der Darstellung eines solchen linearen Systems in einem rechtwinkligen Koordinatensystem der resultierende Graph mit einem Lineal ziehen lässt (siehe zum Beispiel die Darstellung des Ausdrucks f(x)=2x-1 in Abbildung 6.4). Der Begriff „nicht-linear“ beschreibt in diesem Fall Systeme, deren Input-Output-Verhältnis bei der Darstellung in einem rechtwinkligen Koordinatensystem nicht als gerade Linie erscheint (Beispiele sind die Darstellung des Aus3 drucks f(x)=x in Abbildung 6.4 und die Hystereseschleife in Abbildung 2.5). Diese Verwendung des Begriffspaars findet sich vornehmlich in mathematisch geprägten Kontexten. 2. die operative Geschlossenheit, durch welche Outputs als neue Inputs wieder in die sie produzierenden Systeme eintreten. Ist eine solche Geschlossenheit nicht gegeben (siehe obere Darstellung in Abbildung 6.5), so spricht man von einem „linearen“ System. Liegt eine solche Geschlossenheit vor (siehe auch die mit B markierten Pfade in den Abbildungen 6.3 und 6.12), so spricht man von einem „nicht-linearen“ System (siehe Abbildung 6.5 unten). Dieses Begriffspaar wird vornehmlich in kybernetisch geprägten Kontexten verwendet.

378 | 6 Systeme, Systemgrenzen und Wiedereintritt

f(x)

f(x)=x³

f(x)=2x-1

x

Abb. 6.4: Linearer und nicht-linearer Graph

Abb. 6.5: Lineares (oben) und nicht-lineares System (unten)

Obgleich sich die beiden Interpretationen von (Nicht-)Linearität auf unterschiedliche systemische Charakteristika beziehen, verbindet sie eine indirekte Verwandtschaft. Wiedereintritt von Outputs als Inputs via operativer Geschlossenheit führt zur Ausbildung charakteristischer Dynamiken – sogenannter Eigenformen⁴. Von Foerster (2010b:43) beschreibt diesen Umstand mit seinem Schließungstheorem: In jedem operativ geschlossenen System entstehen Eigen[form]en.

Eigenformen können, wie in Experiment III.12 demonstriert wird, nicht-lineare Verläufe annehmen. In diesen Fällen begünstigt also nicht-linearer Wiedereintritt die Ausbildung nicht-linearer Verhältnisse zwischen Inputs und Outputs. Ein Beispiel hierfür ist der Zinseszins im Bankwesen. Die Verzinsung (Output) von Kapital inklusive bisheriger Zinserträge (Input) führt zu einem exponentiellen Verhältnis von Ertrag und Zeit. Verwendet hingegen ein Elektrizitätswerk einen Teil seiner Produktion (Output) für den eigenen Betrieb (Input), sind diesbezüglich keine nicht-linearen Dynamiken zu erwarten. Die beiden Interpretationen von (Nicht-)Linearität werden – auch in der Kybernetik – nicht immer hinreichend differenziert. Ein frühes Beispiel ist Wieners Diskussion nicht-linearer Schaltkreise wie etwa Spannungsbegrenzer oder Verstärker

4 Von Foerster (1993:254–261) verwendet die Begriffe Eigenwert und Eigenverhalten. Da sich diese jedoch mit den anders besetzten Begriffen Eigenwert und Eigenvektor der linearen Algebra überlappen, hat sich in der Kybernetik der Begriff Eigenform durchgesetzt (Kauffman 2005). Jenseits des kybernetischen Sprachgebrauchs werden Eigenformen, die auf begrenzte Mengen konvergieren, auch als Attraktoren bezeichnet. Diese Bezeichnung wird mitunter als irreführend kritisiert (von Foerster 2003b:316), da sie das Bild externer, im Zahlenraum gegebener Kraftfelder nahelegt, anstatt auf innere Dynamiken operativ geschlossener Systeme zu verweisen.

6.3 Operative Geschlossenheit und Eigenform

|

379

(Wiener 1963:viii). Hier impliziert Wiener eine Artverwandtschaft beider Interpretationen, die keiner Unterscheidung bedarf. Dies lässt sich mit dem kybernetischen Interesse an eben solchen Systemen erklären, die, wie die von Wiener besprochenen Schaltkreise, durch Bezugnahme auf sich selbst ihr Verhalten formen: sogenannte selbstorganisierende Systeme. Andere Auseinandersetzungen mit (Nicht-)Linearität konzentrieren sich auf den Aspekt der Verhältnismäßigkeit, übergehen aber den Aspekt des zirkulären Wiedereintritts via operativer Geschlossenheit (siehe etwa De Langhe 2017). Dies ist wohl mit den in Unterkapitel 3.5 besprochenen Vorbehalten gegenüber zirkulärer Kausalität zu erklären. Eigenschaften systemischen Verhaltens sind hinsichtlich der in Kapitel 5 besprochenen Beobachterabhängigkeit keine Ausnahme. So liegen auch Eigenformen als Charakteristika operativ geschlossener Systeme im Auge des Betrachters. Der Gleichgewichtszustand zwischen Input- und Output, der sich etwa bei der Lösung des Satzes „Dieser Satz hat ... Buchstaben.“ in Experiment III.5 einstellt, mag aus der Sicht Deutsch sprechender Personen klar sein, während er aus der Sicht nicht Deutsch sprechender Personen wahrscheinlich weniger deutlich ist. Besondere Herausforderungen stellen solche operativ geschlossenen Systeme dar, deren Eigenformen sich auf zeitlichen und räumlichen Skalen entwickeln, die unseren Möglichkeiten der Beobachtung und der Anpassung entgehen – insbesondere dann, wenn unser Wohlergehen von diesen Systemen abhängt. Hierzu zählen umweltpolitische Prozesse, in denen Ursachen und Wirkungen in unterschiedlichen Hoheitsgebieten in Erscheinung treten oder die sich über Legislaturperioden oder menschliche Lebensspannen hinweg erstrecken. Unterschiedliche Beobachtungsskalen erlauben auch den Missbrauch systemischer Dynamiken, etwa wenn die längerfristige Gefährdung von Institutionen in Kauf genommen wird, weil dies im Rahmen der Berichtsperioden zuständiger Entscheidungsträger profitabel und lohnend ist. Operativ geschlossene Systeme und Eigenformen finden sich sowohl in der phänomenalen Welt (etwa in sensomotorisch geschlossenen lebenden Systemen) als auch in formellen Beschreibungen (etwa in rekursiven Algorithmen). Sie sind, mit anderen Worten, auf beiden Seiten der in Abbildung 5.11 dargestellten Modeling Relation anzutreffen. Eigenformen operativ geschlossener „natürlicher Systeme“ lassen sich oft nur mit operativ geschlossenen „formellen Systemen“ beschreiben und vorhersagen. Ein Beispiel hierfür ist von Foersters in Unterkapitel 6.2 besprochene Beschreibung des „natürlichen Systems“ Gedächtnis mittels eines „formellen Systems“ in der Form eines rekursiven mathematischen Modells. Auch jenseits empirischer Untersuchungen bedienen wir uns, wie auf den Seiten 286 bis 290 beschrieben, mehr oder weniger formeller Analogien und Brückenschlägen, um auf der Basis angenommener Entsprechungen zu denken und zu handeln. Um für Zwecke dieser Art ein Vokabular typischer systemischer Verhalten zu etablieren, werden in Experiment III.12 exemplarische Eigenformen anhand operativ geschlossener Differenzengleichungen demonstriert.

380 | 6 Systeme, Systemgrenzen und Wiedereintritt

Experiment III.12: Wiedereintritt und Eigenform Dieses Experiment lädt ein, Eigenformen verschiedener Differenzengleichungen zu erkunden. Das Skript in Listing 6.2 implementiert eine operativ geschlossene Umgebung für eine oder mehrere möglicherweise in Wechselbeziehungen stehende Gleichungen. Diese können zwischen den Zeilen 3 und 5 aufgelistet und mit 50 Wiedereintritten (dieser Wert kann in Zeile 2 angepasst werden) berechnet werden. Startwerte für jeweils verwendete Variablen werden nach Programmstart abgefragt und resultierende Datenverläufe daraufhin als Graphen dargestellt. Die Variable i ist für die Indizierung anderer Variablen reserviert.

Listing 6.2: Eigenform (eigenform_DE.py) 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

import pylab iterationen=50 gleichungen=''' N[i]=N[i-1]/2+1 ''' i=0; ertrag={}; fe=[] for z in gleichungen.split('\n'): # Gleichung(en) vorbereiten: z=z.replace(' ', '') if len(z)>1 and z.index('=')>0: fe.append([z.split('[i]=')[0], z]) ertrag[z.split('[i]=')[0]]=[0]*iterationen def maschine(frm, i, iterationen, ertrag): # rekursive Maschine: _c=0; i+=1; _d={} for _n in frm: formel=frm[_c][1] for _o in ertrag: _d[_o]=ertrag[_o] _d['i']=i exec("from math import *;" + formel, _d) for _o in ertrag: ertrag[_o][i]=_d[_o][i] _c+=1 return maschine(frm, i, iterationen, ertrag) if i 2.0: break z = z * z + c screen.set_at((x, y),(i%32*8, i%8*32, int((i*2)%16*16))) print("Bereit.\nZoom: [i], [o] zoom\nVerschieben: Cursor-Tasten\nEnde: [q]") pygame.display.flip() loop = True while loop: loop = False pygame.event.pump(); key = pygame.key.get_pressed() if key[pygame.K_q]: exit() # Programm-Ende elif key[pygame.K_i]: rat_bereich *= 0.9; irrat_bereich *= 0.9 elif key[pygame.K_o]: rat_bereich *= 1.11111111; irrat_bereich *= 1.11111111 elif key[pygame.K_UP]: yoff=yoff + (irrat_bereich / 25) elif key[pygame.K_DOWN]: yoff=yoff - (irrat_bereich / 25) elif key[pygame.K_LEFT]: xoff=xoff - (rat_bereich / 25) elif key[pygame.K_RIGHT]: xoff=xoff + (rat_bereich / 25) else: loop = True

7.4 Amplifikation von Varietät

| 411

Pask (1976) beschreibt Konversation als interaktive epistemische Praxis. Individuen vollziehen diese Praxis in Feedbackprozessen, konstruieren durch Verflechtungen ihrer Erfahrungen Konzepte und verhandeln Bedeutungen. Pasks spätere Interactions of Actors Theory generalisiert die Konversationstheorie und geht der Frage nach, wie das, was sein soll, abgeleitet wird von dem, was ist (de Zeeuw 2001:972). Diese Beschreibung des Erkenntnisprozesses korrespondiert mit Pickerings (2010:29) Charakterisierung der Kybernetik insgesamt als „vorausschauende Suche“ („forward-looking search“). Mit dieser generellen Betrachtung vereint Pask gemeinhin als artfremd verstandene epistemische Ansätze und kommt zu dem Schluss (de Zeeuw 2001:972): [T]here is not one iota of fundamental difference between art, philosophy and science, provided they are all conducted with an appropriate degree of delicacy and integrity.

Pasks mitunter schwer zu durchdringendes und teils unvollendetes Werk wurde von anderen zugänglicher aufbereitet (Pangaro 1993; Glanville 2001a; de Zeeuw 2001; Scott 2009). Insbesondere Glanville entwickelte Pasks Theorien weiter. Ein zentraler Leitsatz hierbei war das Ökonomieprinzip „Occam’s razor“ (Glanville 2009:100, 396), also das puristische Bestreben, unter Einsatz weniger Mittel mehr zu erklären. Das Resultat sind zunächst abstrakte, prozessbasierte Theorien von (Selbst-)Beobachtung und (Selbst-)Referenz in Objekten (Glanville 1988) und black boxes (Glanville 1982) sowie später eine kompakte radikal-konstruktivistische Erkenntnis- und Entwurfstheorie mit ethischen Implikationen (Glanville 2007a; 2007b). Glanville übernahm von Pask die auch in anderen epistemologischen Theorien anzutreffende (Ogilvie 2009) Unterscheidung zwischen Self und Other und stellte sie ins Zentrum seiner Theorien (Glanville 1990). Self ist der subjektive Ausgangspunkt epistemischer Praxis und Other deren Gegenüber – sei er menschlicher, technischer oder anderer Natur. In diesem Sinne qualifizieren sich sowohl menschliche Konversationspartner als auch fehlerhafte MOS-Speicherchips (siehe Seite 362) mit ihren nicht determinierbaren Input-Output-Beziehungen als Others in epistemischen Prozessen. Self und Other stehen in einem zirkulär-kausalen Feedbackverhältnis. Sie sind black boxes füreinander und ihr gemeinsames Wechselverhältnis ist eine black box für beobachtende Dritte. Die Symmetrie ihres Verhältnisses und ihre gegenseitige Nicht-Einsehbarkeit erfordern Parität und beiderseitigen Respekt. Im Gegensatz zu den meisten technischen Feedbacksystemen ist Konversation „außer Kontrolle“: Self und Other erfüllen nicht Ashbys (1956:202) Gesetz der erforderlichen Varietät und sind füreinander nicht determinierbar. Übereinkunft zwischen Self und Other ist nicht immer möglich, erforderlich oder erwünscht. Ist sie hinsichtlich bestimmter Anliegen erwünscht, so erfordert sie im Sinne des auf Seite 363 besprochenen Begriffs des „geteilten“ Verständnisses das Verhandeln zwischen Self und Other (siehe auch Seite 353). Glanville (2007a:378–384) illustriert dies mit dem in Abbildung 7.7 dargestellten Modell des Konversationsprozesses.

412 | 7 Von Determinierbarkeit zu Nicht-Determinierbarkeit

1. denkt...

und drückt dies aus mit dem Wort

„Baum“

2. hört ...

„Baum“ und versteht ...

3.

drückt dies aus mit dem Wort

„arbor“

4. hört ...

„arbor“

5. vergleicht dieses Verständnis mit dem früheren Verständnis

6.

Abb. 7.7: Konversation nach Glanville (2007a:378–384; 2014b:63)

7.4 Amplifikation von Varietät

|

413

Mit diesem Konversationsmodell legt Glanville eine radikal-konstruktivistische Entsprechung des in Abbildung 5.1 dargestellten generellen Kommunikationssystems Shannons vor. Sie zeigt (1) die Begegnung eines Self und eines Other. Die Zuordnung dieser beiden Rollen ist aufgrund ihrer symmetrischen Beziehung beliebig. Für die hier folgende Beschreibung des dargestellten Prozesses wird der Figur auf der linken Seite die Rolle des Other und der Figur auf der rechten Seite die Rolle des Self zugeordnet. Other formt ein mentales Bild und drückt dieses Bild verbal aus (2). Self nimmt dies wahr und formt interpretierend ein eigenes mentales Bild (3). Self verbalisiert jetzt seinerseits sein mentales Bild (4). Other nimmt dies wahr, formt interpretierend ein neues mentales Bild (5) und vergleicht dieses mit seinem ursprünglichen mentalen Bild (6). Erachtet Other seine beiden mentalen Bilder als ähnlich genug, kann es annehmen, dass das mentale Bild von Self dem eigenen ähnlich genug ist und „geteiltes“ Verständnis besteht. Wenn dies nicht der Fall ist, wiederholen Self und Other diesen Prozess, bis sie entweder übereinkommen oder hinnehmen, dass sie sich nicht einigen können (Glanville 2007a:378–384). Glanville (2009:115–123) zieht in seiner Weiterentwicklung der Konversationstheorie Pasks auch Ashbys Begriff der Varietät heran. Varietät sowohl in Self als auch in Other ist eine Voraussetzung für ihre Konversation. Wie zuvor beschrieben, lässt sich durch Reduktion und Amplifikation ihrer Varietäten erforderliche Varietät und somit determinierbare Kontrolle zwischen Self und Other etablieren. Ein Beispiel hierfür ist militärische Kommunikation mittels erzwungener Einschränkungen (Glanville 1997b:46; 2004:1385; siehe auch Seite 286 und Unterkapitel 7.2). Bei einem solchen „unter Kontrolle“ gebrachten Wechselverhältnis handelt es sich aus eben diesem Grund aus kybernetischer Sicht nicht um Konversation. Wie in Abbildung 7.7 dargestellt, ist Varietät beim ausdrücklichen Abgleich von Verständnissen auch ein möglicher Gegenstand von Konversation. Hiermit einhergehende Reduktionen und Amplifikationen von Varietät erfolgen durch negatives beziehungsweise positives Feedback zwischen Self und Other. Glanville (2007a) illustriert diesen Prozess anhand mathematischer Eigenformen (siehe auch Experiment III.12). In diesem Fall ist Varietätsänderung ein möglicher Effekt von Konversation. Hierbei können sich zumindest zeitweilig viable Übereinkünfte einstellen. Somit erreichte Amplifikation von Varietät ist gleichbedeutend mit Erkenntnis, Lernen und Erfindung. Weiterhin ist Varietät auch ein mögliches Ziel von Konversation, wenn diese zum Zweck des Erkenntnisgewinns, der Entwicklung von Fähigkeiten oder kreativen Gestaltens geführt wird. Anders, als man vielleicht intuitiv annehmen würde, kann Einschränkung von Varietät insbesondere in kreativen Prozessen unterstützend wirken¹³ (Fischer und Richards 2017:38). Konversation impliziert die wechselseitige Beeinflussung von Varietät der jeweiligen Konversationspartner. Die Kybernetik zweiter Ordnung bezeichnet dies als Interaktion. Sie setzt voraus, dass der Output von Other nicht

13 „Not macht erfinderisch.“

414 | 7 Von Determinierbarkeit zu Nicht-Determinierbarkeit vollständig mit der Input-Varietät von Self übereinstimmt und dass Self unerwartetem Output von Other aufgeschlossen begegnet. So ist der Konversationsprozess unausweichlich von Missverständnissen geprägt (Glanville 1997b:47). Glanville erklärt deren Wert: Missverständnisse erlauben das Voranschreiten von Konversationen und Überraschungen (Glanville 1996:453; 2014a:1296), sind Quelle des Neuen (Glanville 2007b:1187) und bieten die Möglichkeit, von einschränkender Kontrolle zu Kontrolle im Sinne dynamischer Stabilität zu gelangen (Glanville 2009:309; Seite 286). In dieser Wertschätzung von Missverständnissen (sowie von error, noise etc.) liegt ein wesentlicher Unterschied zwischen der Kybernetik zweiter Ordnung und der Kybernetik erster Ordnung. Im Sinne dieser Wertschätzung von Missverständnissen und Überraschungen zieht von Foerster (Segal 1986:106; Sander 1999:CD 1, Track 3, 9:00–9:27; Pörksen 1998:55) neben seiner NTM eine weitere Illustration von Nicht-Trivialität heran, die Äußerung eines Schulkindes: 2 × 2 = grün

Das Kind kommt für seine Nicht-Trivialität nicht ungeschoren davon und wird institutioneller Trivialisierung unterzogen (von Foerster 2003b:311; 1993:208; 2010b:32). Doch es sind, so Glanville (2007b:1178), eben diese Überraschungen im Konversationsprozess, mit denen wir zum Neuen gelangen. Unser Potenzial für spontane Kreativität dieser Art lässt sich experimentell demonstrieren. Hört man der ständig wiederholten Wiedergabe der Tonaufnahme eines gesprochenen Wortes zu, so nimmt man nach wenigen Minuten (etwa 50 bis 150 Wiederholungen) plötzlich ein anderes Wort, eine sogenannte Alternante, wahr. Nach 10 bis 30 weiteren Wiederholungen ändert sich die Wahrnehmung dieser Alternante wiederum in eine andere und so weiter. Von Foerster (2003b:213; 2006:27) berichtet von einer Durchführung dieses Experiments mit 200 Testpersonen und einer Aufnahme des englischen Wortes „cogitate“. Die Testpersonen gaben insgesamt 758 verschiedene Alternanten zu Protokoll, zum Beispiel: agitate, annotate, arbitrate, artistry, back and forth, brevety, ca d’etait, candidate, can’t you see, can’t you stay und so weiter. Dieses spontane In-Erscheinung-Treten von Alternanten kann in Experiment III.17 nachvollzogen werden. Experiment III.17: Alternanten Dieses Experiment demonstriert das In-Erscheinung-Treten von Alternanten mittels Audio-Schleifen gesprochener Wörter. Als dieses Experiment in den 1970er-Jahren durchgeführt wurde, mussten für diesen Zweck analoge Magnetbandschleifen angefertigt werden. Mit dem folgenden Skript kann dies bequemer und ohne Tonbänder nachvollzogen werden. Es ruft Audioaufnahmen der Aussprache deutscher und englischer Wörter in einem Online-Wörterbuch ab¹⁴ und gibt diese dann in einer Audioschleife aus.

14 Für diesen Zweck analysiert das Skript den HTML-Code von Einträgen auf https://www.linguee.de. Sollte sich der Aufbau dieser Webseite ändern, können Anpassungen des Skriptes erforderlich werden.

7.4 Amplifikation von Varietät

| 415

Listing 7.4: Alternanten (alternants_DE.py) 1 2

import urllib.request, shutil, os plrs={"play":"repeat -", "mplayer":"-loop 0", "omxplayer":"--loop", "mpg123": "--loop -1"} print("Suche Audio-Player...", end='') for c in plrs: if shutil.which(c) != None: break exit("Kein Audio-Player gefunden.") if c=="" else print(c, "gefunden.")

3 4 5 6 7 8 wort = input("Wort eingeben: ") 9 if not shutil.os.path.isfile("./"+wort+".mp3"): 10 print("Lade Audio-Datei...") 11 url="https://www.linguee.de/deutsch-englisch/search?query="+wort 12 page = urllib.request.urlopen(url).read().decode('gb2312',errors='ignore') 13 page=page[page.index("playSound(this,\"")+16:] 14 page=page[:page.index(",")-1] 15 soundurl="https://www.linguee.de/mp3/"+page+".mp3" 16 # Audio-Datei laden: 17 with urllib.request.urlopen(soundurl) as response, open("./"+wort+".mp3", 'wb') as datei: 18 data = response.read() 19 datei.write(data) 20 print("control+c = Ende") 21 22 os.system("sox ./"+wort+".mp3 tmp.mp3 silence 1 0 1% reverse silence 1 0 1% reverse >/dev/null 2>&1") # Stille abschneiden 23 os.system("mv ./tmp.mp3 ./"+wort+".mp3 >/dev/null 2>&1") 24 op = "./"+wort+".mp3 " + plrs[c] if c == "play" else plrs[c] + " ./"+wort+".mp3 " 25 os.system(c + " " + op + " >/dev/null 2>&1") # Wiedergabe 26 # Audio-Datei loeschen? 27 if input("\nAudio-Datei löschen [j/n]?\n")=="j": os.remove("./"+wort+".mp3")

Da sich der Wert spontaner Überraschungen und somit des Neuen dort zeigen kann, wo Unerwartetem aufgeschlossen begegnet wird (Glanville 2007b:1189), kommt bedachtem „Zuhören“ (bezogen auf Wahrnehmung generell) eine zentrale Rolle zu (Fantini und Glanville 2013). Empfänglichkeit gegenüber Unerwartetem und dessen Integration in das eigene mentale Repertoire konstituieren den zentralen epistemischen Akt: die Amplifikation von Varietät. Wie bereits erwähnt, wird der Weg dorthin mitunter durch Varietätsreduktion bereitet. Ein Beispiel hierfür ist ein Stück unbeabsichtigter Poesie im stilbildenden Einsatz von Vocodern in der Musik der Band Kraftwerk. In dem Track Die Roboter auf dem 1978er-Album Die Mensch-Maschine proklamiert eine Vocoder-verzerrte Stimme auf Russisch: Я твой слуга. Я твой работник.

416 | 7 Von Determinierbarkeit zu Nicht-Determinierbarkeit Auf Deutsch übersetzt bedeutet dies: „Ich bin dein Sklave. Ich bin dein Arbeiter.“ Der Titel des Tracks spielt mit der Idee der Ausbeutung eines neuen, robotischen Sklaventums. Die Cover-Gestaltung von Mensch-Maschine ist inspiriert von konstruktivistischer russischer Kunst, insbesondere dem Avantgarde-Künstler El Lissitzky. Der Name des Albums referiert auf den deutschsprachigen Titel der zweiten KybernetikMonografie „Mensch und Menschmaschine“ Wieners (1950), der bereits in Cybernetics feststellte, dass die Kybernetik der Menschheit automatisierte Sklaven beschert (Wiener 1961:27). In der Tat automatisierte sich Kraftwerk selbst mittels vier Robotern, denen die Band sowohl die Werbekampagne für das Album als auch Bühnenauftritte überließ (Bussy 1993:102). So war es für Kraftwerk-Fans und die Band selbst um so überraschender, als die Vocoderstimme des Roboters beim Rückwärts-Abspielen der Mensch-Maschine auf Englisch proklamierte: Nobody owns me, noone sells me.

Glückliche Zufälle dieser Art sind ein zentrales Element künstlerischer und gestalterischer Praxis. Dort werden sie oft strategisch in Kauf genommen oder herbeigeführt. In diesem Sinne ist Gestaltung eine zirkulär-kausale Konversation eines Self mit einer Situation, herangezogenen Ressourcen und imaginären Szenarien (Other) mit zunehmender Varietät und unterwegs verhandelbarem Ziel (Glanville 1997b:47; 1999:88; 2009:146). Beispiele für die Inkaufnahme und das Aufgreifen des Unerwarteten finden sich überall dort, wo gestaltet wird – oder umgekehrt: Dort, wo das Unerwartete nicht in Kauf genommen und aufgegriffen wird, findet kein Gestalten statt. Ein einfaches, nichtsdestotrotz geeignetes Beispiel für den kreativen Prozess ist die Entwicklung des in Abbildung 2.1 dargestellten einfachen Thermostats. Für die Demonstration zirkulär-kausaler Feedbackschleifen im Unterricht benötigte ich (Autor) ein kompaktes, transportables Gerät. Ein Heizlüfter erschien weder handlich noch anschaulich genug. Auf der Suche nach einer visuell deutlicheren Alternative testete ich herkömmliche Glühbirnen und Bimetallschalter. 60W-Birnen erwiesen sich als zu hell für direkte Beobachtung; 25W-Birnen erwiesen sich als besser geeignet. Da sich mein anfänglicher Wunsch nach Kompatibilität mit sowohl 110-Volt- als auch 230Volt-Versorgungsspannungen nicht mit derselben Glühbirne realisieren ließ, begnügte ich mich mit bloßem 230-Volt-Betrieb. Anstatt eine endgültige Form für das Gerät zu entwerfen, um anschließend Mittel und Wege für deren Umsetzung zu finden, stöberte ich auf der Suche nach möglicherweise geeigneten Komponenten durch Bestände und Märkte. Ein Nylon-Kabelbinder erwies sich zur Befestigung des Bimetallschalters an der Glühbirne als wenig verlässlich. Eine Metallmanschette war deutlich stabiler, erforderte aber die zusätzliche Verdrahtung eines Schutzleiters. Demonstrationen des Gerätes im Unterricht sollten unkompliziert binnen weniger Minuten vonstatten gehen. Da das Einstecken und Ziehen des Netzsteckers zwei freie Hände erfordert, ich aber im Unterricht meist auch Mikrofon, Zeigegerät und Computer handhabe, sollte das Gerät einhändig bedienbar sein und brauchte daher schließlich noch einen

7.4 Amplifikation von Varietät

|

417

eingebauten Schalter. Während dieses Prozesses beeinflusste ich das sich entwickelnde Gerät und es beeinflusste mich. Die Eigenschaften des entstehenden Produkts schwebten mir zunächst nur schemenhaft vor und wurden während des Prozesses kontinuierlich verhandelt. Dass sich mit dem dabei entstandenen Gerät schließlich auch eine Möglichkeit für die Illustration dieses Teilbandes ergab, war nicht geplant, aber ein durchaus willkommener Bonus. Die Akzeptanz des Unerwarteten und das strategische Herbeiführen glücklicher Zufälle ist Gegenstand sogenannter „surrealistischer Spiele“. Diese schlagen zum Beispiel das Dichten auf der Basis zerschnittener Dokumente vor (Brotchie und Gooding 1995:65). Ein anderer Vorschlag ist das Spiel der Syllogismen für drei Personen: Die erste Person schreibt einen mit „Alle ...“ beginnenden Obersatz auf ein Stück Papier, die zweite Person schreibt einen Untersatz auf und die dritte Person schreibt eine Schlussfolgerung auf. Danach sind die drei Sätze zusammenzufügen (Brotchie 1995:29). Auch diese Strategien beruhen auf interaktiver, zirkulär-kausaler Konversation zwischen Self und Other(s). Glanville (2000:4) beobachtet: Betweenness is the source of interaction and also its mode and its site.

Obgleich digitale Technologie zunächst mit erforderlicher Varietät entwickelt und in der Regel dementsprechend linear-kausal verwendet wird, bietet das zirkulärkausale Verhältnis – beispielsweise zwischen digitalen Computern und ihren Nutzern – Gelegenheit zur kreativen Interaktion. Bateson (1972:317) erklärt: The computer is only an arc of a larger circuit which always includes a man and an environment [...].

Somit ist nicht-determinierbare Konversation selbst mit digitaler Technologie lediglich eine Frage der Sichtweise der Nutzer. Die kombinatorischen Möglichkeiten der Varietät digitaler Computer bietet hierfür enormes Potenzial. Ein möglicher Ansatz ist das spielerische Verfolgen divergierenden Outputs des Computers, anstatt diesen rational konvergierend auf intendierte Ziele zu richten. So lassen sich beispielsweise Texteditoren in Instant Messaging-Apps als kreative Werkzeuge verwenden, indem beim Schreiben beliebige Vorschläge der „Auto-Text“-Funktion aufgegriffen werden. Alternativ kann die Rechtschreibprüfung von Textverarbeitungsprogrammen verwendet werden. Hierzu lädt das folgende Experiment ein. Experiment III.18: Spellchecker Poetry Dieses Experiment (Glanville 1994:100–102) lädt ein zum Schreiben eines Gedichtes unter Verwendung eines digitalen Werkzeugs als Medium im kybernetischen Sinn. Öffnen Sie hierfür ein Textverarbeitungsprogramm (zum Beispiel FocusWriter, LibreOffice Writer, Microsoft Word oder ähnlich) mit kontinuierlicher Rechtschreibprüfung in Ihrer bevorzugten Sprache. Tippen Sie nun mit geschlossenen Augen wahllose, etwa fünf bis fünfzehn Zeichen lange Buchstabenketten. Nun wird die Rechtschreibkontrolle die Mehrheit der Zeichenketten als nicht korrekt geschriebene Wörter erkennen und rot unterstreichen. Für jede dieser Zeichenketten wird ihnen die Rechtschreibprüfung nun (üblicherweise per Rechtsklick) Korrekturvorschläge anbieten. Wählen Sie nun unter den

418 | 7 Von Determinierbarkeit zu Nicht-Determinierbarkeit Vorschlägen jeweils denjenigen aus, der Ihnen am besten gefällt oder welchen Sie als besonders poetisch empfinden. Wiederholen Sie dies und manipulieren Sie währenddessen den entstehenden Text nach Belieben. Sollte sich im Zuge dieses Prozesses eine Stimmung oder eine thematische Richtung herausbilden, dann können Sie versuchen, diese mit Ihren weiteren Entscheidungen zu verfolgen und zu verstärken. Es empfiehlt sich aber, das allzu bewusste und absichtliche Verfolgen formeller Versmaße oder Reime zu vermeiden. Spielen Sie!

Abb. 7.8: Rechtschreibkontrolle als dichterisches Medium, basierend auf Glanville (1994:100–102)

Auf dieser Dynamik basiert der kybernetische Medienbegriff Glanvilles (1997b:48). Demgemäß ist ein Medium eine nicht-determinierbare black box, also ein varietätsamplifizierendes Other in einer Konversation, die Self und Other, getragen von sowohl negativem als auch positivem Feedback, außer Kontrolle zur mentalen und physikalischen Konstruktion des Neuen führt: a medium is a tool that „kicks back“

8 Ausblick In diesem Teilband wurde die Kybernetik aus medienwissenschaftlicher Sicht sowohl praktisch als auch theoretisch vorgestellt. Anstatt sie in umfassender Breite und in erschöpfender Tiefe zu behandeln, wurde lediglich ein Grundriss kybernetischer Konzepte skizziert. Er beschränkt sich auf Charakteristika und Grundannahmen, mit denen sich die Kybernetik am deutlichsten von anderen Zweigen der Systemforschung und der Naturwissenschaft abgrenzt: zirkuläre Kausalität, Beobachterabhängigkeit, Nicht-Determinierbarkeit und Selbstorganisation. Die enthaltenen Experimente sollten zum handelnden Lernen anregen und Lust auf praktische Spekulation und auf „experimentelle Epistemologie“ machen. Begriffsklärungen sollten Lesern bezüglich häufig gestellter Verständnisfragen entgegenkommen. Die diskutierten Beispiele gesellschaftlicher und technischer Entwicklungen sollten die anhaltende Relevanz kybernetischen Denkens illustrieren. Die Relevanz der Kybernetik spiegelt sich gegenwärtig nur begrenzt in der Bereitstellung von Forschungs- und Bildungsressourcen oder in öffentlichen Diskursen wider. Sie zeigt sich jedoch in gesellschaftlichen, ökonomischen und politischen Entwicklungen. Hierzu gehören unter anderem Herausforderungen ökonomischer Regulierung, der Legitimation und Strukturierung von Macht, durch menschliche Aktivität herbeigeführte Umweltschäden und mit diesen Herausforderungen einhergehende Fragen zur Validität und Integrität wissenschaftlicher und journalistischer Arbeit. Dahinter stehen grundsätzlichere epistemologische Fragen bezüglich der medialen Apparaturen, mit denen wir die Welt wahrnehmen, verstehen und auf sie Einfluss nehmen. Angesichts der zunehmenden Autonomie und Nicht-Determinierbarkeit dieser Medien sowie ihrer in zwei Richtungen expandierenden Reichweiten – „hinaus in die Welt“ und „hinein in unsere Nervensysteme“ – erweist sich das Ideal der Medienkompetenz als ein bewegliches Ziel von großer Bedeutung für unsere Zukunft. Vor diesem Hintergrund sollte mit den hier angestellten Überlegungen auch das Potenzial der generalistischen, reflexiven, kritischen und kreativen kybernetischen Sichtweise für die Ausbildung zentraler Zukunftskompetenzen aufgezeigt werden. Für das weiterführende Studium dieser faszinierenden und facettenreichen kybernetischen Sichtweise wird im folgenden Kapitel Literatur empfohlen. Wichtiger als das Absorbieren bereits beantworteter Fragen ist jedoch das gemeinsame Handeln auf der Suche nach neuen Fragen sowie die praktische Beobachtung von Beobachtung, das Verstehen von Verstehen und anhaltende Konversation über unsere Beobachtungen und Verständnisse zwischen verschiedenen akademischen, professionellen und künstlerischen Feldern und Traditionen – auf dass sich praktische und gedankliche Spielräume jenseits erforderlicher Varietät im Sinne von Foersters (1993:147) ethischem Imperativ gegenseitig erweitern und bereichern mögen: Ich werde stets so handeln, dass die Gesamtzahl der Handlungsmöglichkeiten zunimmt.

https://doi.org/10.1515/9783110496253-027

9 Lektüreempfehlungen Abschließend seien hier noch einige Quellen für das weiterführende und vertiefende Studium der Kybernetik sowie ergänzende Literatur zum radikalen Konstruktivismus empfohlen und kurz besprochen. Frank, Helmar, Hrsg. (1964): Kybernetische Maschinen. Prinzip und Anwendung der automatischen Nachrichtenverarbeitung, Frankfurt am Main, S. Fischer Verlag (deutsch). Frank, Helmar, Hrsg. (1970): Kybernetik – Brücke zwischen den Wissenschaften. 24 Beiträge namhafter Wissenschaftler und Ingenieure, Frankfurt am Main, Umschau Verlag (deutsch). Ashby, W. Ross (1956): An Introduction to Cybernetics, London, Chapman&Hall (englisch). Diese drei Bände behandeln die frühe Kybernetik erster Ordnung. Bei den ersten beiden handelt es sich um deutschsprachige Bände in der in diesem Teilband weniger berücksichtigten deutschen Kybernetik-Tradition. Bei dem dritten Band handelt es sich um ein nach wie vor sehr lesenswertes einführendes Handbuch des britischen Kybernetikers W. Ross Ashby. Es kursiert als kostenlos verfügbares Dokument im Internet. von Foerster, Heinz (1984): Observing Systems, Seaside, CA, Intersystems Publications (englisch). von Foerster, Heinz (2003): Understanding Understanding. Essays on Cybernetics and Cognition, New York, Springer (englisch). Diese beiden englischsprachigen Sammelbände tragen herausragende Arbeiten des Begründers der Kybernetik zweiter Ordnung Heinz von Foerster zusammen. Der erste wurde von Francisco Varela herausgegeben und mit einem Vorwort versehen, trägt aber den Namen von Foersters als Autor auf dem Einband. Dieser Band ist vergriffen, mit etwas Glück aber durchaus noch antiquarisch zu finden. Die zweite, exzellente Sammlung von Artikeln von Foersters aus dem Jahr 2003 wurde 2010 neu aufgelegt. Sie ist leicht erhältlich, aber nicht gerade erschwinglich. Aufgrund seiner weiten Verbreitung eignet sich dieser Band als Referenz in internationalen Diskursen. von Foerster, Heinz (1993): Wissen und Gewissen: Versuch einer Brücke, Frankfurt am Main, Suhrkamp Verlag (deutsch). von Foerster, Heinz (2006): Sicht und Einsicht. Versuche zu einer Operativen Erkenntnistheorie, Wiesbaden, Springer (deutsch). von Foerster, Heinz (2008): Der Anfang von Himmel und Erde hat keinen Namen, Berlin, Kulturverlag Kadmos (deutsch). von Foerster, Heinz (2008): KybernEthik, Berlin, Merve Verlag (deutsch). Diese vier Bände sind exzellente Sammlungen wichtiger Arbeiten von Foersters in deutscher Sprache. Sie enthalten vornehmlich Übersetzungen zunächst auf Englisch https://doi.org/10.1515/9783110496253-028

9 Lektüreempfehlungen

|

421

erschienener Artikel. Diese Bände sind für deutschsprachige Leser leicht zugänglich, relativ erschwinglich und geeignet als Referenzen in deutschsprachigen Diskursen. Segal, Lynn (1986): The Dream of Reality. Heinz von Foerster’s Constructivism, New York, NY, Springer (englisch). Keeney, Bradford P. (2002): Aesthetics of Change, zweite Aufl., New York, NY, Guilford Press (englisch). Diese beiden Bände bieten leicht zugängliche, allerdings wiederum englischsprachige Einführungen in die Kybernetik zweiter Ordnung. Sie richten sich an NichtKybernetiker und fassen weite kybernetische Themenbereiche knapp und verständlich zusammen. Segals Buch beleuchtet insbesondere konstruktivistische Aspekte der Kybernetik zweiter Ordnung. Keeneys Buch richtet sich an Familientherapeuten, eignet sich aber durchaus für eine breitere Leserschaft. Pias, Claus, Hrsg. (2003): Cybernetics | The Macy Conferences 1946–1953. Transactions / Protokolle, Zürich und Berlin, Diaphanes Verlag (englisch und deutsch). Bei diesem von Claus Pias herausgegebenen Band handelt es sich um eine Neuauflage der von Heinz von Foerster herausgegebenen Tagungsbände der Macy-Konferenzen von 1949 bis 1953. In den Jahren, bevor von Foerster 1949 zum ersten Mal an dieser Konferenz-Serie teilnahm und (um sein Englisch zu verbessern) als Herausgeber für deren Tagungsbände auserkoren wurde, sind keine Protokolle dieser Treffen angefertigt worden. Da von Foersters Tagungsbände heute vergriffen, selten und mitunter recht teuer sind, ist diese Neuauflage ein wertvoller Beitrag für die andauernde Auseinandersetzung mit den Grundlagen und der Geschichte der Kybernetik. Glanville, Ranulph (2009): The Black B∞x Vol. III. 39 Steps, Wien, edition echoraum (englisch). Glanville, Ranulph (2012): The Black B∞x Vol. I. Cybernetis Circles, Wien, edition echoraum (englisch). Glanville, Ranulph (2014a): The Black B∞x Vol. II. Living in Cybernetic Circles, Wien, edition echoraum (englisch). Nach Heinz von Foerster war Ranulph Glanville ein maßgeblicher Kybernetiker zweiter Ordnung der jüngeren Vergangenheit. Wie auch von Foerster produzierte Glanville seine Schriften vornehmlich in Artikel-Form. Es gelang ihm, einen großen Teil seiner wichtigen Arbeiten in der Trilogie The Black B∞x zusammenzutragen und zu veröffentlichen. Typisch für Glanvilles spielerischen Stil sind die drei Bände nicht in der zu erwartenden Reihenfolge nummeriert. Die Trilogie (in Anspielung an Glanvilles Black-Box-Theorie auch als limitiertes Box-Set in komplett schwarzem Einband erhältlich) setzt sich mit Kybernetik vornehmlich in Bezug auf Design, Wissenschaft und Philosophie auseinander. Entsprechend Glanvilles lebenslanger Ambition, mehr mit weniger zu erklären, sind seine Texte recht zugänglich. Unter den in der Trilogie gesammelten Artikeln seien hier Glanvilles Entwicklung eines kybernetischen, auf

422 | 9 Lektüreempfehlungen Nicht-Determinierbarkeit basierenden Medienbegriffs (Vol. II, 135–149), eine illustrierte Entwicklung einer auf Konversation aufgebauten kybernetischen Epistemologie und Ethik (Vol. I, 559–604) sowie eine ausführliche Einführung in die Kybernetik zweiter Ordnung hervorgehoben. Letztere war zunächst in einer schwer zugänglichen Enzyklopädie erschienen und konnte mit der Reproduktion in der Trilogie einer breiteren Leserschaft zugänglich gemacht werden (Vol. I, 175–207). Glanville, Ranulph (2014b): Cybernetics. Thinking through the technology, in D. Arnold, Hrsg., ‘Traditions of Systems Theory: Major Figures and Contemporary Developments’, New York, Routledge, 45–77 (englisch). Glanville, Ranulph (2014c): ‘How Design and Cybernetics Reflect Each Other’, Protokoll einer Keynote-Präsentation, vorgetragen auf der RSD3 Relating Systems Thinking and Design Conference an der Oslo School of Architecture and Design am 15. Oktober 2014. (englisch, auch als Video-Aufzeichnung verfügbar: https://youtu.be/tTN_9mJIWNw – Abruf: 10.07.2018). Auch nach Abschluss seiner Arbeit an den drei Bänden produzierte Glanville bis zu seinem Tod im Jahr 2014 weitere Texte. Zu empfehlen sind hiervon insbesondere der obige, aus medientechnischer Sicht wichtige Beitrag zu einem Sammelband sowie seine letzte Keynote-Präsentation, die sich mit dem Verhältnis zwischen Kybernetik und Design auseinandersetzt. Maturana, Humberto R. und Varela, Fransisco J. (1987): The Tree of Knowledge. The Biological Roots of Human Understanding, Boston, MA, Shambala Publications (englisch). Bei diesem Werk handelt es sich um eine englischsprachige, als Lehrbuch für das Studium konzipierte Einführung in die kybernetische Erkenntnistheorie der chilenischen Neurobiologen Humberto Maturana und Francisco Varela. von Glasersfeld, Ernst (1987): Wissen, Sprache und Wirklichkeit. Arbeiten zum Radikalen Konstruktivismus, Braunschweig und Wiesbaden, Vierweg (deutsch). Gumin, Heinz und Meier, Heinrich, Hrsg. (2010): Einführung in den Konstruktivismus, München und Zürich, Pieper (deutsch). Diese beiden Bände behandeln den mit der Kybernetik zweiter Ordnung eng verwandten radikalen Konstruktivismus. Der erste ist eine deutschsprachige Sammlung wichtiger Arbeiten des Begründers des radikalen Konstruktivismus und Kybernetikers Ernst von Glasersfeld. Es folgt eine ebenfalls deutschsprachige Sammlung von Beiträgen zum radikalen Konstruktivismus verschiedener Autoren. Heims, Steve Joshua (1991): The Cybernetics Group 1946–1953, Constructing a Social Science for Postwar America, Cambridge, MA, MIT Press (englisch). Conway, Flo und Siegelman, Jim (2005): Dark Hero of the Information Age. In Search of Norbert Wiener the Father of Cybernetics, New York, NY, Basic Books (englisch).

9 Lektüreempfehlungen

| 423

Pickering, Andrew (2010): The Cybernetic Brain. Sketches of Another Future, Chicago und London, The University of Chicago Press (englisch). Dyson, George (2012): Turing’s Cathedral. The Origins of the Digital Universe, New York, NY, Pantheon Books (englisch). Kline, Ronald R. (2014): The Cybernetics Moment. Or Why We Call Our Age the Information Age, Baltimore, MA, Johns Hopkins University Press (englisch). Rid, Thomas (2016): Rise of the Machines. A Cybernetic History, New York, NY, Norton and Company (englisch). Bei diesen sechs Werken handelt es sich um empfehlenswerte englischsprachige Monografien, die sich auf die eine oder andere Weise mit der Geschichte der Kybernetik auseinandersetzen: eine Geschichte der Macy-Konferenzen und ihrer Rolle in der Entwicklung der Sozialwissenschaft, eine exzellente Biografie Norbert Wieners, eine Geschichte der Kybernetik mit Fokus auf den Arbeiten von vier britischen Kybernetikern, eine Frühgeschichte des digitalen Computers aus der Perspektive des Institute of Advanced Study in Princeton, New Jersey sowie zwei weitere geschichtliche Abrisse der Kybernetik im angloamerikanischen Raum. Blohm, Hans, Beer, Stafford und Suzuki, David (1986): Pebbles to Computers. The Thread, Toronto, Oxford University Press (englisch). Eames, Charles und Eames, Ray (1990): A Computer Perspective. Background to the Computer Age, Cambridge, MA, Harvard University Press (englisch). Bei diesen beiden aufwendig illustrierten Bänden handelt es sich um sowohl technikals auch kulturhistorisch fundierte Darstellungen der mit der Kybernetik eng verbundenen Geschichte des Computers. Rashid, Tariq (2014): Make Your Own Mandelbrot, North Charleston, SC, CreateSpace Independent Publishing (englisch). Sayama, Hiroki (2015): Introduction to the Modeling and Analysis of Complex Systems, Geneseo, NY, Open SUNY Textbooks (englisch, kostenlos online: https://textbooks.open suny.org/download/introduction-to-the-modeling-and-analysis-of -complex-systemssayama-pdf – Abruf: 10.07.2018). Janert, Philipp K. (2014): Feedback Control for Computer Systems. Introducing Control Theory to Enterprise Programmers, Sebastopol, CA, O’Reilly (englisch). Diese drei englischsprachigen Werke sind im weiteren systemischen Umfeld der Kybernetik verortet und illustrieren Inhalte ebenfalls auf der Basis von Python-Skripten.

Literatur 1970 Defense Procurement Authorization Act (1969): Public Law 91-121, Section 203. Abrahamson, H. A., Hrsg. (1960): The Use of LSD in Psychotherapy. Transactions of a Conference on D-Lysergic Acid Diethlyamide (LSD-25), New York, NY, Josiah Macy, Jr. Foundation. Aitken, H. G. J. (1985): The Continuous Wave. Technology and American Radio, 1900–1932, Princeton, NJ, Princeton University Press. Ampère, A.-M. (1834): Essai sur la philosophie des sciences, ou exposition analytique d’une classification naturelle de toutes les connaissances humaines, Paris, Bachelier. Anokhin, P. K. (1979): Системные механизмы высшей нервной деятельности, издательство Наука, Akademie der Wissenschaften der UdSSR. Arquilla, J. und Ronfeldt, D. (1993): Cyberwar is coming!, Comparative Strategy 12(2), 141–165. Artmann, S. (2010): Kybernetik zwischen Ingenieurwesen und Metaphysik. Eine Fallstudie zum Gebrauch von Analogien in den Strukturwissenschaften, Acta Historica Leopoldina 56, 399–417. Ashby, W. R. (1951): Journal 13, Barnwood House, Gloucester. (http://www.rossashby.info/journal/page/3075.html – Abruf: 10.07.2018). Ashby, W. R. (1952): Journal 17, Barnwood House, Gloucester. (http://www.rossashby.info/journal/page/4312.html – Abruf: 10.07.2018). Ashby, W. R. (1954a): Design for a Brain, New York, NY, Wiley & Son. Ashby, W. R. (1954b): Journal 18, Barnwood House, Gloucester. (http://www.rossashby.info/journal/page/4950.html – Abruf: 10.07.2018). Ashby, W. R. (1956): An Introduction to Cybernetics, London, Chapman & Hall. Ashby, W. R. (1957): Journal 20, Barnwood House, Gloucester. (http://www.rossashby.info/journal/page/5580.html – Abruf: 10.07.2018). Ashby, W. R. (1991): Introductory remarks at panel discussion, in Facets of Systems Science, New York, NY, Springer (1964 zum ersten Mal veröffentlicht), 507–510. Barnhart, R. K. (1986): The American Heritage Dictionary of Science, Boston, MA, Houghton Mifflin. Bateson, G. (1972): Steps to an Ecology of Mind, New York, NY, Ballantine Books. Bateson, G. (1979): Mind and Nature. A Necessary Unity, New York, NY, E. P. Dutton. Beer, A. S. (1974): Designing Freedom, London, John Wiley & Sons. Beer, A. S. (2002): What is cybernetics?, Kybernetes 31(2), 209–219. Beer, S. A. (1959): Cybernetics and Management, London, English Universities Press. Begley, J. (2017): After 12 rejections, Apple accepts app that tracks U.S. drone strikes, The Intercept. 28.03.2017 (https://theintercept.com/2017/03/28/after-12-rejections-apple-accepts-appthat-tracks-u-s-drone-strikes – Abruf: 10.07.2018). Bessen, J. (2016): The automation paradox. When computers start doing the work of people, the need for people often increases, The Atlantic. 19.01.2016 (https://www.theatlantic.com/busine ss/archive/2016/01/automation-paradox/424437 – Abruf: 10.07.2018). Bilstein, R. E. (1996): Stages to Saturn. A Technological History of the Apollo/Saturn Launch Vehicles, NASA History Office, Washington D.C. Black, E. (2012): IBM and the Holocaust. The Strategic Alliance between Nazi Germany and America’s most Powerful Corporation, Washington, DC, Dialog Press. Blackman, R. B., Bode, H. W. und Shannon, C. E. (1946): Data smoothing and prediction in firecontrol systems, in Summary Technical Report, Div. 7, National Defense Research Committee, Vol. 1, Gunfire Control, Washington, DC, National Defense Research Committee, 71–159, 166– 167. Bogdanov, A. A. (1989): Тектология. Всеобщая Организационная Наука, Moskau, Institut für Wirtschaft der UdSSR und Institut für Systemwissenschaften der UdSSR. https://doi.org/10.1515/9783110496253-029

Literatur

|

425

Bossomaier, T. R. J. und Green, D. (1998): Patterns In The Sand: Computers, Complexity, And Everyday Life, Reading, MA, Perseus Books. Braun, A., Hrsg. (2008): Bertelsmann Jugend Lexikon, Gütersloh, Wissen Media Verlag. Brautigan, R. G. (1986): All watched over by machines of loving grace, Cybernetic 2(1), 39. Bremermann, H.-J. (1962): Optimization through evolution and recombination, in M. C. Yovits, G. T. Jacobi und G. D. Goldstein, Hrsg., Self-Organising Systems, Washington DC, Spartan Books, 93–106. Bröcker, Monika und von Foerster, H. (2007): Teil der Welt. Fraktale einer Ethik – oder Heinz von Foersters Tanz mit der Welt, Heidelberg, Carl-Auer Verlag. Brotchie, Alastair und Gooding, M., Hrsg. (1995): A Book of Surrealist Games, Boston, MA, Shambala. Brün, H. (2004a): For anticommunication, in A. Chandra, Hrsg., When Music Resists Meaning. The Major Writings of Herbert Brün, Middletown, CN, Wesleyan University Press, 60–70. Brün, H. (2004b): Toward composition, in A. Chandra, Hrsg., When Music Resists Meaning. The Major Writings of Herbert Brün, Middletown, CT, Wesleyan University Press, 79–88. Busch, W. (2014): Gedichte, North Charleston, SC, CreateSpace. Bussy, P. (1993): Kraftwerk. Man, Machine and Music, SAF, Wembley. Cannon, W. B. (1932): The Wisdom of the Body, New York, NY, Norton. Church, A. (1936): An unsolvable problem of elementary number theory, American Journal of Mathematics 58(2), 345–363. Clarke, A. C. (1973): Profiles of the Future. An Inquiry into the Limits of the Possible, London, Pan Books. Clarke, B. (2014): Neocybernetics and Narrative, Minneapolis, MN, University of Minnesota Press. Coleman, E. G. (2013): Coding Freedom. The Ethics and Aesthetics of Hacking, Princeton, NJ and Oxford, Princeton University Press. Coleman, E. G. (2014): Hacker, Hoaxer, Whistleblower, Spy. The Many Faces of Anonymous, London, Verso. Condon, R., Hrsg. (1959): The Manchurian Candidate, New York, NY, McGraw Hill. Conlan, R., Hrsg. (1986): Computer Verstehen. Software, Amsterdam, Time-Life Books. Conway, Flo und Siegelman, J. (2005): Dark Hero of the Information Age. In Search of Norbert Wiener the Father of Cybernetics, New York, NY, Basic Books. Cowell, C. (2013): The Hong Kong Fever of 1843: Collective trauma and the reconfiguring of colonial space, Modern Asian Studies 47(2), 329–364. Curchman, C. W. (1971): The Design of Inquiring Systems. Basic Concepts of Systems and Organization, New York, NY, Basic Books. Curtis, A. (2011): All watched over by machines of loving grace. Episode 2. The use and abuse of vegetational concepts, BBC, London. (https://vimeo.com/groups/96331/videos/80799352 – Abruf: 10.07.2018). Dammbeck, L. (2003): Das Netz. Adorno, LSD und das Internet (Film), Berlin, absolut Medien. De Langhe, B., Puntoni, S. und Larrick, R. P. (2017): Linear thinking in a nonlinear world, Harvard Business Review 95(3), 130–139. De Latil, P. (1957): Thinking by Machine. A Study of Cybernetics, Boston, Houghton Mifflin. de Zeeuw, G. (2001): Interaction of arctors theory, Kybernetes 30(7/8), 971–983. Demetrios, E. (2006): An Eames Primer, New York, NY, Universe Publishing. Dent, E. B. und Umpleby, S. A. (1998): Underlying assumptions of several traditions in system theory and cybernetics, in R. Trappl, Hrsg., Cybernetics and Systems '98, Wien, Österreichische Studiengesellschaft für Kybernetik, 513–518. Dostojewski, F. (1984): Aufzeichnungen aus dem Kellerloch, Stuttgart, Reclam. Dyson, G. (2012): Turing’s Cathedral. The Origins of the Digital Universe, New York, NY, Pantheon. Eastlake, D. (1972): ITS Status Report. AI Lab Memo No. 238, Technical report, Massachusetts Institute of Technology, Cambridge, MA.

426 | Literatur Ebbinghaus, H. (1885): Über das Gedächtnis. Untersuchungen zur experimentellen Psychologie, Leipzig, Duncker & Humbolt. Engel, S. M. (1980): Analyzing Informal Fallacies, Englewood Cliffs, NJ, Prentice Hall. Ernst, W. (2004): Den A/D-Umbruch aktiv denken – medienarchäologisch, kulturtechnisch, in J. Schröter und A. Böhnke, Hrsg., Analog/Digital – Opposition oder Kontinuum?, Bielefeld, transcript, 49–66. Evans, M. G. (1970): The effects of supervisory behavior on the path-goal relationship, Organizational Behavior and Human Performance 5(3), 277–298. Fantini van Ditmar, D. und Glanville, R. (2013): Listening: Proceedings of the ASC cinference 2011, Cybernetics & Human Knowing 20(1/2), 5–11. Feld, S. L. (1991): Why your friends have more friends than you do, American Journal of Sociology 96(6), 1464–1477. Fischer, T. (2013): Enigmatic mechanisms in defense of the capability to have new ideas, Kybernetes 42(9/10), 1374–1386. Fischer, T. (2015): Blind spots obscuring circular causality in design and elsewhere, Kybernetes 44(8/9), 1233–1239. Fischer, T. und Richards, L. (2017): From goal-oriented to constraint-oriented design. The systemic intersection of design theory and systems theory, Leonardo 50(1), 36–41. Fleck, L. (1980): Entstehung und Entwicklung einer wissenschaftlichen Tatsache. Einführung in die Lehre vom Denkstil und Denkkollektiv, Frankfurt am Main, Suhrkamp. Foucault, M. (2004): Die Geburt der Biopolitik. Vorlesungen am Collège de France, 1978–1979, Suhrkamp, Frankfurt am Main. Frank, H. (1964): Was ist Kybernetik?, in H. Frank, Hrsg., Kybernetik. Brücke zwischen den Wissenschaften, fünfte Aufl., Frankfurt am Main, Umschau Verlag, 11–22. Frankl, V. E., Hrsg. (1983): Ärztliche Seelsorge. Grundlagen der Logotherapie und Existenzanalyse, München, DTV. Freire, P. (2005): Pedagogy of the Oppressed, New York, NY, Continuum. Galison, P. (1994): The ontology of the enemy: Norbert Wiener and the cybernetic vision, Critical Inquiry 21(1), 228–266. Gerovitch, S. (2002): From Newspeak to Cyberspeak. A History of Soviet Cybernetics, Cambridge, MA and London, MIT Press. Gerovitch, S. (2009): The cybernetics scare and the origins of the Internet, Baltic Worlds II(1), 32–38. Gilens, M. und Page, B. I. (2014): Testing theories of american politics: Elites, interest groups, and average citizens, Perspectives on Politics 12(3), 564–581. Glanville, R. (1982): Inside every while box there are two black boxes trying to get out, Behavioural Science 27(1), 1–11. Glanville, R. (1990): The self and the other. The purpose of distinction, in R. Trappl, Hrsg., Cybernetics and Systems '90, Singapore, World Scientific, 349–356. Glanville, R. (1994): Variety in design, Systems Research 1(3), 95–103. Glanville, R. (1996): Communication without coding, Modern Language Notes 111(3), 441–462. Glanville, R. (1997a): A ship without a rudder, in R. Glanville und G. de Zeeuw, Hrsg., Problems of Excavating Cybernetics and Systems, Southsea, BKS+, 131–142. Glanville, R. (1997b): The value when cybernetics is added to CAAD, in J. V. Koenraad Nys, Tom Provoost und J. Verleye, Hrsg., AVOCAAD First Conference Proceedings, Brussels, Hogeschool voor Wetenschap en Kunst Sint-Lucas, 39–56. Glanville, R. (1999): Researching Design and Designing Research, Design Issues 15(2), 825–833. Glanville, R. (2000): The value of being unmanageable. Variety and creativity in cyberspace, in H. Eichmann, J. Hochgerner und F. Nahrada, Hrsg., Netzwerke, Falter, Falter Verlag, 27–40. Glanville, R. (2001a): And he was magic, Kybernetes 30(5/6), 652–673.

Literatur

| 427

8 8

Glanville, R. (2001b): Between now and then. The auto-interview of a lapsed musician, Leonardo Music Journal 11, 35–42. Glanville, R. (2004): The purpose of second-order cybernetics, Kybernetes 33(9/10), 1379–1386. Glanville, R. (2007a): Grounding difference, in A. Müller und K. H. Müller, Hrsg., An unfinished revolution? Heinz von Foerster and the Biological Computer Laboratory 1958–1976, Wien, edition echoraum, 361–406. Glanville, R. (2007b): Try again. fail again. fail better. the cybernetics in design and the design in cybernetics, Kybernetes 36(9/10), 1173–1206. Glanville, R. (2009): The Black B x Vol. III. 39 Steps, Wien, edition echoraum. Glanville, R. (2012a): The Black B x Vol. I. Cybernetic Circles, Wien, edition echoraum. Glanville, R. (2012b): Radical constructivism = second-order cybernetics, Cybernetics & Human Knowing 19(4), 27–42. Glanville, R. (2014a): Acting to understand and understanding to act, Kybernetes 43(9/10), 1293– 1300. Glanville, R. (2014b): Cybernetics. Thinking through the technology, in D. Arnold, Hrsg., Traditions of Systems Theory. Major Figures and Contemporary Developments, New York, NY, Routledge, 45–77. Glanville, R., Hrsg. (1988): Objekte, Berlin, Merve Verlag. Greenberg, A. (2013): This Machine Kills Secrets. Julian Assange, the Cypherpunks, and Their Fight to Empower Whistleblowers, New York, NY, Plume. Grössing, G., Müller, A., Korn, W. und Umpleby, S. (2005): Heinz von Förster. The Stanford Lectures, Wien, edition echoraum (die Zahlen im Text sind Zeitangaben). Haidt, J. (2012): The Righteous Mind. Why Good People Are Divided by Politics and Religion, New York, NY, Random House. Haraway, D. J. (1991): Simians, Cyborgs, and Women. The Reinvention of Nature, New York, NY, Routledge. Harrison, N. (2004): Can I get an Amen? (http://nkhstudio.com/pages/popup_amen.html – Abruf: 10.07.2018). Harrison, N. (2017): Reflections on the Amen Break. A continued history, an unsettled ethics, in E. Navas, O. Gallagher und x. burrough, Hrsg., The Routledge Companion to Remix Studies, New York, NY, Routledge, 444–452. Hasen, R. L. (2016): Plutocrats United: Campaign Money, the Supreme Court, and the Distortion of American Elections, New Haven, CT, Yale University Press. Hegel, G. W. H. (1989): Phänomenologie des Geistes, Band 3, Suhrkamp, Frankfurt am Main. Heims, S. J. (1982): John von Neumann and Norbert Wiener. From Mathematics to the Technologies of Life and Death, Cambridge, MA, MIT Press. Hejl, P. M. (2010): Konstruktion der sozialen Konstruktion. Grundlinien einer konstruktivistischen Sozialtheorie, in H. Gumin, Heinz und Meier, Hrsg., Einführung in den Konstruktivismus, München, Pieper, 109–146. Hermes, H. (1961): Aufzählbarkeit, Entscheidbarkeit, Berechenbarkeit. Einführung in die Theorie der Rekursiven Funktionen, Berlin, Springer. Hess, A. (2017): How YouTube’s Shifting Algorithms Hurt Independent Media, The New York Times. (ht tps://www.nytimes.com/2017/04/17/arts/youtube-broadcasters-algorithm-ads.html – Abruf: 10.07.2018). Heylighen, Francis und Cliff Joslyn (2001): Cybernetics and second-order cybernetics, in R. A. Meyers, Hrsg., Encyclopedia of Physical Science and Technology, dritte Aufl., New York, NY, Academic Press. Hilbert, D. und Ackermann, W. (1928): Grundzüge der Theoretischen Logik, Berlin, Springer.

428 | Literatur Hinsley, S. H. (1996): (1996), The Influence of ULTRA in the Second World War, Transcript einer Vorlesung vom 19. Oktober 1993 an der Cambridge University. (http://www.cdpa.co.uk/UoP/HoC/Lec tures/HoC_08e.PDF – Abruf: 10.07.2018). Hirsch, Joachim und Roth, R. (1986): Das neue Gesicht des Kapitalismus. Vom Fordismus zum PostFordismus, Hamburg, VSA. Hodges, A. (2012): Alan Turing. The Enigma, London, Vintage Books. Holofernes, J. und Roy, P. (2007): Stiller, in Wir sind Helden, Hrsg., Soundso, EMI Music, Track 11. Hope-Jones, M. (2006): Große Momente. „Das Boot“ und die Geburtsstunde der ARRIFLEX IIIC, VisionARRI 06/06(2), 44–47. Hughes, T. P. (1998): Rescuing Prometheus, New York, NY, Vintage Books. Husbands, P. und Holland, O. (2008): The Ratio Club: A hub of British cybernetics, in P. Husbands, O. Holland und M. Wheeler, Hrsg., The Mechanical Mind in History, Cambridge, MA, MIT Press, 91–148. Jordan, H. (1957): Das Elektronengehirn. Theorie und Praxis der Automation, Wiesbaden, Rheinische Verlags-Anstalt. Kahn, H. (1961): On Thermonuclear War, Princeton, NJ, Princeton University Press. Kaspar, F. und Schuster, H.-G. (1987): Easily calculable measure for the complexity of spatiotemporal patterns, Physical Review A 36(2), 842–848. Kauffman, D. L. (1980): Systems 1. An Introduction to Systems Thinking, Minneapolis, MN, Future Systems. Kauffman, L. H. (2005): Eigenform, Kybernetes 34(1/2), 129–150. Kay, L. E. (2000): Who wrote the book of life? A history of the genetic code, Stanford, CA, Stanford University Press. Kirwan-Taylor, H. (2008): Are you suffering from: The Streisand Effect, Management Today (01.02.2008), 17. Kittler, F. (1986): Grammophon Film Typewriter, Berlin, Brinkmann & Bose. Kittler, F. (1993): Draculas Vermächtnis, Leipzig, Reclam. Kline, R. R. (2015): The Cybernetics Moment. Or Why We Call Our Age the Information Age, Baltimore, MA, Johns Hopkins University Press. Klir, G. J., Hrsg. (1991): Facets of Systems Science, New York, NY, Springer. Kolman, A. J. (1955): Что такое кибернетика?, Вопросы философии 4, 148–159. Kolman, A. J. (1959): A Soviet view of cybernetics (englische übersetzung von Anatol Rapoport), Behavioral Science 4(1), 132–146. Kolmogorov, A. (1941): Интерполирование и экстраполирование стационарных случайных последовательностей, серия математическая 5(1), 3–14. Kolmogorov, A. (1998): On tables of random numbers, Theoretical Computer Science 207(2), 387– 395. Korzybski, A. (1995): Science and Sanity. An Introduction to Non-Aristotelian Systems and General Semantics, fünfte Aufl., Brooklyn, NY, Institute of General Semantics. Kozaczuk, W. (1984): Enigma. How the German machine cipher was broken, and how it was read by the Allies in World War Two, Frederick, MD, University Publications of America. Kuhn, T. S. (1962): The structure of scientific revolutions, Chicago, IL, University of Chicago Press. Langton, C. C. (1996): Artificial life, in M. A. Boden, Hrsg., The Philosophy of Artificial Life, New York, NY, Oxford University Press, 39–94. Lempel, A. und Ziv, J. (1976): On the complexity of finite sequences, IEEE Transactions on Information Theory 22(1), 75–81. Levien, Roger und Melvin Earl Maron (1964): Cybernetics and its Development in the Soviet Union, Santa Monica, CA, RAND Corporation. Levy, S. (1984): Hackers. Heroes of the Computer Revolution, New York, NY, Doubleday.

Literatur

| 429

Levy, S. (2001): Crypto. How the Code Rebels Beat the Government Saving Privacy in the Digital Age, New York, NY, Penguin Press Science. Lincke, F. (1880): Das mechanische Relais. Mechanismen zur Ausführung indicirter Bewegungen. Eine synthetische Studie., Berlin, Gaertner. Lowell, A. L. (1898): Oscillations in politics, The Annals of the American Academy of Political and Social Science 12, 69–97. Luhmann, N. (1984): Soziale Systeme: Grundriß einer allgemeinen Theorie, Frankfurt am Main, Suhrkamp. Luhmann, N. (1996): Die Realität der Massenmedien, 2. Aufl., Opladen, Westdeutscher Verlag. Lutz, M. (2013): Learning Python, fünfte Aufl., Sebastopol, CA, O’Reilly. Macintyre, B. (2007): Agent Zigzag. A True Story of Nazi Espionage, Love and Betrayal, New York, NY, Harmony Books. Malik, F. (2008): Strategie des Managements komplexer Systeme. Ein Beitrag zur ManagementKybernetik evolutionärer Systeme, zehnte Aufl., Bern, Haupt Verlag. Marks, J. D. (1991): The Search for the „Manchurian Candidate“. The CIA and Mind Control: The Secret History of the Behavioral Sciences, New York, NY, W. W. Norton & Company. Maruyama, M. (1963): The second cybernetics. Deviation-amplifying mutual causal processes, American Scientist 5(2), 164–179. Maturana, H. R. (2002): Autopoiesis, structural coupling and cognition: A history of these and other notions in the biology of cognition, Cybernetics & Human Knowing 9(3/4), 5–34. Maturana, H. R. (2016): Reflections, Patterns, Spring/Summer 1996. Maturana, H. R. und Pörksen, B. (2004): From Being to Doing. The Origins of the Biology of Cognition, Heidelberg, Carl Auer Systeme. Maturana, Humberto R. und Varela, F. J. (1987): The Tree of Knowledge. The Biological Roots of Human Understanding, Boston, MA, Shambala Publications. May, T. C. und Woods, M. H. (1979): Alpha-particle-induced soft errors in dynamic memories, IEEE Transactions on Electron Devices 26(1), 2–9. McCarthy, John, M., Marvin, Rochester, N. und Shannon, C. E. (1955): A proposal for the Dartmouth summer research project on Artificial Intelligence, 31. August 1955. (http://www-formal.stanfor d.edu/jmc/history/dartmouth/dartmouth.html – Abruf: 10.07.2018). McCulloch, W. S. (1945): A heterarchy of values determined by the topology of nervous nets, The Bulletin of Mathematical Biophysics 7(2), 89–93. McCulloch, Warren S. und Pitts, W. (1943): A logical calculus of the ideas immanent in nervous activity, The Bulletin of Mathematical Biophysics 5(4), 115–133. McLuhan, M. (1964): Understanding Media. The Extensions of Man, Cambridge, MA, MIT Press. McMullin, B. (1997): Computational autopoiesis: The original algorithm, Santa Fe Institute Working Paper: 1997-01-001. (https://www.santafe.edu/research/results/working-papers/computation al-autopoiesis-the-original-algorithm – Abruf: 10.07.2017). McMullin, B. und Varela, F. J. (1997): Cybernetics of cybernetics, in P. Husbands und I. Harvey, Hrsg., Proceeedings of the Fourth European Conference on Artificial Life, Cambridle, MA, MIT Press, 38–47. Mead, M. (1968): Cybernetics of cybernetics, in H. von Foerster, Hrsg., Purposive Systems. Proceedings of the First Annual Symposium of the American Society for Cybernetics, New York, NY, Spartan Books, 1–11. Medina, E. (2011): Cybernetic Revolutionaries. Technology and Politics in Allende’s Chile, Cambridge, MA, MIT Press. Miller, T. P. und Leon, A. (2017): Introduction to special issue on literacy, democracy, and fake news. Making it right in the era of fast and slow literacies, Literacy in Composition Studies 5(2), 10– 23.

430 | Literatur Mindell, D. A., Hrsg. (2008): Digital Apollo, Cambridge, MA, MIT Press. Minsky, M. (1985): The Society of Mind, New York, NY, Simon & Schuster. Mitroff, I. (1974): The subjective side of science: Philosophical inquiry into the psychology of the Apollo moon scientists, Amsterdam, Elsevier. Nature (1970): Mansfield Amendment cut down, Nature 228, 107. Nelson, T. H. (1974): Computer Lib. You can and must understand computers now / Dream Machines. New freedoms through computer screens – a minority report, Eigenverlag. Norris, P. (2015): Why Elections Fail, New York, NY, Cambridge University Press. NYT (1920): A severe strain on credulity. Topics of the Times, The New York Times, 13.01.1920, 12. NYT (1969): A correction, The New York Times, 17.07.1969, 43. Odobleja, Ştefan. (1938 und 1939): Psychologie consonantiste, Paris, Librairie Maloine. Ogilvie, D. M. (2009): Competing epistemologies, Psychological Inquiry 3(1), 50–53. O’Toole, G. (2013): Good artists copy; great artists steal, Quote Investigator. (https://quoteinvestiga tor.com/2013/03/06/artists-steal – Abruf: 10.07.2018). Pangaro, P. (1993): Pask as dramaturg, Systems Research 10(3), 135–142. Pariser, E. (2011): The Filter Bubble: What the Internet Is Hiding from You, New York, NY, Penguin. Pask, G. (1975): The Cybernetics of Human Learning and Performance. A Guide to Theory and Research, London, Hutchinson Educational. Pask, G. (1976): Conversation Theory. Applications in Education and Epistemology, Amsterdam, Elsevier. Peters, B. (2016): How Not to Network a Nation. The Uneasy History of the Soviet Internet, Cambridge, MA, MIT Press. Pias, C. (2004): Elektronenhirn und verbotene Zone. Zur kybernetischen Ökonomie des Digitalen, in J. Schröter und A. Böhnke, Hrsg., Analog/Digital – Opposition oder Kontinuum?, Bielefeld, transcript, 295–310. Pias, C., Hrsg. (2003): Cybernetics | The Macy Conferences 1946–1953. Transactions / Protokolle, Zürich und Berlin, Diaphanes Verlag. Pickering, A. (2010): The Cybernetic Brain. Sketches of Another Future, Chicago und London, The University of Chicago Press. Pollack, A. (1999): Missing what didn’t add up, NASA subtracted an orbiter, The New York Times . (http://www.nytimes.com/1999/10/01/us/missing-what-didn-t-add-up-nasa-subtracted-anorbiter.html – Abruf: 10.07.2018). Popper, K. (2005): The Logic of Scientific Discovery, London, Taylor & Francis. Pörksen, B. (1998): „Die Naturgesetze können von uns geschrieben werden“. im gespräch mit heinz von foerster, Communicatio Socialis 31(1), 47–61. Pörksen, B. (2002): Die Gewissheit der Ungewissheit. Gespräche zum Konstruktivismus, Heidelberg, Carl Auer Systeme. Pruckner, M. (2002): 90 Jahre Heinz von Foerster. Die praktische Bedeutung seiner wichtigsten Arbeiten (DVD), St. Gallen, Malik Managment Zentrum (die Zahlen im Text sind Zeitangaben). Ramage, M. und Shipp, K. (2009): System Thinkers, London, Springer. Randy, A. (2008): Nov. 4, 1952: UNIVAC gets election right, but CBS balks, Wired.com. (https://www. wired.com/2010/11/1104cbs-tv-univac-election – Abruf: 10.07.2018). Rashid, T. (2014): Make Your Own Mandelbrot, North Charleston, SC, CreateSpace. Rheinberger, H.-J. (2000): Experiment: Präzision und Bastelei, in C. Meinel, Hrsg., Instrument – Experiment. Historische Studien, Berlin, GNT Verlag, 52–59. Richards, L. (2016): A history of the history of cybernetics. An agenda for an ever-changing present, Cybernetics & Human Knowing 23(1), 42–49. Richardson, L. F. (1961): The problem of contiguity: An appendix to Statistics of Deadly Quarrels, in A. Rapoport, L. von Bertalanfly und R. L. Meier, Hrsg., General Systems. Yearbook of the Society

Literatur

|

431

for the Advancement of General Systems Theory, Band 6, Ann Arbor, MI, University of Michigan Press, 139–187. Rid, T. (2016): Rise of the Machines. A Cybernetic History, New York, NY, Norton and Company. Ritschl, W. (1987): Menschenbilder – die Sendung vom geglückten Leben. Zauberei und Kybernetik – Heinz von Foerster, Wien, ORF Radio Österreich 1. (https://www.mediathek.at/atom/0174367E3C5-02053-00000DBC-01733A62 – Abruf: 10.07.2018; die Zahlen im Text sind Zeitangaben). Robinson, M. (1979): Classroom control: Some cybernetic comments on the possible and the impossible, Instructional Science 8(4), 369–392. Roffman, A. E. (2008): Men are grass. Bateson, Erickson, utilization and metaphor, American Journal of Clinical Hypnosis 50(2), 247–257. Rogers, P. (2003): Streisand’s home becomes hit on Web, The Mercury News, 24.06.2003. (http://www.californiacoastline.org/news/sjmerc5.html – Abruf: 10.07.2018). Rosen, R. (1999): Essays on Life Itself, New York, NY, Columbia University Press. Rosen, R. (2012): Anticipatory Systems. Philosophical, Mathematical, and Methodological Foundations, zweite Aufl., New York, NY, Springer. Rosenblueth, Arturo, N. W. u. J. B. (1943): Behavior, purpose and teleology, Philosophy of Science 10(1), 18–24. Russell, B. (1967): The Autobiography of Bertrand Russell 1872-1914, Boston und Toronto, Little, Brown and Company. Sander, K. (1999): Heinz von Foerster. 2 × 2 = grün (CD), Köln, supposeé. Schmidt, H. (1940): Die Regelungstechnik als technisches und biologisches Grundproblem, Zeitschrift des Vereines Deutscher Ingenieure 85(4). Schmidt, H. (1941): Regelungstechnik. Die technische Aufgabe und ihre wirtschaftliche, sozialpolitische und kulturpolitische Auswirkung, Zeitschrift des Vereines Deutscher Ingenieure 86(4), 81–88. Scott, B. (2009): Conversation, individuals and concepts. Some key concepts in Gordon Pask’s Interaction of Actors and Conversation Theories, Constructivist Foundations 4(3), 151–158. Segal, L. (1986): The Dream of Reality. Heinz von Foerster’s Constructivism, New York, NY, Springer. Selby-Bigge, L. A., Hrsg. (1888): Hume’s Treatise of Human Nature, Oxford, Clarendon. Seven Towns Ltd. (2010): Rubik’s Cube Solution Guide, London. (http://lghttp.38568.nexcesscd n.net/8013252/pdf/uploads/general_content/Rubiks_cube_3x3_solution-en.pdf – Abruf: 10.07.2018). Shannon, C. E. (1948): A mathematical theory of communication, The Bell System Technical Journal 27(3/4), 379–423 und 623–656. Shishko, R., Aster, R. und Chamberlain, R. G. (1995): NASA Systems Engineering Handbook, Washington, DC, NASA. Simon, H. A. (1985): What we know about the creative process, in R. L. Kuhn, Hrsg., Frontiers in Creative and Innovative Management, Cambridge, MA, Ballinger Publishing, 3–20. Sloan, S. (1999): Doing the School for Designing a Society and doing cybernetics, Paper presented at the 1999 International Syntegration Workshop and 32nd Annual Conference of the American Society for Cybernetics, 29.03. – 01.04.1999, Falls Church, VA. Sobolev, S. L., Lyapunov, A. A. und Kitov, A. I. (1953): Кому служит кибернетика (publiziert unter dem pseudonym „Materialist“), Вопросы философии 5, 210–219. Springer, C. (1996): Electronic Eros. Bodies and Desire in the Postindustrial Age, Austin, TX, University of Texas Press. Steichen, E., Hrsg. (1955): The Family of Man. The greatest photographic exhibition of all time, New York, NY, Museum of Modern Art. Taylor, F. W. (1911): The Principles of Scientific Management, London, Harper & Brothers. Tessmann, O. (2008): Collaborative design procedures for architects and engineers, Norderstedt, Books on Demand.

432 | Literatur Treister, S. (2017): Hexen 2.0, London, Black Dog Publishing. Trentowski, B. F. (1843): Stosunek Filozofii do Cybernetyki. Czyli Sztuka Rządzenia Narodem, Posen, Nakładem Księgarni J. K. Żupańskiego. Turing, A. M. (1936): On computable numbers with an application to the Entscheidungsproblem, Proceedings of the London Mathematical Society, 2 42(1), 230–265. Turing, A. M. (1950): Computing machinery and intelligence, Mind LIX(236), 433–460. Turner, F. (2013): The Democratic Surround: Multimedia and American Liberalism from World War II to the Psychedelic Sixties, Chicago, IL, University of Chicago Press. Ulmann, B. (2010): Analogrechner. Wunderwerke der Technik. Grundlagen, Geschichte und Anwendung, Oldenburg, DeGruyter. Ulmann, B. (2014): AN/FSQ-7. The Computer that Shaped the Cold War, Hawthorne, NJ, DeGruyter. Ulmann, B. (2015): Mathematik. Eine Einführung für Praktiker, Oldenburg, DeGruyter. Umpleby, S. (2003): Heinz von Foerster and the Mansfield Amendment, Cybernetics & Human Knowing 10(3/4), 187–190. Uribe, R. (1991): Tractatus Paradoxico-Philosophicus. Eine Philosophische Annäherung an Bildung. (http://bcl.ece.illinois.edu/Uribe/Deutsch/ContentsBi.htm – Abruf: 10.07.2018). Vahrenkamp, R. (2017): Die erste Informationsexplosion. Die Rolle der Lochkartentechnik bei der Bürorationalisierung in Deutschland 1910 bis 1939, TG Technikgeschichte 84, 3. Varela, F. J. (1984): Introduction. The ages of Heinz von Foerster, in F. J. Varela, Hrsg., Observing Systems, Seaside, CA, Intersystems Publications, xiii–xviii. Varela, F. J. (1997): Patterns of life: Intertwining identity and cognition, Brain and Cognition 34(1), 72–87. Varela, F. J. (2007): A brief history of the BCL. Heinz von Foerster and the Biological Computer Laboratory, in A. Müller und K. H. Müller, Hrsg., An unfinished revolution? Heinz von Foerster and the Biological Computer Laboratory/BCL, 1958–1976, Wien, edition echoraum, 277–302. Varela, F. J., Maturana, H. R. und Uribe, R. (1974): Autopoiesis. the organization of living systems, its characterization and a model, Biosystems 5(4), 187–196. von Bertalanffy, L. (1968): General System Theory. Foundations, Development, Applications, New York, NY, George Braziller. von Foerster, H. (1977): The curious bevavior of complex systems. Lessons from biology, in H. A. Linstone und W. H. C. Simmonds, Hrsg., Future Research, Reading, MA, Addison-Wesley, 104–113. von Foerster, H. (1984): Principles of self-organization – in a socio-managerial context, in H. Ulrich und G. J. B. Probst, Hrsg., Self-Organization and Management of Social Systems. Insights, Promises, Doubts, and Questions, Berlin, Springer, 2–24. von Foerster, H. (2003a): Quantum mechanical theory of memory, in C. Pias, Hrsg., Cybernetics | The Macy-conferences 1946–1953, Zürich-Berlin, Diaphanes, 98–121. von Foerster, H. (2003b): Understanding Understanding. Essays on Cybernetics and Cognition, New York, NY, Springer. von Foerster, H. (2005): Mit den Augen des anderen, in D. Batthyány und O. Zsok, Hrsg., Viktor Frankl und die Philosophie, Wien, Springer, 95–108. von Foerster, H. (2006): Sicht und Einsicht. Versuche zu einer Operativen Erkenntnistheorie, Wiesbaden, Springer. von Foerster, H. (2008): KybernEthik, Berlin, Merve Verlag. von Foerster, H. (2010a): Entdecken oder Erfinden. Wie läßt sich Verstehen verstehen?, in H. Gumin und H. Meier, Hrsg., Einführung in den Konstruktivismus, München, Pieper, 41–88. von Foerster, H. (2010b): Für Niklas Luhmann: Wie rekursiv ist Kommunikation?, in A. Ofak und P. von Hilgers, Hrsg., Rekursionen: Von Faltungen Des Wissens, Paderborn, Fink, 25–45. von Foerster, H. und Pörksen, B. (2013): Wahrheit ist die Erfindung eines Lügners. Gespräche für Skeptiker, Heidelberg, Carl Auer Verlag.

Literatur

| 433

von Foerster, H. und Schmidt, S. J., Hrsg. (1993): Wissen und Gewissen. Versuch einer Brücke, Frankfurt am Main, Suhrkamp Verlag. von Glasersfeld, E. (1987): Wissen, Sprache und Wirklichkeit. Arbeiten zum Radikalen Konstruktivismus, Braunschweig und Wiesbaden, Vierweg. von Glasersfeld, E. (1991): Abschied von der Objektivität, in P. W. und Peter Krieg, Hrsg., Das Auge des Betrachters. Beiträge zum Konstruktivismus, München, Carl Auer Verlag, 17–30. von Glasersfeld, E. (1992): Declaration of the American Society for Cybernetics, in C. V. Negoita, Hrsg., Cybernetics and Applied Systems, New York, NY, Marcel Dekker, 1–5. von Glasersfeld, E. (2005): Zwischen den Sprachen. Eine persönliche Geschichte des Radikalen Konstruktivismus (CD), Köln, supposeé (die Zahlen im Text sind Zeitangaben). von Glasersfeld, E. (2007): Aspects of constructivism. Vico, Berkeley, Piaget, in M. Larochelle, Hrsg., Key Works in Radical Constructivism, Rotterdam, Sense, 91–99. von Weizsäcker, E. U., Lovins, A. B. und Lovins, L. H. (1995): Faktor Vier: Doppelter Wohlstand – halbierter Naturverbrauch. Der neue Bericht an den Club of Rome, München, Droemer Knaur. Watzlawik, P. (2003): Die Erfundene Wirklichkeit, München und Zürich, Piper. Weinberg, G. (2001): An Introduction to General Systems Theory, New York, NY, Dorset House. Whitaker, R. (2011): From Rosenblueth to Richmond. Seminarvortrag am 10.07.2011 während einer ASC-Konferenz in Richmond, Indiana. (https://www.youtube.com/playlist?list=PL242A1FFCF3 53DC66 – Abruf: 10.07.2018; die Zahlen im Text sind Zeitangaben). Whitehead, A. N. u. B. R. (1910–1913): Principia Mathematica, London, Cambridge University Press. Wiener, N. (1948): Cybernetics; or, Control and Communication in the Animal and the Machine, Cambridge, MA, MIT Press. Wiener, N. (1949): Extrapolation, Interpolation and Smoothing of Stationary Time Series. With Engineering Applications, Cambridge, MA, MIT Press. Wiener, N. (1950): The Human Use Of Human Beings. Cybernetics And Society, Boston, MA, Houghton Mifflin. Wiener, N. (1961): Cybernetics. Or Control and Communication in the Animal and the Machine, zweite Aufl., Cambridge, MA, MIT Press. Wiener, N. (1963): Kybernetik. Regelung und Nachrichtenübertragung in Lebewesen und Maschine, Düsseldorf und Wien, Econ. Amerikanische Erstauflage Cambridge 1948. Wilden, A. (1980): System and Structure. Essays in Communication and Exchange, zweite Aufl., London, Travistock Publications. Wittgenstein, L. (1963): Tractatus Logico-Philosophicus. Logisch-Philosophische Abhandlung, Frankfurt am Main, Suhrkamp. Yans-McLaughlin, V. (1986): Science, democracy and ethics. Mobilizing culture and personality for World War II, in G. W. Stocking, Hrsg., Malinowski, Rivers, Benedict and Others: Essays on Culture and Personality, Madison, WI, University of Wisconsin Press, 184–217. Zetter, K. (2014): Countdown to Zero Day: Stuxnet and the Launch of the World’s First Digital Weapon, New York, NY, Crown. Ziccardi, G. (2013): Resistance, Liberation Technology and Human Rights in the Digital Age, Dordrecht, Springer.

Schlagwortverzeichnis Namen Adelson–Velski, Georgi Maximowitsch 4 Ahl, David H. 182, 198, 202 al–Chwarizmi, Abu Abdallah Muhammad ibn Musa 29, 40 Allende, Salvador 298 Ampère, André M. 282 Anokhin, Pyotr K. 283 Aristoteles 317, 329 [FN], 334 Ashby, W. Ross 279 [FN], 361f., 370f., 391f., 393 [FN], 394, 401, 403–406, 420, Babbage, Charles 30f. Bachmann, Paul 49 Backus, John 11 Bateson, Gregory 293f., 297, 300, 317f., 323, 325, 353, 417 Bavelas, Alex 389 Beer, A. Stafford 291 [FN], 298, 322 [FN], 423 Bertalanffy, Ludwig von 369 Bigelow, Julian 283, 310, 321, 324f., 330 Bogdanov, Alexander A. 282 Brautigan, Richard 292 Bremermann, Hans–Joachim 394 Brodie, Leo 55 Brün, Herbert 369, 399f. Chomsky, Noam 13 Church, Alonzo 24, 311 Conway, John H. 179 Cook, Stephen A. 106f. Dijkstra, Edsger Wybe 8, 103 Dostojewski, Fjodor M. 400 Eames, Charles und Ray 397, 423 Ebbinghaus, Hermann 373–376 Eckert, J. P. 31, 334 Eisenhower, Dwight D. 334f. Epimenides 322–324 Eratosthenes 191f. Euklid 29, 40, 184 Euler, Leonard 111 [FN] Foerster, Heinz von 276, 280, 284, 196f., 301, 318, 320, 324, 351, 353f., 355f., 359–361, 365, 371–373, 375f., 378–383, 388, 400f., 404–408, 414, 419–421 Forrester, Jay W. 290 https://doi.org/10.1515/9783110496253-030

Foucault, Michel 288 Frank, Helmar 420 Frege, Gottlob 323 Fremont–Smith, Frank 294, 325 Galilei, Galileo 296 [FN] Galles, David 68, 79 Gauß, Carl Friedrich 184, 187f., 193 Glanville, Ranulph 291 [FN], 297, 361f., 392, 395, 397, 411–414, 417f., 421f. Goddard, Robert H. 336–340 Henderson, Gordon 221 Hilbert, David 311 Hoare, C. A. 63 Hodges, Andrew 311, 314, 364, 402 [FN] Jarník, Vojtěch 103 Karp, Rabin 106, 116 Kauffman, Stuart 369 Kemeny, John G. 169f., 179, 187 [FN], 201f. Kennedy, John F. 290 Kitov, Anatoliy I. 299 Kittler, Friedrich A. 1, 209 [FN], 260 [FN], 263, 280, 293, 311, 388 Kolman, Arnošt J. 299 Kolmogorov, Andrey N. 331 [FN] Kraftwerk (Band) 299, 415f. Kruskal, Joseph 101–103 Kuhn, Thomas S. 287 [FN] Kurtz, Thomas E. 169f., 172 [FN], 201f. Landau, Edmund 49 Landis, Jewgeni Michailowitsch 74 Leibniz, Wilhelm Gottfried 30 Lincke, Felix 282, 285 Lissitzky, Eliezer 416 Lovelace, Ada 31 Luhmann, Niklas 386f. Lyapunov, Alexey A. 299 Machiavelli, Niccolò 52 Mandelbrot, Benoît 184 Markow, Andrei Andrejewitsch 260 Marx, Karl 303, 341 Maturana, Humberto R. 280, 355, 360, 372, 386f., 422 Mauchly, John W. 31, 334

Schlagwortverzeichnis

May, Timothy C. 364f., 368 McCreight, Edward M. 78 McCulloch, Warren 276 [FN], 289, 298, 325 McLuhan, Marshall 280, 303, 396 [FN] Mead, Margaret 293, 294 [FN]325, 388 Minsky, Marvin 327, 359 [FN] Morrison, Donald R. 89 Müller, Urban 198 Nassi, Isaac 45 Naur, Peter 11 Nelson, Theodor H. 392 Nietzsche, Friedrich 1, 209 Odobleja, Stefan 283 Olson, Frank 294 Pascal, Blaise 29f. Pask, A. Gordon 408, 411, 413 Petersen, Wolfgang 336 Piaget, Jean 360, 362 Pitts, Walter 289, 298 Platon 282, 360, 388 Popper, Karl R. 366 Puschkin, Alexander 260 Ries, Adam 29 Ringelnatz, Joachim 52 Ritchie, Dennis M. 36, 134, 204, 231, 235 Rosen, Robert 266f., 369, 371 Rosenblueth, Arturo S. 283, 321, 324f., 330 Russell, Bertrand 323, 408 Schickard, Wilhelm 29 Schmidt, Hermann 283, 296

| 435

Shannon, Claude E. 74 [FN], 260, 263 [FN], 280, 331 [FN], 341–347, 351, 353, 359 [FN], 363, 391, 413 Shneiderman, Ben 45 Sokrates 282, 318 Thompson, Ken 36 Turing, Alan M. 24f., 42, 187, 280, 292, 311f., 358f., 364, 403, 406 Uribe, Ricardo 357, 386 Van Orman Quine, Willard 195f. van Rossum, Guido 237, 245 Varela, Francisco J. 280, 355, 372, 386, 420, 422 von Foerster, Heinz 276, 280, 296f., 318, 320, 324, 334 [FN], 351, 353–356, 359–361, 365, 371–373, 375f., 378, 383, 400f., 404– 408, 414, 420f. von Glasersfeld, Ernst 324 [FN], 360–363, 422 von Neumann, John 32f., 64, 179, 285f., 290f. von Pisa, Leonardo (Fibonacci) 53 [FN] Watzlawik, Paul 389 Weizenbaum, Joseph 188 Whitehead, Alfred North 323 Whitehead, Robert 337 Wiener, Norbert 264, 280, 283, 285, 295, 297, 311, 323–325, 330f., 333f., 340–342, 379, 403, 422 Wilkes, Maurice V. 34 Wilson, Sophie 170 Wirth, Nikolas 12 Zuse, Konrad 31, 179

Apparate Abakus 29f., 310f., 355 [FN], 357f. Acorn B 202f. Aggregat 4 (V2) 340 Amiga 500 117–119 Amoeba 237 AN/FSQ–7 290 Analytical Engine 31 Android 38f. Archimedes 38, 171, 201 Arduino 2f., 34, 135, 154, 159 [FN], 163f., 221 [FN], 234f. ARM 37f., 172, 176, 201, 213 Arriflex–Kamera 337

Ashby Box 404–406 Ashby’s elementary NTM 404 AT&T–Nebenstellenanlage 364 BBC BASIC 2, 134, 170–203 BBC Micro 170f., 176, 194 [FN], 201, 203 Brunsviga Rechenmaschinen 289 [FN] Colossus 25, 292 Commodore 1084 117f.; C. 1541 118f.; C. 64 168, 194, 196, 202; C. PET 117–119; C.– BASIC V2 196 Dampfmaschine 282f., 284, 321f., 338 Dartmouth–BASIC 177–179, 215 Difference Engine 30f.

436 | Schlagwortverzeichnis dRAM 311, 376 Drohne 340 EDSAC 34 EDVAC 33f. Einstein 171 ELIZA 188 ENIAC 31–34, 138 [FN] Enigma 401–406; E.–Code 25 Epson HX20 117f. ESP8266 235 Fernschreiber 298, 362 Ferritkernspeicher 310f., 316 Fieseler Fi 103 (V1) 339 fig–FORTH 57f. Fritz X 339 Game of Life 179f., 182, 184 HP–12C 118f. HP–35 RPN Calculator 57 IAS–Computer 290 IBM AP–101 352 IBM–701 138 Intel 4004 37 Intel 8080 37 Intel 8086 37 iOS 38 Kenyon–Kreiselstabilisator 337 Linux 205, 269, 277, 384 Lorenz–Schlüsselmaschine 25, 292 M–OS 147, 155–157, 160f., 165f. macOS 205, 239 [FN], 277 Mark I 34 Mars Climate Orbiter 352 Mephisto Schachcomputer 117–119 MIOS 147, 155, 166 MOS 6502 2, 21, 61, 134, 140–157, 161, 165f., 167f., 176, 193, 213 MOS 6850/M6850 (ACIA) 147, 154 Motorola 68000 37, 150 [FN], MOUSE 2, 48, 134, 141, 147, 1541–157, 159, 162f., 165f., 214 [FN]

MOUSE2Go 134, 154, 159 [FN], 165 [FN], 166 [FN] NC–100 171 [FN] NC–150 171 [FN] NC–200 171 [FN] NeuroSky Brainwave Starter Kit 126 OpenBCI 126 Pascaline 29f. PDP–11 36f. PDP–7 36 Pianola 328 [FN] Raspberry Pi 3, 38, 135, 172, 176, 197 [FN], 201, 205, 213, 216, 221–223, 235, 237, 255, 264–268, 277f., 306 Raspbian 205, 207 [FN], 211, 215, 239 [FN], 265f., 277 RISC OS 201 SAGE 290, 363 [FN] Saturn Launch Vehicle Digital Computer 316 Saturn V 316 SCR–584 Radar 340 SIGSALY 397f. Soviet Cybernetics Review 294 Space Shuttle Discovery 352 Steadicam 336 Sun Ultra5 117–119 True BASIC 202 UNIVAC I 334f. VCS 158 VICE 196 Visual BASIC 170 W65C02 154 Whirlwind 290 Whitehead–Torpedo 337 Williamsröhre 376 X–System 397 Z3 31 Z80 21, 61, 151 [FN], 152 [FN] ZX Spectrum 57f.

Begriffe Abakus 29f., 310f., 355, 367f. Abbruchbedingung 52, 63, 189f., 224f., 232d., 257 ABC (Programmiersprache) 237

Absturz 155f., 160, 197, 352, 364 Adressbus 142f., 146f.

Schlagwortverzeichnis

Adresse 28, 138, 141–152, 155–158, 160– 163, 165f., 173, 197, 213, 217f., 226–230, 233 Adressierung 143 [FN], 148, 153, 204, 213, 227 Akkumulator (Akku) 143, 148–150, 153, 156 ALGOL–60 (Programmiersprache) 11, 169 Algorithmus 2, 7–13, 29, 32, 40–68, 75, 79, 87 [FN], 89 [FN], 91, 98, 100–107, 111–115, 125–128, 133–135, 138, 158f., 164–169, 176f., 184–189, 192–194, 202, 263, 288, 311, 348f., 379, 389 Alphabet 10f., 19, 21, 25f., 92, 101, 136 ALU 33, 136, 140 [FN], 141–143, 215 [FN] Amplifikation von Varietät 393, 395, 408–417 analog 7, 315, 320, 357, 397, 414 Analogcomputer 330, 358 Analogie 7, 73, 75, 286–289, 298, 318, 353 [FN], 360f., 370, 372, 379, 391, 409 Angewandte Informatik 1, 8f., 126 Anpassung 281–286, 295, 302, 328, 333f., 336–339, 372, 379, 400 Apfelmännchen 184–187 ARPANET 298 Array 44, 54, 61, 66, 82, 97f., 175, 181, 192, 205 [FN], 215 [FN], 229–232, 253, 319, 343, 374f., 406 ASCII 82–84, 156, 194, 251 [FN] Assembler (Programmiersprache) 2, 37, 50, 61, 133–168, 169, 173, 175f., 193f., 198, 200, 204, 209, 212–215, 227, 231, 238, 243, 250 Assemblierer 138, 144, 147, 156–158, 212 Atombombe 286 [FN], 300 Attribut 44, 86, 187, 271 [FN], 239, 241f., 245f., 249, 262, 349, 351, 394 Auge 51, 354, 417 [FN] Ausnahme 256, 262, 267 Aussagenlogik s. Logik Auszeichnungssprache 11 Automat 2, 8, 10, 18–27, 41, 125; Zellulara. 179–181, 387 Automatentheorie s. Automat Automatisierung 8, 30, 126, 295, 300, 303, 311, 325, 330, 334, 340, 416 Autonomie 289, 372, 419 Autopoiese 386–388 awk (Programmiersprache) 15 B (Programmiersprache) 209

| 437

Backus–Naur–Form (BNF) 11–13, 17; Erweiterte BNF 12f. BASIC (Programmiersprache) 2, 11, 134, 169– 202, 204, 206, 209, 219 [FN], 223, 229 [FN], 237f., 240, 241 [FN], 250, 255, 257 bedingter Sprung 27, 31, 152, 159, 223f., 315f. Befehlssatz (instruction set) 134, 151–153, 168 Beobachter 3, 188, 259, 275, 279, 286, 296, 303, 318, 328 [FN], 339, 349, 351–353, 358–363, 367, 369.372, 377, 379, 388, 391–393, 405 Beobachterabhängigkeit 275, 358, 367, 369– 371, 377, 379, 388, 391–393, 419 Berechenbarkeit 8, 10, 27f., 40, 42, 311 Betriebssystem 9, 36–38, 48, 69, 71, 139, 147, 148 [FN], 155f., 160f., 164–166, 174, 200f., 204f., 207, 214, 236f., 239, 264, 266, 268, 277f., 306 Bibliothek 38, 58, 64, 100, 205–207, 209, 2011–215, 221–223, 225, 230, 232, 235, 247 [FN], 260, 264–267, 331 binär 14, 23, 30f., 34, 66, 70–75, 77, 79– 81, 94, 119–122, 137–139, 165, 187, 308, 310, 315, 344–347, 357, 393 Bistabilität 309f., 316, 324, 335 Bit 31, 84, 87, 141–144, 146, 148f., 151f., 156, 165f., 193, 242, 315, 345 [FN], 347f., 364f. Black Box 177, 361f., 403f., 407f., 411, 418, 421 Bombe 292, 403 Boole’scher Ausdruck 44, 138, 175, 224 Brainfuck (Programmiersprache) 198–200 Bremermann–Grenze 394f. Brute Force 98, 108f., 193 Bus 33f., 141–148, 151 Byte 81, 94, 138, 144, 146f., 149, 152, 155, 157, 159, 166, 198, 215f., 237, 251 [FN], 315; Halbb./Nibble 144f.; Highb. 146, 150f., 153, 155, 163, 165; Lowb. 146, 150f., 153, 155, 163, 165; Kilob. 142, 144, 147, 154; Terab. 84 C (Programmiersprache) 2, 11, 14, 19f., 36f., 134, 175 [FN], 200, 204–236, 238–242, 245f., 250, 252f., 255–257, 262 C++ (Programmiersprache), 11, 234 [FN], 235, 245 [FN], 268

438 | Schlagwortverzeichnis Chinesischer Kompasswagen 282 Chomsky–Hierarchie 13 Cloud 38f. COBOL (Programmiersprache) 169 Compiler 9, 15, 18f., 35, 49, 134, 198, 205, 208, 210, 231, 236, 238; Brainfuck–C. 198f.; BASIC–C.169, 176; C–C. 37, 134, 205, 207–215, 217f., 220, 222, 228 [FN], 230 Compilerbau s. Compiler Computergrafik 9, 86, 170, 187; G.–Prozessor 87; G.ausgabe 159, 174, 176, 185f.; G.– Cursor 175; Farbg. 181, 184; Pixelg. 345 Computerschach 71, 98–100, 117–119, 187, 357 Computerspiel 103, 197, 202f.; C.konsole 158 Cyber warfare 285, 299 Cyberspace 285, 299 Dateisystem 71, 81 Datenbank 9, 58, 78, 175 Datenbus s. Bus Datenkapselung 175, 245 Datenkomprimierung 89, 347f. Datenstrukturen 2, 7–9, 40, 54–57, 66, 69, 72, 75, 78f., 82, 91f., 94, 97, 125, 127, 215 [FN], 258, 268, 327 Datentyp 54, 174, 185, 193, 211, 212, 214– 219, 221, 224, 231f., 240f., 245, 250, 252f., 257f., 267 Datenverarbeitung 9f., 24, 40, 57, 106, 143, 237, 394 Debugger 115, 139, 209 Deklaration 230; Variablend. 174, 178, 215, 217f., 221, 227; Funktionsd. 211, 230; Array–D. 229 [FN], 253 Design Flaw s. Fehler Determinierbarkeit 275, 302f., 314, 316, 320, 336, 368, 377, 391, 401, 407; Nicht–D. 398 [FN], 401, 403, 405, 407, 419, 422 Determiniertheit 41, 303, 317 Determinismus 41, 302f., 321, 368; Nicht–D. 23, 108 determinstisch 18–27, 41, 51, 106, 279, 269, 320; nicht–d. 18, 23–27, 41, 106 Devide and Conquer 51f., 63f., 190 dezimal 29–32, 40, 144f., 175, 178, 193, 216–218, 345 [FN], 357f.

Diagramm 18, 31, 142, 165; Flussd. 44f., 165, 349 [FN]; Aktivitätsd. 46; diagrammatisch 2; Funktionsd. 142 Dialekt 134 [FN], 138, 167, 169–173, 178, 183, 194–196, 200–202, 204, 214 digital 7, 136, 167, 290, 293, 304, 306, 308–310, 311, 314–316, 320, 358, 367, 371, 376, 385f. 388, 393 [FN], 397, 417; D.computer 1f., 7, 42 [FN], 134, 136–139, 144, 290, 304, 311f., 324, 326 [FN], 395 [FN], 376, 417, 423; D. Humanities 1, 195; d.e Rechteverwaltung, DRM 386; D.kamera 38 Digitalisierung 7, 133, 397f., 406 Dijkstra–Algorithmus 103f. Dimension 25, 82, 97, 175, 179, 184, 253 [FN], 307, 309, 311, 324 [FN], 331, 345, 409 Disassembler 156 [FN], 158, 161, 164–167, 212f., 229 [FN] diskret 36, 136, 140 [FN], 314f., 320, 357, 375, 391, 397; zeitd. 179, 315 Dualzahl 144f., 152, 156, 178, 242 dynamisch 19; d. Finitheit 41; d. Speicherverwaltung 234 [FN], 214, 234; d. Laufzeitverhalten 46; d. Programmierung 53–55, 239, 249; d. Stabilität 286, 337–340, 370, 414 Editor 15 [FN], 173, 198 [FN], 207, 209, 244 [FN], 277, 417 Effizienz 42, 46f., 229; Energiee.38 Eigenform 376, 378–381, 383, 386, 388, 408f., 413 Einschränkung 17, 286, 292, 368, 392f., 395f., 400, 408, 413 Elektronenröhre 31f., 140, 336 [FN], 393 [FN] Emergenz 137, 179, 288 Empirie 287, 303, 317, 329, 364–368, 373, 379 Emulator/Emulation 2, 37, 57f., 134f., 154, 159 [FN], 162 [FN], 166 [FN], 168, 170 [FN], 200, 207 Endlichkeit 12, 18–21, 23, 25, 27f., 40f., 69, 312, 320, 396 Entscheidung 51, 106, 119, 121, 126, 208, 335, 351, 357, 418; E.baum 119–121, 126; E.problem 106, 311; if–E. 223f., 246 Epistemologie 2, 133, 173, 193, 276 [FN], 302, 360–362, 411, 419, 422 EPROM 34, 154 [FN] Erster Weltkrieg 330

Schlagwortverzeichnis

Ethik 127, 286, 296–301, 369, 372, 383, 417 [FN], 411, 419, 422 Eulerkreis 111f. Extrapolation 330f., 333 Feedback 278f., 282–284, 294, 321, 325, 333, 339–341, 392, 396, 411, 416; positives F. 338–340, 388, 409, 413, 418); negatives F. 337–340, 362, 409 Feedforward 333f., 341 Fehler/Error 22–24, 35, 44, 126, 138f., 150 [FN], 158, 160, 173, 178, 205, 208, 210– 212, 215, 217f., 226–228, 230, 241, 243f., 247 [FN], 252, 256f., 262 [FN], 269, 324, 335, 338, 342, 347, 380, 411, 414f. Fehlerkorrektur 320, 347 Fibonacci–Sequenz 33, 53f., 381 FIFO 56 finite state machine (FSM) s. Zustandsautomat Fliehkraft 338; F.pendel 282; F.regler 282–284 Fließkommazahl 31, 175, 215, 217–220, 227, 240 Flip–Flop 143, 310f., 324 Flugabwehr 330, 333f. Forth (Programmiersprache) 21, 55, 57f. Fraktal 184, 185f., 352, 408f. Freiheit 291–293, 408; Wertf. 289, 358; Willensf. 302, 321; F.bewegung 291 Frequenz 125 [FN], 309, 340, 344f., 347, 353, 356, 364, 396, 398; Taktf. 31, 159; F.spektrum 396 Funktion (math./algor.) 19, 21–23, 25f., 30, 41f., 49, 52f., 56, 66., 82–86, 91, 103, 106, 137, 148 [FN], 165, 172, 174–176, 179, 187, 189–191, 201, 210f., 213f., 216f., 219–223, 224, 226 [FN], 227–234, 240– 242, 244 [FN], 245–247, 249, 251, 254, 256f., 259 [FN], 263f., 266, 318f., 333, 349 [FN], 373, 375, 417 Funktion (techn.) 1, 31, 34, 136f., 139–142, 156, 164f., 167, 170, 288, 300, 311, 317– 319, 324, 327, 336, 383, 401, 404–408 Gedächtnis 138, 373, 376f., 379, 383 Gehirn 25, 289, 296; G.wäsche 294; G.ströme 126 Genealogie 133, 195 Generalisierung 204, 223 Geometrie 40, 184 Gimbal 337, 339 GNU 205, 269, 277, 384

| 439

GOTO 28, 170, 173–175, 194, 198, 202, 223, 226 Grammatik 10–18, 27 Graph 2, 9, 40, 45, 90–105, 107–111, 125, 307, 375 [FN], 377f., 380 Graphical Processing Unit (GPU) 87 Greedy–Algorithmus 103, 109, 119 Gyroskop 337–340, 372 Hacking/Hack 156, 167 [FN], 176, 179, 195, 200, 237, 268 Halbbyte (Nibble). s. Byte Halbleiter 8; H.strukturen 10; H.industrie 364, 368 Hardware 3, 7, 21, 31, 38f., 134f.; H.entwurf 9, 19; H.architektur 34; H.plattform 49 Hashing 9, 53, 82–87, 125, 258, 259 [FN] Haufen (heap) 66–68, 228 [FN], 234 Heimcomputer 21, 57f., 168, 177, 184, 187, 194, 201, 237 Heuristik 9, 40, 51, 106–124, 125, 188 hexadezimal 19, 20, 144, 144 [FN], 145, 146 [FN], 152, 156–158, 175, 178 Homeostat 370f. Homöostase 321, 338, 355 HTML 11, 266 [FN], 414 Hysterese 309, 316, 335, 377 I/O 140, 142, 147, 154–156, 158, 161, 168, 175; I/O–Maschine 311, 318, 324, 403, 405 imperative Programmierung 57, 137, 174, 235, 241 Information 7, 8, 20, 29, 56, 69, 82, 89 [FN], 90f., 101, 125, 146, 263 [FN], 279, 341 343, 347; I.sgehalt 347–349, 353, 357, 360, 363, 376; I.sgesellschaft 295, 423; I.stheorie 1, 74 [FN], 188, 341f.; I.sübertragung 10, 353; I.sverarbeitung 8– 10, 89, 125, 251 [FN], 334 Initialisierung 160, 170, 222, 244f., 262 Innovation 291, 385 Instanz 240, 242f., 245, 247 Integer 84, 175, 210, 215 Interaktion 9, 136, 280, 327, 361, 388, 413, 417 Interdisziplinarität 1, 133, 276, 278, 301, 330 Interpolation 330f., 357 Interpreter 134, 139, 169, 172–174, 176, 198f., 207 [FN], 237–244, 247, 256, 258f., 264 Interrupt 144, 147, 155, 161–164, 214 [FN]

440 | Schlagwortverzeichnis Iteration/Iterator 184–186, 188f., 255–260, 262, 267, 269, 380 Java (Programmiersprache) 11, 32, 44, 245 [FN], 255 Javascript (Programmiersprache) 86, 168 Kalkül 137, 289 Kalter Krieg 290f., 298 Kellerautomat 18, 20–24, 27 Kellerspeicher 21–24, 56 Kolmogorov–Komplexität 347f. Kombinatorik 51, 116, 417 Kommunikation 1, 11, 33, 125, 147, 156, 278–281, 284, 292f., 341–344, 346, 352f., 362f., 386–388, 393, 396, 400, 413; K.stheorie 280, 342, 347 komplexe Zahl 184f., 409 Komplexität 2, 7, 8, 10, 19, 25, 30, 40, 42, 44, 46–50, 57, 60, 64, 66–68, 106f., 125, 136, 138, 167, 170, 205, 214, 215 [FN], 241, 248 [FN], 253, 258 [FN], 264, 269, 287–289, 347–351 Kontext 16, 261f., 275, 283, 287, 295f., 298, 300f., 303, 322, 325, 326 [FN], 329, 338 [FN], 341, 345, 351f., 361f., 365 [FN], 369, 371, 377, 384–386, 407; k.freie Sprache 13, 15–18, 22, 27; k.sensitive Sprache 13, 16–18, 27 Kontrolle 78, 278f., 285f., 291 [FN], 292–294, 296, 298, 300, 302, 306 [FN], 320f., 325, 336, 340f., 357, 386, 392f., 395–397, 411, 413f., 418; Rechtschreibtk. 278, 417f. Konversation 365 [FN], 408f., 411–419, 422; K.stheorie 408, 411, 413 Konvertierung 178f., 194, 264f., 398 Korrektheit 10f., 15, 22, 29, 42, 57, 61, 138, 142, 150 [FN], 158, 161, 208, 210–212, 214, 216, 226, 230, 233, 243, 310, 326, 330, 361, 365, 389, 400, 417 Kreativität 44, 355, 359 [FN], 365, 385f., 413f., 416f., 419 Kryptographie/Kryptologie 25, 86, 106, 292f., 362, 364, 403, 405 Kulturtechnik 133, 176, 204 Künstliche Intelligenz (KI/AI) 1, 9, 38, 187f., 297, 327, 359, 384 Kybernetik 1f., 134, 237, 264, 274–433; K. erster Ordnung 3, 296f., 303, 321, 341, 414, 420; K. zweiter Ordnung 3, 263, 275f., 296f., 299–302, 325, 330 [FN], 341, 361f.,

367–370, 372, 387, 396 [FN], 407 [FN], 408, 413f., 420–422 Label 28, 138, 173, 223 [FN] Laufzeit 42, 46–50, 53, 59f., 63f., 67, 77, 85, 88, 92, 94, 134, 173, 200, 224; L.analyse 59f., 64, 74, 86; L.fehler 139; L.leitung 376 lineare Kausalität 325, 329, 367 LISP (Programmiersprache) 198 Liste 11 [FN], 54–67, 74, 77, 82, 85, 88, 92, 116, 242, 245, 253–263, 266, 278, 314, 326, 333; Adjazenzl. 91f.; Parameterl. 210– 212, 219, 242, 245–247 Lochkarte 31, 35, 291 Logik 1f., 8, 10, 30, 127, 136f., 195, 266, 279, 318, 322, 324, 328f., 368; L.gatter 289, 310, 320; Kontroll. 141; Aussagenl. 318, 322, 324, 328 Logo (Programmiersprache) 170 Mächtigkeit 13, 27, 32, 264 Macy–Konferenzen 278, 289, 294, 299 [FN], 310, 325, 370, 373, 389, 421, 423 Magnetband 385, 414 Mandelbrot–Menge s.Fraktal Maschinensprache 36, 136–139, 147, 155, 157 [FN], 160, 168, 170, 173, 175f., 193, 194 [FN], 212–215, 219 [FN], 223f., 236, 238 Mathematik 8, 29, 31, 40, 74, 101, 103, 111 [FN], 127f., 169, 179, 184, 188, 192, 260, 265 [FN], 280, 286, 296, 311, 323f., 331, 334, 400 Medien M.geschichte 172; M.kompetenz 389, 419; M.wissenschaft 1, 2, 7, 9, 100, 127, 133–135, 139, 154, 164, 172, 200–202, 204, 209, 235, 237, 241 [FN], 258, 260, 268, 275, 278–280, 341, 419; M.archäologie 205, 238 [FN], 279; Multimedia 9, 136; Massenm. 293, 335, 384, 400; soziale M. 90, 335, 388f. Mengenlehre 8, 323, 329 [FN] Messung 152, 221, 224, 226, 282, 284, 296, 306–309, 325, 337f., 347f., 352f., 357, 364f., 367, 397 Methode 1, 72, 86, 88, 148, 219, 241f., 244– 246, 247 [FN], 249–251, 254, 256, 259, 262f., 279f., 293, 311, 330f., 333, 342, 347, 352, 366; M.definition 244 [FN], 245f.; M.aufruf 246; Kongruenzm. 84; Modellierungsm. 46

Schlagwortverzeichnis

Mikrocontroller 7, 34, 37f., 167 [FN], 221 [FN], 234f., 340 Mikroelektronik 136f. Mikroprogramm (Micro Code) 9, 137, 139– 141, 152 Mikroprozessor (CPU) 21, 33, 37, 56, 134, 137, 139–144, 146–148, 151f., 154, 156, 158–161, 163, 165, 167f., 176, 213, 215, 266, 306 [FN], 333 Militär 25, 32, 52, 283, 285, 290–294, 297– 299, 334, 336, 385, 395, 413 Miniaturisierung 7, 36f. Minicomputer 36, 140 [FN], 144 [FN] MKULTRA 294, 299 Mnemonic 138, 156 [FN], 158, 174, 176, 213, 318 [FN] Modeling Relation 366f., 379 Modellrechner 18 Mondlandung 182, 290f. Monitor (Software) 35, 165 Moral 363, 372 Morse–Kommunikation 393, 396, 401 MOS (Metal Oxide Semiconductor) 364, 367, 411; CM. 151 [FN] Multitasking 36, 136, 161 Mustererkennung 38, 126, 389f. Navigation 104, 282, 409; N.sgerät 38, 88f., 340 Nervensystem 280, 289, 327, 353–356, 360, 388, 419 Netzwerk 9, 38, 90, 101, 107, 285, 289f., 292, 298, 326 [FN], 328 [FN], 371, 386, 388; N.protokoll 19, 101 Nibble s. Byte Nicht–Linearität Nicht–Trivial 320, 335 [FN], 414; N.e Maschine 320, 405f. NP–vollständig 106, 116 Objektivität 277, 280, 287, 289, 302f., 322, 347, 353, 359–363, 365, 367–370 objektorientiert 2, 29, 46, 69, 72, 86, 116, 134f., 175, 219 [FN], 226, 234, 241–250, 253, 268f. Opcode 137f., 141, 143f., 146, 148, 151–153, 155, 159–162, 165, 168, 175f.; illegaler O. 151 [FN]; Pseudo–O. 138, 157 [FN], 158, 212 Operator 26f., 56f., 215–217, 220, 227f., 230, 233f., 246 [FN], 254, 256 [FN]

| 441

Optimierung 59, 62, 119, 156, 236, 295; O.problem 100, 106f.m 116, 119 Orakel 23f., 106 Ordnung 57, 66, 69, 73, 260, 263, 288, 292, 304, 347, 351,;O.kriterium/–prinzip 66, 79, 377, 390 orthogonal 134, 143 [FN] Oszillation 309, 321, 324, 328, 335, 382 Output 189, 212, 221f., 225, 304, 316–319, 325f., 355 [FN], 361f., 365, 376–379, 388, 398f., 402–406, 408, 411, 413f., 417 Palindrom 23f. Papiermaschine 25, 165 [FN] paradox 110, 196, 302, 325, 328f., 352, 388; Lügnerp. 277; Logisches P. 322–324 Pascal (Programmiersprache) 12, 170, 219 [FN], 237 Peripherie 140, 147, 165 Perl (Programmiersprache) 15, 255 [FN] PHP (Programmiersprache) 255 [FN] physical computing 235, 268, 395 Plattform 37, 47–49, 51, 134, 170, 171–172, 200, 205, 235, 268 [FN], 277f., 385 Portierung 170, 172, 194, 214 Praktische Informatik 7f. Primzahl 40, 84, 106 [FN], 191f., 306 [FN], 345 Principia Mathematica 323, 408 Programmierparadigma 134f., 137, 169, 219 Programmierschnittstelle (API) 58, 245, 268 Project Cybersyn 298 Prozessorientierung 328 [FN], 329, 368 Pseudocode 43f., 46, 127, 134 Quellcode (Source Code) 166f., 177f., 194 [FN], 195, 206–208, 210f., 214, 218 [FN], 231 [FN], 235f., 238f., 244f., 247, 251, 258 [FN], 266 Quine (Software)195–197 Radar 330, 340 Radio 7, 341 RAM 34, 140, 142f., 146–150, 154f., 157, 160, 162, 165, 167 Raumfahrt 290, 299, 336 Re–Enactment 2, 176 Rechenschieber 357f. Rechentabelle 30 Redundanz 298, 316, 348 Regelkreis 281–283, 286, 327f., 392 Regelungstechnik 283, 296

442 | Schlagwortverzeichnis Register 28, 31, 139–144, 146, 148– 153, 162, 165, 213–215, 224, 229 [FN]; (R.maschine) 27f. regulär 13–15, 17–19, 27; (r.er Ausdruck) 14f., 264 Regulierung 281f., 284, 291f., 306, 333, 338, 371, 419 Rekursion/rekursiv 13, 16–18, 27, 52–54, 63f., 66, 69, 72, 186, 189–191, 367, 374, 379f., 409 Relais 31, 140, 286 Resilienz 288, 298 Resource 394 Retrocomputing 170, 197, 200 reverse engineering 177 Ringkern 35f. ROM 34, 140, 147f., 154f., 164f., 170 Routing 104 Rückkopplung 279, 338 Sampling 385, 396, 399 Schaltdifferenz 309 Schaltpunkt 309 Schleife 31, 44, 46–50, 52, 139, 159f., 162f., 166, 174f., 186, 188, 193, 224, 226, 232, 233f., 255–257, 259, 262, 276, 279, 309, 324, 332f., 377, 410, 414f. Schnittstelle 9, 58, 136, 161, 200, 204f., 245, 268, 278, 280, 303, 306, 362, 400 Schranke 49, 50, 119, 121, 399 Schreibmaschine 304, 311, 314, 316f., 401 schweres Problem 9, 40, 106, 125 sed (Programmiersprache) 15 Selbstbestimmung 372, 400 Selbsterhaltung 369, 370 Selbstorganisation 275, 285, 377, 383, 388, 419 Selbstreferenz 196, 296, 372, 442 Selbstregulierung 285, 324, 327, 384 Selbstwahrnehmung 300, 384, 388 Semantik 10f., 363 Sequenz 33, 49, 255–257, 288, 318, 345, 351, 381, 385, 387 seriell 147, 156, 34 Shannon–Entropie 347 shell 174, 239 Signale 136f., 142, 161, 162f., 176, 260, 263– 266, 279f., 284, 315f., 320, 327f., 336, 338, 340–342, 344–347, 353–356, 360, 376, 388, 392f., 396–398, 401f.

Simulation 3, 32, 37, 133, 168, 182, 184, 203, 298 Skriptsprache 14, 237 Smalltalk (Programmiersprache) 268 Software 3, 7, 18, 21, 31, 38, 42, 44, 46, 49, 117, 137f., 147, 154f., 162, 167, 238, 268f., 277, 384 ;S.–Agent 126; S. Studies 194f., 202 Sound 170, 174, 176, 343, 415 Sowjetunion/sowjetisch 74, 286, 288–290, 294, 298f., 303 soziales Netzwerk 90, 388 Speicher/Speicherung 8f., 21, 31–33, 55f., 59, 71, 81f., 84f., 88, 89, 91, 94, 134, 136– 139, 141–144, 146–149, 152, 155, 156 [FN], 157f., 160f., 167, 170, 175, 189f., 197, 207, 212, 214–218, 223, 226f., 229–231, 238f., 245 [FN], 246, 247 [FN], 249, 259 [FN], 261, 263, 277, 309–312, 316, 347, 359 [FN], 364, 367, 373f., 391, 411; S.werk 31, 33 Spiel 103, 179, 184, 187, 189, 197, 226, 372, 417; S.theorie 290f.; S.uhr 328 [FN]; S.würfel 391, 407 Sprung 28, 149 [FN]; S.befehl 143, 152, 223f. Stabilität 286, 321, 336, 337, 388f., 414 Stack 21, 54, 56f., 143, 146f., 152f., 155, 160 [FN], 162, 190f., 214, 228, 229, 234f., 374; S. Pointer 143, 146, 190f. Stapelverarbeitung 35 Statistik 101 Status–Bit (Flag) 144, 152 Statusregister 144, 162 Steuerung 2, 18f., 25, 137, 174f., 221, 280f., 285, 296, 311, 333, 336, 340, 372 Steuerungsbus 142 Steuerwerk 19, 33f., 140 [FN], 141 Stochastik 85f., 260, 328 Stoffwechsel 281, 384, 387 Struktogramm 44f. Struktur 50, 69, 74, 133, 139, 152, 173, 184, 194, 213, 223 [FN], 283, 309, 317f., 365f.; S.wissenschaft 3, 275, 286; s.elle Kopplung 360 strukturiert 43, 125 [FN], 137 Supercomputer 237 Syllogismus 318 Symbol/symbolisch 10–12, 14–16, 19–22, 24–26, 31, 42 [FN], 45, 49, 78, 133, 137f.,

Schlagwortverzeichnis

167, 212, 217 [FN], 285, 304, 309, 311, 313–318, 339, 345f., 348, 351, 358f., 397; S.verarbeitung 25, 309, 314, 401; S.vorrat 311, 315, 319f., 347, 391, 396, 397, 405 Syntax (syntaktisch) 10f., 28, 43, 138, 158, 179, 193, 204 [FN], 207 [FN], 208, 210, 219, 242 [FN], 243, 246, 249, 258 [FN], 262 [FN], 266 [FN] Systemgrenzen 300, 339, 369–371, 384 systemische Geschlossenheit 376f. systemische Offenheit 376, 384, 386 Systemprogrammiersprache 134, 204, 214 systems engineering 291 Systemtheorie 277, 283, 369, 376 Takt 152, 159f., 315 Taschenrechner 37, 56, 118f., 381 TCP/IP 11 Technische Informatik 2, 7–9, 29, 125, 136, 237 Teleologie 284, 321 TensorFlow Processing Unit (TPU) 39 Terminiertheit 41 Textverarbeitung/–sprogramm 161, 278, 304, 417 Theoretische Informatik 8–10, 19, 22, 125, 127, 137 Thermodynamik 304, 376 Thermostat 304f., 307–309, 321f., 324, 327f., 391–393, 396, 416 Transistor 35f., 104 [FN], 141, 168, 364, 393 [FN]; T.–T.–Logik, TTL 310 Transkomputabilität 394–396 Trapdoor 86, 106 trial and error 96 Triviale Maschine 304, 306, 319, 361 Trivialisierung 400f., 406, 414 Turing–Mächtigkeit 25, 32 Turing–Test 359 Turingmaschine 18, 23–27, 42, 125, 134, 289, 304, 311–316, 328, 358f. Überlauf 79–81, 151, 230 [FN] unconventional computing 181 [FN] Unicode 251 Unified Modeling Language (UML) 44, 46 Universalmaschine s. Turingmaschine Unix 15 [FN], 36f., 71, 204f., 207, 211f., 214, 236f., 239 Unterlauf 80f., 179

| 443

Unterprogramm/Subroutine 35, 45, 50, 56, 155, 162, 165, 174, 184, 190f., 197, 219 [FN] Variable 11, 14, 28, 32, 44, 138, 146, 170, 174f., 178, 184, 186, 193, 194 [FN], 196, 214–220, 223–229, 23f., 240–242, 245– 247, 250, 253, 255–258, 262, 266, 309, 312, 318, 370 [FN], 375 [FN], 380, 394 verbotene Zone 310, 393 [FN] vernetzt/Vernetzung s. Netzwerk Verstärker/Verstärkung 336 [FN], 338f., 356, 378, 381, 389, 418 Verzweigung (branch) 41, 44–48, 50, 66, 70, 78f., 96, 106, 119, 121, 144, 149, 152, 174, 197f., 316; V.sgrad 70, 78–81, 94 Viabilität/viabel 298, 361, 363, 366, 388, 413 Vinyl–Schallplatten 385 virtuelle Realität 290, 299 Vocoder 398, 415f. Von–Neumann–Architektur 33f., 134, 137, 160, 359 Warteschlange 56, 92f. Warteschleife 50, 139, 158–160, 224 [FN] Werkzeug (Tool) 1f., 8, 14f., 28, 46, 100, 125, 136, 168, 178, 192, 204, 209, 215, 226, 281, 352, 359 [FN], 364, 417f. Wissen 1f., 133, 167, 177, 192, 236, 267, 353 [FN], 372, 420, 422 Wissenschaft 1, 8, 10, 237, 275f., 280–283, 286–288, 291, 299, 317, 325, 329, 331, 364–368, 372, 399, 419, 421; W.theorie 361 Wortbreite 84, 144, 167 XML 11 Zeichenkette 14, 23, 87f., 174, 197, 199, 210, 213–216, 229 [FN], 230–233, 246, 250– 255, 258, 262f., 266, 312, 348, 417 Zeit (medial) 2, 41, 47, 48–51, 64, 66, 68, 82, 159, 226, 229, 308, 379, 391f., 394; Z.komplexität 42, 47f., 82, 96, 106, 159, 189, 192, 402; z.kritisch 158, 175; z.gleich 34, 36, 396; z.diskret 136, 179, 304, 315, 348, 376 Zellularautomat 179, 181, 386 Zeropage 146, 149–153, 155 Zufall 264; Z.generator 187, 194, 206, 225, 406 Zustand 18–22, 24–27, 42, 113–116, 137f., 144, 165 [FN], 260, 304, 308–310, 312,

444 | Schlagwortverzeichnis 314–316, 320f., 324, 328, 338, 348, 370 [FN], 376, 392, 402, 406, 408; Z.sautomat 18–21, 23, 25, 27, 41, 314, 401; Z.änderungen/wechsel/übergang 18,

21–23, 308f., 321, 328, 364, 402, 404; systemische Z. 289, 391–396 Zweiter Weltkrieg 278–281, 283, 292f., 325, 330f., 342, 397, 400f., 403, 406