• Keine Ergebnisse gefunden

Das Variablenkonzept des symbolischen Rechnens

Wir hatten bereits gesehen, dass die Analyse symbolischer Ausdr¨ucke zur Laufzeit, die ja im Mittelpunkt des Interpreters eines CAS steht, weniger ¨Ahnlichkeiten zum Laufzeitverhalten einer klassischen Programmiersprache hat als vielmehr zu den Techniken, die Compiler oder Interpreter derselbenzur ¨Ubersetzungszeitverwenden.

Das trifft insbesondere auf das Variablenkonzept zu, in dem statt der klassischen Bestandteile Bezeichner, Wert, Speicherbereich und Datentyp, von denen in symbolischen Umgebungen so-wieso nur die ersten beiden eine Bedeutung besitzen, neben dem Bezeichner verschiedenartige symbolische Informationen eine Rolle spielen, die wir als Eigenschaften dieses Bezeichners zu-sammenfassen wollen.

Die entscheidende Besonderheit in der Verwendung von Variablen in einem symbolischen Kontext besteht aber darin, dass sich Namensraum und Wertebereich ¨uberlappen. In der Tat ist in einem Ausdruck wiex2+ynicht klar, ob der Bezeichnerxhier alsSymbolvariablef¨ur sich selbst steht oder alsWertvariableContainer eines anderen Werts ist. Mehr noch kann sich die Bedeutung je nach Kontext unterscheiden. So wird etwa in einem Aufruf

u:=int(1/(sin(x)*cos(x)-1),x);

xsymbolisch gemeint sein, selbst wenn der Bezeichner bereits einen Wert besitzt.

Sehen wir uns diese Besonderheit des Variablenkonzepts zun¨achst in einigen Maple-Beispielen an.

p:=9*x^3-37*x^2+47*x-19;

9x3−37x2+ 47x−19 x:=2;

p;

−1

Das ist das erwartete Verhalten. Aus derSymbolvariablenxwurde durch die Wertzuweisung eine Wertvariable, derenWertin die nachfolgende Auswertung vonpeingeht.

Versuchen wir nun, diese Umwandlung r¨uckg¨angig zu machen, etwa mit dem Versuch x:=unknown;

p;

9unknown3−37unknown2+ 47unknown−19

xist noch immer eine Wertvariable, also Container eines nunmehr allerdings symbolischen Wertes, und kein Symbol.

x:=x;

x:=unknown Auch diese

”Verzweiflungstat“ half nicht weiter, denn bei einer Zuweisung wird die rechte Seite ausgewertet und derenWertder linken Seite zugewiesen.

Umxals Symbolvariable zu verwenden, m¨ussen wir diese Auswertung verhindern, was inMaple wie folgt erreicht wird:

x:=’x’; p;

x:=x

9x3−37x2+ 47x−19

Allerdings wurde hierbei nicht dem Bezeichner x das Symbol x als Wert zugewiesen, wie die Syntax des Befehls suggeriert, sondern der Wert des Bezeichners xgel¨oscht und dieser damit in seinen (urspr¨unglichen) Symbolvariablenzustand zur¨uckversetzt. In den anderen CAS wird dieser Sachverhalt durch die Syntax des entsprechenden Befehls deutlicher ausgedr¨uckt.

Axiom )clear value x Maxima kill(x)

Maple x:=’x’

Mathematica Clear[x]

MuPAD delete x Reduce clear x

Tabelle 3: Bezeichner in Symbolvariable zur¨uckverwandeln

Bezeichner werden, wie bereits beschrieben, in einerSymboltabelleerfasst, um sie an allen Stellen, an denen sie im Quellcode auftreten, in einheitlicher Weise zu verarbeiten. F¨ur jeden Bezeichner existiertgenauein Eintrag in der Tabelle, unter dem auch weitere Informationen vermerkt sind.

Da in einem CAS jede in irgendeinem Ausdruck auftretende Symbolvariable sp¨ater als Wertvariable verwendet werden kann, muss dieser Mechanismus der eindeutigen Referenz in einem solchen

Kontext aufalleauftretenden Symbole ausgedehnt werden. Dementsprechend wird bei der Analyse der einzelnen Eingaben jeder String, der einen Bezeichner darstellen k¨onnte, daraufhin gepr¨uft, ob er bereits an anderer Stelle aufgetreten ist und in diesem Fall eine Referenz an die entsprechende Stelle der Symboltabelle eingetragen. Andernfalls ist die Symboltabelle um einen neuen Eintrag zu erweitern.

In einigen CAS kann man sich diese Symboltabelle ganz oder teilweise anzeigen lassen. Maple verf¨ugt sogar ¨uber zwei solche Funktionen.unames()listet alle Symbolvariablen (unassigned na-mes) auf,anames()alle Wertvariablen3.

