C/C++ symbolische Mathematik beibringen...
-
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)*ca*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)*cArgh! 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 gehenWenn man das, was das kleine Programm jetzt schon kann, in Java oder C++
machen wollteDann musst du ihm ja ALLES vorgeben --> der leitet
sich nicht die Hälfte selbst her :p Also ich werde das Projekt weiter
fortsetzenJust 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
fortsetzenJust 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 (1x+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.
-
Kannst Du ihn vielleicht doch mit dem normalen x^n versorgen und das da über Substitution lösen?
-
Jester schrieb:
Kannst Du ihn vielleicht doch mit dem normalen x^n versorgen und das da über Substitution lösen?
hab was besseres.
ein prädikat match, das die verkomplizierungen macht.
zum beispiel
match(1X+0,X).
und wenn ich dann mal nen paramterer brauche, der wie AX+B aussieht, kann ich das prädikat matchen lassen, statt es in prolog direkt hinzuschreiben.und ne andere bedeutung kriegt match auch noch:
match löst auch das problem mit
a*b+b*a, denn die alte formel
simplify(X+X,2X).
wird ersetzt durch
simplify(X+Y,2X):-
match(X,Y).match muss rausfinden können, ob zwei terme gleich sind. sollte eigentlich gehen, indem produkte ausgeklammert werden, bis nur noch ne summe von produkten dasteht, und dann kann man ja die summanden vergleichen (hoffentlich).
also ich brauche jetzt was, was feststellt, ob zwei terme gleich sind. und komme wiedermal nicht weiter. das ausklammern kriege ich schon nicht hin.
-
Einen Match bekommst du mit "=". Also: T=sin(_)
Wenn in T irgendwo ein sin(bla bla bla) steht, TRUE.
Es kann auch vor und hinter dem Sinus nach was kommen -> ist egal.Wenn zwei Terme gleich sein sollen, muss man wohl beide miteinander
matchen:match(A,B,deine Rückgabe) :- A=B, B=A.
EDIT:
Man kann natürlich T=sin(D) sagen. Dann wird das Argument von Sinus
dem D zugewiesen etc.
-
Jester schrieb:
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.
Die Division durch null würde ich noch extra definieren!
Aber der Betrag von x, statt x ... das hatte ich noch
nicht beachtet, danke.
-
volkard schrieb:
ths schrieb:
Also ich werde das Projekt weiter
fortsetzenJust 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.
Ja klar. Werde am Wochenende mal die Testfälle sammeln. Ich teste die Testfälle
mit einem TI-89 und dem PC. Oder wenn sie trival sind, eben so...
-
volkard schrieb:
ich schlug den bronstein auf und fand da ne tabelle unbestimmter inegrale.
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.Nun... wir müssen eine Entscheidung treffen.
Hintergrund:
Wenn du diese allgemeinen 500 Möglichkeiten in einen TI-89 eingibst, dann
kann der bei weitem auch nicht alle vereinfachen! Warum soll unser CAS
das dann können?So wie ich das gelesen habe, ist das Derive CAS sehr sehr klein (ein paar
MB in der PC-Fassung). ( http://www.derive-europe.com/specs.asp?screenshots )
Übrigens: Derive läuft auch auf dem TI-89 und dem TI-92 (Plus)!!! So klein
war es mal.Dagegen ist Mathematica und Maple wohl sehr schwer-gewichtig (vom Speicher
her). Nun kann ich mir gut vorstellen, dass ein Maple noch einiges mehr
vereinfachen kann, als ein Derive (das so klein ist, dass es auf einem
Taschenrechner läuft).Mit anderen Worten:
Wollen wir einen symbolischen Rechner, der zuverlässig die häufigsten
Sachen vereinfachen kann .... oder wollen wir ein Maple schreiben, dass
ALLES lösen kann?In dem Fall, dass man einen Maple-Ersatz schreiben will, kann man auch
die 500 Zeilen tippen -- das ist legitim.Und im Derive-Fall gibt man sich mit den etwas längeren Termen zufrieden
wenn nun unser integralsucher aber ein x^17 vor sich sieht, kriegt
der das doch überhaupt nicht auf ne form wie (1*x+0)^17, die in prolog
matchen würde.Was meinst du? Meinst du X^17, statt x^17? Also einen beliebigen Term
hoch 17...
-
ths schrieb:
Einen Match bekommst du mit "=". Also: T=sin(_)
Wenn in T irgendwo ein sin(bla bla bla) steht, TRUE.
Es kann auch vor und hinter dem Sinus nach was kommen -> ist egal.ich kann doch jetzt prolog. das war mir klar.
Wenn zwei Terme gleich sein sollen, muss man wohl beide miteinander
matchen:
match(A,B,deine Rückgabe) :- A=B, B=A.
EDIT:
Man kann natürlich T=sin(D) sagen. Dann wird das Argument von Sinus
dem D zugewiesen etc.[/quote]
das reicht mir aber nicht. matchen mit = findet keinen match bei
match(a+b,b+a).
deswegen will ich mir doch erlauben, ne match-klausel zu benutzen.
ungefähr so:
match(A,A).
match(A*B,B*A).
match(A+B,B+A).
match(A,A1).
und noch ein paar...
und unten
simplify(A+B,2A):-
match(A,B).
so schafft er es, aus
bla*blubb+blubb*bla ein 2*blubb zu machen.
vielleicht sollte ich das match in dieser verwendung eher equals nennen.
-
volkard schrieb:
match muss rausfinden können, ob zwei terme gleich sind. sollte eigentlich gehen, indem produkte ausgeklammert werden, bis nur noch ne summe von produkten dasteht, und dann kann man ja die summanden vergleichen (hoffentlich).
geht nicht immer.
was soll er aus (1-sin(a)2)*x2 und cos(a)2*x2 machen? sie sind gleich, aber das wird er vermutlich nie sehen.
den ansatz mit dem ausklammern ging http://www.furchur.de/files/labore/logprog/symbdiff.pdf bereits sehr wert. die ergebnisse sind auch beeindruckend.
-
ths schrieb:
Mit anderen Worten:
Wollen wir einen symbolischen Rechner, der zuverlässig die häufigsten
Sachen vereinfachen kann .... oder wollen wir ein Maple schreiben, dass
ALLES lösen kann?ALLES versuchen und bald aufgeben.
Was meinst du? Meinst du X^17, statt x^17? Also einen beliebigen Term
hoch 17...ich meinte es in
int( (A*X+B)^N , X , (1/(A*(N+1))(AX+B)^(N+1) ):- ...
und dann im aufruf
int(x^17,x,R).
x^17 wird nicht auf (AX+B)^N matchen können, weshalb die integrierklausel übersehen wird.
macht man aber
int( M , X , (1/(A(N+1))(AX+B)^(N+1) ):-
match(M,AX+B),...
dann kann man an anderer stelle beschreiben, was matchen soll, und zwar nicht nur das prolog-matchen:
match(A,A).
sondern auch ein erweitertes:
match(1A,A).
match(A+0,A).
match(1*A+0,A).
damit kommt man schon verdammt weit, fürche ich.
um mehr zu kriegen, muß match eigentlich matchen, wenn der eine teil *irgendwie* in den anderen teil überführbar ist. angenommen, simplify würde unabhängig von match funktiponieren, und schon laufen:
match(A,B):-
simplify(A-B,0).%wenn die differenz gleich 0 ist, sind die terme gleichwertig.