Ist es möglich, das Problem des Anhaltens zu lösen, wenn Sie eine eingeschränkte oder vorhersehbare Eingabe haben?


18

Das Halteproblem kann im allgemeinen Fall nicht gelöst werden. Es ist möglich, definierte Regeln zu entwickeln, die zulässige Eingaben einschränken, und kann das Problem des Anhaltens für diesen speziellen Fall gelöst werden?

Zum Beispiel ist es wahrscheinlich, dass eine Sprache, die beispielsweise keine Schleifen zulässt, sehr leicht zu erkennen ist, ob das Programm anhält oder nicht.

Das Problem, das ich gerade zu lösen versuche, ist, dass ich versuche, einen Skriptprüfer zu erstellen, der die Gültigkeit des Programms überprüft. Kann das Problem des Anhaltens gelöst werden, wenn ich genau weiß, was von Skriptautoren zu erwarten ist, was sehr vorhersehbare Eingaben bedeutet. Wenn dies nicht genau gelöst werden kann, welche guten Approximationstechniken eignen sich dazu?

Antworten:


10

Die intuitive Antwort lautet: Wenn Sie keine unbegrenzten Schleifen haben und keine Rekursion haben und nicht gehen, werden Ihre Programme beendet. Dies ist nicht ganz richtig, es gibt andere Möglichkeiten, um die Nichtbeendigung einzuschleichen, aber es ist gut genug für die meisten praktischen Fälle. Natürlich ist die Umkehrung falsch, es gibt Sprachen mit diesen Konstrukten, die keine nicht terminierenden Programme zulassen, aber sie verwenden andere Arten von Einschränkungen, wie zum Beispiel hochentwickelte Typsysteme.

Rekursion

Eine häufige Einschränkung in Skriptsprachen besteht darin, eine Rekursion dynamisch zu verhindern: Wenn A aufruft, B aufruft, C aufruft, ... aufruft, gibt der Interpreter (oder in Ihrem Fall der Checker) auf oder signalisiert einen Fehler, selbst wenn die Rekursion tatsächlich beendet werden könnte. Zwei konkrete Beispiele:

  • Der C-Präprozessor lässt ein Makro intakt, während er dieses Makro erweitert. Am häufigsten wird ein Wrapper um eine Funktion definiert:

    #define f(x) (printf("calling f(%d)\n", (x)), f(x))
    f(3);
    

    Dies erweitert sich zu

    (printf("calling f(%d)\n", (3)), f(3))
    

    Die gegenseitige Rekursion wird ebenfalls behandelt. Dies hat zur Folge, dass der C-Präprozessor immer beendet wird, obwohl Makros mit hoher Laufzeitkomplexität erstellt werden können.

    #define f0(x) x(x)x(x)
    #define f1(x) f0(f0(x))
    #define f2(x) f1(f1(x))
    #define f3(x) f2(f2(x))
    f3(x)
    
  • Unix-Shells erweitern Aliase rekursiv, jedoch nur, bis sie auf einen Alias ​​stoßen, der bereits erweitert wird. Wiederum besteht der Hauptzweck darin, einen Alias ​​für einen Befehl mit ähnlichem Namen zu definieren.

    alias ls='ls --color'
    alias ll='ls -l'
    

nn

Es gibt allgemeinere Methoden, um zu beweisen, dass rekursive Aufrufe beendet werden, z. B. das Auffinden einer positiven Ganzzahl, die von einem rekursiven Aufruf zum nächsten immer abnimmt, die jedoch erheblich schwerer zu erkennen sind. Sie sind oft schwer zu überprüfen, geschweige denn abzuleiten.

Schleifen

formn

Insbesondere mit for-Schleifen (und sinnvollen Sprachkonstrukten wie Bedingungen) können Sie alle primitiven rekursiven Funktionen schreiben und umgekehrt. Sie können primitive rekursive Funktionen syntaktisch erkennen (wenn sie unverschlüsselt geschrieben sind), da sie keine while-Schleife oder goto oder recursion oder einen anderen Trick verwenden. Primitive rekursive Funktionen werden garantiert beendet, und die meisten praktischen Aufgaben gehen nicht über die primitive Rekursion hinaus.


