Determine whether some expression contains a given symbol
Try FreeQ
FreeQ[x^2, t]
(*True*)
FreeQ[x^2, x]
(*False*)
ruebenko provides the built-in function, but supposing FreeQ
was not provided we can find another way. You are on the right track to use ReplaceAll
, but it would be much better to give a result as soon as the search pattern is found.
freeQ[expr_, pat_] :=
Catch[expr /. pat :> RuleCondition@Throw[False, "freeQ"]; True, "freeQ"]
RuleCondition
(1)(2)(3) is needed in the case that expr
is Hold[ ]
or the Throw
will never evaluate.
Creating a massive expression (~1GB) and doing Timings (each in a separate session to circumvent caching) shows that this is reasonably fast.
big = Expand[(1 + x + y)^200 (2 - q)^150];
! FreeQ[big, q] // Timing
{1.03, True}
! freeQ[big, q] // Timing
{1.311, True}
Block[{q, s}, (big /. q -> s) =!= big] // Timing
{6.739, True}
Another approach that is cleaner, but perhaps less didactic, that will also return as soon as the pattern is found uses Cases
:
freeQ2[expr_, pat_] :=
{} === Cases[expr, pat, {0, -1}, 1, Heads -> True]
! freeQ2[big, q] // Timing
{0.983, True}
An important difference is that ReplaceAll
(short form /.
) will scan from the outside in while Cases
, like most Mathematica functions, will scan inside out. See:
- How to perform a depth-first preorder traversal of an expression?
And more examples:
- ReplaceRepeated seemingly omits some rules
- How to remove redundant {} from a nested list of lists?
- Using ReplaceAll to replace a head
- why Level does not sort output according to their levels
- How to ReplaceAll independent of depth?
- Is Replace doing double work?