|
Liebe Mathematica-User, ich habe ein Problem mit der Rechenzeit beim Multiplizieren zweier Polynome. Die Polynome haben Funktionen als Koeffizienten (n[] und CI[]). Es ist eine Funktionalgleichung bekannt, die fuer n[]*CI[] und CI[]+CI[] wieder Werte von CI[] liefert. In dem Beispiel ist der Einfachheit halber CI[x]*n[y] = CI[x*y] und CI[x]+CI[y] = CI[x+y]. Die naheliegende Erweiterung von Plus durch Plus[x_CI,y_CI] := CI[(Identity@@x) + (Identity@@y)] fuehrt jedoch zu enormen Rechenzeiten (Out[13] im Vergleich zu Out[8]+Out[9]). Schneller geht es mit Definition einer eigenen Funktion plus (In[6], In[7]), die im wesentlichen wieder auf das Original-Plus zurueckgreift. Meine Fragen: Warum wird Mathematica durch die Umdefinition von Plus derart aus dem Tritt gebracht? Warum passiert das nicht auch bei der Umdefinition von Times (In[4])? Was ist grundsaetzlich bei der Definition von Funktionen mit Pattern zu beachten um kurze Rechenzeiten zu erreichen? Mathematica 3.0 for IBM RISC System/6000 Copyright 1988-97 Wolfram Research, Inc. -- Terminal graphics initialized -- (* Definition der beiden Polynome *) In[1]:= f = z^3*CI[1] + z^5*CI[2] + z^4*CI[3] 3 5 4 Out[1]= z CI[1] + z CI[2] + z CI[3] In[2]:= g = n[4] + z^1*n[5] + z^5*n[6] + z^7*n[7] 5 7 Out[2]= n[4] + z n[5] + z n[6] + z n[7] (* Definition der Multiplikation CI[x]*n[y]=CI[x*y] *) In[3]:= Unprotect[Times]; In[4]:= Times[x_CI,y_n] := CI[(Identity@@x) (Identity@@y)]; In[5]:= Protect[Times]; (* Eigenes plus CI[x]+CI[y]=CI[x+y] *) In[6]:= plus[x_CI, y_CI] := CI[(Identity@@x) + (Identity@@y)]; In[7]:= plus[t__] := Plus[t]; (* Multiplikation der Polynome und Zusammenfassen der Koeffizienten *) In[8]:= Timing@Collect[f g,z] 3 8 6 4 Out[8]= {0.01 Second, z CI[4] + z CI[6] + z CI[10] + z (CI[5] + CI[12]) + 10 12 5 9 > z (CI[7] + CI[12]) + z CI[14] + z (CI[8] + CI[15]) + z CI[18] + 11 > z CI[21]} In[9]:= Timing[ %[[2]] //. Plus->plus ] 3 8 6 12 Out[9]= {0. Second, z CI[4] + z CI[6] + z CI[10] + z CI[14] + 4 9 10 11 5 > z CI[17] + z CI[18] + z CI[19] + z CI[21] + z CI[23]} (* Nochmal mit Umdefinition von Plus *) In[10]:= Unprotect[Plus]; In[11]:= Plus[x_CI,y_CI] := CI[(Identity@@x) + (Identity@@y)] In[12]:= Protect[Plus]; (* Liefert dasselbe Ergebnis, nur wesentlich langsamer *) In[13]:= Timing@Collect[f g,z] 3 8 6 12 Out[13]= {5.09 Second, z CI[4] + z CI[6] + z CI[10] + z CI[14] + 4 9 10 11 5 > z CI[17] + z CI[18] + z CI[19] + z CI[21] + z CI[23]} (* Es geht noch schlimmer mit anderen Pattern (x_ statt x_CI) *) In[14]:= Unprotect[Plus]; In[15]:= Plus[x_,y_] := CI[(Identity@@x) + (Identity@@y)] /; Head@x==CI && Head@y==CI; In[16]:= Protect[Plus]; (* ff und gg sind kuerzer als f und g *) In[17]:= ff = z^3*CI[2] + z^5*CI[2]; In[18]:= gg = n[4] + z^1*n[5] + z^5*n[6]; In[19]:= Timing@Collect[ff gg,z] 3 5 4 6 Out[19]= {34.73 Second, z CI[8] + z CI[8] + z CI[10] + z CI[10] + 8 10 > z CI[12] + z CI[12]} Noch eine Frage am Rande: Wie erreicht man dass die Summe in Out[1] nach Potenzen von z geordnet wird anstatt nach den Argumenten von CI[]? Also: z^3*CI[1] + z^4*CI[3] + z^5*CI[2] statt: z^3*CI[1] + z^5*CI[2] + z^4*CI[3] Jan Lahmann -- Jan-R. Lahmann Jan.Lahmann@XXXXXXX.de |