C/C++ symbolische Mathematik beibringen...



  • 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++...



  • kettenregel funktioniert!

    /*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.
    
    diff(X,X,1).
    diff(T,X,0) :- const(T,X).
    diff(C*X,X,C) :- const(C,X).
    
    diff(F*G,X,V) :- diff(F,X,DF), diff(G,X,DG), simplify(DF*G+F*DG,V).
    diff(F*G,X,V) :- diff(F,X,DF), diff(G,X,DG), simplify(DF*G-F*DG,V).
    
    diff(sin(X),X,cos(X)).
    diff(cos(X),X,-sin(x)).
    
    /*Kettenregel*/
    diff(FG,X,V) :- 
      functor(FG,F,1), 
      arg(1,FG,A), 
      diff(FG,A,DF), 
      diff(A,X,DG), 
      simplify(DF*DG,V).
    
    diff(T,x,S) :- simplify(T,S).
    
    simplify(1*X,V) :- simplify(X,V).
    simplify(X*1,V) :- simplify(X,V).
    simplify(X+X,V) :- simplify(2*X,V).
    simplify(X+X,V) :- simplify(X*2,V).
    simplify(A+B,SC) :- simplify(A,SA),simplify(B,SB),simplify(SA+SB,SC).
    simplify(X,X) :- !.
    
    :- diff(sin(2*x),x,V),print(user_output,V),nl,flush.
    :- halt.
    


  • wie vereinfachst du a*b+b*a ?



  • wie vereinfachst du a*b+b*a ?



  • Ich habe unter Addition diese Regel:
    a(Y*X+Z*X,V) :- a(Y+Z,W), m(W*X,V), !.



  • ths schrieb:

    Ich habe unter Addition diese Regel:
    a(Y*X+Z*X,V) :- a(Y+Z,W), m(W*X,V), !.

    die tut's nicht!
    die vereinfacht nur a*b+a*b.
    ich will aber a*b+b*a.
    und ncht durch aufzähling aller möglichkeiten, denn das wird doof bei
    a*b*c+a*c*b+b*a*c+b*c*a+c*a*b+c*b*a.
    da soll aber 6*a*b*c rauskommen.



  • Hast recht. Werde es mir mal ansehen. Ich bin gerade beim vereinfachen
    von anderen Dingen...



  • Macht's das hier besser?
    a(Y*X+X*Z,V) :- a(Y+Z,W), m(W*X,V)

    Wie sieht's aus, wenn wir noch das da dazunehmen?
    a(Y*X*R+U*X*Z,V) :- a(Y*R+U*Z,W), m(W*X,V)

    Das müßte es doch erlauben X an beliebiger Stelle rauszuziehen. Fehlen zwar noch ein paar Fälle, aber vielleicht nützt's was.

    MfG Jester



  • Naja... du hast wohl den selben Ansatz.

    Ich habe das eben mal probiert: Er macht es 100%ig richtig, solange nur
    die Reihenfolge nicht so wild ist.

    Dann hab ich es für den Fall a*b+b*a probiert: Mit einer Rekursion und einer
    zusätzlichen Zeile gings dann... natürlich auch mit mehr als dreien.

    Meine These:
    Wenn man alle Kombinationen für a*b+b*a in den Code nimmt, geht es.
    Hey -- das sind ein paar Zeilen mehr, ja. Aber dann sollte er es für
    n-Variablen herleiten können 😃 Ich prüfe diese These gerade 😉



  • Nein -- macht er nicht 😞 Hab alle Kombinationen von den 2er-Fall (ab+ab)
    definiert. Aber bei mehr als 2 Variablen schlägt er immer noch fehl, wenn
    die Variablen durcheinander sind...

    @Jester: Nein, deine beiden Vorschläge genügen auch nicht 😞 Ich werd mir
    mal was zu Essen machen, und nochmal drüber nachdenken 👍



  • Jo, genügen tun sie nicht, aber nützen sie was?

    Was ist, wenn wir noch die fehlenden Fälle dazunehmen: eine Variable am rechten/linken Rand, die andere in der Mitte... sind halt 4 Stück, aber das sollte ja nicht so wild sein. Dann müßte er doch in der Lage sein beliebig auszuklammern, oder nicht?

    MfG Jester



  • Ja klar bringen deine beiden was -- nur nicht genug.

    Ich hatte eben alle 2er Kombinationen drinne:

    a(Y*X+Z*X,V) :- a(Y+Z,W), m(W*X,V).
    a(Y*X+X*Z,V) :- a(Y+Z,W), m(W*X,V).
    a(X*Y+Z*X,V) :- a(Y+Z,W), m(W*X,V).
    a(X*Y+X*Z,V) :- a(Y+Z,W), m(W*X,V).
    

    Dann konnte er alles mit 2er Kombinationen ausklammern. Klar.
    Aber bei drei ging es nicht mehr... Er macht es natürlich jetzt
    schon mit n-Variablen -- sie müssen immer nur in der selben
    Reihenfolge stehen 😉



  • Okay, aber wenn Du jetzt die beiden von oben und noch die 4 Fälle, wo einer am Rand steht und einer in der Mitte dazunimmst, dann müßte er doch immer sofort ausklammern können, oder?



  • wir müssen die terme normalisieren, sonst hat das keinen zweck.
    zuerstmal nur produkte.

    * ist eine binäre funktion.
    a*b*c ist kein dreistelliges *(a,b,c), sondern ist
    (a*b)*c

    a*b*(c*(d*e)*fg
    steht innendrin als
    ((a,b),(
    (((c,*(d,e)),f),g)))
    also ein binärbaum.

    der müßte mal geschüttelt und gerüttelt werden, daß alle klammern rausfallen.
    ich arbeite dran aber komme nicht weiter.

    nach dem klammernrausschütteln noch die elemente sortieren und man hat ne gute
    ausgangsbasis für wasauchimmer.



  • volkard schrieb:

    * ist eine binäre funktion.
    a*b*c ist kein dreistelliges *(a,b,c), sondern ist
    (a*b)*c

    Argh! Da bin ich voll reingeflogen...



  • rütteln geht.

    sumToList(X,Result):-
      X=..[+|Parts],
      maplist(sumToList,Parts,Result),
      !.
    sumToList(X,X):-
      atomic(X).
    
    listToSum([H],H):-!.
    listToSum([H|T],Result):-
      listToSum(T,ST),
      Result=H*ST.
    
    normalizeSum(X,Result):-
      sumToList(X,List),
      flatten(List,FList),
      msort(FList,SList),
      listToSum(SList,Result).
    
    :- setof(V,normalizeSum(a+b+a+(c+(d+e)+f+g),V),B),print(user_output,B),nl,flush.
    /*:- setof(V,listToSum([a,b,c,d],V),B),print(user_output,B),nl,flush.*/
    :- halt.
    

    aber der code ist völlig unfruchtbar. ersten fühlt er sich total deplaziert an. irendwie ist das prozedural und ich sae dem kumpel haarklein, was er machen soll. dann brächte ich auch kein prolog zu nehmen. und um so weiterzumchen, muße man ins normalizeSum noch einbauen, daß die einzelnen summanden normalizeProduct aufrufen (geht ja gut mit maplist/3). und zusammenfassen müßte zum normalisieren gehören, daß er im beispiel die beiden hintereinanderstehenden summanden a zu 2*a macht. und schwupps, sind entscheidende vereinfachungsschritte mitten im tiefsten listengewühle.

    das ist absolut nicht das, was ich wünsche.

    die andere richtung, ist alles offen zu lassen, dafür aber viel rechenzeit zu bezahlen. kein simplify mehr, sondern ein transform und transform gibt alle möglichen transformationen aus. eine der möglichkeiten wird schon der weg zu weiteren vereinfachungen sein.

    man hat den auswerter nicht in der hand und kann den suchbaum schlecht kapen, wo man mag. nicht so sachen wie "wenn der baum über 5 transformationen nicht blätter verloren hat, suche ich hier nicht weiter".
    edit: man kann doch. einfach allen transorm-klauseln nen zuätzlichen parameter (zum beispiel noch erlaubte rekursionstiefe) mitgeben. evtl dynamisch anpassen (also mit tiefenboost, wenn man nen schritt gemacht hat, der bestimmt ok war (die schritte im ableiten sind so fälle, die bestimmt ok sind)).



  • man hat den auswerter nicht in der hand und kann den suchbaum schlecht kapen, wo
    man mag. nicht so sachen wie "wenn der baum über 5 transformationen nicht blätter
    verloren hat, suche ich hier nicht weiter".

    Man kann aber einen Zähler verwenden, und dazu eine "globale Variable".
    Dann könnte man nach 5 Schritten zum Beispiel aufhören.

    Ich habe unter dessen mit anderen Sachen weiter gemacht. 😉 Diverse
    weitere Vereinfachungen:

    • irgendwas^1 ==> irgendwas
    • sqrt(x) ==> x^(1/2)
    • cos(n * pi) und n Element N ist (-1)^n
    • sin(n * pi) und n Element N ist immer 0
    • n-te Wurzel von x zu "x^(1/n)"
    • Hab angefangen die Division ins ganze System zu integrieren
    • sin(bla)2+cos(bla)2 ist immer 1
    • X*X wird nun zu power(x,2)
    • X*X*X*X*... wird zu power(x,...)
    • X / X ==> 1 (meine erste Divisions-Regel)
    • Differenzieren von negativen Exponenten ist nun möglich

    Ich hab dem Anwender nun weiterhin die Eingabe von der n-ten Wurzel
    ermöglicht: root(n,Funktion). Die Zahl pi kann nun auch verwendet
    werden... und die Potenzen heissen nicht mehr pot() sondern natürlich
    power().

    Im Prinzip läuft alles glatt, bis eben auf das eine Problem... 😞 👍
    Jetzt noch etwas Bruchrechnung definieren, und alles etwas mehr ausprobieren,
    dann kanns zu den Integralen gehen 😃

    Wenn man das, was das kleine Programm jetzt schon kann, in Java oder C++
    machen wollte 😮 Dann musst du ihm ja ALLES vorgeben --> der leitet
    sich nicht die Hälfte selbst her :p Also ich werde das Projekt weiter
    fortsetzen 👍 Just for fun 🙂



  • Da wär ich aber vorsichtig bei der Divisionsregel:

    X/X==>1 definert auch 0/0 zu 1. Ich würde lieber noch X!=0 fordern.
    Aufpassen mußte auch pei Potenzen:

    sqrt(x^2) = abs(x), nicht x.

    MfG Jester



  • ths schrieb:

    Also ich werde das Projekt weiter
    fortsetzen 👍 Just for fun 🙂

    und just for fun könntest du noch ein paar testfälle sammeln. bin zwar noch lange nicht so weit, und teste noch gar nix, aber wenn du schon welche hast, wenn ich sie bald brauche, ist das nett.



  • habe ein probem.
    ich schlug den bronstein auf und fand da ne tabelle unbestimmter inegrale.
    die erste formel sieht wohl so aus:
    int( (A*X+B)^N , X , (1/(A*(N+1))(AX+B)^(N+1) ):-
    const(A,X),
    const(B,X),
    const(N,X),
    N \= -1;
    also kein gezappele mit
    int( X^N , ...
    , sondern gleich ne allgemeinere form.
    von diesen allgemeinen formen finden sich 515 stück in der tabelle.
    ist ja auch eigentlich sehr toll. nur so kriegt man einigermaßen
    viele integralformeln unter, ohne endlos viel code zu schreiben.
    wenn nun unser integralsucher aber ein x^17 vor sich sieht, kriegt
    der das doch überhaupt nicht auf ne form wie (1x+0)^17, die in prolog
    matchen würde.
    erlaube ich aber dem automaten, den term immer weiter zu komplizieren, bis
    er x^17 auch mal zu (1
    x+0)^17 umgewandelt hat, dann gibt es keine grenze
    den komplizierens. warum nicht (1*x+0)^(1*17+0*1)?
    bei versuchen kam aus a+b+c fein so schrott wie ((a*1+b*1)*1+c*1)*1 raus,
    aber nach wenigen tausend solchen termin ist der local stack voll und das
    programm bricht ab.


Anmelden zum Antworten