use super::frac::{Fraction, FractranNat, StepResult};
use std::iter::Iterator;
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Program<T: FractranNat> {
fracs: Vec<Fraction<T>>,
}
impl<T: FractranNat> Program<T> {
pub fn new(fracs: Vec<Fraction<T>>) -> Program<T> {
Program{
fracs
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub(crate) struct Evaluator<T: FractranNat> {
program: Vec<Fraction<T>>,
curr_state: T,
finished: bool,
}
impl<T: FractranNat> Iterator for Evaluator<T> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
if self.finished {
None
} else {
for frac in self.program.clone() {
if let StepResult::Changed(new_state) = frac.exec(self.curr_state.clone()) {
self.curr_state = new_state;
return Some(self.curr_state.clone());
}
}
self.finished = true;
None
}
}
}
impl<T: FractranNat> Evaluator<T> {
pub fn new(program: Vec<Fraction<T>>, input: T) -> impl Iterator<Item = T> {
if program.is_empty() {
panic!("Cannot run empty program!");
}
Evaluator {
program,
curr_state: input,
finished: false,
}
}
}
impl<T: FractranNat> Program<T> {
pub fn lazy_exec(self, input: T) -> impl Iterator<Item = T> {
Evaluator::new(self.fracs, input)
}
pub fn exec_to_completion(self, input: T) -> T {
self.lazy_exec(input)
.inspect(|step| {
dbg!(step);
})
.last()
.unwrap()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::primebasis::PrimeBasis;
fn make_program(nums: Vec<u64>, denoms: Vec<u64>) -> Program<PrimeBasis> {
let mut prog: Vec<Fraction<PrimeBasis>> = vec![];
for (num, denom) in nums.into_iter().zip(denoms) {
prog.push(Fraction::new(
PrimeBasis::try_new(num).unwrap(),
PrimeBasis::try_new(denom).unwrap(),
));
}
Program { fracs: prog }
}
#[test]
fn test_basic_program() {
let div_then_stop = Program {
fracs: vec![Fraction::new(1_u64, 2_u64)],
};
let mut iter = div_then_stop.clone().lazy_exec(4_u64);
assert_eq!(iter.next(), Some(2_u64));
assert_eq!(iter.next(), Some(1_u64));
assert_eq!(iter.next(), None);
assert_eq!(div_then_stop.exec_to_completion(4_u64), 1_u64);
}
#[test]
fn test_multiply() {
let mult_pb = make_program(vec![455, 11, 1, 3, 11, 1], vec![33, 13, 11, 7, 2, 3]);
assert_eq!(
mult_pb
.exec_to_completion(PrimeBasis::try_new(72).unwrap())
.value(),
5_u64.pow(6)
);
}
#[test]
fn test_readme_primes() {
let nums: Vec<u64> = vec![17, 78, 19, 23, 29,
77, 95, 77, 1, 11,
13, 15, 15, 55];
let denoms: Vec<u64> = vec![91, 85, 51, 38, 33,
29, 23, 19, 17, 13,
11, 14, 2, 1];
let fracs: Vec<Fraction<u64>> = nums.into_iter()
.zip(denoms)
.map(|(num, denom)| Fraction::new(num, denom))
.collect();
let prog = Program::new(fracs);
let mut primes = vec![];
for out in prog.lazy_exec(2).take(2000) {
if out.is_power_of_two() {
primes.push(out.trailing_zeros());
}
}
assert_eq!(primes, vec![2, 3, 5, 7]);
}
#[test]
fn test_readme_primes_2e() {
let nums: Vec<u64> = vec![17, 78, 19, 23, 29,
77, 95, 77, 1, 11,
13, 15, 15, 55];
let denoms: Vec<u64> = vec![91, 85, 51, 38, 33,
29, 23, 19, 17, 13,
11, 14, 2, 1];
let fracs: Vec<Fraction<PrimeBasis>> = nums.into_iter()
.zip(denoms)
.map(|(num, denom)| Fraction::new(
PrimeBasis::try_new(num).unwrap(),
PrimeBasis::try_new(denom).unwrap(),
))
.collect();
let prog = Program::new(fracs);
let mut primes = vec![];
for out_pb in prog.lazy_exec(PrimeBasis::try_new(2).unwrap())
.take(100_000) {
if out_pb.exps[1..].iter().all(|&exp| exp == 0) {
primes.push(out_pb.exps[0]);
}
}
assert_eq!(primes, vec![2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37]);
}
}