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
|