ISibboI / evalexpr

A powerful expression evaluation crate 🦀.
GNU Affero General Public License v3.0
325 stars 54 forks source link

How to access list of variables indentifier #37

Closed mestachs closed 5 years ago

mestachs commented 5 years ago

I'd like to port my go implementation of "equation solver" https://github.com/BLSQ/go-hesabu to rust. Your crate looks really promising.

But one requirement to re-implement my lib it is to list variables used in an expression and deduce by a topological sort the expression by dependencies.

Is there a way to access the variable names of an expression ? eg : "a + 10 * sin(b)" => ["a","b"]

ISibboI commented 5 years ago

Welcome, and thank you for the interest in my crate. I think the rust ecosystem would benefit from a port of hesabu.

At the moment, this crate does not support listing the variable names in an equation. But it is certainly possible to implement that feature in this crate.

What kind of ordering do you need? The order they appear in the equation? Or a prefix, postfix or infix order? I don't know exactly what you mean by topological sorting, but does the way you want to order the variables fit one of these orderings?

On Thu, 4 Apr 2019, 20:29 Stéphan Mestach, notifications@github.com wrote:

I'd like to port my go implementation of "equation solver" https://github.com/BLSQ/go-hesabu to rust. Your crate looks really promising.

But one requirement to re-implement my lib it is to list variables used in an expression and deduce by a topological sort the expression by dependencies.

Is there a way to access the variable names of an expression ? eg : "a + 10 * sin(b)" => ["a","b"]

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/ISibboI/evalexpr/issues/37, or mute the thread https://github.com/notifications/unsubscribe-auth/ACQJ3rVbR3utFuH8AJSZaDl2w3mitFYdks5vdkSJgaJpZM4cdb1a .

mestachs commented 5 years ago

No special order required. I just need a list of variables identifiers for a given expression (any order of appearance, even with duplicates is ok).

Ideally I would like to avoid tokenizing/parsing twice as I may need to solve problems with more than 100000 equations. In my go implementation, this was possible as I was using govaluate and it offer an api where you first parse and then allow evaluation later.

for my hesabu port and to give you more context, the algorithm to solve the problems is as follow:

Given the following problem

{
  "c": "a + 10 * b",
  "a": "10",
  "b": "10+a"
}

1. parse all equations and extract their dependencies

{
  "c": ["a","b"],
  "a": [ ],
  "b": [ "a" ]
}

2. to deduce the order of evaluation of the various expressions, we do a reverse topological sort based on these dependencies

["a", "b", "c"]

example implementation in rust

3. evaluate the equations one by one and store their values in the context for further reuse

3.1 evaluate "10" and store as "a"

{
  "a": "10"
}

3.2 evaluate "10+a" and store as "b"

{
  "a": "10"
  "b": "20"
}

3.3 evaluate "a + 10 * b" and store as "c"

  "a": "10",
  "b": "20",
  "c": "210"

4. solution complete !

ISibboI commented 5 years ago

Hey mestachs,

iterating all appearing identifiers in a formula should be a really easy task. I should be able to do that soon.

I think I understand what your algorithm is doing. Do you want to use the assignment operator for your formulas? I mean do you pass formulas like a = 5 * b to evalexpr, or do you resolve the = yourself and then just pass the expression after the assignment, meaning 5 * b in this case? Because if you would pass the formula with the = to evalexpr, then there should be a way to get the identifier before the =, should there?

(I just started a new job and moved to a new location, so my work on this is slowed down a bit. But as soon as I get internet at home, I will be able to care for this crate properly again.)

ISibboI commented 5 years ago

I implemented an iterator over the identifiers of an expression.

In your use case, you would precompile an expression and then iterate over its identifiers like this:

use evalexpr;

if let Ok(tree) = build_operator_tree("a + b") {
    let mut iter = tree.iter_identifiers();
    // ...
}

Is this what you needed? If you need more features from this crate, feel free to open more issues :)

mestachs commented 5 years ago

No need for assignment. Thanks a lot ! Sorry I'm on holidays. Will give it a try next week.

Le ven. 12 avr. 2019 à 19:30, ISibboI notifications@github.com a écrit :

I implemented an iterator over the identifiers of an expression.

In your use case, you would precompile an expression and then iterate over its identifiers like this:

use evalexpr; if let Ok(tree) = build_operator_tree("a + b") { let mut iter = tree.iter_identifiers(); // ... }

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/ISibboI/evalexpr/issues/37#issuecomment-482657918, or mute the thread https://github.com/notifications/unsubscribe-auth/AAC2X3ABQUOCUYNPIRJ25PLPQDBK3ANCNFSM4HDVXVNA .

mestachs commented 5 years ago

Is there a way to distinguish functions from variables in the identifiers ? eg "a + sin(b)" , the iterators returns a,b,sin

I'm learning rust, so don't really know yet what I'm doing : https://github.com/mestachs/rust-hesabu#development

ISibboI commented 5 years ago

This is currently not possible. But I will quickly add separate iterators for function and variable identifiers.

ISibboI commented 5 years ago

Now there is a method Node::iter_variable_identifiers() to iterate over all variable identifiers within an expression tree.

mestachs commented 5 years ago

Thanks a lot !