Get symbols from string or Expression


#1

Is there a standard way to obtain a list of used symbols from the string or Expression?

Pseudocode:

let expr = Infix.parseOrThrow("sin(x) * y")
expr.GetSymbols() //return array [| "x"; "y" |]

#2

Workaround for me:

let getsymbols(expr:Expression) = 
    let rec loop (expr:Expression) (acc:Symbol list) = 
        match expr with
        |Identifier(x) -> x::acc
        |Function(x,y) -> loop y acc
        |Product(x)
        |Sum(x) -> x |> List.fold(fun t el -> t @ loop el acc) acc
        |Power(x,y) -> loop x acc @ loop y acc
        |Number(_) -> acc
        | _ -> acc
    loop expr []
    |> Set.ofList
    |> Set.toList

(I know that some option not checked)


(Christoph Rüegg) #3

Surprisingly this functionality was indeed missing. I’ve just committed support for this in the Structure module to master and plan to do a new release soon.

The idea is similar to your implementation but reuses the existing Structure.fold function and is a bit more general:

let collect (chooser:Expression->'T option) x =
    let rec impl (acc:'T list) x =
        match chooser x with
        | Some result -> result::acc
        | None -> fold impl acc x
    impl [] x

This can then be used to find all identifier as follows (the actual committed implementation also sorts and drops duplicate entries):

let collectIdentifiers x =
    x |> collect (function | Identifier _ as expr -> Some expr | _ -> None)

let collectIdentifierSymbols x =
    x |> collect (function | Identifier symbol -> Some symbol | _ -> None)

Test Cases (==+> calls Infix.print on each list entry):

collectIdentifierSymbols (x*cos(y)) --> [ Symbol "x"; Symbol "y" ]
collectIdentifiers (x*cos(y)) ==+> [ "x"; "y" ]
collectIdentifiers (z/x*cos(y)**x) ==+> [ "x"; "y"; "z" ]

collectFunctionTypes (x*cos(y)) --> [ Cos ]
collectFunctions (x*cos(y)) ==+> [ "cos(y)" ]

collectNumberValues (x*cos(2*y-4)/3) --> [ -4N; 1N/3N; 2N; ]
collectNumbers (x*cos(2*y-4)/3) ==+> [ "-4"; "1/3"; "2" ]

#4

Hmm, I would expect from such input data:

"z *sin(x) + x * cos(y) "

these results:

["y"; "x"; "z"]

But I get:

["y"; "x"; "x"; "z"]


(Christoph Rüegg) #5

With the routines I committed to the repo/master, or with the simplified ones I’ve posted here (where I did not include sorting and distinct)?


#6

Exactly, was inattentive. Thank you!


(Christoph Rüegg) #7

FYI, I’ve released the changes (including some others) as MathNet.Symbolics v0.8.0.