use {
crate::{monomial::Monomial, formula::NeedBrackets::*, traits::Required},
rand::{thread_rng, Rng},
};
#[derive(PartialEq, Copy, Clone)]
pub enum NeedBrackets {
True,
False,
Never,
}
#[derive(Debug)]
enum Operators<T: Required> {
Add(Box<Formula<T>>, Box<Formula<T>>),
Sub(Box<Formula<T>>, Box<Formula<T>>),
Mul(Box<Formula<T>>, Box<Formula<T>>),
Div(Box<Formula<T>>, Box<Formula<T>>),
Pow(Box<Formula<T>>, T),
Wrap(Monomial<T>),
}
#[derive(Debug)]
pub struct Formula<T: Required> {
operator: Operators<T>,
}
impl<T: Required> Formula<T> {
pub(crate) fn generate(depth: T, exponent_limit: T, coefficient_limit: T) -> Self {
let mut rng = thread_rng();
let operator = if depth == T::zero() {
Operators::Wrap(Monomial::generate(
rng.gen_range(T::zero(), exponent_limit),
coefficient_limit,
))
} else {
let depth = depth - T::one();
match rng.gen_range(0, 5) {
0 => Operators::Add(
Box::new(Formula::generate(
depth,
exponent_limit,
coefficient_limit,
)),
Box::new(Formula::generate(
depth,
exponent_limit,
coefficient_limit,
)),
),
1 => Operators::Sub(
Box::new(Formula::generate(
depth,
exponent_limit,
coefficient_limit,
)),
Box::new(Formula::generate(
depth,
exponent_limit,
coefficient_limit,
)),
),
2 => Operators::Mul(
Box::new(Formula::generate(
depth,
exponent_limit,
coefficient_limit,
)),
Box::new(Formula::generate(
depth,
exponent_limit,
coefficient_limit,
)),
),
3 => Operators::Div(
Box::new(Formula::generate(
depth,
exponent_limit,
coefficient_limit,
)),
Box::new(Formula::generate(
depth,
exponent_limit,
coefficient_limit,
)),
),
4 => Operators::Pow(
Box::new(Formula::generate(
depth,
exponent_limit,
coefficient_limit,
)),
if T::one() + T::one() >= exponent_limit {
T::one() + T::one()
} else {
rng.gen_range(T::one() + T::one(), exponent_limit)
},
),
_ => unreachable!(),
}
};
Self { operator }
}
pub fn export(&self, father_need_brackets: NeedBrackets) -> String {
let self_need_brackets = self.need_brackets();
let origin = match &self.operator {
Operators::Add(a, b) => format!(
"{}+{}",
a.export(self_need_brackets),
b.export(self_need_brackets)
),
Operators::Sub(a, b) => format!(
"{}-{}",
a.export(self_need_brackets),
b.export(self_need_brackets)
),
Operators::Mul(a, b) => format!(
"{}\\times{{}}{}",
a.export(self_need_brackets),
b.export(self_need_brackets)
),
Operators::Div(a, b) => format!(
"\\frac{{{}}}{{{}}}",
a.export(self_need_brackets),
b.export(self_need_brackets)
),
Operators::Pow(a, p) => format!("({})^{{{}}}", a.export(self_need_brackets), p),
Operators::Wrap(a) => a.export(),
};
if (father_need_brackets == True) && (self_need_brackets == False) {
format!("({})", origin)
} else {
origin
}
}
fn need_brackets(&self) -> NeedBrackets {
match &self.operator {
Operators::Add(_, _) | Operators::Sub(_, _) => False,
Operators::Mul(_, _) => True,
Operators::Wrap(_) | Operators::Div(_, _) | Operators::Pow(_, _) => Never,
}
}
}