# How to organize expression by symbols (like Collect), but apply different functions to each coefficient

I want to mimic the functionality of Collect[expr, {vars}, func], but with the following modification: The function f that is applied to each coefficient is different, and depends on which variable it is a coefficient of. The vars are expressions of predetermined known heads (which in the example below are _e, _f, _g, _h).

Example:

expr = -2 x e[x] + x e[y] + x^2 e[x] + y e[x] + y e[y] + x^2 f[x] + y^2 f[x] + x^2 g[x] + y^2 h[x]

1. I need to collect expr by e[_], f[_], g[_] and h[_].

2. Apply simpE to the coefficients of e[_], and simpF to the coefficients of f[_], and simpGen to the coefficient of everything else.

3. This needs to work even when certain terms are absent from expr. e.g. if expr doesn't have any e[_] etc.

My idea (which doesn't work) is to do this in two steps:

1. First collect the expression:

Collect[expr, {_f, _e, _g, _h}]

2. Then replace with the rule that makes the transformation on each coefficient.

rule = (Plus[
Optional[Times[exprE_., funcE_e]],
Optional[Times[exprF_., funcF_f]],
rest_.]) :>
(simpE[exprE] funcE + simpF[exprF] funcF + Collect[rest,{_g, _h}, simpRest])


The (not quite correct) result is:

Collect[expr, {_f, _e, _g, _h}] /. rule


e[x] simpE[-2 x + x^2 + y] + f[x] simpF[x^2 + y^2] + g[x] simpRest[x^2] + h[x] simpRest[y^2] + simpRest[(x + y) e[y]]

But this doesn't work because

1. the rule groups e[y] with the rest of the terms and incorrectly applies simpRest to it (see last term of output), instead of simpE[x+y] e[y].

2. If certain terms are absent, then the rule doesn't even match. Consider expr2 below which is absent of f[_]:

expr2 = -2 x e[x] + x^2 e[x] + y e[x] + x e[y] + y e[y] + x^2 g[x] + y^2 h[x]


The rule doesn't match:

Collect[expr, {_f, _e, _g, _h}] /. rule


(-2 x + x^2 + y) e[x] + (x + y) e[y] + x^2 g[x] + y^2 h[x]

I need help with this particular modification of Collect. Is there a sexy way to get this done?

• Perhaps the function myCollect in this thread mathematica.stackexchange.com/questions/85479/… could help. It modifies collect to use a function not just of the coefficient but also of the term itself. You could then just use an if statement in the function you apply to differentiate the different terms. Don't know how sexy this is though. Dec 28 '15 at 14:29
• I notice that you have not Accepted an answer. Do neither of the answers work as you would like? Could you include the exact output that you hope for from each example? Jan 29 '16 at 2:12
• @Mr.Wizard ive been traveling, then got sick... Will come back when I get better Jan 29 '16 at 17:18
• I am sorry to hear that you have been ill. I hope it is entirely temporary and you are well very soon. Jan 29 '16 at 21:49

Maybe the following. Simplifying a left-over constant term along with the other coefficients seems hard to comprise in a single, simple function.

forms = {_f, _e, _g, _h};
funcs = {simpF, simpE, simpG, simpH};
simpConstant[c_] := simpC[c];
Times[c_simpAll, form_] ^:= (c /. simpAll -> (form /. Thread[forms -> funcs])) form;

Collect[2 + expr, {_f, _e, _g, _h}, simpAll] /. simpAll -> simpConstant
Collect[2 + expr2, {_f, _e, _g, _h}, simpAll] /. simpAll -> simpConstant
Collect[2 + x, {_f, _e, _g, _h}, simpAll] /. simpAll -> simpConstant
(*
simpC + e[y] simpE[x + y] + e[x] simpE[-2 x + x^2 + y] +
f[x] simpF[x^2 + y^2] + g[x] simpG[x^2] + h[x] simpH[y^2]

simpC + e[y] simpE[x + y] + e[x] simpE[-2 x + x^2 + y] +
g[x] simpG[x^2] + h[x] simpH[y^2]

simpC[2 + x]
*)


Perhaps

funs = {f, e, g, h}
apply = {sf, se, sgen, sgen}

Collect[z@x expr, Blank/@funs] /. (Times[a___, l: Blank@#, r___] :> k[a r, l] &/@funs)
(*

e[y] se[(x + y) z[x]] +
e[x] se[(-2 x + x^2 + y) z[x]] +
f[x] sf[(x^2 + y^2) z[x]] +
g[x] sgen[x^2 z[x]] +
h[x] sgen[y^2 z[x]]
*)


What about this. First you modify collect so that it doesn't group terms, and so the function acts not only on the coefficient but also on the variable, like so

myCollect[expr_, vars_, funct_ : (#1 #2 &)] :=
Expand@Collect[expr, vars, fDummy] //. {a_ fDummy[x_] :>
fDummy[a, x], a_ fDummy[b_, x_] :> fDummy[a b, x]} /.
fDummy[x_] :> fDummy[1, x] /. fDummy -> funct


Then simply define

simp[arg_e, coeff_] := arg simpE[coeff]
simp[arg_f, coeff_] := arg simpF[coeff]
simp[arg_, coeff_] := arg simpGen[coeff]


and apply:

myCollect[expr, {_f, _e, _g, _h}, simp]
(* e[y] simpE[x + y] + e[x] simpE[-2 x + x^2 + y] +
f[x] simpF[x^2 + y^2] + g[x] simpGen[x^2] + h[x] simpGen[y^2] *)


or for the second case,

myCollect[expr2, {_f, _e, _g, _h}, simp]
(* e[y] simpE[x + y] + e[x] simpE[-2 x + x^2 + y] + g[x] simpGen[x^2] +
h[x] simpGen[y^2] *)