C/C++ symbolische Mathematik beibringen...



  • Ein paar Links zum Thema:

    (CAS == Cumputer Algebra System)

    Erklärung, wie man ein CAS erstellt (allgemein):
    http://www.math.wpi.edu/IQP/BVCalcHist/calctoc.html

    Ein kostenloses CAS, mit Quellcode in C++:
    http://yacas.sourceforge.net/

    Nochmal kostenloses CAS, mit Quellcode:
    http://maxima.sourceforge.net/index.shtml

    Für alle, die Lisp und Prolog noch nicht kennen:
    http://de.wikipedia.org/wiki/PROLOG
    http://de.wikipedia.org/wiki/Lisp

    (PROLOG ist ja echt der Hammer -- werd mich mal mit beiden beschäftigen)



  • Oh -- was interessantes:

    Ladet euch mal das Prolog-Arbeitsbuch runter:
    http://www.bildung-mv.de/download/fortbildungsmaterial/arbeitsbuch_prolog.pdf

    Auf Seite 68 wird erklärt, wie man Prolog das Differenzieren (symbolisch!!!)
    beibringt!

    Also GENAU das, was wir suchen. Ist doch schonmal was. Wie kann ich aber
    Prolog in eine grafische C / C++ / Java - Oberfläche einbinden?



  • Symbolisches Differenzieren ist trivial.



  • mfdg schrieb:

    Symbolisches Differenzieren ist trivial.

    Symbolisches integrieren auch 🙄 Und alles andere auch... für einen
    Menschen. Jedes Problem für sich ist doch kein Problem 🙂 Nur alles jederzeit
    zu ermöglichen in einem Programm ... das ist doch das Problem 😉



  • ths schrieb:

    mfdg schrieb:

    Symbolisches Differenzieren ist trivial.

    Symbolisches integrieren auch 🙄 Und alles andere auch... für einen
    Menschen. Jedes Problem für sich ist doch kein Problem 🙂 Nur alles jederzeit
    zu ermöglichen in einem Programm ... das ist doch das Problem 😉

    war eher anders gemeint, nehme ich an. in zwei oder drei bildschirmen voll mit lisp baut man nen symbolischen ableiter. als übung für anfänger findet man den in büchern.
    symbolischen integrieren hingegen ist gemein. so gemein, daß ich noch kein computeralebrasystem gesehen habe, das mich in dieser hinsicht befriedigte. mußte oft in büchern nachgucken und rumprobieren, bis ich ne umformung gefunden hatte, von der ausgegend das prog es schaffte. zum glück ist aber differenzieren trivial, und darum konnte ich mit dem prog immer die probe machen.



  • Ist das sooo gemein zu programmieren? 😮 Ich habs noch nicht
    probiert 😉 Ich werde es mal mit der Prädikatenlogik mit Prolog
    probieren ... 1,5 Wochen Semester-Ferien hab ich ja noch 😃



  • ths schrieb:

    Ist das sooo gemein zu programmieren? 😮 Ich habs noch nicht
    probiert 😉 Ich werde es mal mit der Prädikatenlogik mit Prolog
    probieren ... 1,5 Wochen Semester-Ferien hab ich ja noch 😃

    beim differenzieren hat man halt 5 regeln und für sin(x), cos(x) exp(x) und noch ein paar ne direkte formel und fertig.
    beim integrieren stehen ja bereits in der formelsammlung 30 seiten mit wissenswerten integralen. und das fiese ist, daß selbst nach reinklopfen der 30 seiten der rechner noch relativ blind ist (aber endlich anständig lahm).
    beim differenzieren kann man immer direkt die ableitung hinschreiben. eventuell müssen nachher unterterme weiter abgeleitet werden.
    beim integrieren kann man evtl erst ne formel benutzen, nachdem! man 5 zauberhafte umformungen getan hat. udn die methoden, die der mensch benutzt, erscheinen so willkürlich und vage. "mal was substituieren". jo, soll der rechner doch alle möglichen teilterme mal substituieren und inegration durch substitution probieren. er hat ja keinen blick dafür, zu sehen, was vielversprechende substitutionsopfer sind.
    also mir erscheint es nicht einfach.



  • Ich arbeite gerade das Differential-Beispiel von Prolog durch. Immerhin
    hab ich noch nie was mit Prolog gemacht. Wenn ich es dann kapiert habe,
    wie Prolog das macht, werde ich die Integration anfagen 😃 Mal sehen,
    wo ich auf Probleme stoße...

    Aber substituieren und partielle Integration... könnten mit Prolog
    schwer werden. Da braucht man dann, die schon öfter erwähnte, Heuristik 😉 😞



  • volkard schrieb:

    beim integrieren kann man evtl erst ne formel benutzen, nachdem! man 5 zauberhafte umformungen getan hat. udn die methoden, die der mensch benutzt, erscheinen so willkürlich und vage. "mal was substituieren". jo, soll der rechner doch alle möglichen teilterme mal substituieren und inegration durch substitution probieren. er hat ja keinen blick dafür, zu sehen, was vielversprechende substitutionsopfer sind.

    Ich frage mich, ob man beim symbolischen Intergrieren vielleicht besser mit Potenzreihen arbeiten könnte.

    ...also in der Art:

    1. Funktion in Potenzreihe entwickeln bzw. Potenzreihen der "Teilfunktionen" betrachten und gesamt vereinfachen.
    2. Potenzreihe integrieren.
    3. Potenzreihe wieder in bekannte Funktionen "zerlegen".

    ...nur so ne undurchdachte Idee.



  • ...nach etwas drüber nachdenken -> dumme Idee. 🙄



  • Das ist echt blöd... es gibt kein Prolog-Forum 😮

    Also das Differenzieren geht ohne Probleme -- sehr beeindruckend.
    Auch das automatische Vereinfachen von Termen geht. Was nicht geht,
    ist beides gleichzeitig 😡

    Dafür brauch ich mal nen Prolog-Experten 🙂

    Differenzieren in 16 Zeilen (!!!) :

    d(X,X,1).
    d(C,X,0) :- atomic(C), C \= X.
    d(pot(U,N),X,N*pot(U,N1)*DU) :- N>1, N1 is N-1, d(U,X,DU).
    d(pot(U,N),X,N*pot(U,N1)*DU) :- N<0, N1 is N-1, d(U,X,DU).
    d(sin(U),X,cos(U)*DU) :- d(U,X,DU).
    d(cos(U),X,0-sin(U)*DU) :- d(U,X,DU).
    d(exp(U),X,exp(U)*DU) :- d(U,X,DU).
    d(log(U),X,(1/X)*DU) :- d(U,X,DU).
    d(U+C,X,DU) :- atomic(C), C \= X, d(U,X,DU), !.
    d(C+U,X,DU) :- atomic(C), C \= X, d(U,X,DU), !.
    d(F+G,X,DF+DG) :- d(F,X,DF), d(G,X,DG).
    d(U-C,X,DU) :- atomic(C), C \= X, d(U,X,DU), !.
    d(C-U,X,0-DU) :- atomic(C), C \= X, d(U,X,DU), !.
    d(F-G,X,DF-DG) :- d(F,X,DF), d(G,X,DG).
    d(F*G,X,DF*G+F*DG) :- d(F,X,DF), d(G,X,DG).
    d(F/G,X,(G*DF-F*DG)/(G*G)) :- d(F,X,DF), d(G,X,DG).
    

    Das Vereinfachen der Terme ist etwas länglicher:

    vereinfacht(T,T) :- atomic(T).
    vereinfacht(T,V) :- T=L*R, vereinfacht(L,L1), vereinfacht(R,R1), m(L1*R1,V).
    vereinfacht(T,V) :- T=L+R, vereinfacht(L,L1), vereinfacht(R,R1), a(L1+R1,V).
    vereinfacht(T,V) :- T=L-R, vereinfacht(L,L1), vereinfacht(R,R1), s(L1-R1,V).
    
    a(X+0,X) :- !.
    a(0+X,X) :- !.
    a(X+Y,Z) :- integer(X), integer(Y), Z is X+Y.
    a(Y+X+W,V) :- integer(Y), integer(W), a(Y+W,Z), a(Z+X,V).
    a(X+Y+W,V) :- integer(Y), integer(W), a(Y+W,Z), a(Z+X,V).
    a(Y+X+W,V) :- a(Y+W,Z), Z \= Y+W, a(Z+X,V), !.
    a(X+Y+W,V) :- a(Y+W,Z), Z \= Y+W, a(Z+X,V), !.
    a(X+X,V) :- m(2 * X,V), !.
    a(Y*X+X,V) :- a(Y+1,W), m(W*X,V), !.
    a(X+Y*X,V) :- a(Y+1,W), m(W*X,V), !.
    a(Y*X+Z*X,V) :- a(Y+Z,W), m(W*X,V), !.
    a(X+Y,Y+X) :- integer(Y), !.
    a(X+Y,X+Y). /* Default-Klausel */
    
    s(X-0,X) :- !.
    s(X-Y,Z) :- integer(X), integer(Y), Z is X-Y, !.
    s(X-X,0) :- !.
    s(X-Y-W,V) :- integer(Y), integer(W), a(Y+W,Z), s(X-Z,V), !.
    s(Y-X-W,V) :- integer(Y), integer(W), s(Y-W,Z), s(Z-X,V), !.
    s(X-Y-W,V) :- s(Y+W,Z), Z \= Y+W, s(X-Z,V), !.
    s(Y-X-W,V) :- s(Y-W,Z), Z \= Y-W, s(Z-X,V), !.
    s(Y+X-W,V) :- integer(Y), integer(W), s(Y-W,Z), a(Z+X,V), !.
    s(Y+X-W,V) :- s(Y-W,Z), Z \= Y-W, a(X+Z,V), !.
    s(X+Y-W,V) :- s(Y-W,Z), Z \= Y-W, a(X+Z,V), !.
    s(Y*X-X,V) :- s(Y-1,W), m(W*X,V), !.
    s(X-Y*X,V) :- s(1-Y,W), m(W*X,V), !.
    s(Y*X-Z*X,V) :- s(Y-Z,W), m(W*X,V), !.
    s(X-Y,X-Y). /* Default-Klausel */
    
    m(0*X,0) :- !.
    m(X*0,0) :- !.
    m(1*X,X) :- !.
    m(X*1,X) :- !.
    m(X*Y,Z) :- integer(X), integer(Y), Z is X*Y, !.
    m(X*Y*W,V) :- integer(Y), integer(W), m(Y*W,Z), m(Z*X,V), !.
    m(Y*X*W,V) :- integer(Y), integer(W), m(Y*W,Z), m(Z*X,V), !.
    m(X*Z,Z*X) :- integer(Z), !.
    m(X*Y,X*Y) :- !.  /* Default-Klausel */
    

    Das Problem ist nun, dass "der Vereinfacher" sin(U), cos(U) etc. nicht
    als Atom anerkennt. Ist auch richtig. Wenn man jetzt statt sin(U)
    'sin(U)' schreiben würde, wäre sin(U) auch ein Atom -- es würde gehen.
    Aber dann kann man sin(U) nicht mehr differenzieren 😞

    Man muss also die erste Zeile "des Vereinfachers" ändern. Wenn ich
    vereinfacht(T,T) :- atomic(T) | compound(T). nehme, geht es.
    Nur auf compound(T) trifft alles zu -- auch die zu vereinfachen
    Terme :p Geht also auch nicht.

    Wie auch immer...

    ==================================

    Ich habe mal drüber nachgedacht, wies mit der Integration wäre:
    Integration durch Substitution und partielle Integration wäre
    kein Problem...

    Substitution
    Zwei Möglichkeiten:

    • Man kann ihn immer substituieren lassen. Mein Gott: Dann substituiert
      er halt auch x zu x im einfachen Fall! Davon geht die Welt nicht unter.
      Beim differenzieren wird auch immer die Kettenregel benutzt, auch wenn es
      nicht nötig wäre --> auch kein Problem.
    • Oder man überprüft einfach mit atomic() oder var() ob
      in der Funktion eine weitere steht, wie:
      sin(x) --> atomic(X) ist true --> nicht substituieren
      sin(x^2) (heisst im Code: sin(pot(x,2))) --> atomic ist false --> substituieren... etc.

    Die partielle Integration an sich ist ja kein Problem: Differenzieren
    kann er ja schon -- das ist eine Voraussetzung 😉 Man muss sich eine Bedingung
    ausdenken, ab wann er versuchen soll es partiell zu machen... Sollte nicht
    das Problem sein.

    Integrieren, elementar:
    Kann er schon, ähnlich, wie es Jester vorher gesagt hatte 😉 Ist ja auch
    logisch: Die einfache Integration ist nur die Umkehrung der Differentiation.
    Gibt man dem Programm die Ableitung vor, und lässt ihm die Aufleitung suchen,
    so findet er sie ab und zu -- nicht immer 😉

    Also könnte man schon das erste Prädikat für die Integration aus dem
    Stehgreif hinschreiben:

    integral(I,X,V) := d(V,X,I).

    Das ist der Grundstein. Dann muss man halt die ganzen Besonderheiten
    berücksichtigen...

    Aber erstmal will ich, dass der Vereinfacher mit dem Differenzierer zusammen
    arbeitet 🙄 Erst dann kann man auf dem Gesamtergebnis den Integrierer
    definieren...

    Gibt es hier einen Prolog-Expertern 😕



  • Nachtrag (der andere Beitrag war schon zu lang):

    Es gibt für Prolog ein C++- und Java-Interface 😉
    Wir können dann also eine GUI basteln, und eine
    beliebige Eingabe an Prolog weiterleiten...

    Dann catch man die Ausgabe von Prolog und gibt
    sie in der GUI wieder aus. Wenn der User noch
    ein numerisches Ergebnis möchte, oder ein grafisches
    Ergebnis, dann wird die Ausgabe noch geparst und
    man setzt für die Variablen Werte ein ... bla bla.

    Die Ausgabe könnte man in Java mit einem StringTokenizer
    auseinander nehmen...



  • haste wo ein kleines prolog zum downloaden? dann probiere ich's mal.



  • Ja, SWI-Prolog ist kostenlos.
    http://www.swi-prolog.org/

    Einfach installieren, und die Quellcodes als .pro oder .pl Datei
    in deinen Prolog-Ordner packen. Bei mir wurde der Prolog-Ordner
    auf dem Desktop erzeugt. Dort kommen nur Quellcodes hinein.

    Das Programm wird natürlich schön sauber im Order Programme
    installiert, klar.

    Nach dem Start von Prolog musst du jede Quellcode-Datei einzel
    mit consult(DATEINAME). laden. Aber ohne die Dateiendung!
    Und immer den Punkt mitschreiben!

    Differenzieren kannst du mit:
    d(FUNKTION,Variable,Ziel). <-- Punkt nicht vergessen!

    "Funktion" ist klar. x^y geht mit pot(x,y) --> x^2 => pot(x,2)
    cos(..), sin(..), exp(..) .... etc. ist klar. In der Funktion
    alles klein schreiben!

    "Variable" ist die zu differenzierende Variable, __kleingeschrieben__!
    Also z. B.: "x".

    Und Ziel ist eine __großgeschriebene__ Variable. Name ist egal.

    Beispiel:
    d(pot(x,2),x,V).
    d((sin(pot(x,2))*pot(x,5))/cos(x),x,V).

    Vereinfachen kannst du mit:
    vereinfacht(ALT,NEU).

    Beispiel:
    vereinfach(0*x+5,V).

    Viel Spaß. Danke das du es auch probierst 👍 Ich werde mich jetzt ins
    Usenet begeben -- dort gibt es Prolog-Bereiche 😃



  • zwischenstand:

    thx. SWI prolog ist praktisch.

    mit dem code bin ich aber unzufrieden.
    d(C,X,0) :- atomic(C), C \= X.
    kann eigentlich nicht sein. hier ist doch gemeint, C ist von X unabhängig. dafür muß ne klausel gebaut werden.

    /*C ist konstant bezüglich X
    also C ist nicht abhängig von X
    genaue implemetierung fehlt noch*/
    const(C,X) :- atomic(C), C \= X.
    

    und der rest vom code ist so kompliziert, daß ich alles verwerfe und neu anfange. vielleicht kapiere ich ja dann meinen eigenen.

    ich fürchte, er wird sogar recht einfach. muss jetzt aber erstmal pizza und bier einkaufen und vertilen.



  • Ich habe gestern Abend und gestern Nacht diesen Schritt gewagt, und alles
    neu gemacht 😉

    Du kannst dir diesen Schritt, nach der Pizza, sparen. Ich werde es dir
    erklären 👍

    Der Code ist total einfach 💡

    Wichtig:

    • a) Vergiss mal Java, C++ etc. Das hier ist auf einer ganz anderen Ebene!
    • b) Wir teilen dem Programm nur Fakten mit. Alles andere, wie weitere
      Rückschlüße, zieht das Programm alleine. Wir müssen nicht jede Kombination
      von Regel(n) niederschreiben.

    Code:
    d(X,X,1).

    Bedeutet, dass wenn du ein beliebiges X (ist nicht die Variable x, sondern
    irgendwas), nach X ableiten willst, kommt immer 1 heraus.

    Also x nach x ableiten, etc.

    Code:
    d(C,X,0) :- atomic(C), C \= X.

    C ist deine gegebene Gleichung, X deine gewünschte Variable. Wenn die
    Gleichung nur eine Konstante enthält (das prüft man mit atomic()), und
    C ungleich X ist, ist dass Ergebnis 0. Ungleichheit wird also mit \=
    bezeichnet.

    Code:
    d(pot(U,N),X,N*pot(U,N1)*DU) :- N>1, N1 is N-1, d(U,X,DU).

    pot(U,N) soll U^N sein. Wenn wir also U^N ableiten wollen, über X, so lautet
    das Ergebnis N*pot(U,N1)*DU ... WENN:
    a) N>1
    b) N-1 berechnet, und N1 zugewiesen wurde
    c) und d(U,X,DU). erfolgreich verlauffen ist. Diese Regel arbeitet also Rekrusiv.

    Das "," ist die UND-Verknüpfung!!! Mit ":-" definiert man die Bedingungen,
    wann die Regel auf der linken Seite gültig ist.

    Code:
    d(sin(U),X,cos(U)*DU) :- d(U,X,DU).

    Wieder das Selbe. Das Ergebnis von sin(U) (hier ist gleich die Kettenregel
    dabei!) über X abgeleitet, ist cos(U)*DU, WENN:
    Die Ableitung (Rekrusiv) von d(U,X,DU). erfolgreich verlief.

    Damit kann man das ganze Differential-Programm verstehen. Eine Sache noch:
    Das "!" ist eine Abbruchbedingt, wird Cut genannt. Damit wird der Vorgang
    abgebrochen. Damit das Programm nicht noch eine andere Regel auf das fertige
    Ergebnis anwendet.

    Ach ja: Prolog kennt kein negativen Operator... also -5 geht nicht! Man
    muss leider 0 - 5 schreiben. Leider geht also auch 5 * (-1) nicht.

    Für das Vereinfachen mache ich einen neuen Beitrag. 😉

    Nochmal zur Klarheit:
    Wir brauchen dem Programm nicht beibringen, wie man eine Konstante ableitet,
    die unter einem Bruchstrich steht etc. Denn diese Aussage fehlt im Code,
    wie viele andere auch. Aber das Programm leitet sich das selbst her. Es hat
    eine gewisse "KI" wenn man so will.

    Es weiß ja, dass gilt:
    d(C,X,0) :- atomic(C), C \= X.
    ... und diese Regel wird es nun in allen anderen Kombinationen selber anwenden.



  • Zum vereinfachen-Programm (siehe weiter oben den Code):

    Zuerst einmal, ist das "=" KEINE Zuweisung, wie in C etc. Mit dem "=" wird
    ein match geprüft, also "finde ich in dieser Variable dieses und jenes".

    Code:
    vereinfacht(T,T) :- atomic(T).

    Wenn T ein Atom ist (also nur noch ein Zeichen, eine Konstane etc., also
    kein "Sring" mehr, keine Operatoren ...) dann ist das Ergebnis der Vereinfachung
    T selbst.

    Logisch: Wenn wir zum Vereinfachen "0*x+5" geben, und irgendwann durch die
    Rekursion nur noch "5" übrig bleibt, ist der Job erledigt. Das macht diese
    Regel.

    Code:
    vereinfacht(T,V) :- T=L*R, vereinfacht(L,L1), vereinfacht(R,R1), m(L1*R1,V).

    Also gegeben ist ein Ausdruck T und das Ergebnis soll nach V. Das ist genau
    dann der Fall, wenn:

    • T=LR hat mir auch zunächst Kopfschmerzen bereitet 😉 Aber, wie schon
      gesagt, ist das "=" keine Zuweisung. T ist gegeben, klar. Nun passiert
      folgendes. Stellt euch vor, "L
      R" sei eine Maske. Nun wird versucht, ob diese
      Maske in den gegebenen Ausdruck T passt. Das ist nur dann der Fall, wenn es
      sich um eine Multiplikation handelt. Dann wird L aber auch gleich dem "Teilstring"
      zugewiesen, und auch R seinem Teil.
    • (Wieder beachten: "," ist das UND!)
      Nun werden rekrusiv die beiden "Teilstrings" L und R vereinfacht, und den
      Variablen L1 und L2 zugewiesen.
    • m() ist die Multiplikation, s() Subtraktion, a() Addition. Es werden
      also zum Schluß L1 und R1 multipliziert, und V zugewiesen.
    • Wenn das alles positiv verläuft, dann wird das V als Ergebnis zurück
      geliefert.

    Code:
    a(X+0,X) :- !.

    Wenn ein Ausdruck X + 0 bei der Addition auftaucht, dann ergibt dies immer
    (hier ohne Bedingungen) X. Und wenn das der Fall ist, wird der Vorgang sofort
    abgebrochen mit dem "!", dem Cut.

    Code:
    a(X+Y,Z) :- integer(X), integer(Y), Z is X+Y.

    X+Y ist gleich Z, wenn:
    a) X eine Zahl ist (integer prüft glaube ich nur auf natürliche Zahlen)
    b) Y eine Zahl ist
    c) die Zuweisung positiv verläuft. Hier wird Z das Ergebnis von X+Y zugewiesen
    (also ist das "=" aus Java, C und C++ das "is" in Prolog).

    Code:
    a(X+Y,X+Y). /* Default-Klausel */

    Diese default Klausel gibt es, damit alle anderen Fälle direkt durch gehen.
    Sonst würde es öfters zu einem "no" führen.

    Damit kann man sich auch dieses Programm erklären. Was meint ihr, wie lange
    es gedauert hat, dass alles heraus zu finden 🙄 Die Dokumentationen
    und eBooks zu Prolog sind sehr sehr dürftig. 😞 Und echte Bücher gibt es
    auch keine, oder nur sehr sehr sehr wenige.

    Echt schade.

    Jetzt habe ich aber eine Idee. Vielleicht kann ich cos(...) etc. mit "="
    erkennen.... 😮 Das muss ich gleich mal probieren...



  • Edit:
    Also nun hab ich die Lösung. Ich hab den Vereinfacherer mit dem Differenzierer
    vereinigt.

    Differenzierer:

    d(X,X,1).
    d(C,X,0) :- atomic(C), C \= X.
    d(pot(U,N),X,OUT) :- N>1, N1 is N-1, d(U,X,DU), simplify(N*pot(U,N1)*DU,OUT).
    d(pot(U,N),X,OUT) :- N<0, N1 is N-1, d(U,X,DU), simplify(N*pot(U,N1)*DU,OUT).
    d(sin(U),X,OUT) :- d(U,X,DU), simplify(cos(U)*DU,OUT).
    d(cos(U),X,OUT) :- d(U,X,DU), simplify(0-sin(U)*DU,OUT).
    d(exp(U),X,OUT) :- d(U,X,DU), simplify(exp(U)*DU,OUT).
    d(log(U),X,OUT) :- d(U,X,DU), simplify((1/X)*DU,OUT).
    d(U+C,X,OUT) :- atomic(C), C \= X, d(U,X,DU), simplify(DU,OUT), !.
    d(C+U,X,OUT) :- atomic(C), C \= X, d(U,X,DU), simplify(DU,OUT), !.
    d(F+G,X,OUT) :- d(F,X,DF), d(G,X,DG), simplify(DF+DG,OUT).
    d(U-C,X,OUT) :- atomic(C), C \= X, d(U,X,DU), simplify(DU,OUT), !.
    d(C-U,X,OUT) :- atomic(C), C \= X, d(U,X,DU), simplify(0-DU,OUT), !.
    d(F-G,X,OUT) :- d(F,X,DF), d(G,X,DG), simplify(DF-DG,OUT).
    d(F*G,X,OUT) :- d(F,X,DF), d(G,X,DG), simplify(DF*G+F*DG,OUT).
    d(F/G,X,OUT) :- d(F,X,DF), d(G,X,DG), simplify((G*DF-F*DG)/(G*G),OUT).
    

    "Der Vereinfacher":

    simplify(T,T) :- atomic(T) | T=sin(_) | T=cos(_) | T=pot(_,_) | T=exp(_).
    simplify(T,V) :- T=L*R, simplify(L,L1), simplify(R,R1), m(L1*R1,V).
    simplify(T,V) :- T=L+R, simplify(L,L1), simplify(R,R1), a(L1+R1,V).
    simplify(T,V) :- T=L-R, simplify(L,L1), simplify(R,R1), s(L1-R1,V).
    
    a(X+0,X) :- !.
    a(0+X,X) :- !.
    a(X+Y,Z) :- integer(X), integer(Y), Z is X+Y.
    [...]
    

    Bei dem Vereinfacher habe ich nur den Anfang neu geposted. Der Rest ist
    gleich -- siehe eine oder zwei Seiten weiter vorne.

    Erklärung:
    Nach dem differenzieren wird jedes Ergebnis (von den beiden trivalen Fällen
    mal abgesehen) an den Vereinfacher weiter geleitet.

    Code:
    simplify(T,T) :- atomic(T) | T=sin() | T=cos() | T=pot(,) | T=exp(_).

    Hier ist die einzigste richtige Neuerung zu finden. Dazu muss man wissen, dass
    das ""-Zeichen in Prolog für ALLES steht. Also bedeutet "sin()", dass hier
    ein Sinus mit irgend einem beliebigen Inhalt stehen kann / darf.

    T=sin(_) bedeutet also, dass in T nach einem Sinus mit einem unbekannten
    Argument gesucht wird. Wenn dies gefunden wurde, wird true zurück gegeben.
    Und das "|" ist das logische ODER.

    Damit wäre das vom Tisch. 😃 Ich werde das auch mal in einem Dokument
    zusammenfassen... das Ganze. Schön sauber mit LaTeX.

    Beeindruckend:
    Ich hab ja nur diese Ausnahme hinzugefügt, diese eine Zeile geändert.
    Und schwups: Er kann trotzdem Sachen wie "sin(bla bla bla) * 0 * 45054"
    erkennen, und vereinfachen -- hab ich ihm aber nicht gezeigt. Hat er es
    sich selbst hergeleitet 😮 😃

    Ich werde jetzt noch ein paar weitere Regeln zum vereinfachen definieren.
    Also das er nicht immer pot(x,1) --> x^1 schreibt, sondern eben x.
    Etc. ... und dann kann es mit den Integralen weiter gehen 😉



  • ths schrieb:

    Ich habe gestern Abend und gestern Nacht diesen Schritt gewagt, und alles
    neu gemacht 😉

    Du kannst dir diesen Schritt, nach der Pizza, sparen. Ich werde es dir
    erklären 👍

    ok, code ist klar.
    ich setze neu an, weil ich mit ein paar details einfach unzufrieden bin.
    ich bewege mich also in ne andere reichtung.
    und dabei gucke ich dir natürlich möglichst viel ab.
    und vielleicht kannste bald bei mir auch ein wenig abgucken.

    am konzept mit const halte ich fest.
    er muß ja (a*b)*x differenzieren können, und das geht nur, wenn
    er (a*b) als const bezüglich erkennt, vermute ich. ich "weiß"
    einfach, daß das richtig ist. könnte aber auch falsch sein.

    ich fasse differenzieren und vereinfachen insofern zusammen, als daß bei
    jedem differenzierschriff gleich das ergebnis vereinfacht werden soll.

    diff(X,X,1).
    diff(T,X,0) :- const(T,X).
    diff(F*G,X,V) :- diff(F,X,DF), diff(G,X,DG), simplify(DF*G+FDG,V).
    diff(F*G,X,V) :- diff(F,X,DF), diff(G,X,DG), simplify(DF*G-F
    DG,V).

    die elementaren funktionen möchte ich auch direkt ableiten, keine tricks durch
    einbettung in kettenregel.

    diff(sin(X),X,cos(X)).
    diff(cos(X),X,-sin(x)).

    const benutze ich gleich mal.
    diff(C*X,X,C) :- const(C,X).

    kann zur zeit die kettenregel nicht definieren, suche im netz nach nem vollständigen
    handbuch.



  • volkard schrieb:

    ich setze neu an, weil ich mit ein paar details einfach unzufrieden bin.

    Ist ja okay. Wir können uns ja dann auf ein Modell einigen, und die Teilprogramme
    zusammenfügen.

    ich fasse differenzieren und vereinfachen insofern zusammen, als daß bei
    jedem differenzierschriff gleich das ergebnis vereinfacht werden soll.

    Siehe meinen anderen Beitrag, den ich eben editiert habe 😃 Da hab ich das
    auch so 😉

    die elementaren funktionen möchte ich auch direkt ableiten, keine tricks durch
    einbettung in kettenregel.

    Habs nur so, weil es in dieser PDF so drinne stand. Und die meinten, es ginge
    nicht anders. Wenn du es schaffst... gut.

    kann zur zeit die kettenregel nicht definieren, suche im netz nach nem
    vollständigen handbuch.

    Wie? Du suchst die Kettenregel? Nimm mein Mathe-Dokument:
    http://www.cyberzone2001.de/documents/Mathematik.pdf

    Oder was meinst du? Oder suchst du ein Handbuch für Prolog? Dann wünsche
    ich dir viel Spaß. Ich habs aufgegeben... Die Dinger im Netz sind alle
    nicht sooo gut. Nicht so schön wie für Java und C oder C++...


Anmelden zum Antworten