Giter VIP home page Giter VIP logo

meval-rs's Introduction

Build Status meval at docs.rs

meval

This Rust crate provides a simple math expression parsing and evaluation. Its main goal is to be convenient to use, while allowing for some flexibility. Currently works only with f64 types. A typical use case is the configuration of numerical computations in Rust, think initial data and boundary conditions, via config files or command line arguments.

Documentation

Installation

Simply add the corresponding entry to your Cargo.toml dependency list:

[dependencies]
meval = "0.2"

Requires Rust 1.26.

Simple examples

fn main() {
    let r = meval::eval_str("1 + 2").unwrap();

    println!("1 + 2 = {}", r);
}

Need to define a Rust function from an expression? No problem, use Expr for this and more:

fn main() {
    let expr: meval::Expr = "sin(pi * x)".parse().unwrap();
    let func = expr.bind("x").unwrap();

    let vs: Vec<_> = (0..100+1).map(|i| func(i as f64 / 100.)).collect();

    println!("sin(pi * x), 0 <= x <= 1: {:?}", vs);
}

Custom constants and functions? Define a Context!

use meval::{Expr, Context};

let y = 1.;
let expr: Expr = "phi(-2 * zeta + x)".parse().unwrap();

// create a context with function definitions and variables
let mut ctx = Context::new(); // built-ins
ctx.func("phi", |x| x + y)
   .var("zeta", -1.);
// bind function with a custom context
let func = expr.bind_with_context(ctx, "x").unwrap();
assert_eq!(func(2.), -2. * -1. + 2. + 1.);

For functions of 2, 3, and N variables use Context::func2, Context::func3 and Context::funcn, respectively. See Context for more options.

If you need a custom function depending on mutable parameters, you will need to use a Cell:

use std::cell::Cell;
use meval::{Expr, Context};
let y = Cell::new(0.);
let expr: Expr = "phi(x)".parse().unwrap();

let mut ctx = Context::empty(); // no built-ins
ctx.func("phi", |x| x + y.get());

let func = expr.bind_with_context(ctx, "x").unwrap();
assert_eq!(func(2.), 2.);
y.set(3.);
assert_eq!(func(2.), 5.);

Supported expressions

meval supports basic mathematical operations on floating point numbers:

  • binary operators: +, -, *, /, % (remainder), ^ (power)
  • unary operators: +, -, ! (factorial)

It supports custom variables and functions like x, weight, C_0, f(1), etc. A variable or function name must start with [a-zA-Z_] and can contain only [a-zA-Z0-9_]. Custom functions with a variable number of arguments are also supported.

Build-ins (given by the context Context::new() and when no context provided) currently supported:

  • functions implemented using functions of the same name in Rust std library:

    • sqrt, abs
    • exp, ln, log10
    • sin, cos, tan, asin, acos, atan, atan2
    • sinh, cosh, tanh, asinh, acosh, atanh
    • floor, ceil, round
    • signum
  • other functions:

    • max(x, ...), min(x, ...): maximum and minimumum of 1 or more numbers
  • constants:

    • pi
    • e

Deserialization

Expr supports deserialization using the serde library to make flexible configuration easy to set up, if the feature serde is enabled (disabled by default).

#[macro_use]
extern crate serde_derive;
extern crate toml;
extern crate meval;
use meval::{Expr, Context};

#[derive(Deserialize)]
struct Ode {
    #[serde(deserialize_with = "meval::de::as_f64")]
    x0: f64,
    #[serde(deserialize_with = "meval::de::as_f64")]
    t0: f64,
    f: Expr,
}

fn main() {
    let config = r#"
        x0 = "cos(1.)"
        t0 = 2
        f = "sin(x)"
    "#;
    let ode: Ode = toml::from_str(config).unwrap();

    assert_eq!(ode.x0, 1f64.cos());
    assert_eq!(ode.t0, 2f64);
    assert_eq!(ode.f.bind("x").unwrap()(2.), 2f64.sin());
}

Related projects

This is a toy project of mine for learning Rust, and to be hopefully useful when writing command line scripts. There is no plan to make this anything more than math expression -> number "converter". For more advanced uses, see:

  • evalexpr -- A more complete expression evaluator that supports value types, boolean operators, strings, assignment operators, ...
  • dyon -- A rusty dynamically typed scripting language
  • gluon -- A static, type inferred programming language for application embedding
  • rodolf0/tox -- another shunting yard expression parser

