In Kapitel 1 haben wir diskutiert, was unter einem Computeralgebrasystem (CAS), ein solches ist Mathematica ja, zu verstehen ist. Letztlich kann ein (reines) CAS nur jene Probleme angehen, deren Lösung sich algebraisieren lässt. Als Beispiel hatten wir das Thema der Differentiation von Funktionen erwähnt: Obwohl die Ableitung einer Funktion über eine Grenzwertbeziehung und damit in analytischer, aber nicht algebraischer Weise definiert ist, kann man zu gegebener Funktion die Ableitung praktisch berechnen, wenn man ein paar elementare Ableitungen und Differentiationsregeln kennt. Unter diesen Voraussetzungen handelt es sich dann aber um ein algebraisches Problem, welches also prinzipiell einem CAS zugänglich ist. Tatsächlich kann Mathematica auch derartige Ableitungen berechnen, etwa mit Hilfe des in Abschnitt 8.2 besprochenen Befehls D
. Um verstehen zu können, wie Mathematica dabei vorgeht, wollen wir „das Rad neu erfinden“, d. h. wir wollen unseren eigenen Ableitungsoperator definieren, wie es auch in Abschnitt 2.7 bei Koepf (2006) vorgeschlagen wird. Das gut lesbare Buch von Koepf (2006) ist übrigens generell einem jeden zu empfehlen, der mal etwas „hinter die Kulissen“ von Mathematica blicken will. Einen Ansatz zur Definition eines eigenen Integrationsoperators findet der interessierte Leser in Abschnitt 2.3 bei Wolfram (2003).
Zuerst wollen wir in diesem Kapitel kurz zusammenfassen, wie „algebraisches Differenzieren“ theoretisch aussehen wird. Unsere Überlegungen wollen wir anschließend, soweit es geht, in Mathematica umsetzen. Dabei müssen wir insbesondere auf Mathematicas Fähigkeit zur Mustererkennung zugreifen, siehe Abschnitt 7.7. Die nötigen Kenntnisse sollen hier in einer solchen Form zusammengefasst werden, dass auch der Leser, der bisher Abschnitt 7.7 noch nicht durchgearbeitet hat, den Ausführungen dieses Anhangs leicht folgen kann. Zu guter Letzt nehmen wir dann unser eigentliches Ziel in Angriff, die Definition eines Ableitungsoperators.
Die Ableitung einer differenzierbaren Funktion f : ℝ → ℝ an einer Stelle x ϵ ℝ ist definiert als der Grenzwert des zugehörigen Differenzenquotienten, also
Einige elementare Beispiele sind die Ableitungen der folgenden Funktionen:
Zusammen mit der Kenntnis der folgenden Differentiationsregeln kann man die Ableitungen einer großen Vielfalt von Funktionstypen bestimmen:
–Summenregel: (f + g)′(x) = f ′(x) + g′(x);
–Produktregel: (f · g)′(x) = f ′(x) · g(x) + f (x) · g′(x);
–Kettenregel: (f ∘ g)′(x) = f ′(g(x)· g′(x).
Als eine erste Konsequenz erhält man aus Ketten- und Produktregel die Quotientenregel (f / g)′(x) = f ′(x) · g(x) − f (x) · g′(x)/g2(x), und schließlich die Ableitung von Funktionen wie
–f (x) = 2x + 1, nämlich f ′(x) = 2 (Summen- und Produktregel),
–f (x) = tan x = sin x/ cos x, nämlich f ′(x) = 1/ cos2 x (Quotientenregel),
–f (x) = ax = exp (x · ln a), a > 0, nämlich f ′(x) = ax · ln a (Ketten- und Produktregel), u. v. m.,
alles durch Anwendung der Regeln und der grundlegenden Ableitungen, aber ohne explizite Grenzwertberechnung. Dieses Vorgehen wollen wir auch Mathematica beibringen, zum zweiten Mal, denn eigentlich kann Mathematica das ja schon, siehe Abschnitt 8.2. Konkret wollen wir einen Ableitungsoperator A
definieren, der, angewendet auf eine Funktion f (x) eines Argumentes x, die Ableitung f ′(x) bestimmt. Das dazu nötige Hintergrundwissen in puncto Wolfram Language vermittelt der folgende Abschnitt A.2.
Vereinfacht formuliert ist ein jeder Ausdruck der Wolfram Language eine Funktion, d. h. von der Bauart Name [
x1,x2,...]
mit einer bestimmten Zahl an Argumenten x1,x2,... Diese interne Darstellung kann man sich jederzeit von FullForm
anzeigen lassen, wie in Abschnitt 5.3 erläutert. Selbst Operationen wie „+
“, „*
“, „ˆ
“, etc., werden intern durch die Funktionen Plus
, Times
bzw. Power
dargestellt. Insofern müssen auch Befehle, die z. B. Umformungen an einer Funktion (im klassischen Sinne) vornehmen sollen, wie etwa der von uns angestrebte Ableitungsoperator A
, als eine Funktion definiert werden, welcher über die Argumente die nötigen Informationen über ihren konkreten „Auftrag“ mitgeteilt werden. Bei der Programmierung einer solchen Funktion greifen wir auf Mathematicas Potential zur Mustererkennung zurück. Dieses haben wir eigentlich schon in Abschnitt 7.7 erörtert, die nötigen Aspekte der Mustererkennung sollen hier aber trotzdem nochmal kurz vorgestellt werden.
Ein Muster wird dabei mit Hilfe des Unterstrichs „_
“ ausgedrückt, der als Platzhalter dient, siehe auch Abschnitt 7.1. Um dem Platzhalter einen Namen zu geben, so dass man Mathematica anschließend erläutern kann, was es bei dessen Auftreten machen soll, setzt man vorneweg eine Bezeichnung, z. B. x_
für einen Ausdruck namens x. Ein Beispiel: Wenn wir wünschen, dass die Funktion f von ihrem Argument stets den Sinus berechnet, so bringen wir dies Mathematica wie folgt bei:
Das zu erkennende Muster ist hierbei das erste und einzige Argument, wir nennen es x, und damit soll die Berechnung sin x angestellt werden. Wollen wir bei Fehlen des Musters eine Fehlermeldung umgehen und stattdessen einen Vorgabewert verwenden, verwenden wir „_:
“, siehe auch die Abschnitte 7.6 und 7.7. Ein Beispiel:
Es sind aber auch komplexere Muster erlaubt als nur das Argument der neu definierten Funktion. Wollen wir erreichen, dass eine Funktion h Summen in Produkte umwandelt, so können wir definieren:
Die Bestandteile des Musters sind nun also aus einer Summe herauszusuchen, d. h. letztlich die Argumente der innenstehenden Funktion Plus
. Das letzte Beispiel scheitert dabei, da Mathematica in manchen Situationen automatisch Vereinfachungen durchführt, bevor es eine weitere Funktion anwendet. Dies wird uns im folgenden Abschnitt einiges Kopfzerbrechen bereiten. Weiterführende Informationen zum Thema Muster findet der Leser in Abschnitt 7.7.
Nachdem wir in Abschnitt A.2 das nötige Wissen zu Mathematicas Fähigkeiten in puncto Mustererkennung gesammelt haben, wollen wir nun versuchen, einen Ableitungsoperator A
zu definieren, der eine gegebene Funktion ableitet. Konkret: Wir wollen einen Befehl der Syntax A[f[x],x]
, der als Ausgabe die Ableitung f ′(x) liefert. Um dies zu erreichen, soll das Vorgehen aus Abschnitt A.1 umgesetzt werden.
Als erste Regel wollen wir dabei die Ableitung einer Konstanten, d. h. eines Ausdrucks frei von der betrachteten Variablen, implementieren. Dabei verwenden wir das Kommando FreeQ
, welches prüft, ob ein gegebener Ausdruck c von einem anderen, etwa x, abhängt; ist dies nicht der Fall, d. h. ist c bzgl. x konstant, so wird True
zurückgegeben.
Das Kommando „/;
“ ist hierbei der Bedingungsoperator, siehe Abschnitt 7.2. Offenbar funktioniert A
bis dato korrekt, kann aber natürlich noch nicht die Funktion 2x + 1 nach x ableiten. Bringen wir also dem Operator als Nächstes bei, wie Potenzfunktionen xα abzuleiten sind:
Der Operator A
achtet nun also darauf, ob sein erstes Argument eine Potenz ist, d. h. von der Funktion Power
umschlossen wird. Deren zweites Argument, also der Exponent, wird auf Konstantheit bzgl. x geprüft. Der Vorgabewert 1 wird dabei benötigt, da Mathematica, genau wie wir auch, die Potenz x1 nicht als solche auszeichnet, sondern kurz x nennt. Der Operator arbeitet erneut wie gewünscht, erkennt sogar Brüche der Art 1/xa als Potenz x−a. Letzteres liegt schlicht daran, dass Mathematica einen solchen Bruch intern als negative Potenz speichert:
Noch immer kann Mathematica nicht die Funktion 2x+1 ableiten, da es sich dabei weder um eine Konstante, noch um eine reine Potenzfunktion handelt.Was A
noch nicht kennt, sind Summen- und Produktregel. Bevor wir diese implementieren, bringen wir Mathematica erst noch die Ableitung von ein paar weiteren Standardfunktionen bei:
Auf die Exponentialfunktion verzichten wir vorerst, da diese im Gegensatz zu den anderen Funktionen bei Mathematica nicht als eigenständiger Funktionstyp implementiert ist:
Nun ergänzen wir der Reihe nach die Summen- und Produktregel und testen diese an Beispielen:
Im letzten Beispiel kommt A
ohne Kenntnis der Ketten- bzw. Quotientenregel aus, da der Bruch intern recht günstig dargestellt wird:
Implementieren wir schließlich noch die Kettenregel:
Bis zu dieser Stelle haben wir A
exakt jenes Vorgehen beigebracht, wie wir es selbst in der Schule gelehrt wurden. Wenn nun A
noch wüsste, wie die Exponentialfunktion abzuleiten ist, und dass man beliebige Potenzen a(x)f (x), a(x) > 0, auch als exp (f (x) · ln a(x))schreiben kann, womit sie zusammen mit Ketten- und Produktregel abgeleitet werden könnten, wäre unsere Aufgabe gelöst. Hier jedoch beginnen die Probleme, die im Wesentlichen darauf beruhen, dass die Exponentialfunktion intern mit Hilfe von Power
dargestellt wird, siehe oben. Deshalb müssen wir hier gleich einen Schritt weitergehen und Mathematica den allgemeinen Fall
beibringen, der dann als Spezialfall auch die Exponentialfunktion beinhaltet:
Damit haben wir einen sehr mächtigen Ableitungsoperator programmiert. Einen Überblick über die implemetierten Regeln erhält der Leser durch Ausführung von ?A
. Rein theoretisch müsste dieser nun auch in der Lage sein, weitere Funktionen wie etwa den Tangens abzuleiten, schließlich ist tan x = sin x/ cos x. Leider ist der Tangens als eigenständige Funktion implementiert, so dass Mathematica hier keinen Quotienten erkennt. Auch scheitert eine an sich plausible Regel wie A[Tan[f_],
Tan[f]
verwandelt, man sich also im Kreise dreht. Um den Ableitungsoperator zu vollenden, müsste der Leser somit noch eine Reihe weiterer Funktionstypen wie Tangens, Cotangens, usw., direkt implementieren, was sicherlich eine sinnvolle Übung wäre.