This is a follow-up to my (solved) question How to distribute a generic function of two arguments (without evaluating the arguments)

Say, I have a binary function

f[x : a_List, y : b_List] := g[a, b]

Now if

u={u1,u2};

v={v1,v2};

w={w1,w2};

I want do distribute f[u,v+w] prior to evaluating v+w which works fine with the solution proposed by Mr. Wizard to my previous question

Distribute[Unevaluated@f[u,v+w]]

(** g({u1,u2},{v1,v2})+g({u1,u2},{w1,w2}) **)

But now what if I do

expr = v + w;

and try to distribute f[u,expr]? I would like to get the same result as before, however this yields

f[u,expr]

(** g({u1,u2},{v1+w1,v2+w2}) **

as of course v+w is evaluated when assigning to expr. Now a SetDelayed approach expr := v+w also doesn’t help. I then thought of doing

expr = Hold[v+w];

Distribute[Unevaluated@ftest[u, ReleaseHold[expr]]]

(** g({u1,u2},{v1+w1,v2+w2}) **)

but this also gives the wrong (i.e. not the desired) result.

So, how do I do this?

=================

BTW: If anyone can think of a better title for this question, suggestions or edits would be highly welcome. I just don’t really know how to put this problem into a concise title..

– janitor048

Oct 24 ’12 at 16:44

=================

2 Answers

2

=================

You are better off thinking that in Mathematica you can control when and if an expression evaluates or not. But, if it evaluates, it does it until it doesn’t change any more.

In this case, you can make expr either stay as is, or evaluate

(1) expr

->

(2) {v,w}

->

(3) {{v1,v2}+{w1, w2}}

->

(4)

{{v1+w1, v2+w2}};

Actually, since your definition of expr is immediate (you used Set) it is actually stored as {{v1+w1, v2+w2}} already.

If you don’t want that to happen, you have to change your design (for example, using a wrapper other than List for your vectors), or temporarily disable the definitions you want to hold. For the distributibity to work, the evaluation must stop at step (2) or (3)

Change your expr definition to a SetDelayed

expr := v + w;

and now either block Plus so it is no longer Listable while you distribute (step (3) ), or block your symbols (step (2) )

Block[{Plus}, Distribute@f[u, expr]]

Block[{v, w}, Distribute@f[u, expr]]

g[{u1, u2}, {v1, v2}] + g[{u1, u2}, {w1, w2}]

g[{u1, u2}, {v1, v2}] + g[{u1, u2}, {w1, w2}]

That looks familiar. +1

– Mr.Wizard♦

Oct 24 ’12 at 19:58

Hehe, good luck with the 400 bounty @Mr.Wizard

– Rojo

Oct 24 ’12 at 20:01

I’m not aiming for that. I don’t really understand the problem, and even if I did I’m not sure I have much to offer. I did manage to fix an inefficient For loop, but that’s about it. Nevertheless when I see someone put a big bounty on something I know they really want an answer, so I did what I could.

– Mr.Wizard♦

Oct 24 ’12 at 20:03

1

Yeah, I’m also active today not for the rep… only to not focus on my work

– Rojo

Oct 24 ’12 at 20:05

Rojo got my favorite method already but for illustration here is a way to make your Hold approach work.

expr = Hold[v + w];

f[u, expr] /. h_Hold :> Distribute@h // Distribute // ReleaseHold

g[{u1, u2}, {v1, v2}] + g[{u1, u2}, {w1, w2}]

Good example of “changing the design”. +1

– Rojo

Oct 24 ’12 at 20:18