7

I want to check if a user input the function with all the specified variables or not. For that I choose the replace variables with some values and check for if the result is a number or not via a doloop. I am thinking there might be more elegant way of doing it such as ReplaceList but it is not working the way I want it.

Lets assume

   u = z^2 Sin[π x] + z^4 Cos[π y] + I y^6 Cos[2 π y] + w;
   (*and user give variables as *)
   vas = {x, y, z, w};
   (* I need to check if all the variables are in the function *)

   Do[

   u = u /. vas[[i]] -> 1.1; 
   (* 1.1 is within where the function is going to get \
    evaluated *)

   If[i == 4, numc9 = NumericQ[u]; Print[numc9];]; 
   (* if numc9 False either there infinity or one of \
   the variables in the list is not present in the function or function      \
    has extra variable(s) *)

    Print[u];

    , {i, 4}]

Is there more elegant way doing it?

EDIT I

After @Mr.Wizard 's answer I realized that my question was not covering everything I wanted. @Mr. Wizard answer is working, if I was checking all the variables are present in u. However, at the same time I want to check if there is no extra variables in u. Because at the end I want to evaluate u using vars and if u has an extra variable I won't get a value at the end.

For example:

  u = z^2 Sin[π x] + z^4 Cos[π y] + I y^6 Cos[2 π y] + w + z^p;
  vas = {z, x, y, p};

Level and FreeQ commands give all the variables in function u. After that you check if all the variables in vas are present in this list of variables coming from Level or FreeQ and in the example above its.

In this situation @J.M. undocumented command does what I need. Or I will need to stick with my DoLoop.

Mr.Wizard
  • 271,378
  • 34
  • 587
  • 1,371
Erdem
  • 869
  • 4
  • 11
  • @Micheal E2 I am not sure if I am following your question. – Erdem Aug 01 '16 at 11:53
  • What if the user enters u = y z^2 w^3? Would that be valid or invalid if the variables are specified as {x, y, z, w}? Or does the user have to specify exactly the variables that literally occur? – Michael E2 Aug 01 '16 at 11:56
  • Are constant functions allowed? Would the variables have to be specified as vas = {}? (Your Do-loop allows constant functions, BTW, but the accepted answer does not. It also allows some variables to be missing. Change u to u = 1, for example.) – Michael E2 Aug 01 '16 at 12:15
  • 1
    u= y z^2 w^3 is an acceptable function and user can enter vas={x,y,z,w} and Sort[vas] === Variables @ Level[u, {-1}] result in False so I won't do the calculation (Because there is one extra variable.) I checked u=1; with the accepted answer and it does work. The rhs produce {} and is it not equivalent with Sort[vas]. About vas, the user will actually enter set of variables with set of limits like {x,-1,1},{w,0,2} for the u function. I will subtract variables from there. – Erdem Aug 01 '16 at 12:40
  • One might use a strategy similar to NIntegrate[] in that case. I'll try to work up an answer. – Michael E2 Aug 01 '16 at 14:23
  • What do you intend to do with a + w + x + y + z - a, which contains all the variables and an extra variable that contributes nothing to evaluation (in fact easily simplifies away)? – Eric Towers Aug 02 '16 at 02:10
  • For me it does contribute to the evaluation it just does not change the result. As long as, a is given in the vas for the purpose of calculation it is fine – Erdem Aug 02 '16 at 09:05

5 Answers5

11

Using an undocumented function:

Reduce`FreeVariables[u] === Sort[vas]
J. M.'s missing motivation
  • 124,525
  • 11
  • 401
  • 574
  • (If u had been a polynomial function, use the documented function Variables[] instead.) – J. M.'s missing motivation Aug 01 '16 at 09:57
  • Nice! Shouldn't this been in (805)? – Mr.Wizard Aug 01 '16 at 09:57
  • I guess... I'll write something up later. – J. M.'s missing motivation Aug 01 '16 at 09:58
  • I think you could also give this in answer to (30038) – Mr.Wizard Aug 01 '16 at 10:03
  • Thank you for the answer. But some in this forum I read that using undocumented functions might be problem from version to version. Also, how do you reach to undocumented functions? I know there is a topic open in here but I never understood why they have undocumented functions. – Erdem Aug 01 '16 at 10:06
  • @Erdem, that's right, and that's why I emphasized undocumented. I don't have a better answer for "how to find them" than by looking through stuff in Contexts[] and using Information[]. – J. M.'s missing motivation Aug 01 '16 at 10:09
  • @Erdem It is true; undocumented functions may change or be removed. They are either experimental or necessary for internal functionality but not deemed stable enough for permanent inclusion. Some may crash kernel if given input that does not match expectation. – Mr.Wizard Aug 01 '16 at 10:10
  • This works fine for me (I had to edit my question because I realized my question was not complete. ) You suggestion works for both situation. – Erdem Aug 01 '16 at 10:42
10

Update

Following your updated question I recommend filtering Level output with Variables as I proposed here. Then Sort vas and check for equivalence.

Sort[vas] === Variables @ Level[u, {-1}]

Original proposals

The first idea that came to mind:

Level[u, {-1}] ⋂ vas === Sort[vas]

Equivalently:

Complement[vas, Level[u, {-1}]] === {}

A method using FreeQ

Nor @@ Through @ Map[FreeQ][vas][u]

Or without version 10 Operator Forms:

Nor @@ Through @ (FreeQ /@ vas)[u]
Mr.Wizard
  • 271,378
  • 34
  • 587
  • 1,371
  • Thank you. I realized that I missed a point in my question. I edited it. You answer works fine what I wrote initially. – Erdem Aug 01 '16 at 10:40
  • @Erdem Please check my updated proposal and let me know if it has problems. – Mr.Wizard Aug 01 '16 at 10:47
  • Works like a charm :) – Erdem Aug 01 '16 at 11:05
  • @Erdem Glad I could help, and thanks for the Accept. – Mr.Wizard Aug 01 '16 at 11:42
  • 2
    @Erdem I see you switched the Accept to J. M.'s answer after my comment. That is entirely your prerogative, but may I ask why? Did my method prove inferior or did you ease your concern about undocumented functions? – Mr.Wizard Aug 01 '16 at 11:59
  • No but that works too. I simply did not know that I had to choose only one answer. I just wanted to give credit to J.M. too for taking his time and posting an answer. Several answers show that there are different ways to reach to same result and on the way you might learn to do other things. I wanted to show that for my issue both yours and @J.M. s answer are working. And from your answer I learnt the command Level and from his answer the undocumented function. After checking the Level command I see I can put 2 instead of -1 and get more complex structure. I have no ill will – Erdem Aug 01 '16 at 12:51
3

Another undocumented function: Internal`LiterallyOccurringQ:

