DMUG-Archiv 2000

Frühere   Chronologischer Index   Spätere
Vorherige   Thematischer Index   Nächste

Re: PrioritXre Evaluation von Funktionsargumenten

Hartmut Wolf schrieb:
> 
> Wolfgang Ludwig schrieb:
> >
> > Liebe Mathematica Spezialisten,
> > mir liegt folgendes Problem auf:
> > Die Funktion NIntegrate ist in der Lage, eine  Funktion func[a,b] so
> > abzuarbeiten, daß zuerst die numerischen Werte in die Argumente
> > eingesetzt werden, und danach die Funktion evaluiert wird.
> > Es sei
> > func=Compile[{{a,_Real,1},{b,_Real,1}},Plus@@Flatten[Outer[Times,a,b]]]
> > eine compilierte Function mit vektoriellen Argumenten.
> > a und b werden z.B. definiert nach
> > a={c,d};b={e,f}
> >
> > für die Werte c bis d gibt es eine Werteanweisung entsprechend
> > rpl={c->1.,d->2.,e->3.,f->4.}.
> >
> > Mit NIntegrate kann ich die Funktion so aufrufen, daß zuerst die
> > Argumente, dann die Funktion evaluiert werden.
> > NIntegrate[func[a, b], {c, 0, 1}, {d, 0, 1}, {e, 0, 1}, {f, 0, 1}]
> > Ergebnis: 1.
> > Keine Fehlermeldung!
> >
> > Ich möchte nun eine Funktion test erzeugen, die in Bezug auf den
> > Funktionsaufruf dasselbe leistet.
> >
> > test[model_, parsNum_, pars_] :=
> >   Module[{rpl},
> >     rpl = MapThread[Rule, {pars, parsNum}];
> >     model /. rpl
> >     ]
> > Der Aufruf
> > test[func[a, b], {1, 2, 3, 4}, {c, d, e, f}]
> > ergibt jedoch einen Error, weil die complilierte Funktion zuerst die
> > Variablen anstelle der Werte bekommt.
> >  Mir ist bisher keine Möglichkeit bekannt, die Auswertereihenfolge
> > herumzudrehen. Auch mit HoldForm und ähnlichen Tricks habe ich es nicht
> > geschafft.
> >
> > Ich würde mich freuen, wenn mir jemand den Trick verraten könnte. Es muß
> > gehen, da NIntegrate es ja schafft.
> >
> > Herzlichen Dank
> >
> > Wolfgang Ludwig
> >
> 
> Hallo Wolfgang,
> 
> sicherlich verstehe ich dein Problem nicht ganz. Aber vielleicht helfen
> dir folgenden Beobachtungen:
> 
> 
> In[1]:= Clear[a, b]      (* das ist wichtig *)
> 
> In[2]:= func = Compile[{{a, _Real, 1}, {b, _Real, 1}},
>     Plus @@ Flatten[Outer[Times, a, b]]]
> Out[2]=
> CompiledFunction[{a, b},
>   Plus @@ Flatten[Outer[Times, a, b]], "-CompiledCode-"]
> 
> In[3]:= test[model_, parsNum_, pars_] :=
>   Module[{rpl}, rpl = MapThread[Rule, {pars, parsNum}];
>     Unevaluated[model] /. rpl]
> 
> In[4]:= test[Unevaluated[func[a, b]], {{1, 2}, {3, 4}}, {a, b}]
> Out[4]= 21.
> 
> Eine *reelle* 21.!
> 
> Die Function func wird solange unevaluiert gehalten, bis die Platzhalter
> a, b substituiert sind. Das erste Unevaluated (im Aufruf von test) ist
> verzichtbar, wenn test das Attribut HoldFirst hat. Beachte aber das
> zweite Unevaluate im Funktionsrumpf von test, das ist entscheidend!
> 
> Oder wickle den Ausdruck, der func mit symbolischen Variablen enthält,
> in With, wodurch diese (durch textuelle Substitution) Werte bekommen.
> 
> In[6]:= With[{x = {1, 2}, y = {3, 4}}, g[{x^2 .y}, func[x, y]]]
> Out[6]=
> g[{19}, 21.]
> 
> Oder in Funktionen wie Plot werden ohnehin erst die Argumente
> substituiert, bevor die Funktion gerufen wird:
> 
> In[11]:=
> Plot[func[{r, r + 1}, {r + 2, r + 3}], {r, 0, 1000}]
> 



Lieber Wolfgang

Mir kommt da noch eine andere Idee. Vielleicht gehst du so vor: du hast
die compilierte Funktion mit zwei Parametern a, b; diese ersetzt du
durch die Modellparameter a={c,d}, b={e,f} *symbolisch*.  Bei Ausführung
des Modells haben dann die Modellparameter Werte. Dein Problem ist, daß
wenn immer func[a, b] evaluiert, die numerischen Werte für c,d,e,f
vorliegen müssen. Das kannst du mit Block erreichen:


In[1]:= func = Compile[{{a, _Real, 1}, {b, _Real, 1}}, 
    Plus @@ Flatten[Outer[Times, a, b]]]
Out[1]=
CompiledFunction[{a, b}, 
  Plus @@ Flatten[Outer[Times, a, b]], "-CompiledCode-"]

In[2]:= ClearAll[test2]
In[3]:= SetAttributes[test2, HoldAll]

In[4]:= test2[model_, parsNum_, pars_] := Block[pars, pars = parsNum;
model]

In[5]:= a = {c, d}; b = {e, f};
In[6]:= Clear[c, d, e, f]

In[7]:= {test2[func[a, b], {1, 2, 3, 4}, {c, d, e, f}],     {a, b}}
Out[7]= 
{21., {{c, d}, {e, f}}}


Du kannst dann die Werte der Symbole a, b im Laufe deiner Berechnung
umdefinieren:

In[10]:= a = {c, d, e}; b = {f, g, h};
In[11]:=
test2[func[a, b], {1, 2, 3, 4, 5, 6}, {c, d, e, f, g, h}]
Out[11]= 90.



Zuvor solltest du aber prüfen, ob du nicht einfach mit einer
Neudefinition auskommen kannst:

In[14]:= func2[c_, d_, e_, f_] := func[{c, d}, {e, f}]

In[15]:= func2[1, 2, 3, 4]
Out[15]= 21.

Dann hast du deine aktuell variierenden Parameter und nutzt die
kompilierte Funktion.


Gruß, Hartmut


Verweise:
Frühere   Chronologischer Index   Spätere
Vorherige   Thematischer Index   Nächste

DMUG DMUG-Archiv, http://www.mathematica.ch/archiv.html