# Delayed evaluation of assignment

I have a set of PDE's that depend on parameters. They depend on many parameters, but for simplicity we can here assume that they depend only on one, say a.

I want to solve them for many parameter sets, using something of the form

With[{a=1},NDSolve[...]]

But since I have many sets of parameters, and it is very inconvenient to enter them each time, I want to have something like

p1 = {a=1};
p2 = {a=Pi+4};
...
With[p1,NDSolve[...]]
With[p2,NDSolve[...]]


This clearly doesn't work because evaluating p1={a=1} assigns a value for a, and I don't want that (because I want to continue doing symbolic manipulations in other parts of the notebook). SetDelayed and RuleDelayed don't seem to work neither. Any ideas?

EDIT

I was asked to improve the description of my problem, so I try (and, on the way, thank all the people who tried to help).

The situation is this. I have a notebook that contains many formulas, which depend on many parameters. For example, I have

 f[x_]:= Sin[a x^b];
g[x_]:= a/x +Exp[-b]x;
diffEq={x'[t]==f[x[t]] x[t]^2-x/g[x[t]], x[0]==123};


I want to do symbolic manipulations on the formulas, so I don't want to assign numerical values to a,b. At the same time, I want to to solve the differential equation diffEq, and for this I want numerical values, and I want to solve it for different sets of paramters a,b. So I want to have variables which are assignments, something like

ass1={a->1,b->3};
ass2={a->123,b->Pi};
ass3={a->-32,b->1241203853};
...


So that I could easily do

With[ass1,NDSolve[...]]
With[ass2,NDSolve[...]]
....


and play around with the variables. I hope this better describes what I want to do.

-
Not sure I quite understand what you want. Would nested With be acceptable? For example, With[{p1 := {a = 1}, p2 := {a = Pi + 4}}, With[p1, Print[a]]; With[p2, Print[a]];]; – Oleksandr R. Apr 3 '12 at 12:40
@OleksandrR. But then I have to retype each time the assignments (a=1, etc.). I have around 12 parameters to type each time and I seek a way to circumvent it. – yohbs Apr 3 '12 at 13:28
I guess the problem is that I don't understand what "each time" means in this context, i.e. what your broader use case is. How about this: withp1 = Function[Null, With[{a = 1}, #1], HoldAll]. This lets you write withp1[...], e.g. withp1@Print[a] gives 1. I think this might be closer to what you want, assuming you can specify your parameter sets fully in advance? – Oleksandr R. Apr 3 '12 at 14:07
Related: (28610), (31708), (55833), (69590), (75417) – Mr.Wizard Jan 25 at 20:27

I think this does what you want, it is like a Block that accepts the local variables given as rules. Using Block instead of With should solve the problem that some of your parameters are "hidden in complicated functions":

ClearAll@blockrules

SetAttributes[blockrules, HoldAll]

blockrules[rules_, expr_] := Block @@ Join[
Hold @@ {rules} /. Rule -> Set,
Hold[expr]
]


use it like e.g.:

blockrules[ass1, NDSolve[diffEq, {x}, {t, 0, 1}]]


While I think this should solve the problem you were describing, you probably should think about rearranging your code so that it does not use global symbols hidden deeply in complicated functions as parameters but rather make those parameters explicit arguments to those functions. You are asking for all kind of hard to detect errors with those "hidden" parameters...

-

Perhaps something like this:

NDSolve @@ (f[arg, p2] /. {p2 :> (Pi + 4)})


where f is a dummy variable that should have the exact arguments NDSolve needs. Then, after the replacement of p2, f is replaced by NDSolve and evaluation commences.

-

Just use rule replacement normally on your list of equations, instead of on the NDSolve expression as a whole. For convenience, I recommend assigning the equations to a variable. For example:

In[23]:= eqns = {x'[t] == a y[t], y'[t] == -b y[t], x[0] == 1, y[0] == 0};

In[24]:= NDSolve[eqns /. {a -> 1, b -> 2}, {x, y}, {t, 0, 10}]
Out[24]= {{x -> InterpolatingFunction[{{0.,10.}},<>],
y -> InterpolatingFunction[{{0.,10.}},<>]}}

-
Thanks for the suggestion. This will not work because the parameters are hidden in complicated functions. For example, f[a]=Sin[a]; eqns={x'[t]=f[a] x[t],...} – yohbs Apr 3 '12 at 12:53
@yohbs, that does not work because it is not correct syntax. Try: f[a] = Sin[a]; eqns = {x'[t] == f[a] x[t]} /. {a :> (Pi + 4)} – user21 Apr 3 '12 at 13:41

This can be stated as:

I want to create a list of "assignments" that do not actually assign, but have a form like {x=1,y=2,z=3}, so that I can use these temporarily with With[].

One solution is to abandon your original approach and see if you can achieve your goal in another fashion. You cannot do this in Mathematica:

q={x=1,y=2,z=3}
s= Sin[x]+Cos[y]+Tan[z]
With[q,s]


because

1. the list q will evaluate to {1,2,3},
2. the undesirable side effect will assign global values to x, y, and z.

And there appears to be no way of stopping this by Hold etc. that is acceptable to With[].

So you do this:

qq={x->1,y->2,z->3}
s /. qq


Another way, not available in Mathematica, is to have some sort of macro expansion in which you generate a form, which could be With[], or Module[], such that the unevaluated forms of the assignments are assembled and passed into Module, and only then the whole thing is evaluated.

Is there a proper macro facility in Mathematica? It seems to me that it would be rather hard to construct given the evaluation semantics.

-
Richard, I am not really familiar with the "macro" functionality to which you refer but metaprogramming is certainly possible. In fact the Accepted answer to this Question does what I think you describe: it assembles assignments and passes them to Block. – Mr.Wizard Jan 25 at 20:45