7
$\begingroup$

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.

$\endgroup$
8
  • $\begingroup$ @Micheal E2 I am not sure if I am following your question. $\endgroup$
    – Erdem
    Commented Aug 1, 2016 at 11:53
  • $\begingroup$ 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? $\endgroup$
    – Michael E2
    Commented Aug 1, 2016 at 11:56
  • $\begingroup$ 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.) $\endgroup$
    – Michael E2
    Commented Aug 1, 2016 at 12:15
  • 1
    $\begingroup$ 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. $\endgroup$
    – Erdem
    Commented Aug 1, 2016 at 12:40
  • $\begingroup$ One might use a strategy similar to NIntegrate[] in that case. I'll try to work up an answer. $\endgroup$
    – Michael E2
    Commented Aug 1, 2016 at 14:23

5 Answers 5

11
$\begingroup$

Using an undocumented function:

Reduce`FreeVariables[u] === Sort[vas]
$\endgroup$
8
  • $\begingroup$ (If u had been a polynomial function, use the documented function Variables[] instead.) $\endgroup$ Commented Aug 1, 2016 at 9:57
  • $\begingroup$ Nice! Shouldn't this been in (805)? $\endgroup$
    – Mr.Wizard
    Commented Aug 1, 2016 at 9:57
  • $\begingroup$ I guess... I'll write something up later. $\endgroup$ Commented Aug 1, 2016 at 9:58
  • $\begingroup$ I think you could also give this in answer to (30038) $\endgroup$
    – Mr.Wizard
    Commented Aug 1, 2016 at 10:03
  • $\begingroup$ 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. $\endgroup$
    – Erdem
    Commented Aug 1, 2016 at 10:06
10
$\begingroup$

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]
$\endgroup$
7
  • $\begingroup$ Thank you. I realized that I missed a point in my question. I edited it. You answer works fine what I wrote initially. $\endgroup$
    – Erdem
    Commented Aug 1, 2016 at 10:40
  • $\begingroup$ @Erdem Please check my updated proposal and let me know if it has problems. $\endgroup$
    – Mr.Wizard
    Commented Aug 1, 2016 at 10:47
  • $\begingroup$ Works like a charm :) $\endgroup$
    – Erdem
    Commented Aug 1, 2016 at 11:05
  • $\begingroup$ @Erdem Glad I could help, and thanks for the Accept. $\endgroup$
    – Mr.Wizard
    Commented Aug 1, 2016 at 11:42
  • 2
    $\begingroup$ @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? $\endgroup$
    – Mr.Wizard
    Commented Aug 1, 2016 at 11:59
3
$\begingroup$

Another undocumented function: Internal`LiterallyOccurringQ:

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

True

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

False

$\endgroup$
1
  • $\begingroup$ Since vas is a list of (literal) Symbols is there any benefit to this over FreeQ? $\endgroup$
    – Mr.Wizard
    Commented Aug 1, 2016 at 10:49
3
$\begingroup$

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  *)
$\endgroup$
2
  • $\begingroup$ 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. $\endgroup$
    – Erdem
    Commented Aug 2, 2016 at 9:10
  • $\begingroup$ @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. $\endgroup$
    – Michael E2
    Commented Aug 2, 2016 at 11:05
1
$\begingroup$

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

$\endgroup$
3
  • 1
    $\begingroup$ With ContainsAll you don't have to care about anything more than vars. $\endgroup$
    – Kuba
    Commented Aug 1, 2016 at 12:09
  • $\begingroup$ You missed a number of other constants, like EulerGamma and MachinePrecision; if you really must test for these, a common feature is that they all have the Constant attribute. $\endgroup$ Commented Aug 1, 2016 at 12:13
  • $\begingroup$ @J.M. Variables[in] seems to filter them well also. $\endgroup$
    – BoLe
    Commented Aug 1, 2016 at 12:21

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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