{"id":2572,"date":"2013-08-30T13:53:36","date_gmt":"2013-08-30T11:53:36","guid":{"rendered":"http:\/\/fernuni.digreb.net\/?p=2572"},"modified":"2025-11-25T22:48:11","modified_gmt":"2025-11-25T21:48:11","slug":"kleiner-exkurs-utm-smn-theorem-und-programmiersprachen","status":"publish","type":"post","link":"https:\/\/fernuni.digreb.net\/?p=2572","title":{"rendered":"Kleiner Exkurs: utm-\/smn-Theorem und Programmiersprachen&#8230;"},"content":{"rendered":"\n<p>&#8230; und unsere Nummerierungen von \\(P^{(1)}\\).<\/p>\n\n\n\n<p>Da ich mittlerweile ein paar Mails zu diesem Thema bekommen habe, w\u00fcrde ich hier gerne noch etwas erl\u00e4utern. F\u00fcr viele ist das Theorem noch nicht greifbar. Ebensowenig die Nummerierung \\(\\varphi\\) der einstelligen, berechenbaren Funktionen&nbsp;\\(P^{(1)}\\). Auch den Begriff Modellprogrammiersprache in Bezug auf \\(\\varphi\\) haben ein paar geh\u00f6rt, k\u00f6nnen das aber noch nicht so ganz &#8222;anfassen&#8220;. Ich versuche mal mal Gl\u00fcck, vielleicht wird es nach meinen Ausf\u00fchrungen f\u00fcr euch etwas deutlicher.<\/p>\n\n\n\n<p><strong>Achtung<\/strong>: w\u00e4hrend wir im Skript \\(P^{(1)}\\) direkt nummerieren, gehe ich zun\u00e4chst einen etwas anderen Weg. Also nicht erschrecken. Am Ende folgt die Aufl\u00f6sung.<\/p>\n\n\n\n<p><strong>Zun\u00e4chst: Warum ist \\(\\varphi\\) eine Programmiersprache?<\/strong><\/p>\n\n\n\n<p>Sicher habt Ihr schon einmal im Kurs imperative Programmierung (01613) oder Einf\u00fchrung in die objektorientierte Programmierung (01618) belegt. Dort programmieren wir in Java und Pascal. Was hat nun Java und Pascal mit uns und \\(\\varphi\\) zu tun?!<\/p>\n\n\n\n<p>Z\u00e4umen wir das Pferd mal von hinten auf.<\/p>\n\n\n\n<p>Nehmen wir zun\u00e4chst eine Funktion \\(f(x)=x\\), d.h. unsere Identit\u00e4tsfunktion aus&nbsp;\\(P^{(1)}\\). Im Endeffekt wollen wir diese Funktion auf unserem Computer, unserer Turingmaschine berechnen. Wir k\u00f6nnen, wie man sich leicht vorstellt, eine beliebige Funktion nehmen. Aber \\(f\\) reicht f\u00fcr unsere Zwecke komplett aus.<\/p>\n\n\n\n<p>So sieht unser Programm in PASCAL aus:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>begin\n\n  writeln(ParamStr(1));\n\nend.<\/code><\/pre>\n\n\n\n<p>Und so in Java<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>public static void main(String &#091;]args){\n\n  System.out.println(args&#091;0]);\n\n}<\/code><\/pre>\n\n\n\n<p>(Bitte nicht darauf festnageln, dass ich &#8222;public class&#8220; bei Java und &#8222;program&#8220; bei PASCAL vergessen habe, mir geht es nur um&#8217;s Verst\u00e4ndnis)<\/p>\n\n\n\n<p>Wir sind uns einig, dass damit die Funktion&nbsp;\\(f\\) berechnet wird? Gut. Und da wir \\(\\varphi\\) eine Programmiersprache genannt und gesagt haben, dass es nur eine Programmiersprache zu geben braucht (\u00c4quivalenz und so), nennen wir die Programmiersprache Java einfach \\(\\kappa\\) (Kappa) und PASCAL \\(\\omicron\\) (Omicron). Das sind also unsere Nummerierungen von \\(P^{(1)}\\), bzw. sollen es einmal werden.<\/p>\n\n\n\n<p>Erinnert Ihr euch, wie \\(\\varphi\\) definiert war? Das machen wir mit \\(\\kappa\\) und \\(\\omicron\\) genauso! Wir haben nur ein anderes Alphabet. Hatten wir bei \\(\\varphi\\) das Alphabet&nbsp;\\(\\Omega:=(1\\mid{B}\\mid{(}\\mid{)}\\mid{,}\\mid{:}\\mid{R}\\mid{L})\\), so sind wir bei&nbsp;\\(\\kappa\\) und \\(\\omicron\\) bei ein paar mehr Zeichen. Ich f\u00fchre sie jetzt nicht alle auf, aber die paar sollten gen\u00fcgen. Wir m\u00fcssen unsere Programme von oben mit Zeichen aus diesem Alphabet darstellen k\u00f6nnen:<\/p>\n\n\n\\(\\Omega_\\kappa:=(b\\mid{e}\\mid{g}\\mid{i}\\mid{n}\\mid{(}\\mid{)}\\mid{;}\\mid{.}, &#8230;)\\)\n\n\n\\(\\Omega_\\omicron:=(p\\mid{u}\\mid{b}\\mid{l}\\mid{i}\\mid{(}\\mid{)}\\mid{[}\\mid{:}\\mid{]}\\mid{;}, &#8230;)\\)\n\n\n\n<p>Wie gesagt: nicht alle Zeichen drin. Hauptsache Ihr wisst, worauf ich hinaus will. Kommen wir nun zu unseren Nummerierungen \\(\\kappa\\) und \\(\\omicron\\). Diese werden genauso definiert wie unser \\(\\varphi\\).<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Ordnungsfunktion \\(a\\) und \\(b\\) f\u00fcr die Alphabete \\(\\Omega_\\kappa\\) und \\(\\Omega_\\omicron\\), so dass wir mit \\(\\nu_{\\Omega_\\kappa}\\) und \\(\\nu_{\\Omega_\\omicron}\\)\u00a0die Nummerierung aller Worte aus \\(\\Omega_\\kappa^{*}\\) und \\(\\Omega_\\omicron^{*}\\)\u00a0haben. Und wie bei \\(\\nu_\\Omega\\) nicht nur Programme, sondern auch Kauderwelsch wie z.B. \\(&#8222;g(;b&#8220;\\).<\/li>\n\n\n\n<li>\\(\\nu_P\\kappa : \\mathbb{N} \\rightarrow BP\\), z.B. \\(\\nu_P\\kappa(i)\\) als die Nummerierung des Bandprogramms \\(i\\). Es ist definiert durch:<br><\/li>\n<\/ul>\n\n\n\\(\\nu_P\\kappa(i)=\\begin{cases}\\nu_{\\Omega_\\kappa}(i)&amp;\\text{ wenn }\\nu_{\\Omega_\\kappa}(i)\\in{BP}\\\\Endlosschleife&amp;\\text {sonst}\\end{cases}\\)\n\n\n\n<p>Wir bekommen damit zur Nummer \\(i\\) das zugeh\u00f6rige Bandprogramm wenn es tats\u00e4chlich ein Bandprogramm ist. Oder einfach nur eine Endlosschleife wenn die Nummer \\(i\\) zu irgendwelchem Kauderwelsch geh\u00f6rt, denn mit \\(\\nu_{\\Omega_\\kappa}\\) haben wir (siehe oben) alle Worte \u00fcber \\(\\Omega_\\kappa\\), d.h. auch Unsinn, nummeriert.\n<\/p>\n\n\n\n<li>&nbsp;\\(\\nu_P\\omicron: \\mathbb{N} \\rightarrow BP\\) wird genauso definiert wie&nbsp;\\(\\nu_P\\kappa : \\mathbb{N} \\rightarrow BP\\)<\/li>\n\n\n\n<li>\\(\\nu_{M\\kappa} : \\subseteq \\Omega_\\kappa^{*} \\rightarrow BM\\) und \\(\\nu_{M\\omicron} : \\subseteq \\Omega_\\omicron^{*} \\rightarrow BM\\). Damit bekommen wir zum den Worten \\(\\omega_\\kappa\\) und \\(\\omega_\\omicron\\)&nbsp;(Achtung: die Worte sind nach der Definition von \\(\\nu_P\\kappa\\)&nbsp;und \\(\\nu_P\\omicron\\) immer die Worte eines echten Bandprogramms aus der Sprache PASCAL (\\(\\Omega_\\kappa\\)) oder Java (\\(\\Omega_\\omicron\\)). &nbsp;Auch wenn es Endlosschleifen sind, weil die Zahl nicht zu einem Bandprogramm, sondern zu Kauderwelsch geh\u00f6rt hat.<\/li>\n\n\n\n<li>Funktion \\(\\xi:BM \\rightarrow P^{(1)}\\) mit &nbsp;\\(\\xi(M) := \\iota^{-1}{f{_M}}\\iota\\).&nbsp;\\(\\xi(M)\\) ist also die Funktion aus \\(P^{(1)}\\), welche die Funktion der Bandmaschine \\(M\\) berechnet.\n<p>Warum haben wir kein \\(\\xi_\\kappa\\) und kein&nbsp;\\(\\xi_\\omicron\\)? Sehen wir gleich!<\/p><\/li>\n\n\n\n<p>Wir haben mit Java und Pascal also das gemacht, was wir mit&nbsp;\\(\\varphi\\) getan haben. Nur nutzten wir nicht&nbsp;\\(\\Omega:=(1\\mid{B}\\mid{(}\\mid{)}\\mid{,}\\mid{:}\\mid{R}\\mid{L})\\) als &#8222;Programmieralphabet&#8220;, sondern&nbsp;\\(\\Omega_\\kappa\\) f\u00fcr unsere Zeichen der PASCAL-Programme und&nbsp;\\(\\Omega_\\omicron\\) f\u00fcr Java.<\/p>\n\n\n\n<p>Das f\u00fchrt uns zu ihren Kompositionen:<\/p>\n\n\n\\(\\kappa = \\xi\\circ\\nu_M\\kappa\\circ\\nu_P\\kappa\\)\n\n\n\\(\\omicron = \\xi\\circ\\nu_M\\omicron\\circ\\nu_P\\omicron\\)\n\n\n\n<p>Die ebenfalls Nummerierungen von \\(P^{(1)}\\) sind. Damit sie zu \\(\\varphi\\) \u00e4quivalent sind, m\u00fcssen sie das utm- und das smt-Theorem erf\u00fcllen. Kommen wir daher zum utm-Theorem.<\/p>\n\n\n\n<p><strong>utm-Theorem f\u00fcr \\(\\kappa\\) und \\(\\omicron\\)<\/strong><\/p>\n\n\n\n<p>Intuitiv wisst Ihr schon, dass beide Programmiersprachen das utm-Theorem erf\u00fcllen. Sie k\u00f6nnen interpretiert\/compiliert werden und unsere Funktion berechnen. Das k\u00f6nnt Ihr im zugeh\u00f6rigen Compiler testen.<\/p>\n\n\n\n<p>Und genau das ist unser \\(u\\) aus der Definition des utm-Theorems:<\/p>\n\n\n\\(u_\\varphi(i,x) = \\varphi_i(x)\\)\n\n\n\\(u_\\kappa(i,x) = \\kappa_i(x)\\)\n\n\n\\(u_\\omicron(i,x) = \\omicron_i(x)\\)\n\n\n\n<p>Euch ist sicherlich auch klar, dass jeder Compiler\/Interpreter f\u00fcr jede Programmiersprache unterschiedlich ist. W\u00e4hrend ich f\u00fcr PASCAL Befehle wie &#8222;<em>Writeln()<\/em>;&#8220; interpretieren und in Maschinencode f\u00fcr x86 (oder andere Prozessoren) \u00fcbersetzen darf, muss ich f\u00fcr Java Zeug in Form von &#8222;<em>System.out.println();<\/em>&#8220; interpretieren. W\u00e4hrend beide g\u00e4nzlich unterschiedliche Worte \u00fcber ihren Alphabeten&nbsp;\\(\\Omega_\\kappa\\) und \\(\\Omega_\\omicron\\) sind, so sind die daraus entstehenden Bandmaschinen jedoch <strong>gleich<\/strong>!<\/p>\n\n\n\n<p>Und genau das ist der Grund, warum wir nur einmal \\(\\xi\\) definiert haben. Wir nutzten zwar unterschiedliche Programmiersprachen (\\(\\kappa\\) und \\(\\omicron\\)) und hatten nat\u00fcrlich auch unterschiedliche Programme \\(BP\\), aber immer ein Berechnungsmodell, d.h. nur eine \\(BM\\),&nbsp;z.B. die gleichen Assembler Befehle f\u00fcr einen x86 Prozessor (oder die gleichen Befehle f\u00fcr eine Turingmaschine).<\/p>\n\n\n\n<p>Ich nehme also die Programmiersprachen-Kommandos &#8222;<em>Writeln()<\/em>;&#8220; und&nbsp;&#8222;<em>System.out.println();<\/em>&#8220; &nbsp;und \u00fcbersetze sie mit den zugeh\u00f6rigen Funktionen die gleiche Bandmaschine, die auf dem x86 Prozessor ausgef\u00fchrt wird.<\/p>\n\n\n\n\\(\\nu_{M\\kappa}(&#8222;Writeln();&#8220;)=BM_1\\)\n\n\n\n\\(\\nu_{M\\omicron}(&#8222;System.out.println();&#8220;)=BM_1\\)\n\n\n\n<p>Nur haben wir oben nicht einen x86 Befehlssatz als Berechnungsmodell, sondern eine Turingmaschine gew\u00e4hlt. D.h. die Bandmaschine \\(BM_1\\) hat die Befehle in der Form, wie unsere Turingmaschine sie versteht. Denn die TM ist unser mathematisches, einfaches Modell f\u00fcr unsere Berechnungen. Und nach der Church\/Turing-These ist sie genauso m\u00e4chtig wie unser x86 Prozessor. Nur brauchen wir uns um die komplizierten Befehle des Prozessors nicht zu k\u00fcmmern und verbleiben bei den \u00fcberschaubaren Befehlen der TM \ud83d\ude09<\/p>\n\n\n\n<p>Im Endeffekt hat also <strong>jede<\/strong> Nummerierung, d.h. <strong>jede<\/strong> Programmiersprache ihren <strong>eigenen<\/strong> Interpreter, die universelle Funktion \\(u\\), der die Befehle der Programmiersprache in die Befehle des Berechnungsmodells (sei es TM, x86, Registermaschine oder sonstwas \u00e4quivalentes) \u00fcbersetzt.<\/p>\n\n\n\n<p>Und da wir am Ende immer auf einem Berechnungsmodell landen (landen <strong>k\u00f6nnen<\/strong>, dazu gleich auch noch mehr), egal welche (\u00e4quivalente) Programmiersprache\/Nummerierung wir verwenden, liegt ein Schluss sehr nahe: wir k\u00f6nnen zwei \u00c4quivalente Sprachen auch ineinander \u00fcbersetzen.<\/p>\n\n\n\n<p>Und das ist dann auch der Bezug zum \u00dcbersetzungslemma, dem <strong>smn-Theorem<\/strong>. Nennen wir diese Funktion einfach mal \\(r\\), so k\u00f6nnen wir unsere Programmiersprachen Pascal und Java ineinander \u00fcbersetzen, so dass mathematisch gilt:<\/p>\n\n\n\\(\\kappa(i)(x) = \\omicron(r(i))(x)\\)\n\n\n\n<p>Wie \\(r\\) funktioniert, k\u00f6nnt Ihr euch sicher bereits im Kopf zurechtschustern. Z.B. w\u00fcrde \\(r\\) uns die \u00e4quivalenten Befehle&nbsp;&#8222;<em>Writeln()<\/em>;&#8220; und&nbsp;&#8222;<em>System.out.println();<\/em>&#8220; ineinander \u00fcbersetzen:&nbsp;Tun wir mal so, als w\u00e4ren das Befehle funktionierender Programme, so haben sie durch die Nummerierungen \\(\\kappa\\) und \\(\\omicron\\) auch entsprechende Nummern. Seien die willk\u00fcrlichen Nummer der beiden Befehle:<\/p>\n\n\n\n<p>\\(\\kappa(27181)=&#8220;Writeln(x);&#8220;\\) und<\/p>\n\n\n\n<p>\\(\\omicron(516322)=&#8220;System.out.println();&#8220;\\),<\/p>\n\n\n\n<p>so \u00fcbersetzen wir mit \\(r\\) letztendlich:<\/p>\n\n\n\n\\(\\kappa(27181)(x) = \\omicron(r(27181))(x) = \\omicron(516322)(x)\\)\n\n\n\n<p>Wie geht \\(r\\) dazu vor? \\(r\\) nutzt einfach die universellen Funktionen von \\(\\kappa\\) und \\(\\omicron\\). Da beide Interpreter am Ende die gleiche Bandmaschine f\u00fcr&nbsp;&#8222;<em>Writeln()<\/em>;&#8220; und&nbsp;&#8222;<em>System.out.println();<\/em>&#8220; ausspucken, k\u00f6nnen wir das problemlos tun.<\/p>\n\n\n\n<p><strong>Und hier kommt das &#8222;Mehr&#8220; und die Aufl\u00f6sung<\/strong><\/p>\n\n\n\n<p>Wir sind sogar nicht einmal auf das gleiche Berechnungsmodell, bzw. die gleiche Bandmaschine \\(BM\\) angewiesen. Auch wenn unsere Programmiersprachen g\u00e4nzlich andere Berechnungsmodelle f\u00fcttern (z.B. wir interpretieren PASCAL f\u00fcr x86 und Java f\u00fcr ARM), so haben wir dennoch eine gemeinsame Basis! Die Nummern beider Programme werden zwar auch auf anderen Berechnungsmodellen (x86 und ARM) ausgef\u00fchrt, haben alle eigene Bandmaschinen \\(BM\\), berechnen aber die gleiche Funktion aus \\(P^{(1)}\\)!<\/p>\n\n\n\n<p>Denn hier f\u00fchrt am Ende alles hin: egal welche Programmiersprache und welches Berechnungsmodell. Haben wir eine Programmiersprache\/Nummerierung, die eine berechenbare universelle Funktion \\(u\\) (utm-Theorem) besitzt&nbsp;und das smn-Theorem erf\u00fcllt, so sind diese \u00e4quivalent und berechnen alle das Gleiche: die Funktionen aus \\(P^{(1)}\\).<\/p>\n\n\n\n<p>Und da das so ist, kann ich PERL weiterhin Java und PASCAL guten Gewissens vorziehen \ud83d\ude09<\/p>\n","protected":false},"excerpt":{"rendered":"<p>&#8230; und unsere Nummerierungen von . Da ich mittlerweile ein paar Mails zu diesem Thema bekommen habe, w\u00fcrde ich hier gerne noch etwas erl\u00e4utern. F\u00fcr viele ist das Theorem noch nicht greifbar. Ebensowenig die Nummerierung der einstelligen, berechenbaren Funktionen&nbsp;. Auch den Begriff Modellprogrammiersprache in Bezug auf haben ein paar geh\u00f6rt, k\u00f6nnen das aber noch nicht &hellip; <\/p>\n<p class=\"link-more\"><a href=\"https:\/\/fernuni.digreb.net\/?p=2572\" class=\"more-link\"><span class=\"screen-reader-text\">\u201eKleiner Exkurs: utm-\/smn-Theorem und Programmiersprachen&#8230;\u201c <\/span>weiterlesen<\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4],"tags":[],"class_list":["post-2572","post","type-post","status-publish","format-standard","hentry","category-theoretische-informatik"],"_links":{"self":[{"href":"https:\/\/fernuni.digreb.net\/index.php?rest_route=\/wp\/v2\/posts\/2572","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/fernuni.digreb.net\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/fernuni.digreb.net\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/fernuni.digreb.net\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/fernuni.digreb.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=2572"}],"version-history":[{"count":23,"href":"https:\/\/fernuni.digreb.net\/index.php?rest_route=\/wp\/v2\/posts\/2572\/revisions"}],"predecessor-version":[{"id":3519,"href":"https:\/\/fernuni.digreb.net\/index.php?rest_route=\/wp\/v2\/posts\/2572\/revisions\/3519"}],"wp:attachment":[{"href":"https:\/\/fernuni.digreb.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2572"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/fernuni.digreb.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2572"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/fernuni.digreb.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2572"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}