I want to implement the following type evaluation symbolically

$$(f^2g + fg + g)(x) \to f(x)^2 g(x) + f(x) g(x) + g(x)$$

In general, on left hand side there is a polynomial in an arbitrary number of functions (e.g. $f, g^3 h, (f_1 + f_2 + f_3)^3, \dots$ and on the right hand side all the functions have been evaluated at the same element $x$. I would to define a function eval or a rule such that

In[1]:= (f^2g + fg + g)[x] // eval
In[2]:= f[x]^2 g[x]+ f[x] g[x] + g[x]

What is a good way of accomplishing this?

polyThrough[h_[a___]] := h /. Map[#1 -> #1[a] &, Variables[h]]
((3 f^2 g + 5 f g + g)^2 )[x, y, z] // polyThrough

enter image description here

((a - b)/(x + y) - 2/z)[] // polyThrough

enter image description here

  • $\begingroup$ That's concise! For arbitrary coefficients one can filter Variables[h] with /. v_?coeffQ -> Sequence[] given the Boolean function coeffQ. $\endgroup$ – Ryogi Aug 8 '12 at 16:48

The first thing that comes to mind is to use Through, as in

Through[(f + g)[x]]

f[x] + g[x]

However, this is a little tricky to apply when you also have powers as in f^2 - so in your case it seems to be more efficient to make use of the fact that all symbols are evaluated at the same x anyway (i.e., there isn't any f[y] and f[z] anywhere). Then you could simply do this:

eval = s_?(MemberQ[{f, g}, #] &) :> s[x]

(* ==> s_?(MemberQ[{f, g}, #1] &) :> s[x] *)

f^2 g + f g + g /. eval

(* ==> g[x] + f[x] g[x] + f[x]^2 g[x] *)


The above replacement rule eval restricts the names of your functions to f and g, but the list could be expanded arbitrarily. Having an explicit "white list" of names for allowed functions is safer in my opinion. However, one can also construct patterns that don't rely on a knowledge of the function names, as long as we can make some other assumptions.

In response to the comment, let's assume that your polynomial has the added special property that it contains no symbolic constants as coefficients. Then we can be sure that all symbols that aren't arithmetic operations must be functions of x, and therefore, we could test for the property NumericFunction among the Attributes of a symbol:

eval = 
 s_Symbol?(! MemberQ[Attributes[#], NumericFunction] &) :> s[x]

==> s_Symbol?(! MemberQ[Attributes[#1], NumericFunction] &) :> 

f^2 g + f g + g /. eval

(* ==> g[x] + f[x] g[x] + f[x]^2 g[x] *)

This allows you to use any symbol for your functions, as long as it's not a reserved name for a numeric function such as Plus, Times or Power.

  • $\begingroup$ Thanks for you answer. Your solution works fine when a small number of symbols is involved. In my case I do not know beforehand the "function" names. $\endgroup$ – Ryogi Aug 8 '12 at 0:48
  • 1
    $\begingroup$ Well, in general when specifying a polynomial one does have to state what are the variables and what are the coefficients. The list {f, g} serves that purpose of identifying what space your polynomial lives in. So are you saying that all the possible coefficients in your polynomial are going to be numerical values? $\endgroup$ – Jens Aug 8 '12 at 0:53
  • $\begingroup$ Thanks for the edit. You are correct in that I need to specify a pattern for either the polynomial variables or the coefficients. $\endgroup$ – Ryogi Aug 8 '12 at 2:05
  • $\begingroup$ Is there any advantage of your pattern s_?(MemberQ[{f, g}, #] &) over the simpler s:(f|g)? $\endgroup$ – celtschk Aug 8 '12 at 15:00
  • $\begingroup$ @celtschk No, except that you could define vars = {f, g} as a list beforehand as a global variable and then use it here as vars. $\endgroup$ – Jens Aug 8 '12 at 15:10

The following seems to work pretty well, and not only for polynomials.

Not sure about its robustness.

eval[r_] := r /. u_[s__] :> u /. x_Symbol /; Context@x == "Global`" :> x @@ Level[r, {-1}]

Test drive

(3 f^2 g + f g + g)[u, w] // eval
-> g[u, w] + f[u, w] g[u, w] + 3 f[u, w]^2 g[u, w]

(f^g + d)[w, v] // eval
-> d[w, v] + f[w, v]^g[w, v]

(Sin[h] f + 3 d)[u] // eval
-> 3 d[u] + f[u] Sin[h[u]]
  • $\begingroup$ Is there a simple way to introduce coefficients other than numeric symbols? $\endgroup$ – Ryogi Aug 8 '12 at 5:55
  • $\begingroup$ @RYogi Define them in any Context other than Global :) $\endgroup$ – Dr. belisarius Aug 8 '12 at 5:57
  • $\begingroup$ @RYogi If you decide to try this answer, please comment about its robustness, as I'm afraid I did a very limited testing $\endgroup$ – Dr. belisarius Aug 8 '12 at 6:04
  • $\begingroup$ Context ... of course ;) $\endgroup$ – Ryogi Aug 8 '12 at 6:05
  • $\begingroup$ It doesn't behave on expression like the last example in my answer. In a sense it's too flexible to play nice with polynomials. $\endgroup$ – Ryogi Aug 8 '12 at 6:09

Here is slight modification that generalizes Jens's.

eval[sympoly_, coeffQ_:False] := Head@sympoly /. s_?
       Variables[Head@sympoly] /. v_?coeffQ -> Sequence[]
       , #] &
     ) :> s[Level[sympoly, 1] /. List -> Sequence]

The pattern sympoly_ holds an expression of the form (f^2g + fg + g)[x], as in the question. Jen's evaluation rule is applied to the Head of sympoly, while the evaluation point is extracted using Level and the r.h.s. of Jen's rule s[x] modifed to s[Level[sympoly, 1] /. List -> Sequence].

Which expressions in sympoly are to be considered variables is checked with a Boolean test (MemberQ). First, all possible variables are obtained using Variables. Then, they are filtered with a rule to exclude coefficients (using the ad-hoc test function coeffQ). By default numerical symbols are coefficients as they are not recognized as variables by Variables. The variables of sympoly are the output of

Variables[Head@sympoly] /. v_?coeffQ -> Sequence[]

Here's an example

(3 f^2 g + f g + g)[x] // eval
g[x] + f[x] g[x] + 3 f[x]^2 g[x]

Here coefficients are h[i], h[j], h[k] (any symbol with head h):

eval[(h[i] f^2 g + h[j] f g + h[k] g)[x], Head[#] == h &]
f[x]^2 g[x] h[i] + f[x] g[x] h[j] + g[x] h[k]

The function eval works also on more general symbols

(3 f[1]^2 f[2] + ff g[f[h]])[x, y, z] // eval
3 f[1][x, y, z]^2 f[2][x, y, z] + ff[x, y, z] g[f[h]][x, y, z]

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.