# Extract variables from sum of unevaluted functions

I have sums of the form

sum = a f[1,1,0] + b f[1,2,0] + c f[1,2,1] + ...


It is always linear in f[a,b,c]. I would like a function that returns a list of all f[a,b,c] appearing in the sum. Following an answer from this question, I have created the following function, which behaves correctly when evaluated on sum:

getVariables[expr_, f_] := DeleteDuplicates@Cases[expr,f, Infinity];
getVariables[sum, f[_,_,_]]
(*{f[1, 1, 0], f[1, 2, 0], f[1, 2, 1], ...}*)


The problem is that when there's a single function it does not work:

getVariables[f[a,b,c], f[_,_,_]]
(* {} *)


It only fails when it's exactly f[a,b,c] and works fine for e.g. 2f[a,b,c].

What am I missing here? I do not get why it would fail in that case.

• The level specification Infinity (which is equivalent to {1, Infinity} does not include level 0 (i.e. the whole expression), which is why nothing is found in f[a,b,c]. You can use {0, Infinity} or All instead to also include level 0 Oct 13 '19 at 15:19

Expanding on @Lukas Lang's comment, the problem comes from the default level specification of Cases and the fact that f appears as the head (or rather, at part 0/only in level 0) in f[a,b,c].

From the Cases documentation

The default value for levelspec in Cases is {1}.

So when a level is specified, say for example as Cases[f[a, b, c], _f, Infinity], Mathematica implicitly interprets this is Cases[f[a, b, c], _f, {1, Infinity}]. This works great for expressions like your sum since it has the form

a f[1, 1, 0] + b f[1, 2, 0] + c f[1, 2, 1] // FullForm
Level[%, {1}]


Plus[Times[a, f[1, 1, 0]], Times[b, f[1, 2, 0]], Times[c, f[1, 2, 1]]]

{a f[1, 1, 0], b f[1, 2, 0], c f[1, 2, 1]}

and the stuff you want to work with starts at level 1.

Now with that being said, just the single instance of f[a, b, c] has a different structure and its elements on level 1 are

Level[f[a, b, c], {1}]


{a, b, c}

So when the above usage of Cases (i.e. starting at level 1) is called on this structure, it doesn't see the f, and thus doesn't return anything.

Then we return to the Cases documentation to see

Level 0 corresponds to the whole expression.

And there we have our solution. If we want to search the whole expression, instead of starting at level 1, we need to call Cases as

Cases[f[a, b, c], _f, {0, Infinity}]


{f[a, b, c]}

• Thanks for expanding @Lukas Lang's explanation, that was indeed the culprit. Oct 14 '19 at 15:33