Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Utility to extract variables from an expression

I'm looking for a utility that would take an expression and extract all variables in that expression. Following five examples cover pretty much all of my variable patterns

a,Subscript[a,....],Subscript[a,...][...],a[...],a[...][...]

Here are two test cases.

expr1 = -Log[Subscript[\[Mu], 2][]] Subscript[\[Mu], 2][] - 
   Log[Subscript[\[Mu], 2][2]] Subscript[\[Mu], 2][2] + 
   Log[Subscript[\[Beta], 1, 2][]] Subscript[\[Beta], 1, 2][] + 
   Log[2] Subscript[\[Beta], 1, 2][1] + 
   Log[Subscript[\[Beta], 1, 2][1]] Subscript[\[Beta], 1, 2][1] + 
   Log[2] Subscript[\[Beta], 1, 2][2] + 
   Log[Subscript[\[Beta], 1, 2][2]] Subscript[\[Beta], 1, 2][2] + 
   Log[Subscript[\[Beta], 2, 3][]] Subscript[\[Beta], 2, 3][] + 
   Log[Subscript[\[Beta], 2, 3][2]] Subscript[\[Beta], 2, 3][2] + 
   Log[2] Subscript[\[Beta], 2, 3][3] + 
   Log[Subscript[\[Beta], 2, 3][3]] Subscript[\[Beta], 2, 3][3];

expr2 = Log[\[Beta][{1, 2}][{}]] \[Beta][{1, 2}][{}] + 
  Log[2] \[Beta][{1, 2}][{1}] + 
  Log[\[Beta][{1, 2}][{1}]] \[Beta][{1, 2}][{1}] + 
  Log[2] \[Beta][{1, 2}][{2}] + 
  Log[\[Beta][{1, 2}][{2}]] \[Beta][{1, 2}][{2}] + 
  Log[\[Beta][{2, 3}][{}]] \[Beta][{2, 3}][{}] + 
  Log[\[Beta][{2, 3}][{2}]] \[Beta][{2, 3}][{2}] + 
  Log[2] \[Beta][{2, 3}][{3}] + 
  Log[\[Beta][{2, 3}][{3}]] \[Beta][{2, 3}][{3}] - 
  Log[\[Mu][{2}][{}]] \[Mu][{2}][{}] - 
  Log[\[Mu][{2}][{2}]] \[Mu][{2}][{2}]

On[Assert];
Assert[Union@extractVariables@expr1 === Union[Variables[expr1][[9 ;;]]]]
Assert[Union@extractVariables@expr2 === Union[Variables[expr2][[9 ;;]]]]

Here's MrWizard's solution

extractVariables[formula_] := (
   pat = _Symbol[___][___] | Subscript[_Symbol, __][___] | Subscript[_Symbol, __] | _Symbol;
   Union@Cases[formula, pat, -1]
);
like image 743
Yaroslav Bulatov Avatar asked Feb 03 '23 18:02

Yaroslav Bulatov


2 Answers

Here is some code I use to get at "variables" in various types of expression (lists, equations, inequalities, and inside numeric functions).

headlist = {Or, And, Equal, Unequal, Less, LessEqual, Greater, 
   GreaterEqual, Inequality};

getAllVariables[f_?NumericQ] := Sequence[]
getAllVariables[{}] := Sequence[]
getAllVariables[t_] /; MemberQ[headlist, t] := Sequence[]

getAllVariables[ll_List] := 
 Flatten[Union[Map[getAllVariables[#] &, ll]]]

getAllVariables[Derivative[n_Integer][f_][arg__]] := 
 getAllVariables[{arg}]

getAllVariables[f_Symbol[arg__]] := 
 Module[{fvars}, 
  If[MemberQ[Attributes[f], NumericFunction] || MemberQ[headlist, f], 
   fvars = getAllVariables[{arg}],(*else*)fvars = f[arg]];
  fvars]

getAllVariables[other_] := other

One example from provided tests:

In[36]:= getAllVariables[expr2]

Out[36]= {[Beta][{1, 2}][{}], [Beta][{1, 2}][{1}], [Beta][{1, 2}][{2}], [Beta][{2, 3}][{}], [Beta][{2, 3}][{2}], [Beta][{2, 3}][{3}], [Mu][{2}][{}], [Mu][{2}][{2}]}

This could be extended to handle a larger class of expressions, e.g. Boolean, math with dummy variables (e.g. Sum or Integrate), some programmatic constructs. Expect thorny issue to appear.

Anecdote: Way back in the last millenium someone in the Kernel Dept scheduled a meeting to discuss the issue of "What is a variable?" This was within the setting of Mathematica, not general math or CS. All the same, it is an elusive thing to pin down because different functions seem to have different requirements for such entities. My own take on it was to reply that I would be sick that day (of the intended meeting). I do not recall if I was asked how I knew that in advance...

Daniel Lichtblau

like image 101
Daniel Lichtblau Avatar answered Feb 18 '23 13:02

Daniel Lichtblau


The obvious (but presumably incorrect) approach would be:

pat = _Symbol[___][___] | Subscript[_Symbol, __][___] |  Subscript[_Symbol, __] | _Symbol;

Cases[expr1, pat, -1]
Cases[expr2, pat, -1]

But frankly I don't understand you question well enough to know where this goes wrong.


If that actually works for you, then I recommend:

extractVariables[formula_] := 
  With[{pat = _Symbol[___][___] | Subscript[_Symbol, __][___] | Subscript[_Symbol, __] | _Symbol},
    Union@Cases[formula, pat, -1]
  ]
like image 38
Mr.Wizard Avatar answered Feb 18 '23 13:02

Mr.Wizard