License

This project is dual-licensed under the Unlicense and MIT licenses.

You may use this code under the terms of either license.

meval-rs's People

Contributors

abagshaw avatar meh avatar rekka avatar sjeohp avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

meval-rs's Issues

implementation for discontinuous functions

Some functions given certain inputs can produce an undefined result as I am sure you are aware, so if at all possible having Expr.bind return an Option who's value is determined by a check for divide by zero would be appreciated. I realize that this isn't needed as rust checks divide by zero, but for the purpose of creating graphing libraries / calculators it would make sense to have an easy way to check if a function is undefined at any given point.

Boolean comparisons?

I've been looking at a Rust alternative for ExprTK, and meval seems like a good and simple library. However, I wonder if you would ever consider implementing boolean operators? In ExprTK, booleans don't exist as separate type (as far as I understand), comparisons just evaluate to 0 or 1, which makes it probably quite simple to implement.
Thank you very much.

Bind multiple variables

The library looks great so far!
Do you think it would be possible to add a function to bind several variables?

Something like the following:

pub fn bind_multiple<'a>(self, vars: &[&str])

It would be also helpful if we could evaluate the expression by providing a Map of variables tied with their values.

let expr = meval::Expr::from_str("sin(pi * x + y)").unwrap();
let mut map: HashMap<String, f64> = HashMap::new();
map.insert("x".to_owned(), 42f64);
map.insert("y".to_owned(), 24f64);
let r = expr.eval(map).unwrap();

Or maybe it could be done this way:

let mut expr = meval::Expr::from_str("sin(pi * x + y)").unwrap();
expr = expr.bind("x", 42f64).unwrap();
expr = expr.bind("y", 24f64).unwrap();
let r = expr.eval().unwrap();

`extern crate` deprecated

extern crate meval; // deprecated

has been deprecated for Rust 2018. The below must be used in all subsequent documentation:

use meval;

f64 precision problem

(2.27 - 2) / 3 should be 0.09, but got 0.09000000000000000001

Is there a solution to this problem?
Looking forward to your reply. Thanks
err

Doesn't compile with default-features = false

Hey!

When I build the latest version with "meval = {version = "*", default-features = false}" I get the following error:

error[E0432]: unresolved import `serde::de`
 --> /root/.cargo/registry/src/github.com-1ecc6299db9ec823/meval-0.0.8/src/de.rs:2:5
  |
2 | use serde::de;
  |     ^^^^^^^^^ Maybe a missing `extern crate serde;`?

error[E0432]: unresolved import `serde::de::Error`
 --> /root/.cargo/registry/src/github.com-1ecc6299db9ec823/meval-0.0.8/src/de.rs:3:5
  |
3 | use serde::de::Error;
  |     ^^^^^^^^^^^^^^^^ Maybe a missing `extern crate serde;`?

error[E0432]: unresolved import `serde::Deserialize`
 --> /root/.cargo/registry/src/github.com-1ecc6299db9ec823/meval-0.0.8/src/de.rs:4:5
  |
4 | use serde::Deserialize;
  |     ^^^^^^^^^^^^^^^^^^ Maybe a missing `extern crate serde;`?

This is not supposed to happen, right?

Consider adding inverse functions

Having a way to get the inverse function, if it exists, would be great.

let expr = meval::Expr::from_str("3 / (1 - x)").unwrap();
let func = expr.bind("x").unwrap();
let inverse_func = /* magic */;

assert_eq!(10, inverse_func(func(10)));

Feel free to close this issue if you think it's unrelated to the aim of the create.

Found a panic case

Please check below for the panic case and the stack trace:

Code:

