2017-03-10 8 views
0

Wenn ich einen Ausdruck wie x * x * x, wie in einer Datenstruktur gespeichert: mult (var x, mult (var x, var x))Recursively Grund Ausdruck Differenzierung

Und ich will implementieren Sie eine Funktion zur rekursiven Unterscheidung der Gleichung (so zu 3 * x * x oder x * x + (x + x) * x usw., keine Vereinfachung erforderlich), irgendwelche Vorschläge, wie das zu sein?

+0

Ich bin nicht klar, in welcher Datenstruktur Sie den Ausdruck speichern. 'mult (var x, mult (var x, var x))' sieht für mich mehr wie eine Funktion aus als eine Datenstruktur –

+0

* "wie" *: Wenn Sie einen Ausdruck differenzieren möchten, ist diese Frage zu weit gefasst. Wenn nicht, sei bitte spezifisch, worum es bei der Frage geht (Potenzen von * x *? Irgendein polynomischer Ausdruck? Spaltungen? ...), und deine Versuche und wo du ein Problem hast. – trincot

+1

Das ist ein sehr schönes Problem, aber es ist nicht trivial. Ein Standardweg ist die "Vereinigung". Die Ausdrücke werden als Syntaxbäume dargestellt. Die Differenzierungsregeln werden als L-> R-Paare dargestellt, wobei L und R Syntaxbäume sind, die freie Variablen enthalten. Z.B. 'd (A * B, x) -> d (A, x) * B + A * d (B, x)' wobei 'A',' B' und 'x' frei sind. Bei der Vereinheitlichung wird ein Eingabeausdruck mit der linken Seite einer Regel verknüpft. Wenn es erfolgreich ist, erzeugt es eine "Ersatz" -Karte, die Variablen zu Teilbäumen nimmt. Wenn Sie die Karte auf die rechte Seite der Regel anwenden, erhalten Sie einen neuen Ausdruck. Stoppen Sie, wenn keine Regeln übereinstimmen. – Gene

Antwort

2

Sie würden eine übereinstimmende Differenzierungsregel finden und anwenden. Zum Beispiel in diesem Fall haben wir die Regel (wobei A und B für die ganze Unterausdrücke stehen)

diff(mult(A, B)) -> add(mult(diff(A),B), mult(A, diff(B))) 

Die linke Seite dieser Regel entspricht die Formel, wenn wir

A = var x 
B = mult(var x, var x) 

gesetzt So können wir anwenden Diese Regel auf die Formel und erhalten

Nun machen Sie das gleiche rekursiv für die verbleibenden Diff-Operationen.

Die anderen anderen Regeln, die Sie hier brauchen, sind:

diff(var x) -> 1 
2

Nur ein Hinweis, dass die Sprache, darauf hinzuweisen Unterschied machen kann. Lisp ist besonders gut für dieses Problem.

(defun d (f x) 
    (etypecase f 
    (number 0) 
    (symbol (if (eq f x) 1 0)) 
    (list (df (first f) (rest f) x)))) 

(defun df (op args x) 
    (let ((a (first args)) 
     (b (second args))) 
    (case op 
     ((+ -) `(,op ,(d a x) ,(d b x))) 
     (* `(+ (* ,a ,(d b x)) (* ,(d a x) ,b))) 
     (/ `(/ (- (* ,(d a x) ,b) (* ,a ,(d b x))) (^ ,b 2))) 
     (^ `(* (* ,b (^ ,a ,(1- b))) ,(d a x))) 
     (sin `(* (cos ,a) ,(d a x))) 
     (cos `(* (- (sin ,a)) ,(d a x)))))) 

Lisp mag Prefix-Notation. Dies entspricht einem abstrakten Syntaxbaum für Ausdrücke. Binäre Operationen sehen wie (op lhs rhs) aus. So zu unterscheiden (3 sin(x^2))^2,

> (d '(^ (* (sin (^ x 2)) 3) 2) 'x) 
(* (* 2 (^ (* (SIN (^ X 2)) 3) 1)) 
(+ (* (SIN (^ X 2)) 0) (* (* (COS (^ X 2)) (* (* 2 (^ X 1)) 1)) 3))) 

Dies ist eine richtige Antwort, aber klar, es ist alles andere als einfach Form. Der nächste Schritt besteht darin, einen Ausdruckvereinfacher hinzuzufügen. Mit einem sehr rudimentär ein,

> (simplify (d '(^ (* (sin (^ x 2)) 3) 2) 'x)) 
(* (* 2 (* (SIN (^ X 2)) 3)) (* (* (COS (^ X 2)) (* 2 X)) 3)) 

mit Infixschreibweise ist dies 2(3 sin(x^2)) (3 cos(x^2) (2x)). Offensichtlich ist mehr Vereinfachung möglich, aber durch eine nützliche Definition zu "am einfachsten" zu kommen, ist ein kompliziertes Thema.