C/C++ symbolische Mathematik beibringen...



  • Also deine Idee mit den Match-Prädikaten ist interessant. Das werde ich mir
    mal genauer ansehen -- nach meinem TV-Nachmittag 😉

    Und die Lösung in dem PDF-Dokumnt ist ja beeindruckend. Schön sauber und
    recht kurz. Ich bin bei ~ 230 Zeilen im Moment... und es sieht mehr wie
    Kraut und Rüben aus :p Aber solange man noch durchsteigt...
    230 Zeilen inklusive Kommentare natürlich 😉



  • ths schrieb:

    Ich bin bei ~ 230 Zeilen im Moment... und es sieht mehr wie
    Kraut und Rüben aus

    ich bin erst bei 26 zeilen. 🕶



  • mal zum ALLES-ansatz:
    mit

    termTrans(Term,Result):-
      Term=..[Functor|Args],
      maplist(termTrans,Args,TArgs),
      Term2=..[Functor|TArgs],
      trans(Term2,Result).
    

    kann man von eime term alle subterme durch ein prädikat trans/2 schicken.

    trans/2 kann weitgehend aus einem mathebuch abgeschrieben werden.

    % zusammenfassen von atomen
    trans(A+B,C):-
      number(A),
      number(B),
      C is A+B.
    
    % steht in selten im mathebuch, aber ein term ist er selbst
    trans(A,A).
    
    % Kommutativgesetz der Addition
    trans(A+B,B+A).
    
    % Assoziativgesetz der Addition
    trans(A+(B+C),(A+B)+C).
    trans((A+B)+C,A+(B+C)).
    
    % Neutrales Element der Addition
    trans(A,A+0).
    trans(A+0,A).
    
    % Kommutativgesetz der Multiplikation
    trans(A*B,B*A).
    
    % Assoziativgesetz der Multiplikation
    trans(A*(B*C),(A*B)*C).
    trans((A*B)*C,A*(B*C)).
    
    % Neutrales Element der Multiplikation
    trans(A,A*1).
    trans(A*1,A).
    
    % Distributivgesetz
    trans(A*(B+C),A*C+B*C).
    trans(A*C+B*C,A*(B+C)).
    

    der aufruf für a+a

    process(Term):-
      termTrans(Term,V),
      writeln(V),
      fail.
    process(_).
    
    :-
    %  Term=a*b*c + a*c*b + b*a*c + b*c*a + c*a*b + c*b*a,
      Term=a+a,
      process(Term).
    

    erzeugt auch lecker viele varianten.

    a+a
    a+a
    a+a+0
    (a+a)*1
    a+ (a+0)
    a+0+a
    a+a+0
    a+ (a+0)+0
    (a+ (a+0))*1
    a+a*1
    a*1+a
    a+a*1+0
    (a+a*1)*1
    a+0+a
    a+ (a+0)
    a+ (0+a)
    a+0+a+0
    (a+0+a)*1
    a+0+ (a+0)
    a+0+ (a+0)
    a+0+a+0
    a+ (0+ (a+0))
    a+0+ (a+0)+0
    (a+0+ (a+0))*1
    a+0+a*1
    a*1+ (a+0)
    a+ (0+a*1)
    a+0+a*1+0
    (a+0+a*1)*1
    a*1+a
    a+a*1
    a*1+a+0
    (a*1+a)*1
    a*1+ (a+0)
    a+0+a*1
    a*1+a+0
    a*1+ (a+0)+0
    (a*1+ (a+0))*1
    a*1+a*1
    a*1+a*1
    a*1+a*1+0
    (a*1+a*1)*1
    a* (a+1)
    

    schickt man die weider in den selben transformator, wird er aus a*1+a*1
    auch a*(1+1) machen und danach daraus a*2.

    beim wiederbeschicken sollte man vorher die ergebnisliste nach komplexität sortieren
    und zuerst die kleinsten reinschicken. große monster voller *1+0 halten dann nicht
    so lange auf.
    sortieren nach komplexität geht ja auch.

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % kostenfunktion für terme
    
    % ein atom kostet nichts
    cost(Term,0):-
      atomic(Term),
      !.
    
    % jede funktion kostet 1
    cost(Term,Cost):-
      Term=..[_|Args],
      maplist(cost,Args,Costs),
      sumlist(Costs,CostsSum),
      Cost is CostsSum+1.
    
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % vergleich nach kosten
    
    % bei gleichen kosten zieht der normale termvergleich
    compareByCost(R,A,B):-
      cost(A,CA),
      cost(B,CB),
      compare(=,CA,CB),
      compare(R,A,B),
      !.
    
    % bei ungleichen kosten ziehen die kosten
    compareByCost(R,A,B):-
      cost(A,CA),
      cost(B,CB),
      compare(R,CA,CB).
    

    und wenn man dazu noch macht, daß terme, die bereits einmal als quelle der umformungen
    benutzt wurden, nicht mehr weiter beachtet werden (mit dem global dictionary), frisst
    er sich immer weiter in komplexere terme, bis er mal ne tolle vereinfacheung findet.

    und wenn man dann sobald ne tolle vereinfachung stattfand (kosten des gefundenen terms
    kleiner als kosten des ausgangsterms) ein cut setzt (alle lokalen stacks löscht), das
    dictionary leert und von vorne anfängt, müßte man auch die speicherexplosion einigermaßen
    im griff haben.

    ich kommentiere mal die regeln für die neutralen elemente aus.
    ausgabe:

    a+a
    a+a
    

    jo, das ist gut.

    jetzt der lange term, der mir so kopfzerbrechen bereitet.

    Term=a*b*c + a*c*b + b*a*c + b*c*a + c*a*b + c*b*a,
    

    oh, das werden aber viele. vieele! vieeeele!!!!
    in jedem baumknoten bringt er eine unveränderte version und eine vertauscht.
    das sind mal locker 2 hoch knotenanzahl stück.

    ich leite die ausgabe in ne datei um, um dem wachsen derer zugucken zu können...
    100k...
    1M...
    3M...
    10M...
    bei 1G hört er auf, mehr platz hab ich auf der platte nicht.

    schade eigentlich.

    das zwingt dazu, nicht allein die körperaxiome als ausgang für umformungen zu nehmen,
    sondern andere sachen. zum beispiel sollte a*b*c nicht ((a,b),c) sein, sondern
    *(a,b,c). und vertauschungen sollten immer irrelevant sein.

    gegen die explosion gibts noch weitere tricks. man gibt dem transTerm ein MaxCost mit,
    und probiert zuerst nur transTerm(M,Term,Ergebnis) mit M=kosten von Term. nor wenn das
    zu keiner vereinfachung führt, erlaubt man im nächsten durchlauf eins mehr als MaxCost.
    also recursive deepening.



  • Das ist heftig... 😮

    Auf jeden Fall ein prima Ansatz 🙂 Ich bin da einen ganz anderen Weg
    gegangen, daher auch > 200 Zeilen 😉 Im Moment habe ich alles nur mit
    Prädikaten ganz simpel definiert. Ohne Listen etc., ohne so tiefe Rekursion...

    Daher hab ich das Problem nicht, dass der Stack überläuft, oder das solche
    Datenmengen produziert werden. Dafür bekommt man aber nicht immer den perfekt
    vereinfachten Term. Gerade bei solchen Sachen wie...
    b*c + a*c*b + b*a*c + b*c*a + c*a*b + c*b*a
    ... hat er natürlich Probleme.

    Da gäbe es einen anderen Ansatz:
    Wenn man das Prolog-Programm weiter schreiben will, sollte man am Ende ja
    eh eine grafische Oberfläche in C++ der Java dazu schreiben. Ich hab mir mal
    ein paar Java-Interfaces für Prolog angesehen: Bei einem ist es sogar so, dass
    man im Prolog-Programm Methoden aus Java benutzen kann!!!

    Nun ja... nichts leichter als das. Dann gib ich solche Terme, wie oben, zuerst
    an Java zurück, dort werden sie sortiert, und dann ist das eine Kleinigkeit
    für Prolog.

    Für C / C++ wird es sicher auch so'n Interface geben, wo man Funktionen oder
    Methoden aufrufen kann.

    Ich bastel aber an diesen Problemen im Moment nicht weiter, sondern hab es
    hingenommen, dass man es nicht ohne Probleme lösen kann (diese a+b... Terme).
    Hab statt dessen mit Division weiter gemacht. Ist garnicht so einfach, dass
    Prolog in jeder Lebenslage eine Division durch Null erkennt, und als Ergebnis
    dann 'undefined' präsentiert 😃 Habs aber...

    Naja... die n-te Wurzel hab ich auch schon drinne. Und da ich alle Wurzeln in
    Potenzen umwandel, komme ich jetzt mit der Division also an die komplexen
    Zahlen 🙄 Da werde ich wohl erstmal auch 'undefined' oder
    'not real' zurück geben.



  • ths schrieb:

    Nun ja... nichts leichter als das. Dann gib ich solche Terme, wie oben, zuerst an Java zurück, dort werden sie sortiert, und dann ist das eine Kleinigkeit für Prolog.

    nur für's zusammenfassen und sortieren würde ich nicht gleich ne andere sprache nehmen. das geht auch noch in prolog.

    ich schau gerade mal, ob sich das fein in c++ machen läßt, ohne zu viele vorteile von prolog afzugeben.



  • Hab mir gard aus Langeweile mal alles durchgelesen da ich auch mal sowas in der Art versucht hab.
    Ihr macht das bestimmt besser als ich 🙂

    P.S.:
    Bei den ganzen Varianten von a+a = a+0+a ...stimmts am Ende nicht mehr !
    a+a != a*(a+1)

    Greetz



  • ERROR



  • chr1s schrieb:

    Bei den ganzen Varianten von a+a = a+0+a ...stimmts am Ende nicht mehr !
    a+a != a*(a+1)

    Sorry, aber da fehlt mir jetzt echt der Zusammenhang. Was soll nicht stimmen?



  • ich bezog mich auf den längsten deiner posts auf der vorigen Seite.
    aber is nich so wichtig...



  • chr1s schrieb:

    Bei den ganzen Varianten von a+a = a+0+a ...stimmts am Ende nicht mehr !
    a+a != a*(a+1)

    jo.
    wenn ich recht gucke, liegt der fehler an
    trans(A*C+B*C,A*(B+C)).


Anmelden zum Antworten