Re: What's this Mathematica function called?
- To: mathgroup at christensen.cybernetics.net
- Subject: [mg952] Re: What's this Mathematica function called?
- From: villegas (Robert Villegas)
- Date: Thu, 4 May 1995 02:04:01 -0400
- Organization: Wolfram Research, Inc.
In article <3npos0$od2 at news0.cybernetics.net> martind at carleton.edu
(D<martind at carleton.edu>M) writes:
> First let me apologize for what I'm pretty certain is a question
> that I could find if only I searched through the big black book
> long enough. However, I am unable to find an answer anywhere in
> the index, so I'll ask it here.
>
> What is Mathematica function that determines if one expression
> depends on another? i.e. if this function were called Depends, it
> would give output something like this:
>
> Depends[x + 3, x]
> ==> True
>
> Depends[y, x]
> ==> False
>
> y := x^2
>
> Depends[y, x]
> ==> True
>
> Depends[f[g[x]], x]
> ==> True
>
> Depends[f[g[y]], x]
> ==> True
>
> Clear[y]; Depends[f[g[y]], x]
> ==> False
If the variable x (or whatever expression) that you want to find
occurs as an operand in a sum, product, or the like, or is an argument of
a function, then MemberQ will detect it. At its default, MemberQ checks
only the main elements (level 1), so in (x + y^2 + ArcSinh[z]) it will
find
x, but it will miss y and z because they are deeper than level 1.
In[1]:= MemberQ[x + y^2 + ArcSinh[z], x]
Out[1]= True
In[2]:= MemberQ[x + y^2 + ArcSinh[z], y]
Out[2]= False
In[3]:= MemberQ[x + y^2 + ArcSinh[z], z]
Out[3]= False
However, we can tell MemberQ to sweep through every level of the
expression looking for x, from the whole down to the atoms,
by giving an extra argument of {0, -1} (called the _level specification_).
Here are some examples of finding symbols, or more complex objects, in
some expressions.
In[4]:= MemberQ[x, x, {0, -1}]
Out[4]= True
In[5]:= MemberQ[x + 3, x, {0, -1}]
Out[5]= True
In[6]:= MemberQ[x + y^2 + ArcSinh[z], z, {0, -1}]
Out[6]= True
Let's try a case where the item we want is submerged pretty far:
In[7]:= cont = Nest[1 + (1 + 1/#^2)^-1 &, x, 4]
1
Out[7]= 1 + -------------------------------------------
1 -2
1 + (1 + -------------------------------)
1 -2
1 + (1 + -------------------)
1 -2
1 + (1 + -------)
-2
1 + x
In[8]:= MemberQ[cont, 1 + x^-2, {0, -1}]
Out[8]= True
Position tells us how many coordinates it takes to pinpoint the
object, and hence how deep it is:
In[9]:= Position[cont, 1 + x^-2]
Out[9]= {{2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1}}
In[10]:= Length @ First[%]
Out[10]= 14
See pp. 197-199 of the second edition of the Mathematica book for a
discussion of levels. Section 2.3 talks about MemberQ and related
things.
MemberQ, like its cousins Cases, Position, et al, can deal with a pattern,
too. Examples of more generic searches:
In[11]:= MemberQ[cont, 1 + x^_, {0, -1}]
Out[11]= True
In[12]:= MemberQ[cont, 1 + _^-2, {0, -1}]
Out[12]= True
What I gave won't detect the p in T[p][x, y], though. Here, the p
is inside the head T[p] of the expression, but MemberQ ignores heads.
You can tell it not to with the option Heads->True.
In[13]:= MemberQ[T[p][x, y], p, {0, -1}]
Out[13]= False
In[14]:= MemberQ[T[p][x, y], p, {0, -1}, Heads->True]
Out[14]= True
A possibly undesirable side-effect is that it also finds T, which
is likely thought of as the function, of which p is a parameter
that could just as easily have been an argument along with x, say
T[p, x, y]. If the spirit of your question was to find x when it
occurs as a "variable" but not as a "function", then I think you
could put a test on the position of a match. Here's one possibility
(I haven't even defined the problem to my satisfaction, yet, so I
don't know if it will do what you want):
ElementButNotHeadQ[expr_, patt_] :=
Not[ Or @@ Map[MatchQ[#, {___, 0}]&, Position[expr, patt]] ]
Here's how it behaves on something that has functions in the head and
elements:
In[20]:= expr = T[x[a, b], y[c, d]] [ u[p, q], v[r, s] ]
Out[20]= T[x[a, b], y[c, d]][u[p, q], v[r, s]]
(* variables = True: *)
In[21]:= ElementButNotHeadQ[expr, p]
Out[21]= True
In[22]:= ElementButNotHeadQ[expr, c]
Out[22]= True
(* functions = False: *)
In[23]:= ElementButNotHeadQ[expr, T]
Out[23]= False
In[24]:= ElementButNotHeadQ[expr, v]
Out[24]= False
(* Possibly silly, possibly not: *)
In[26]:= ElementButNotHeadQ[expr, y[c, d]]
Out[26]= True
If you can give a precise definition of "depends on" for your purposes,
then something in this direction ought to work.
Robby Villegas
P.S. If you really want to play around with it some more, here is
a function I used to help myself see whether my ElementButNotHeadQ
was really doing what I wanted on all the different parts of the
expression, heads and all. You could use something like it when
you are trying your own tests. It's scary-looking, but all it does
is go through and test every subexpression, and print the outcome
of the test, with indentation to make the results easier to read
(if you don't want the indentation, throw out MapIndexed and use
MapAll, but the output might be a bit harder to read).
result[part_, position_] :=
( Print[""];
Print[Indent[2 Length[position]], part, " ===> ",
ElementButNotHeadQ[expr, part]];
part
)
In[31]:= MapIndexed[result, expr, {0, -1}, Heads->True]
T ===> False
x ===> False
a ===> True
b ===> True
x[a, b] ===> True
[... lines deleted ...]
Out[31]= T[x[a, b], y[c, d]][u[p, q], v[r, s]]