# Controlling Expansion of Functions

Suppose I had the following definitions

const /: N[const] = 1 / Pi^2;
f /: N[f[x_]] := const / x^2;
g /: N[g[x_]] := Pi * Sqrt[f[x]] * x^2;


Now for this example, it is clear that g[x] == x for all values of x, but let's suppose there's a outside reason for defining these functions in this way.

Is there a way of controlling the expansion of g so that the result is in terms of f? For example, suppose I wanted to to simplify g[x] / f[x] while remaining f symbolic. The use of N unfortunately expanded everything which is not what I want.

I have tried using Inactive, but so far my attempts have not succeeded and I'm not sure whether there might be a better option.

• Why not Inactivate?: Inactivate[g[x]/f[x], f] // N – xzczd Sep 8 '20 at 6:13
• In the example above, this is fine; but what if g[x] contains a number of other functions which I don't want expanded? It then becomes a bit more difficult to use Inactivate (especially if I don't know a priori what functions went into defining g[x]). – JP-Ellis Sep 9 '20 at 4:09
• Just Inactivate all possible head that you don't want to expand? You may want to read the Scope section of document of Inactivate. – xzczd Sep 9 '20 at 4:39
• I guess using Inactivate[..., Except[g]] would work. If you want to post that as the answer? – JP-Ellis Sep 9 '20 at 12:22
• You can post an answer yourself :) . – xzczd Sep 9 '20 at 12:48

As mentioned by @xzczd, one possibility that can work in some conditions is to use Inactivate which works very well when there are certain explicit terms that need not be expanded, but it doesn't work terribly well with implicit terms (such as f within g as it isn't inactivated). It is possible to use Block[{f = Inactive[f]}, ...], but it still requires knowing the expansion.

I've managed to find another solution (for my use case) by manipulating the up and down values.

Consider the following base definitions:

const /: N[const] = 1 / Pi^2;
f[x_?InexactNumberQ] := const / x^2;
g /: N[g[x_]] := Pi * Sqrt[f[x]] * x^2;

Attributes[ExpandValues] = {HoldAll};
ExpandValues[symbol_] := Join @@ Through[
{OwnValues, DownValues, UpValues, SubValues, DefaultValues, NValues}[symbol]
] /. {
InexactNumberQ :> (True &),
HoldPattern[N[f_, __]] :> f
}
ExpandValues[symbol_, symbols__] := Join[ExpandValues[symbol], ExpandValues[symbols]]


The definition of ExpandValues function looks at the symbol's values to create a list of replacement, and the left hand side of the rules so they can be applied more broadly (for example, but replacing N[f[x_]] with just f[x_] and removing checks for inexact numbers).

Here are some examples of it being used:

g[x] /. ExpandValues[g]

Pi x^2 Sqrt[f[x]]

g[x] / f[x] //. ExpandValues[g]

Pi x^2 / Sqrt[f[x]]

g[x] / f[x] //. ExpandValues[g, f]

Pi Sqrt[const / x^2] x^4 / const