use pyo3::prelude::*;
fn map_err(e: impl std::fmt::Display) -> PyErr {
pyo3::exceptions::PyValueError::new_err(e.to_string())
}
#[pyfunction]
pub fn integrate_definite_py(expr_str: &str, var: usize, lo: f64, hi: f64) -> PyResult<f64> {
let tree = crate::parse(expr_str).map_err(map_err)?;
let lowered = tree.lower().simplify();
let ctx = crate::EvalCtx::new(&[]);
lowered
.integrate_definite(var, lo, hi, &ctx)
.map_err(map_err)
}
#[pyfunction]
pub fn limit_py(expr_str: &str, var: usize, at: f64) -> PyResult<f64> {
use pyo3::exceptions::PyRuntimeError;
let tree = crate::parse(expr_str).map_err(map_err)?;
let lowered = tree.lower().simplify();
let point = if at.is_infinite() && at > 0.0 {
crate::LimitPoint::PosInf
} else if at.is_infinite() {
crate::LimitPoint::NegInf
} else {
crate::LimitPoint::Finite(at)
};
match lowered.limit(var, point) {
crate::LimitResult::Finite(v) => Ok(v),
crate::LimitResult::PosInf => Ok(f64::INFINITY),
crate::LimitResult::NegInf => Ok(f64::NEG_INFINITY),
crate::LimitResult::DoesNotExist => Err(PyRuntimeError::new_err("limit does not exist")),
crate::LimitResult::Indeterminate => Err(PyRuntimeError::new_err("limit is indeterminate")),
}
}