mathic 0.2.0

A compiler with builtin support of symbolic operations, built with LLVM/MLIR
use criterion::{Criterion, black_box, criterion_group, criterion_main};
use mathic::compiler::{MathicCompiler, OptLvl};
use mathic::executor::MathicExecutor;
use pyo3::types::{PyAnyMethods, PyDict, PyDictMethods};
use std::ffi::CString;

const EXPRS: &[(&str, &str, i64)] = &[(
    "poly10",
    "df main() i32 {
        sym x:expr<i32>;
        let expr: expr<i32> = x * (x + x + x + x);
        return eval(expr,x,10);
    }",
    400,
)];

fn bench_mathic(c: &mut Criterion) {
    let compiler = MathicCompiler::new().unwrap();
    let opts = [OptLvl::None, OptLvl::O1, OptLvl::O2, OptLvl::O3];

    for opt in opts {
        let mut group = c.benchmark_group(format!("mathic_{opt:?}"));

        for &(name, src, expected) in EXPRS {
            let module = compiler.compile_source(src, opt, None).unwrap();
            let executor = MathicExecutor::new(&module, opt).unwrap();

            group.bench_function(name, |b| {
                b.iter(|| {
                    let res = executor.call_function("main").unwrap();
                    black_box(res);
                    assert_eq!(res, expected);
                });
            });
        }

        group.finish();
    }
}

fn bench_sympy(c: &mut Criterion) {
    pyo3::prepare_freethreaded_python();

    let exprs: &[(&str, i64)] = &[("x * (x + x + x + x)", 400)];

    pyo3::Python::with_gil(|py| {
        for (py_expr, expected) in exprs {
            let py_code = CString::new(format!(
                "
from sympy import lambdify, Symbol
x = Symbol('x')
lamb = lambdify(x, {py_expr}, modules='numpy')
res = lamb(10)
"
            ))
            .unwrap();
            let locals = PyDict::new(py);

            py.run(py_code.as_c_str(), None, Some(&locals)).unwrap();

            let res: i64 = locals.get_item("res").unwrap().unwrap().extract().unwrap();
            assert_eq!(res, *expected);

            let mut group = c.benchmark_group("sympy");
            group.bench_function(*py_expr, |b| {
                b.iter(|| {
                    py.run(py_code.as_c_str(), None, Some(&locals)).unwrap();

                    let res: i64 = locals.get_item("res").unwrap().unwrap().extract().unwrap();
                    black_box(res);
                });
            });
            group.finish();
        }
    });
}

criterion_group!(benches, bench_mathic, bench_sympy);
criterion_main!(benches);