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