4

Siehe Terminator und AProVe . Sie tendieren dazu, sich auf Heuristiken zu verlassen, und ich bin nicht sicher, ob sie die Klasse von Programmen, für die sie arbeiten, klar beschreiben. Trotzdem gelten sie als State-of-the-Art, daher sollten sie gute Ausgangspunkte für Sie sein.


4

Ja, das kann möglich sein. Ein üblicher Weg zur Lösung solcher Probleme ist die Berücksichtigung eines zusätzlichen (monotonen) nicht berechenbaren Parameters, der vom Code als Teil der Eingabe abhängt . Die Komplexität des Problems mit diesem Parameter kann stark reduziert werden.

Der Parameter kann nicht berechnet werden. Wenn Sie jedoch wissen, dass die von Ihnen verwendeten Eingabeinstanzen kleine Parameterwerte aufweisen, können Sie ihn auf eine kleine Zahl festlegen und den Algorithmus verwenden.

Diese und ähnliche Tricks werden in formalen Methoden verwendet, um mit der Unentscheidbarkeit des Anhaltens und ähnlichen Problemen umzugehen. Wenn die Entscheidung jedoch kompliziert ist, ist die Komplexität Ihrer Algorithmen wahrscheinlich nicht besser als die Ausführung des Algorithmus auf diesen Instanzen.

Bei der anderen Frage kann das Problem des Anhaltens leicht auftreten, wenn Sie die Eingaben ausreichend einschränken. Wenn Sie beispielsweise wissen, dass es sich bei den Eingaben um polynomiale Zeitalgorithmen handelt, ist es trivial, das Stoppproblem für sie zu bestimmen (da jeder polynomiale Zeitalgorithmus anhält).

Probleme, die bei formalen Methoden auftreten, sind in der Regel unentscheidbar. Lesen Sie in der Literatur nach, wie sie mit diesen Problemen in der Praxis umgehen.


4

Keine formal starre Antwort, aber hier ist es:

Das Problem bei der Bestimmung, ob es für immer anhält oder eine Schleife bildet. Es ist in Ordnung, endliche Sammlungen einzeln oder in Intervallen von Zahlen zu durchlaufen. BEARBEITEN: Dies funktioniert natürlich nur, wenn es verboten ist, die iterierte Sammlung oder das iterierte Intervall zu ändern (z. B. durch Unveränderlichkeit), wenn sie iteriert wird (oder zumindest verboten ist, zu wachsen).

Rekursion ist wahrscheinlich nicht in Ordnung, es sei denn, Sie legen eine künstliche Regel fest, um sie endlich zu machen, z. B. eine maximale Stapeltiefe zuzulassen oder zu erzwingen, dass ein nicht negativer Parameter bei jeder Iteration abnimmt.

Willkürliche Sprünge sind im Allgemeinen schlecht. Rückwärts-Gotos führen sehr wahrscheinlich zu Schleifen, die unendlich sein können.

Whiles- und Do-Whiles-Anweisungen sind ein Problem, da sie von einer Bedingung abhängen, deren Änderung während der Ausführung nicht oder nicht garantiert ist. Ein möglicher (aber wahrscheinlich sehr unbefriedigender) Weg, dies einzuschränken, besteht darin, eine maximale Anzahl möglicher Iterationen anzugeben.


2

Sie müssen eine Definition Ihrer Skriptsprache angeben und was Sie unter "erwarten" von den Skriptautoren verstehen.

O(nω)

Es gibt ein ähnliches Ergebnis für eine Klasse von Polynomprogrammen von Aaron R. Bradley, Zohar Manna und Henny B. Sipma. Aber AFAIK (ich könnte mich hier irren), die Laufzeit ist doppelt exponentiell (im Wesentlichen die Zeit, die benötigt wird, um eine Groebner-Basis zu berechnen).

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.