weresocool_ast 1.0.43

AST for WereSoCool
Documentation
use crate::{
    generator::error_non_generator, handle_id_error, Axis, CoefState, Coefs, GenOp, Generator,
    NormalForm, Normalize, Op, Term,
};
use num_rational::Rational64;
use polynomials::Polynomial;
use rand::{rngs::StdRng, SeedableRng};
use scop::Defs;
use weresocool_error::Error;
use weresocool_shared::helpers::{et_to_rational, f32_to_rational, r_to_f64};

impl CoefState {
    pub fn generate(&mut self, rng: &mut StdRng) -> Result<Op, Error> {
        match &mut self.coefs {
            Coefs::Const(coefs) => {
                let result = self.axis.generate_const(self.state, self.div);
                self.state += coefs[self.idx].get_value(rng)?;
                self.idx += 1;
                self.idx %= coefs.len();
                Ok(result)
            }
            Coefs::Poly(poly) => {
                let result = self.axis.generate_poly(self.state, self.div, poly)?;
                self.state += 1;
                Ok(result)
            }
            Coefs::Expr { expr_str, parsed } => {
                if parsed.is_none() {
                    *parsed = Some(parse_expr(expr_str)?);
                };
                let result = self.axis.generate_expr(
                    self.state,
                    self.div,
                    parsed.as_ref().unwrap(),
                    expr_str,
                )?;
                self.state += 1;
                Ok(result)
            }
        }
    }
}

pub fn bind_x(e: &meval::Expr, s: &str) -> Result<impl Fn(f64) -> f64, Error> {
    let func = e.to_owned().bind("x");
    match func {
        Ok(f) => Ok(f),
        Err(err) => {
            println!("{}", err);
            Err(Error::with_msg(format!(
                "Unable to parse expression: {}",
                s
            )))
        }
    }
}

pub fn parse_expr(s: &str) -> Result<meval::Expr, Error> {
    let expr_parse: Result<meval::Expr, meval::Error> = s.parse();
    match expr_parse {
        Ok(e) => Ok(e),
        Err(err) => {
            println!("{}", err);
            Err(Error::with_msg(format!(
                "Unable to parse expression: {}",
                s
            )))
        }
    }
}

pub fn eval_polynomial(
    polynomial: &Polynomial<Rational64>,
    state: i64,
    div: usize,
) -> Result<Rational64, Error> {
    let result = polynomial.eval(Rational64::new(state, div as i64));
    if let Some(value) = result {
        Ok(value)
    } else {
        println!("Error: Polynomials must have at least one value.");
        Err(Error::with_msg("Polynomial must have at least one value."))
    }
}

impl Axis {
    pub fn at_least_axis_minimum(&self, r: Rational64, div: usize) -> Rational64 {
        match self {
            Axis::F => std::cmp::max(r, Rational64::from_integer(0)),
            Axis::G => std::cmp::max(r, Rational64::from_integer(0)),
            Axis::L => std::cmp::max(r, Rational64::new(1, div as i64)),
            Axis::P => r,
        }
    }

    pub fn evaluate_expr(
        &self,
        state: i64,
        div: usize,
        expr: &meval::Expr,
        s: &str,
    ) -> Result<Rational64, Error> {
        let func = bind_x(expr, s)?;
        let eval = func(state as f64 / div as f64);
        Ok(f32_to_rational(eval as f32))
    }

    pub fn generate_expr(
        &self,
        state: i64,
        div: usize,
        expr: &meval::Expr,
        s: &str,
    ) -> Result<Op, Error> {
        let func = bind_x(expr, s)?;
        let eval = func(state as f64 / div as f64);

        match self {
            Axis::F => Ok(Op::TransposeM {
                m: self.at_least_axis_minimum(f32_to_rational(2.0_f64.powf(eval) as f32), div),
            }),
            Axis::L => Ok(Op::Length {
                m: self.at_least_axis_minimum(f32_to_rational(eval as f32), div),
            }),
            Axis::G => Ok(Op::Gain {
                m: self.at_least_axis_minimum(f32_to_rational(eval as f32), div),
            }),
            Axis::P => Ok(Op::PanA {
                a: self.at_least_axis_minimum(f32_to_rational(eval as f32), div),
            }),
        }
    }

