dynamic_expressions 0.10.1

Fast batched evaluation + forward-mode derivatives for symbolic expressions (Rust port of DynamicExpressions.jl).
Documentation
use dynamic_expressions::expression::Metadata;
use dynamic_expressions::node::PNode;
use dynamic_expressions::operator_enum::builtin;
use dynamic_expressions::operator_enum::builtin::*;
use dynamic_expressions::{EvalOptions, HasOp, OpId, OperatorSet, PostfixExpr, eval_tree_array};
use ndarray::Array2;

dynamic_expressions::op!(Square for<T> {
    eval: |[x]| { x * x },
    partial: |[x], _idx| { (T::one() + T::one()) * x },
});

dynamic_expressions::opset! {
    UserOps for f64 { Sin, Square, Add }
}

fn var(feature: u16) -> PostfixExpr<f64, UserOps, 2> {
    PostfixExpr::new(vec![PNode::Var { feature }], vec![], Metadata::default())
}

fn square(x: PostfixExpr<f64, UserOps, 2>) -> PostfixExpr<f64, UserOps, 2> {
    dynamic_expressions::expression_algebra::__apply_postfix::<f64, UserOps, 2, 1>(<UserOps as HasOp<Square>>::ID, [x])
}

#[test]
fn opset_can_mix_builtin_and_user_defined_ops() {
    let square_op = <UserOps as HasOp<Square>>::op_id();
    assert_eq!(
        square_op,
        OpId {
            arity: 1,
            id: <UserOps as HasOp<Square>>::ID
        }
    );
    assert_eq!(UserOps::lookup("square").unwrap(), square_op);

    let sin = <UserOps as HasOp<builtin::Sin>>::op_id();
    assert_eq!(UserOps::lookup("sin").unwrap(), sin);

    let x = Array2::from_shape_vec((1, 4), vec![-2.0, -1.0, 0.5, 3.0]).unwrap();
    let expr = square(var(0));

    let opts = EvalOptions {
        check_finite: true,
        early_exit: true,
    };
    let (out, ok) = eval_tree_array::<f64, UserOps, 2>(&expr, x.view(), &opts);
    assert!(ok);
    assert_eq!(out, vec![4.0, 1.0, 0.25, 9.0]);
}