use crate::base::arena::Arena;
use crate::base::node::ExprId;
use crate::calculus::summation::{self, SumOutcome};
pub(crate) fn eval_sum_symbolic(
arena: &mut Arena,
body: ExprId,
var: ExprId,
lower: ExprId,
upper: ExprId,
) -> Option<ExprId> {
match summation::summation(arena, body, var, lower, upper) {
SumOutcome::Closed(id) => Some(id),
SumOutcome::Divergent(Some(inf)) => Some(inf),
SumOutcome::Divergent(None) | SumOutcome::Unevaluated => None,
}
}
#[allow(dead_code)]
pub(crate) fn eval_product_symbolic(
arena: &mut Arena,
body: ExprId,
var: ExprId,
lower: ExprId,
upper: ExprId,
) -> Option<ExprId> {
match summation::product(arena, body, var, lower, upper) {
SumOutcome::Closed(id) => Some(id),
SumOutcome::Divergent(Some(inf)) => Some(inf),
SumOutcome::Divergent(None) | SumOutcome::Unevaluated => None,
}
}
#[cfg(test)]
mod tests {
use super::*;
fn eval_sum(power: usize, lo: i64, hi: i64) -> String {
let mut arena = Arena::new();
let var = arena.symbol("k");
let lower = arena.int(lo);
let upper = arena.int(hi);
let body = if power == 1 {
var
} else {
let exp = arena.int(power as i64);
arena.pow(var, exp)
};
let result = eval_sum_symbolic(&mut arena, body, var, lower, upper);
assert!(
result.is_some(),
"Expected closed form for k^{power} from {lo} to {hi}"
);
let expr = result.unwrap();
let evaled = crate::transforms::eval::eval(&mut arena, expr);
arena.display(evaled).to_string()
}
#[test]
fn faulhaber_k_1_to_10() {
assert_eq!(eval_sum(1, 1, 10), "55");
}
#[test]
fn faulhaber_k_sq_1_to_10() {
assert_eq!(eval_sum(2, 1, 10), "385");
}
#[test]
fn faulhaber_k_cube_1_to_10() {
assert_eq!(eval_sum(3, 1, 10), "3025");
}
#[test]
fn faulhaber_k_4_1_to_10() {
assert_eq!(eval_sum(4, 1, 10), "25333");
}
#[test]
fn faulhaber_k_7_big_range_uses_closed_form() {
let mut arena = Arena::new();
let var = arena.symbol("k");
let lower = arena.int(1);
let upper = arena.int(5000);
let seven = arena.int(7);
let body = arena.pow(var, seven);
let result = eval_sum_symbolic(&mut arena, body, var, lower, upper).unwrap();
let evaled = crate::transforms::eval::eval(&mut arena, result);
let s = arena.display(evaled).to_string();
assert_eq!(s, "48867196614583151041668750000");
}
#[test]
fn constant_body() {
let mut arena = Arena::new();
let var = arena.symbol("k");
let lower = arena.int(1);
let upper = arena.int(10);
let body = arena.int(5);
let result = eval_sum_symbolic(&mut arena, body, var, lower, upper);
assert!(result.is_some());
let evaled = crate::transforms::eval::eval(&mut arena, result.unwrap());
assert_eq!(arena.display(evaled).to_string(), "50");
}
#[test]
fn geometric_series() {
let mut arena = Arena::new();
let var = arena.symbol("k");
let lower = arena.int(0);
let upper = arena.int(9);
let two = arena.int(2);
let body = arena.pow(two, var);
let result = eval_sum_symbolic(&mut arena, body, var, lower, upper);
assert!(result.is_some());
let evaled = crate::transforms::eval::eval(&mut arena, result.unwrap());
assert_eq!(arena.display(evaled).to_string(), "1023");
}
#[test]
fn product_shim_factorial() {
let mut arena = Arena::new();
let var = arena.symbol("k");
let n = arena.symbol("n");
let lower = arena.int(1);
let result = eval_product_symbolic(&mut arena, var, var, lower, n).unwrap();
assert_eq!(arena.display(result).to_string(), "n!");
}
}