And @@ (Internal`LiterallyOccurringQ[u, #] & /@ vas)

True

And @@ (Internal`LiterallyOccurringQ[u, #] & /@ {x, y, t})

False

kglr
  • 394,356
  • 18
  • 477
  • 896
3

Since it is user input and guessing from the loop that the OP is calculating something numerical, I think it is better to check that the user has entered a numerical function, not just an expression with only legal variables. I asked about constant functions and other functions such as 2 + y^3 that can be considered functions of {x, y} but have no dependency on x. Such functions come up in plotting and integrating and so forth. For instance,

Plot3D[2 + y^3, {x, 0, 2}, {y, -1, 1}]
NIntegrate[2 + y^3, {x, 0, 2}, {y, -1, 1}]

The OP's comment, on the one hand, seems to affirm that such a function is acceptable, and on the other, it says that it is also acceptable that J.M.'s answer would reject such a function.

Well, I thought that, instead of trying for a third time to make myself clear in a comment, I would post an alternative that works like the OP's Do loop, which accepts constant functions and functions constant with respect to some of the variables. NIntegrate substitutes numeric values and checks whether a numeric value results. This is what the OP's Do loop does, but the loop is awkward, in that it prints out results instead of returning a value.

The OP mentioned that the user input will actually have the form of iterator-intervals like NIntegrate:

input = {{x, 1, 3}, {y, 2, 4}, {z, 3, 5}, {w, 4, 6}};

from which the value for vas will be constructed, perhaps by vas = input[[All, 1]]. One can construct a substitution directly from input to plug in values that are supposed to be valid, as indicated by the intervals. These can be plugged into u to check that it gets a numerical value.

The idea is to pick a random number from each interval to substitute. It is still a numerical check, and there is always the chance of hitting an edge case where it hits a singularity or causes something to cancel out (consider a (x - 3) /. x- > 3. which makes the variable a disappear). But I think one can see that it is highly improbable.

ClearAll[sub2];
sub2[{v_, v1_?NumericQ, v2_?NumericQ}] := v -> RandomReal[{v1, v2}];

SeedRandom[0]; (* optional, for reproducibility *)
sub2 /@ input
(*
  {x -> 2.304935615948057`,
   y -> 3.266140712502736`,
   z -> 4.36562617373332`,
   w -> 5.132703662186646`} 
*)

Testing u would be carried out as above:

NumericQ[u /. sub2 /@ input]
(*  True  *)

Example with not all variables specified (Most@input drops the last variable-interval):

NumericQ[u /. sub2 /@ Most@input]
(*  False  *)
Michael E2
  • 235,386
  • 17
  • 334
  • 747
  • I think what you are doing in here almost the same what I initially was doing but no doloop. Your function example 2+y^3 makes me think about my application. I need to look into what I am required to do with such a function. – Erdem Aug 02 '16 at 09:10
  • @Erdem Yes, my intention (see 3rd paragraph) was to adapt your Do-loop idea to more idiomatic Mathematica. Its core idea of plugging in numbers to check the result is also used in numerical functions within Mathematica. Usually calculating a single value of an expression is relatively fast, so even if there are faster ways, it's not using much of the user's time. – Michael E2 Aug 02 '16 at 11:05
1

I think it's safe to extract all symbols from the underlying expression. Cases doesn't look at expression heads by default, so e.g. Plus and Power aren't returned. Complement that with constant-like symbols like Pi which are not to be checked as variables, and finally do a check with ContainsExactly.

check[expr_, vars_] :=
 With[{constants = {Pi, E, GoldenRatio, Infinity}},
  Module[{in},
   in = Cases[expr, _Symbol, Infinity]~Complement~constants;
   ContainsExactly[in, vars]]]

ContainsExactly is a 10.2 feature, I think one can use Union[in] === Union[vars] instead.

Update

I have a feeling you're fresh with the system, so I'd like to present you with another method that's readily used to collect information about the various parts of an expression, in this case here collecting all interesting symbols.

test = z^2 Sin[Pi x] + z^4 Cos[Pi y] + I y^6 Cos[2 Pi y] + w;
vars = {x, y, z, w, p};

Go through the expression and check every part at every level, and store it if that part is some of the variables you're checking for.

scan = Scan[
   If[MemberQ[vars, #], Sow[#]] &, test, Infinity] // Reap

{Null, {{w, z, y, y, y, z, x}}}

Union will discard the duplicates and sort the result, so (p is missing from test):

Union[scan[[2, 1]]] === Union[vars]

False

BoLe
  • 5,819
  • 15
  • 33