#[test]
fn test_eval_str() {
    let v = vec![10,10,13,10,13,9,10,10,9,9];
    let mut s = String::new();
    for x in v.iter() {
        s.push(std::char::from_u32(*x).unwrap());
    }
    println!("{:?}", s);
    let _ = eval_str(s);

}
running 1 test
"\n\n\r\n\r\t\n\n\t\t"
thread 'expr::replay_fuzz' panicked at 'Unexpected parse result when parsing `




                ` at `




                `: Incomplete(Size(11))', src/tokenizer.rs:330:17
stack backtrace:
   0: std::backtrace_rs::backtrace::libunwind::trace
             at /rustc/81e754c359c471f91263813c46c67955071716a7/library/std/src/../../backtrace/src/backtrace/libunwind.rs:96
   1: std::backtrace_rs::backtrace::trace_unsynchronized
             at /rustc/81e754c359c471f91263813c46c67955071716a7/library/std/src/../../backtrace/src/backtrace/mod.rs:66
   2: std::sys_common::backtrace::_print_fmt
             at /rustc/81e754c359c471f91263813c46c67955071716a7/library/std/src/sys_common/backtrace.rs:77
   3: <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt
             at /rustc/81e754c359c471f91263813c46c67955071716a7/library/std/src/sys_common/backtrace.rs:58
   4: core::fmt::write
             at /rustc/81e754c359c471f91263813c46c67955071716a7/library/core/src/fmt/mod.rs:1117
   5: std::io::Write::write_fmt
             at /rustc/81e754c359c471f91263813c46c67955071716a7/library/std/src/io/mod.rs:1510
   6: std::sys_common::backtrace::_print
             at /rustc/81e754c359c471f91263813c46c67955071716a7/library/std/src/sys_common/backtrace.rs:61
   7: std::sys_common::backtrace::print
             at /rustc/81e754c359c471f91263813c46c67955071716a7/library/std/src/sys_common/backtrace.rs:48
   8: std::panicking::default_hook::{{closure}}
             at /rustc/81e754c359c471f91263813c46c67955071716a7/library/std/src/panicking.rs:198
   9: std::panicking::default_hook
             at /rustc/81e754c359c471f91263813c46c67955071716a7/library/std/src/panicking.rs:217
  10: std::panicking::rust_panic_with_hook
             at /rustc/81e754c359c471f91263813c46c67955071716a7/library/std/src/panicking.rs:526
  11: rust_begin_unwind
             at /rustc/81e754c359c471f91263813c46c67955071716a7/library/std/src/panicking.rs:437
  12: std::panicking::begin_panic_fmt
             at /rustc/81e754c359c471f91263813c46c67955071716a7/library/std/src/panicking.rs:391
  13: meval::tokenizer::tokenize
             at ./src/tokenizer.rs:330
  14: <meval::expr::Expr as core::str::FromStr>::from_str
             at ./src/expr.rs:485
  15: meval::expr::eval_str
             at ./src/expr.rs:476
  16: meval::expr::replay_fuzz
             at ./src/expr.rs:471
  17: meval::expr::replay_fuzz::{{closure}}
             at ./src/expr.rs:464
  18: core::ops::function::FnOnce::call_once
             at /home/ying/.rustup/toolchains/nightly-2020-08-03-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ops/function.rs:233
  19: <alloc::boxed::Box<F> as core::ops::function::FnOnce<A>>::call_once
             at /rustc/81e754c359c471f91263813c46c67955071716a7/library/alloc/src/boxed.rs:1030
  20: <std::panic::AssertUnwindSafe<F> as core::ops::function::FnOnce<()>>::call_once
             at /rustc/81e754c359c471f91263813c46c67955071716a7/library/std/src/panic.rs:318
  21: std::panicking::try::do_call
             at /rustc/81e754c359c471f91263813c46c67955071716a7/library/std/src/panicking.rs:348
  22: std::panicking::try
             at /rustc/81e754c359c471f91263813c46c67955071716a7/library/std/src/panicking.rs:325
  23: std::panic::catch_unwind
             at /rustc/81e754c359c471f91263813c46c67955071716a7/library/std/src/panic.rs:394
  24: test::run_test_in_process
             at /rustc/81e754c359c471f91263813c46c67955071716a7/library/test/src/lib.rs:541
  25: test::run_test::run_test_inner::{{closure}}
             at /rustc/81e754c359c471f91263813c46c67955071716a7/library/test/src/lib.rs:450
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
test expr::replay_fuzz ... FAILED

failures:

failures:
    expr::replay_fuzz

test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 12 filtered out

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.