Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

Given a symbol t and an expression expr, how can I determine whether or not the symbol t appears somewhere in expr?

The best solution I have up with so far is:

Block[{t,s},(expr/.t->s)=!=expr]

which will return True if t is in expr, and False otherwise.

But this feels a bit like a hack because it's not really using /. because it's the right tool, but rather because /. happens to need to search through expr in order to do its unrelated task. This results in having to search through expr at least three times (I think?): once for the /., and twice for each side of the =!=, when clearly its possible to find t in only one search.

share|improve this question
6  
-1? Sure the answer is obvious once you know it, but I spent a very long time looking for an answer, and even longer trying to code my own answer. It's not like FreeQ is a terrible descriptive function name, and it's not listed in the 'Patterns' Guide, or the 'Testing Expressions' guide, or a bunch of other guides that might seem relevant to a newish user. –  Ian Hincks Aug 23 '12 at 17:42
2  
It's in "Testing and Searching List Elements" at least, but I have to agree that the omission of FreeQ[] in the "Testing Expressions" is a most unfortunate omission. –  J. M. Aug 23 '12 at 17:49
    
@J.M. i filed FreeQ as a suggestion to be added to "Testing Expressions" –  user21 Aug 23 '12 at 17:51
2  
Also even if it is obvious and easy to find, at least the question makes sense, is well-written, and doesn't need mind-reading skills to answer. This is more than can be said for lots of others that people upvote –  acl Aug 23 '12 at 18:44
4  
Don't forget FreeQ takes a levelspec optional argument. Can be useful if your quarry is hiding deep inside. Also there is Internal`DependsOnQ[expr,var] which attempts (operative word, that) to determine if expr has a functional dependence on x. Can be useful for tasks where detecting literal symbol presence is not quite what is wanted. Example: In[1]:= Internal`DependsOnQ[f[x], x] Out[1]= True –  Daniel Lichtblau Aug 23 '12 at 19:08
add comment

2 Answers 2

up vote 11 down vote accepted

Try FreeQ

FreeQ[x^2, t]
(*True*)
FreeQ[x^2, x]
(*False*)
share|improve this answer
add comment

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}

share|improve this answer
    
@Mr.Wizard If I am interested in testing for more than one variable I defined freeQ[a_, b_] := FreeQ[a, b] /; Length[b] <= 1; freeQ[a_, b_] := And @@ Map[FreeQ[a, #] &, b] /; Length[b] > 1 Is this the most efficient way to proceed? Why isn't it the default behaviour? –  chris Aug 23 '12 at 18:57
    
@chris I'd suggest trying Alternatives: FreeQ[expr, x | y | z] Or do you mean something else? –  Mr.Wizard Aug 23 '12 at 19:00
    
I understand your answer as I should use freeQ[a_, b_List] := FreeQ[a, Or@@b]/; Length[b] > 1 . (I was after FreeQ taking lists) –  chris Aug 23 '12 at 19:07
    
@chris no, I mean: freeQ[a_, b_List] := FreeQ[a, Alternatives @@ b] -- see Alternatives. –  Mr.Wizard Aug 23 '12 at 19:09
    
Thanks. I guess I have to wrap my head around Trott-Strzebonski, now. :) –  rcollyer Aug 23 '12 at 19:20
show 1 more comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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