Code Monkey home page Code Monkey logo

exmex's People

Contributors

bertiqwerty avatar nereuxofficial avatar terrorfisch avatar titaniumtown 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

Watchers

 avatar  avatar

exmex's Issues

Adding serde support(?)

Hi! Thank you for the crate!

I was wondering if you could add serde support, maybe through a feature flag.

I am using your crate and I am missing serde support for FlatEx.
I noticed that you use smallvec. It has serde support through a feature flag, so it should be easy.

Thanks beforehand!

Found multiple crashes using fuzzing

I fuzzed this crate using honggfuzz and found 3 crashes.

You can fuzz the code yourself and further investigate the crashes with this repo.

In the main function there are also three test functions which can be used to easily reproduce the crashes. If you go into the hfuzz_workspace/Fuzzing Folder you can also see the inputs that crash.

This could help improve the check_preconditions function and i hope this is useful.

Generic value type

Create a generic value type to show-case that it is possible to mix different types, e.g., integers, floats, and booleans, in one expression.

Nth Derivative support

Currently, the partial method only takes the 1st derivative, could a method be added that takes the nth derivative? such as maybe partial_nth or something?

More common math binary operators such as atan2

exmex (partial) derivation feature is awesome but the lack of some common math/trigonometry binary operators reduces its general usefulness. It'd be awesome if operators like atan2 were implemented, including their derivatives.

Catch unicode input

Fuzzing showed that exmex crashes when unicode input is provided. As long as we do not support unicode, we should at least give a sane error message.

Make accepted variable names configurable and do not use regex for it by default

The regex crate is currently used for checking if a string starts with a valid identifier or is a valid identifier. From what I know this is a bit overkill and it's faster to write simple matches explicitly. I suggest doing something like this:

pub trait VarName {
    fn is_start_character(c: char) -> bool;
    fn is_continue_character(c: char) -> bool {
        Self::is_start_character(c) || matches!(c,  '0'..='9')
    }
    fn try_parse(s: &str) -> Option<(&str, &str)> {
        let mut first = true;
        let (name, rest) = s.split_once(|c|
            if first {
                first = false;
                !Self::is_start_character(c)
            } else {
                !Self::is_continue_character(c)
            }
        ).unwrap_or((s, ""));
        if name.is_empty() {
            None
        } else {
            Some((name, rest))
        }
    }
    fn is_exact_variable_name(s: &str) -> bool {
        s.starts_with(Self::is_start_character) && s.chars().skip(1).all(Self::is_continue_character)
    }
}

pub struct ASCII;

impl VarName for ASCII {
    fn is_start_character(c: char) -> bool {
        matches!(c, 'a'..='z' | 'A'..='Z' | '_')
    }
}

pub struct LatinGreek;

impl VarName for LatinGreek {
    fn is_start_character(c: char) -> bool {
        ASCII::is_start_character(c) || matches!(c, 'α'..='ω' || 'Α'..='Ω')
    }
}

#[cfg(feature = "unicode")]
pub struct Unicode;

#[cfg(feature = "unicode")]
impl VarName for LatinGreek {
    fn is_start_character(c: char) -> bool {
        unicode_ident::is_xid_start(c)
    }
    fn is_start_character(c: char) -> bool {
        unicode_ident::is_xid_continue(c)
    }
}

with unicode-ident = { version = "1", optional = true } and a feature unicode = ["unicode-ident"].

If you think this is a good idea I can make a pull request.

Serialization for non-default numbers

Serialization currently assumes that the default number regex-pattern is used to identify numbers or operands. In case one tries to serialize and de-serialize an expression that was created, e.g., by FlatEx::from_regex de-serialization can lead to parse errors or strange behavior. This includes the type Val that can be activated with the feature value.

Convinient owned version of FlatEx (with variable names)

Hi again!

Thanks for the work for #1! I have no complaints, but wanted to ask for a convenience struct for ease of use of the crate.

Request

Add a struct that wraps over FlatEx allowing for:

  • No life parameter
  • Reconstruction of the original input (with variable names)

Use-case

The idea is simple: an online plotter (see website). In my application, the following steps are performed:

  • Get input from the user (which I can transform to String)
  • Parse to a function
  • Evaluate the function
  • Plot
  • Save settings for local persistence in the website

In the last step, I serialize all the input and deserialize upon a new visit.

Work-around

I am serializing and deserializing the input and parsing when reconstructing the struct. Hope this code is helpful.

struct FnInput {
    raw_input: String,
    exp: FlatEx<f64>, // Exmex version 0.7.1
}

impl FnInput {
    pub fn eval(&self, vars: &[f64]) -> Result<f64, ExParseError> {
        self.exp(vars)
    }
}

impl Serialize for FnInput {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        let mut s = serializer.serialize_struct("FnInput", 1)?;
        s.serialize_field("raw_input", &self.raw_input)?;
        s.end() // We do not serialize FlatEx
    }
}