Betrachten wir, wie sich diese beiden Listen im Zuge von Wertzuweisungen ¨andern. Mit den fol-genden Anweisungen kann manMaplezur¨ucksetzen und sich damit den urspr¨unglichen Zustand beider Sequenzen ansehen:

restart: [unames()]; [anames()];

Eine ganze Reihe von Informationen, die beim Start vonMaplegeladen werden, liegen als Strings vor und sind deshalb nach dem beschriebenen Mechanismus in diese Tabelle aufgenommen worden.

Die zweite Menge ist dagegen noch leer.

Betrachten wir einen Teil aus diesem Raum, die Namen der L¨ange 1, und beobachten, wie sich dieser Namensraum durch die Verwendung von Variablen ver¨andert:

[anames()]; select(s->length(s)=1,[unames()]);

[]

[!, ., <, =, I, O, ^, s, x, y]

u; [anames()]; select(s->length(s)=1,[unames()]);

u []

[!, ., <, =, I, O, ^, s, u, x, y]

u:=1; [anames()]; select(s->length(s)=1,[unames()]);

u := 1 [u]

[!, ., <, =, I, O, ^, s, x, y]

u:=’u’;[anames()]; select(s->length(s)=1,[unames()]);

u := u []

[!, ., <, =, I, O, ^, s, u, x, y]

3Die in der Dokumentation gegebene Spezifikation ist allerdings nicht ganz korrekt, da nicht alle Symbole, die einen Wert haben, angezeigt werden, wie man sich leicht ¨uberzeugt, wenn man sich etwa mitanames(integer)alle Symbole mit Integer-Werten anzeigen l¨asst. Außerdem ist das Ergebnis des Aufrufs in Maple 8 unter Linux und Windows unterschiedlich.

In der letzten Zeile istuaus der Liste der Wertvariablen wieder verschwunden, d.h. die angegebene Zuweisung

”l¨oscht“ tats¨achlich den Wert vonu.

Zusammenfassung

In CAS treten Bezeichner in zwei verschiedenenModi, als Symbolvariablen und als Wert-variablen auf. Ein Bezeichner wird so lange als Symbolvariable behandelt, bis ihm ein Wert zugewiesen wird. Durch eine Wertzuweisung verwandelt er sich in eine (globale) Wertvaria-ble.

Steht ein Bezeichner f¨ur eine Wertvariable, so ist zwischen dem Bezeichner als Wertcontainer und dem Bezeichner als Symbol zu unterscheiden.

Durch eine spezielle Deklaration kann ein Bezeichner in den symbolischen Modus zur¨ uck-versetzt werden. Dabei gehen alle Wertzuweisungen an diesen Bezeichner verloren.

Bezeichner werden in einer Symboltabelle zusammengefasst, um ihre eindeutige Referenzier-barkeit zu sichern.

Mit demMathematica-Befehl Removek¨onnen auch Eintr¨age aus dieser Symboltabelle entfernt werden. Eine solche M¨oglichkeit ist aber mit Vorsicht zu verwenden, da es sein kann, dass sp¨ater auf das bereits gel¨oschte Symbol weitere Referenzen gesetzt werden. Stattdessen sollten Sie nur mitClear bzw.ClearAllarbeiten.

Dieses einheitliche Management der Bezeichner f¨uhrt dazu, dass auch zwischen Variablenbezeich-nern und FunktionsbezeichVariablenbezeich-nern nicht unterschieden wird. Wir hatten beim Auflisten der dem System bekannten Symbole bereits an verschiedenen Stellen Funktionsbezeichner in trauter Ein-tracht neben Variablenbezeichnern stehen sehen. Dies ist auch deshalb erforderlich, weil in einen Ausdruck wie D(f), die Ableitung der einstelligen Funktion f, Funktionssymbole auf dieselbe Weise eingehen wie Variablensymbole in den Ausdrucksin(x).

CAS unterscheiden nicht zwischen Variablen- und Funktionsbezeichnern.

Da andererseits Funktionsdefinitionen ebenfalls symbolischer Natur sind und

”nur“ einer entspre-chenden Interpretation bed¨urfen, verwenden einige Systeme wie etwa Maple sogar das Zuwei-sungssymbol, um Funktionsdefinitionen mit einem Bezeichner zu verbinden.

Eine solche einheitliche Behandlung interner und externer Bezeichner erlaubt es auch, Systemva-riablen und selbst -funktionen zur Laufzeit zu ¨uberschreiben oder neue Funktionen zu erzeugen und (selbst in den compilierten Teil) einzubinden. Da dies zu unvorhersagbarem Systemverhalten f¨uhren kann, sind die meisten internen Funktionen allerdings vor ¨Uberschreiben gesch¨utzt. Hier einige Beispiele inMaple:

