use crate::ast::ast_utils::{contains_variable_by_index, transform_expression};
pub mod interpreters;
pub mod polynomial;
pub mod traits;
pub mod variables;
pub use interpreters::*;
pub use traits::*;
pub use variables::*;
pub use crate::ast::ASTRepr;
pub use crate::final_tagless::traits::NumericType;
pub type AST = ASTEval;
pub type Eval = DirectEval;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct IntRange {
pub start: i64,
pub end: i64,
}
impl IntRange {
#[must_use]
pub fn new(start: i64, end: i64) -> Self {
Self { start, end }
}
#[must_use]
pub fn one_to_n(n: i64) -> Self {
Self::new(1, n)
}
#[must_use]
pub fn zero_to_n_minus_one(n: i64) -> Self {
Self::new(0, n - 1)
}
pub fn iter(&self) -> impl Iterator<Item = i64> {
self.start..=self.end
}
}
impl RangeType for IntRange {
type IndexType = i64;
fn start(&self) -> Self::IndexType {
self.start
}
fn end(&self) -> Self::IndexType {
self.end
}
fn contains(&self, value: &Self::IndexType) -> bool {
*value >= self.start && *value <= self.end
}
fn len(&self) -> Self::IndexType {
if self.end >= self.start {
self.end - self.start + 1
} else {
0
}
}
fn is_empty(&self) -> bool {
self.end < self.start
}
}
#[derive(Debug, Clone)]
pub struct ASTFunction<T> {
pub index_var: String,
pub body: ASTRepr<T>,
}
impl<T: NumericType> ASTFunction<T> {
pub fn new(index_var: &str, body: ASTRepr<T>) -> Self {
Self {
index_var: index_var.to_string(),
body,
}
}
pub fn constant_func(index_var: &str, value: T) -> Self {
Self::new(index_var, ASTRepr::Constant(value))
}
pub fn poly(index_var: &str, coefficients: &[T]) -> Self
where
T: Clone,
{
if coefficients.is_empty() {
return Self::new(index_var, ASTRepr::Constant(T::default()));
}
if coefficients.len() == 1 {
return Self::new(index_var, ASTRepr::Constant(coefficients[0].clone()));
}
let i = ASTRepr::Variable(0);
let mut result = ASTRepr::Constant(coefficients[coefficients.len() - 1].clone());
for coeff in coefficients.iter().rev().skip(1) {
result = ASTRepr::Add(
Box::new(ASTRepr::Constant(coeff.clone())),
Box::new(ASTRepr::Mul(Box::new(i.clone()), Box::new(result))),
);
}
Self::new(index_var, result)
}
pub fn power(index_var: &str, exponent: T) -> Self {
let i = ASTRepr::Variable(0); let exp_expr = ASTRepr::Constant(exponent);
let body = ASTRepr::Pow(Box::new(i), Box::new(exp_expr));
Self::new(index_var, body)
}
}
impl<T: NumericType + Clone> SummandFunction<T> for ASTFunction<T> {
type Body = ASTRepr<T>;
fn index_var(&self) -> &str {
&self.index_var
}
fn body(&self) -> &Self::Body {
&self.body
}
fn apply(&self, index: T) -> Self::Body {
transform_expression(&self.body, &|expr| match expr {
ASTRepr::Variable(0) => Some(ASTRepr::Constant(index.clone())),
_ => None,
})
}
fn depends_on_index(&self) -> bool {
contains_variable_by_index(&self.body, 0)
}
fn extract_independent_factors(&self) -> (Vec<Self::Body>, Self::Body) {
(vec![], self.body.clone())
}
}