1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
use crate::core::Distribution; use std::{error::Error, fmt}; #[derive(Debug, Clone)] pub enum ConvolutionError { TooFewVariables, MixedParameters, } pub type ConvolutionResult<T> = Result<T, ConvolutionError>; impl ConvolutionError { #[inline(always)] pub fn check_count<T>(rvs: &Vec<T>) -> ConvolutionResult<usize> { let n = rvs.len(); if n < 2 { Err(ConvolutionError::TooFewVariables) } else { Ok(n) } } } impl fmt::Display for ConvolutionError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { ConvolutionError::TooFewVariables => f.write_str("TooFewVariables"), ConvolutionError::MixedParameters => f.write_str("MixedParameters "), } } } impl Error for ConvolutionError { fn description(&self) -> &str { match *self { ConvolutionError::TooFewVariables => "Convolution requires two or more independent random variables", ConvolutionError::MixedParameters => "Variables must all have the same parameters", } } } pub trait Convolution<T: Distribution = Self> where Self: Sized { fn convolve(self, rv: T) -> ConvolutionResult<Self>; fn convolve_pair(x: T, y: T) -> ConvolutionResult<Self>; fn convolve_many(mut rvs: Vec<T>) -> ConvolutionResult<Self> { let _ = ConvolutionError::check_count(&rvs)?; let rv1 = rvs.pop().unwrap(); let rv2 = rvs.pop().unwrap(); let new_dist = Self::convolve_pair(rv1, rv2); rvs.into_iter().fold(new_dist, |acc, rv| { acc.and_then(|d| d.convolve(rv)) }) } }