ruut-functions 0.2.1

A crate to parse math functions from string (1D,2D,3D,ND) and perform symbolic derivation, gradient, hessian
Documentation
use std::collections::VecDeque;

use crate::Func;

use super::Grammar;

pub(crate) fn build(input: VecDeque<Grammar>) -> Func {
    let mut stack: Vec<Func> = Vec::with_capacity(4);
    for el in input {
        match el {
            Grammar::Num(val) => stack.push(Func::Num(val)),
            Grammar::Var(char) => stack.push(Func::Var(char)),
            Grammar::Param(name) => stack.push(Func::Param(name, 0.)),
            Grammar::Add => {
                let second = stack.pop().unwrap();

                *stack.last_mut().unwrap() += second;
            }
            Grammar::Sub => {
                let second = stack.pop().unwrap();
                let first = stack.pop();

                if let Some(el) = first {
                    stack.push(el - second);
                } else {
                    stack.push(-1 * second)
                }
            }
            Grammar::Mul => {
                let second = stack.pop().unwrap();

                *stack.last_mut().unwrap() *= second;
            }
            Grammar::Div => {
                let first = stack.pop().unwrap();
                let second = stack.pop().unwrap();
                stack.push(second / first);
            }
            Grammar::Pow => {
                let second = stack.pop().unwrap();
                let first = stack.pop().unwrap();
                stack.push(first.pow(second))
            }
            Grammar::E => stack.push(Func::E),
            Grammar::PI => stack.push(Func::PI),
            Grammar::S(kind) => {
                let arg = stack.pop().unwrap();
                stack.push(Func::S(kind, Box::new(arg)));
            }
            Grammar::Sqrt => {
                let arg = stack.pop().unwrap();
                stack.push(arg.pow(Func::Mul(vec![
                    Func::Num(1),
                    Func::Pow(Box::new(Func::Num(2)), Box::new(Func::Num(-1))),
                ])));
            }
            Grammar::LPar => panic!("Found left par in RPN representation"),
        }
    }

    stack.pop().unwrap()
}

#[test]
fn test_builder() {
    use super::to_rpn;
    use crate::FType;

    assert_eq!(
        build(to_rpn("cos(-x)+sqrt(x)+(x^(-3))^2", &['x']).unwrap()),
        build(to_rpn("cos(-x)+x^(1/2)+x^(-6)", &['x']).unwrap()),
    );

    let input = to_rpn("(sin(3+7)/8)-7^2", &['x']).unwrap();
    assert_eq!(
        build(input),
        Func::Add(vec![
            Func::Mul(vec![
                Func::S(FType::Sin, Box::new(Func::Num(10))),
                Func::Pow(Box::new(Func::Num(8)), Box::new(Func::Num(-1))),
            ]),
            Func::Mul(vec![
                Func::Num(-1),
                Func::Pow(Box::new(Func::Num(7)), Box::new(Func::Num(2)))
            ])
        ])
    );

    assert_eq!(
        build(to_rpn("e^(-[eta]xy)", &['x', 'y']).unwrap()),
        Func::Pow(
            Box::new(Func::E),
            Box::new(Func::Mul(vec![
                Func::Num(-1),
                Func::Param("eta".to_string(), 0.),
                Func::Var('x'),
                Func::Var('y')
            ]))
        )
    )
}