> Pi:=3.14;

Error, attempting to assign to ‘Pi‘ which is protected

> unprotect(Pi);

> Pi:=1;

Pi := 1

> eval(arctan(1));

1/4

> gcd:=2;

Error, attempting to assign to ‘gcd‘ which is protected

> unprotect(gcd);

> gcd:=5;

gcd := 5

> gcd(2,3);

5

> gcd(12,13);

5

Wir sehen, dass esMaplenach Entfernen des ¨Uberschreibschutzes selbst erlaubt, Funktionsnamen als Variablennamen zu verwenden. Die meisten CAS unterscheiden jedoch zwischen Wert- und Funktionsdefinitionen und ordnen sie alsunterschiedlicheEigenschaften dem jeweiligen Bezeichner zu.

Auswerten von Ausdr¨ ucken

Die Tatsache, dass der Wert von Bezeichnern symbolischer Natur sein kann, in den Bezeichner eingehen, die ihrerseits einen Wert besitzen k¨onnen, f¨uhrt zu einer weiteren Besonderheit von CAS.

Betrachten wir die folgenden Zuweisungen inMaple a:=b+1; b:=c+3; c:=3;

und sehen uns an, was als Wert des Symbolsaberechnet wird:

a; 7

Es ist also die gesamte Evaluationskette durchlaufen worden: In den Wertb+ 1 von ageht das Symbolbein, das seinerseits als Wert den Ausdruckc+ 3 hat, in den das Symbolceingeht, welches den Wert 3 besitzt. Denkbar w¨are auch eine eingeschr¨ankte Evaluationstiefe, etwa nur Tiefe 1. In Maplekann man diese Tiefe mit speziellen Kommandos variieren:

seq(eval(a,i),i=1..6); b + 1, c + 4, 7, 7, 7, 7

Andern wir den Wert eines Symbols in dieser Evaluationskette, so kann sich auch der Wert von¨ a bei erneuter Evaluation ¨andern.

b:=7*d+3; b := 7 d + 3 a; 7 d + 4 seq(eval(a,i),i=1..3); b + 1, 7 d + 4, 7 d + 4 Die bisher verwendeten Bezeichner auf den rechten Seiten waren Symbolvariable. Werden Wert-variablen verwendet, so m¨ussen wir unterscheiden, ob wir das Symbol oder dessen Wert meinen.

u:=3;a:=u;b:=’u’;

u:= 3 a:= 3 b:=u a;b;

3 3

awurde der Wert 3 des Bezeichnersuzugewiesen,bdagegen das Symbolu, dessen aktueller Wert 3 ist. An dieser Stelle ist bei einer erneuten Auswertung der Unterschied noch nicht zu erkennen.

Betrachten wir jedoch u:=5;a;b;

u:= 5 3 5

so erkennen wir, dass sich ¨Anderungen des Werts vonuaufbauswirken, auf adagegen nicht.

seq(eval(a,i), i=1..5);

3,3,3,3,3 seq(eval(b,i), i=1..5);

u,3,3,3,3

Geht in einen Ausdruck ein Bezeichner als Wertvariable ein, so ist zu unterscheiden, ob der Wert oder das Symbol gemeint ist. Im ersten Fall wird der Bezeichnerausgewertet, im zweiten Fall wird der Bezeichnernicht ausgewertet.

Oft spricht man in diesem Zusammenhang vonfr¨uher Auswertungundsp¨ater Auswertung. Diese Terminologie ist allerdings irref¨uhrend, denn beide Ergebnisse werden nat¨urlich bei einem sp¨ateren Aufruf, wenn sie als Teil in einen auszuwertenden Ausdruck eingehen, auch selbst ausgewertet.

Korrekt m¨usste man also vonfr¨uher Auswertung undfr¨uher Nichtauswertungsprechen.

Generell gibt es zwei verschiedene Mechanismen, eine Wertvariable vor der Auswertung zu be-wahren. Dies geschieht entweder wie inMaple, Maximaoder MuPAD (und LISP) durch eine spezielle Hold-Funktion oder wie in Axiom oder Reduce durch zwei verschiedene Zuweisungs-operatoren, wovon einer die in die rechte Seite eingehenden Bezeichner auswertet, der andere nicht.Mathematicaverf¨ugt sogar ¨uber beide Mechanismen. Diese Besonderheiten sind in einer klassischen Programmiersprache, in der Namensraum und Wertebereich getrennt sind, unbekannt.