impl<'de> Deserialize<'de> for FnInput {
    fn deserialize<D>(deserializer: D) -> Result<FnInput, D::Error>
    where
        D: Deserializer<'de>,
    {
        #[derive(Debug, Clone, Deserialize)]
        struct __FnInput {
            raw_input: String,
        }
        let __fn_input = __FnInput::deserialize(deserializer)?;
        let exp = exmex::parse_with_default_ops::<f64>(&__fn_input.raw_input).unwrap(); // Reparse here 
        Ok(FnInput {
            string: __fn_input.string,
            kind,
        })
    }
}

Note: Another option is to parse for every evaluation, but that is too wasteful...

Details

I presume this would entail a version of FlatEx with no life parameter, but you know better. Feel free to deny this request if it feels out of the scope of the crate for you.

Either way, I do not how to reconstruct how to easily reconstruct my workaround with exmex version 0.9.

Bug reading missing binary operator

Hi there!

exmex = { version: 0.7.1 }

Description
Parsing the expression 2sin({x}) generates a panic, while an error is expected.

Details

Running the following code generates a panic, while it should be a parse error.

fn main() {
    let e = exmex::parse::<f64>("2sin({x})", &exmex::make_default_operators::<f64>());
    println!("{:?}", e);
}

This is the panic error I get This is probably a bug. Expected binary operator but there was none.

lowercase euler's number

Currently only E can be used to represent Euler's number, could e do the same thing as well? I haven't found a good way of accomplishing this.

Vector Math

Hi,

I love the performance and footprint! I guess basic vector math cannot be added via custom types right ?

Thanks

Output of functions without a variable

Currently functions that don't contain a variable don't output a value, so for instance the function π doesn't just simply output 3.14.... no matter the output.

Substitution of variables with expressions

It would be nice to be able to substitute variables with arbitrary expressions.

My current workaround is to unparse, use regex replacement functionality and re-parse the expression.

Partial derivatives

Use derivative operators that transform expressions into their partial derivatives. These derivative operators depend on the defined binary and unary operators.

Unparsable number

In case a custom number pattern is used, a un-parsable number might occur. unwrap leads to panic.

Integration support

Could the reverse of partial be added so a function could be integrated instead? this would be tremendously useful! Thanks.

How to implement Val for i64 and f64

Hello @bertiqwerty
I trying wrap FlaxEx in my struct:

#[derive(Debug, Clone, PartialOrd, PartialEq, Validate)]
pub struct QuickExpression {
    #[validate(length(min = 1), custom = "validate_expression")]
    raw_text: String,
    //expr: exmex::FlatEx<exmex::Val, exmex::ValOpsFactory, exmex::ValMatcher>,
    //expr: exmex::FlatEx<Val<i64>, exmex::ValOpsFactory<i64>, exmex::ValMatcher>,
}


impl QuickExpression
{
 
 pub fn do_something(&self) {
     let big_num = 0xF1F2F3F4F5F6F7u64 as i64;
     let res = self.expr.eval(&[bin_num]);
     //...
 }
 
}

I need to work with f64 and i64:

let text = "2 * {random_value}";
let expr = exmex::parse_val::<i64, f64>(text.as_str());

let my_expr = QuickExpression{raw_text: text, expr: expr};

Partial/to_deepex wrong

For expressions like "-y*(x*(-(1-y))) + 1.7" the computation FlatEx::to_deepex is wrong. Hence, for these expressions also partial is wrong.

User defined variables.

I was wondering if there was an idiomatic may to have variables with user defined values that prissiest between calculations. Similar to how evalexpr handles things.

Theoretical usage:

use exmex::prelude::*;
exmex::parse::<f64>("x=14")?;
let expr = exmex::parse::<f64>("x^2+4*x-3")?;
assert_eq!(expr , 249.0);

Binary operators with function call syntax

Is it possible to add function call syntax to binary operators? Possibly extended to n-ary operations.

My motivating example is that I want to support max and min functions.

A possible workaround for me is to add a tuple variant to my Value type which is built through a , operator and use unary operators for this. Unfortunately this blows up all other code because then there are a lots of non-sensical states representable in the type system as not all values are allowed as operator inputs.

As I see there are the following alternatives:

  1. Do nothing and push this into the Value type if required
  2. Add an optional function name to each binary operator
  3. Add a n-ary operator with function call syntax

`Val` parsing boolean literals

When using the feature value and the value type Val, boolean literals true and false are interpreted as variables instead of literals when using from_str instead of parse_val.

Var names with spaces

If variable names have spaces, an error is returned. Variable names with spaces are valid.

Usage of literal_matcher_from_pattern requires lazy_static

Using the macro literal_matcher_from_pattern! requires adding lazy_static to Cargo.toml in the consuming crate.

If I understand this stack overflow answer correctly this can be fixed by exporting lazy_static (maybe with #[doc(hidden)]?) and refer to it via $crate::lazy_static::lazy_static.

Faster `eval_str`

When calling eval_str, directly parse into FlatEx without creating a DeepEx and evaluate without compilation.

Add support for absolute values

I love this expression evaluator, it's very fast and the api is well designed!

I'm just wondering if it's possible/planned to add the feature of evaluating absolute values, like |-1.5| as 1.5.

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.