I would like to test whether an argument is a valid variable for functions like Solve and DSolve. For instance several functions generate a "dsvar" or "ivar" message on bad input:
DSolve::dsvar: 2 x cannot be used as a variable. >>
Integrate::ivar: Sin[x] is not a valid variable. >>
I would like to check an argument before passing it onto one of these functions.
I used the function withBlockedVars in this answer to come up with what seems like a maybe-not-very-bad way. I block the variable and attempt to assign a value to it.
ClearAll[withBlockedVars];
SetAttributes[withBlockedVars, HoldRest];
withBlockedVars[Hold[expr_], code_] :=
With[{heldVars =
Thread[Cases[Unevaluated[expr],
s_Symbol /; Context[s] === "Global`" && DownValues[s] === {} :> HoldComplete[s],
Infinity,
Heads -> True],
HoldComplete]},
heldVars /. HoldComplete[vars_List] :> Block[vars, code]]
SetAttributes[variableQ, HoldAll];
variableQ[x_] := withBlockedVars[Hold[x], Quiet@Check[x = 0; True, False]];
Tests:
t = 2;
variableQ[2^t]
(* False *)
t = 2; x = 3;
variableQ[x[2^t]]
(* True *)
variableQ[t[2]]
(* True *)
variableQ[Subscript[t, 2]]
(* True *)
My use-case is for defining functions, something like this:
f[eqn_Equal, var_?variableQ] := code
The code might call NDSolve or Plot and so on.
Is there a better way to check var? Perhaps there is a built-in function I missed?
[Edit: Any solution involving Pattern, PatternTest, Condition etc. would be acceptable. I'm not sure I can think of all the alternative possibilities.]
Answer
It seems to me that for the basic case described in the question it would be best to simply check if a System function considers it valid, as I did for Pattern that matches colors. Therefore:
variableQ = Quiet @ ListQ @ Solve[{}, #] &;
Comments
Post a Comment