Die mit einem solchen Verhalten verbundene Konfusion l¨asst sich vermeiden, wenn Wertva-riablen konsequent nur als Wertcontainer verwendet werden, wenn also von Anfang an genau festgelegt wird, welche Bezeichner in ihrer symbolischen Bedeutung verwendet werden sol-len, und diesen Bezeichnern konsequent in ihrem gesamten G¨ultigkeitsbereich (global) kein Wert zugewisen wird.

Muss einer solchen Symbolvariablen in einem lokalen Kontext ein Wert zugewiesen werden, so kann dies unter Verwendung desSubstitutionsoperatorserfolgen. Diese Wertzuweisung ist nur in dem entsprechenden Ausdruck wirksam, ein Moduswechsel des Bezeichners erfolgt nicht. Es ist zu beachten, dass in einigen CAS dabei keine vollst¨andige Evaluation oder gar Simplifikation des Ergebnisses ausgef¨uhrt wird.

System Substitutions-operator

Zuweisung mit Auswertung

Zuweisung ohne Auswertung

Hold-Operator Axiom subst(f(x),x=a) x:=a x==a –

Maxima subst(x=a,f(x)) x:a – ’x

Maple subs(x=a,f(x)) x:=a – ’x’

Mathematica f(x) /.x7→a x=a x:=a Hold[x]

MuPAD subs(f(x),x=a) x:=a – hold(x)

Reduce subst(x=a,f(x)) x:=a let x=a –

Tabelle 4: Substitutions- und Zuweisungsoperatoren der verschiedenen CAS

Bei dem bisherigen Evaluierungsverfahren maximaler Tiefe kann es eintreten, dass ein zu eva-luierendes Symbol nach endlich vielen Evaluationsschritten selbst wieder in dem entstehenden Ausdruck auftritt und damit der Evaluationsprozess stets von Neuem durchlaufen wird wie in folgendem Beispiel (Mathematica):

x:=y+1;

y:=x+1;

x

$RecursionLimit::reclim: Recursion depth of 256 exceeded.

255 + Hold[x + 1]

Solche rekursiven Verkettungen k¨onnen leicht eintreten, wenn man die Konsequenzen der getrof-fenen Wertzuweisungen nicht genau ¨uberblickt. Auch aus diesem Grund spielen lokale Wertzuwei-sungen, die nur innerhalb eines einzigen Aufrufs G¨ultigkeit haben, eine wichtige Rolle. Mathe-maticaverwendet die Systemvariablen $RecursionLimitund $IterationLimitzur Steuerung des Verhaltens in diesem Fall. Die rekursive Auswertung von Symbolen wird nach Erreichen der vorgegebenen Tiefe abgebrochen und der nicht weiter ausgewertete symbolische Ausdruck in ei-ne Hold-Anweisung eingeschlossen, um ihn auch zuk¨unftig vor (automatischer) Auswertung zu sch¨utzen.

MuPADerlaubt rekursive Zuweisungen, bricht aber nach Erreichen einer durch die Systemvariable MAXLEVELvorgegebenen Tiefe mit einer Fehlermeldung ab.

Maple (seit Version 8) sowie Reduce lassen eine solche rekursive Zuweisung erst gar nicht zu, wenn die zu belegende Variable im zuzuweisenden Wert vorkommt.

x:=x+1; Error, recursive assignment Allerdings kann das leicht

”versteckt“ und durch eine scheinbar harmlose Zuweisung ohne Aus-wertung eine solche unendliche Evaluationskette geschlossen werden:

> x:=y+1; > y:=’x’; x;

Maple 8 h¨angt sich an dieser Stelle auf, w¨ahrend Reduce mit einer

”harten“ Fehlermeldung abbricht:

x := y + 1 let y=x; x; ***** Binding stack overflow, restarting...

Maximaverwendet standardm¨aßig nur Auswertungen der Tiefe 1, d.h. betrachtet nach dem ersten Evaluationsschritt auftretende Bezeichner als Symbole, wodurch dieses Problem der rekursiven Wertzuweisung ebenfalls vermieden wird4. Allerdings unterscheidet sich damit das Auswertungs-verhalten von dem der anderen CAS. Das AuswertungsAuswertungs-verhalten der anderen CAS kann (in erster N¨aherung) mit der Funktion ev(..,infeval)erreicht werden. Allerdings k¨onnen mit der Evalu-ierungsfunktionevinMaximakomplexere Effekte erzielt werden.

Zuweisung Maxima (z.B.)Maple

a:=b+1 b+1 b+1

b:=c+1 c+1 c+1

c:=d+1 d+1 d+1

a b+1 d+3

a:=b+1 c+2 d+3

Tabelle 5: Unterschiedliches Auswertungsverhalten vonMaximaundMaple

4Dasselbe gilt etwa inMapleoderMuPADauch f¨ur lokale Bezeichner innerhalb von Prozedurr¨umpfen.