8

Consider the built-in function FunctionDomain to find a domain of a composite function f(f(x)) where f(x)=1/x.

f[x_]:=1/x
FunctionDomain[Composition[f, f][x], x]
FunctionDomain[1/(1/x), x]

The output is True in both cases.

Apparently Mathematica simplifies the argument before applying the FunctionDomain. That's why it gives mathematically incorrect output (x=0 should be excluded). Composition[f,f][x]=f(f(x)) = 1/(1/x)= x. And the domain of x is all real numbers. In case when Hold function is applied to 1/(1/x) the output is x < 0 || x > 0 as it should be.

FunctionDomain[Hold[1/(1/x)], x]

Output: x < 0 || x > 0

But when Hold is applied to Composition[f, f][x] The result is completely different. FunctionDomain[Hold[Composition[f, f][x]], x] returns the input as output.

Why doesn't it work? What am I missing?

MarcoB
  • 67,153
  • 18
  • 91
  • 189
user45937
  • 1,291
  • 9
  • 16

2 Answers2

6

One idea is to convert the Composition into a form that partially evaluates its arguments, something like:

freezeComposition[c_Composition] := Composition[
    Apply@Hold,
    ReplaceRepeated[#, Hold[x_]->x]&,
    Apply@Defer,
    Composition[Hold,Evaluate,#]&/@c
]

Then, we can do:

f[x_]:=1/x
FunctionDomain[freezeComposition[Composition[f,f]][x], x]

x<0||x>0

Carl Woll
  • 130,679
  • 6
  • 243
  • 355
  • @ CarlWoll the function that you have defined works perfectly! However I'm not able to understand the syntax as I am a beginner user of Mathematica. – user45937 Jan 18 '17 at 13:59
  • I'm wondering if it's possible to achieve the same result using any of built-in Hold functions? I noticed that not only FunctionDomain but functions like Reduce and ReplaceAll return mathematically incorrect results. f[x_] := 1/x; {Reduce[1/(1/x) == 0, x, Reals],Reduce[f[f[x]] == 0, x, Reals],Solve[1/(1/x) == 0, x, Reals],Solve[1/(1/x) == 0, x, Reals],FunctionDomain[1/(1/x), x],FunctionDomain[f[f[x]], x],1/(1/x) /. x -> 0,f[f[x]] /. x -> 0} How can I prevent (partial) evaluation of the first argument? – user45937 Jan 18 '17 at 14:25
  • 1
    @roman465. All of these simplifications occur because Mathematica always attempts to find a general solution to the problem while (sort of) ignoring special (or corner) cases. – march Jan 18 '17 at 16:21
2

You could use StrictFunctionDomain function from Domains` package which evaluates given expression in special environment that prevents removal of removable singularities:

f // ClearAll
f[x_] := 1/x

StrictFunctionDomain[Composition[f, f][x], x]
(* x < 0 || x > 0 *)
StrictFunctionDomain[1/(1/x), x]
(* x < 0 || x > 0 *)
StrictFunctionDomain[Hold[1/(1/x)], x]
(* x < 0 || x > 0 *)
jkuczm
  • 15,078
  • 2
  • 53
  • 84