    fn generate_poly(
        &self,
        state: i64,
        div: usize,
        poly: &Polynomial<Rational64>,
    ) -> Result<Op, Error> {
        let eval = eval_polynomial(poly, state, div)?;

        match self {
            Axis::F => {
                let eval_f64 = r_to_f64(eval);
                let eval_in_log = 2.0_f32.powf(eval_f64 as f32);
                let rational = f32_to_rational(eval_in_log);
                Ok(Op::TransposeM {
                    m: self.at_least_axis_minimum(rational, div),
                })
            }
            Axis::L => Ok(Op::Length {
                m: self.at_least_axis_minimum(eval, div),
            }),
            Axis::G => Ok(Op::Gain {
                m: self.at_least_axis_minimum(eval, div),
            }),
            Axis::P => Ok(Op::PanA {
                a: self.at_least_axis_minimum(eval, div),
            }),
        }
    }
    fn generate_const(&self, state: i64, div: usize) -> Op {
        match self {
            Axis::F => Op::TransposeM {
                m: self.at_least_axis_minimum(et_to_rational(state, div), div),
            },
            Axis::L => Op::Length {
                m: self.at_least_axis_minimum(Rational64::new(state, div as i64), div),
            },
            Axis::G => Op::Gain {
                m: self.at_least_axis_minimum(Rational64::new(state, div as i64), div),
            },
            Axis::P => Op::PanA {
                a: Rational64::new(state, div as i64),
            },
        }
    }
}

impl Generator {
    pub fn term_vectors(
        &mut self,
        n: usize,
        rng: &mut rand::rngs::StdRng,
    ) -> Result<Vec<Op>, Error> {
        let mut result: Vec<Op> = vec![];
        let mut coefs = self.coefs.clone();

        for _ in 0..n {
            let mut operations: Vec<Term> = vec![];
            for coef in coefs.iter_mut() {
                operations.push(Term::Op(coef.generate(rng)?))
            }
            result.push(Op::Compose { operations })
        }

        Ok(result)
    }

    pub fn generate(
        &mut self,
        nf: &NormalForm,
        n: usize,
        defs: &mut Defs<Term>,
        rng: &mut rand::rngs::StdRng,
    ) -> Result<Vec<NormalForm>, Error> {
        let mut result: Vec<NormalForm> = vec![];
        let mut coefs = self.coefs.clone();

        for _ in 0..n {
            let mut nf: NormalForm = nf.clone();
            for coef in coefs.iter_mut() {
                coef.generate(rng)?.apply_to_normal_form(&mut nf, defs)?;
            }
            result.push(nf)
        }

        Ok(result)
    }
}

impl GenOp {
    pub fn term_vectors_from_genop(
        self,
        n: Option<usize>,
        defs: &mut Defs<Term>,
    ) -> Result<Vec<Op>, Error> {
        match self {
            GenOp::Named { name, seed } => {
                let generator = handle_id_error(name, defs)?;
                match generator {
                    Term::Gen(mut gen) => {
                        gen.set_seed(seed);
                        gen.term_vectors_from_genop(n, defs)
                    }
                    _ => Err(error_non_generator()),
                }
            }
            GenOp::Const { mut gen, seed } => {
                let length = if let Some(n) = n { n } else { gen.lcm_length() };
                gen.term_vectors(length, &mut SeedableRng::seed_from_u64(seed))
            }

            GenOp::Taken { mut gen, n, seed } => {
                gen.set_seed(seed);
                gen.term_vectors_from_genop(Some(n), defs)
            }
        }
    }
    pub fn generate_from_genop(
        self,
        input: &mut NormalForm,
        n: Option<usize>,
        defs: &mut Defs<Term>,
    ) -> Result<Vec<NormalForm>, Error> {
        match self {
            GenOp::Named { name, seed } => {
                let generator = handle_id_error(name, defs)?;
                match generator {
                    Term::Gen(mut gen) => {
                        gen.set_seed(seed);
                        gen.generate_from_genop(input, n, defs)
                    }
                    _ => Err(error_non_generator()),
                }
            }
            GenOp::Const { mut gen, seed } => {
                let length = if let Some(n) = n { n } else { gen.lcm_length() };

                gen.generate(
                    input,
                    length,
                    defs,
                    &mut rand::SeedableRng::seed_from_u64(seed),
                )
            }

            GenOp::Taken { mut gen, n, seed } => {
                gen.set_seed(seed);
                gen.generate_from_genop(input, Some(n), defs)
            }
        }
    }
}