Lisp
An dieser Stelle soll etwas ausführlicher an aktuellen Beispielen die Programmierung von Lisp Funktionen erläutert werden.
Neue Lisp Funktion combine-factors
Das Problem
Wir haben die zwei Fehlerberichte Bug ID: 2976378 - Solver doesn't finish
und Bug ID: 2944431 - 0.0007s^1.874. Eine Analyse zeigt, dass Maxima ein
Problem hat, die Lösung für eine Gleichung a^x * b^x = c
zu
finden, wobei x
die Unbekannte ist, nach der die Gleichung
aufgelöst werden soll. Das ist erstaunlich, da Maxima kein Problem mit
der Gleichung (a * b)^x = c
hat.
Hier sind die Ergebnisse von Maxima für die genannten Beispiele:
(%i1) solve(a^x*b^x=c, x); x c (%o1) [b = --] x a (%i2) solve((a*b)^x=c, x); log(c) (%o2) [x = --------] log(a b)Maxima hat für Gleichungen der Form
a * f(x)^n + b
einen
speziellen Algorithmus. Dieser wird für eine Gleichung der Form
(a * b)^x = c
angewendet. Maxima erkennt jedoch nicht,
dass es sich bei der Gleichung a^x * b^x = c
um ein
äquivalentes Problem handelt.
Die Idee
Wenn ein Ausdruck der Form a^x * b^x
in einen Ausdruck
(a * b)^x
transformiert wird, sollte Maxima das Problem
lösen können. Die Transformation sollte möglichst Allgemein formuliert
werden.
Die Lisp Funktion
Die folgende Lisp Funktion leistet die gewünschte Transformation.
(defun combine-factors (expr var1 &aux w) (cond ((atom expr) expr) ((not (eq (caar expr) 'mtimes)) ;; Not a mtimes expression, call combine-factors recusively (cons (car expr) (mapcar #'(lambda (u) (combine-factors u var1)) (cdr expr)))) (t ;; At this point we have a mtimes expression. (let ((factors nil) (rest nil)) (dolist (ll (cdr expr)) (when *debug-solve* (format t "~& ll = ~A~%" ll)) (cond ((and (mexptp ll) (free (cadr ll) var1) (eq (caddr ll) var1)) (push (cadr ll) factors)) ((and (mexptp ll) (free (cadr ll) var1) (mtimesp (caddr ll)) (eq -1 (cadr (caddr ll))) (eq var1 (caddr (caddr ll)))) (push (list '(mexpt simp) (cadr ll) -1) factors)) (t ;; Not an expression of the form a^x or a^-x (push (combine-factors ll var1) rest)))) (mul (muln rest t) (if (equal 1 (setq w (muln factors t))) 1 (list '(mexpt simp) w var1)))))))
Test der neuen Funktion
Die neue Funktion kann von einer Maxima-Kommandozeile getestet werden. Hier sind die Ergebnisse für zwei Beispiele. Die Funktion funktioniert für beliebig verschachtelte mathematische Ausdrücke.
(%i1) ?combine\-factors(a^x*b^x,x); x (%o1) (a b) (%i2) ?combine\-factors(a^x*b^x/c^x+sin(a^x/b^x),x); a b x a x (%o2) (---) + sin((-) ) c bMaxima findet für einen transformierten Ausdruck die gewünschte Lösung.
(%i3) solve(?combine\-factors(a^x*b^x=c,x),x); log(c) (%o3) [x = --------] log(a b)
Implementation der neuen Funktion
Zuletzt wird die neue Funktion an einer geeigneten Stelle in den Algorithmus von Maxima zum Lösen von Gleichungen eingefügt. Der Bug sollte damit behoben sein. Hier ein Beispiel für ein neues Ergebnis:
(%i4) solve(a^x*b^x=c, x); log(c) (%o4) [x = --------] log(a b)Wird die Implementation genauer getestet, stellt sich heraus, dass weiterhin ein Problem mit ganzen Zahlen als Basis der Exponentiation besteht. Maxima transformiert z. B. wie gewünscht
2^x/3^x
zu
(2/3)^x
, aber für eine Gleichung 2^x/3^x=c
findet
Maxima weiterhin keine Lösung.An diesem Punkt gilt es tiefer in die Algorithmen von Maxima hineinzuschauen. Die vorhandenen Algorithmen müssen an einigen Stellen verallgemeinert werden, damit Maxima auch für ganze Zahlen Lösungen liefert. Am Ende kann auch dieses Problem gelöst werden:
(%i5) solve(2^x/3^x=c, x); log(c) (%o5) [x = ------] 2 log(-) 3Der Programmcode ist noch nicht veröffentlicht.