probability.rs - source
Description: Source of the Rust file `src/probability.rs`.

#
scicdh/
probability.rs

    1//! # Probability and Stochastic Distribution Suite (`scicdh::probability`)
    2//!
    3//! This module provides foundational discrete probability distributions, combinatorial
    4//! calculation architectures, and joint random vector analysis engines mapped entirely
    5//! onto `f64` scalar float values.
    6//!
    7//! ## Core Architecture Components
    8//! * **Combinatorics Engines:** Safe, bounded definitions for factorials ($n!$), permutations ($P_r^n$), and combinations ($C_r^n$).
    9//! * **Random Vector Framework:** Bivariate discrete spaces executing cross-joint tracking, marginal breakdowns, and conditional expectation parameters.
    10//! * **Discrete Distributions:** Built-in calculation matrices for Binomial, Geometric, Pascal, and Hypergeometric models.
    11
    12
    13
    14///Result Type for the library
    15pub type CDHResult<T> = Result<T,String>;
    16
    17
    18/// Placeholder configuration struct representing the abstract probability execution namespace context.
    19#[derive(Debug)]
    20pub struct Probability;
    21
    22/// Represents a univariate discrete Random Variable containing mapped outcomes and matching probability mass profiles.
    23///
    24/// # Struct Elements
    25/// * `variable`: Contiguous storage tracking distinct numeric real outcomes ($X$).
    26/// * `probability`: Matching distribution array tracking distinct weights or probability mass parameters ($P(X)$).
    27#[derive(Debug,Clone)]
    28pub struct RandomVariable{
    29pub variable:Vec<f64>,
    30pub probability: Vec<f64>
    31}
    32
    33/// A multivariate structure tracking pairs or collections of intersecting random processes over a discrete matrix space.
    34#[derive(Debug)]
    35pub struct RandomVector<T>{
    36pub variables: Vec<RandomVariable>,
    37pub probability_matrix:JointProbability<T>}
    38
    39/// A collection type wrapper containing a two-dimensional grid layout of raw statistical densities.
    40#[derive(Debug,PartialEq)]
    41pub struct JointProbability<T>{
    42pub matrix:Vec<Vec<T>>
    43}
    44
    45
    46/// Runs telemetry diagnostic logging verifications across your module distribution functions to confirm precision alignments.
    47///
    48/// # Errors
    49/// Returns an `Err` variant if an upstream calculation fails or encounters structural mismatch bounds.
    50pub fn check_probability()
    51->CDHResult<()>{
    52println!("+++++ probability.rs results +++++");
    53let x = (0..10).map(|i| i as f64).collect::<Vec<f64>>();
    54let px = x.iter().map(|_| 1f64/10f64)
    55.collect::<Vec<f64>>();
    56let rv = RandomVariable::new(x,px);
    57println!("Random Variable Mean === {:?}"
    58,rv.mean()?);
    59println!("Random Variable Variance === {:?}"
    60,rv.variance()?);
    61println!("Random Variable Standard Deviation === {:?}"
    62,rv.std_deviation()?);
    63println!("Random Variable Moment Generating func(5) === {:?}"
    64,rv.moment_generating_func(5f64)?);
    65let jp: Vec<Vec<f64>> = (0..10).
    66map(|_|{
    67(0..10).map(|_| 1f64/200f64).collect()
    68}).collect();
    69let rvv = RandomVector:: new(vec![rv.clone(),
    70rv.clone()],JointProbability::new(jp))?;
    71println!("Random Vector Covariance === {:?}"
    72,rvv.covariance()?);
    73println!("Random Vector Correlation=== {:?}"
    74,rvv.correlation()?);
    75rvv.get_jointprobability()?.validate_probability();
    76println!("\n\n\n\n");
    77Ok(())
    78
    79}
    80
    81
    82impl JointProbability<f64>{
    83/// Constructs an instance around a raw joint metric distribution table matrix.
    84    ///
    85    /// # Example
    86    /// ```rust
    87    /// # use scicdh::probability::JointProbability;
    88    /// let matrix = vec![vec![0.2, 0.3], vec![0.1, 0.4]];
    89    /// let joint_prob = JointProbability::new(matrix);
    90    /// ```
    91pub fn new(px: Vec<Vec<f64>>)->Self{
    92Self{matrix:px}
    93}
    94
    95/// Accumulates and sums every item in the grid rows to check if the combined weights total 1.0.
    96pub fn validate_probability(&self){
    97println!("Sum of all elements is == {:?}",
    98self.matrix.iter().
    99fold(0f64,|acc,px2|{
    100acc+px2.iter().fold(0f64,|acc2,a|{
    101acc2+a
    102})
    103}));
    104}
    105}
    106
    107
    108impl RandomVariable{
    109   /// Instantiates a new entry tracking outcomes and matching process weights.
    110pub fn new(x:Vec<f64>,px:Vec<f64>)->Self{
    111Self{variable:x,probability:px}
    112}
    113
    114/// Computes the true expectation parameter mean ($E[X]$) of the random process.
    115    ///
    116    /// $$E[X] = \sum x_i p(x_i)$$
    117    ///
    118    /// # Example
    119    /// ```rust
    120    /// # use scicdh::probability::RandomVariable;
    121    /// let rv = RandomVariable::new(vec![1.0, 2.0], vec![0.5, 0.5]);
    122    /// assert_eq!(rv.mean().unwrap(), 1.5);
    123    /// ```
    124pub fn mean(&self)->CDHResult<f64>{
    125self.expectation_from_func(|a|{
    126a
    127})
    128}
    129
    130/// Computes the exact variance ($\text{Var}(X)$) using structural deviations to counter float degradation noise.
    131    ///
    132    /// $$\text{Var}(X) = E[(X - \mu)^2] = \sum (x_i - \mu)^2 p(x_i)$$
    133pub fn variance(&self)->CDHResult<f64>{
    134let summat:f64 = self.variable.iter().
    135zip(self.probability.iter()).
    136fold(0.0,|acc,b|{
    137acc+b.0.powf(2.0)*b.1
    138});
    139Ok(
    140summat-self.mean()?.powf(2.0)
    141)
    142}
    143
    144   /// Transforms elements via an arbitrary closure parameter and sums the targeted transformation grid weights.
    145    ///
    146    /// $$E[h(X)] = \sum h(x_i) p(x_i)$$
    147pub fn expectation_from_func<H>(&self,h:H)
    148->CDHResult<f64>
    149where H: Fn(f64)->f64
    150{Ok(
    151self.variable.iter().zip(self.probability.iter()).
    152fold(0.0,|mut a,b|{
    153a+=h(*b.0)*b.1;
    154a
    155}))
    156}
    157
    158/// Evaluates the functional expectation cross product against an isolated reference sequence slice.
    159pub fn expectation_from_set(&self,hx: &[f64])
    160->CDHResult<f64>{
    161Ok(self.probability.iter().zip(hx.iter()).
    162fold(0.0,|mut a, b|{
    163a+= b.0*b.1;
    164a
    165}))
    166}
    167
    168    /// Computes the standard deviation ($\sigma$) of the isolated distribution.
    169pub fn std_deviation(&self)->CDHResult<f64>{
    170Ok(self.variance()?.powf(0.5))
    171}
    172
    173/// Generates the Moment Generating Function evaluation value ($M_X(t)$) using precise hardware-level scaling exponents.
    174    ///
    175    /// $$M_X(t) = E[e^{tX}]$$
    176pub fn moment_generating_func(&self,t:f64)
    177->CDHResult<f64>{
    178self.expectation_from_func(|a|{
    179let e: f64 = std::f64::consts::E;
    180e.powf(t*a)
    181})
    182}
    183
    184    /// Deprecated method indicating complex real-space value tracking limits.
    185    ///
    186    /// # Errors
    187    /// Always returns an `Err` variant because complex number tracks require imaginary extensions not native to `f64`.
    188#[deprecated(
    189    since = "0.1.0",
    190    note = "Returns Err. f64 cannot represent complex numbers required \
    191            for E[e^(itX)]. Will be implemented when complex number \
    192            support is added."
    193)]
    194pub fn characteristic_func(&self,t:f64)
    195->CDHResult<f64>{
    196/*self.expectation_from_func(|a|{
    197let e: f64 = std::f64::consts::E;
    198e.powf(t*a*(-1.0_f64).powf(0.5))
    199});
    200*/
    201Err("characteristic_func requires complex number support \
    202         which is not yet implemented. f64 cannot represent \
    203         imaginary numbers.".to_string())
    204}
    205
    206/// Calculates dispersion changes over custom functional projections while protecting closure scopes.
    207pub fn variance_operator<H>(&self,h:H)
    208->CDHResult<f64>
    209where
    210H:Clone+ Fn(f64)->f64
    211{
    212self.expectation_from_func(|a|{
    213(h(a) - self.expectation_from_func(h.clone())
    214.unwrap())
    215.powf(2.0)
    216})
    217
    218}
    219
    220}
    221
    222
    223
    224impl RandomVector<f64>{
    225/// Instantiates a new multivariate distribution vector matrix frame context.
    226    ///
    227    /// # Errors
    228    /// Returns an `Err` if the initial input array length drops below 2 or tracking configurations mismatch inside the vectors.
    229pub fn new(x:Vec<RandomVariable>,
    230px:JointProbability<f64>)->CDHResult<Self>{
    231
    232match x{
    233a if a.len()<2 => Err("Vec.len() should be >= 2 in RandomCector::new".to_string()),
    234a => {
    235let len = a[0].variable.len();
    236for i in &a[1..]{
    237if i.variable.len() !=len{
    238return Err("Random Variables should have same size".to_string());
    239}
    240}
    241Ok(Self{variables:a,probability_matrix:px})
    242}
    243}
    244}
    245
    246    /// Evaluates the joint operational probability layout grid configurations.
    247pub fn get_jointprobability(&self)
    248->CDHResult<JointProbability<f64>>{
    249let jp : Vec<Vec<f64>> = self.variables[1]
    250.probability.iter()
    251.map(|&px2|{
    252self.variables[0].probability.iter().
    253map(|&px1| px2*px1).collect()
    254}).collect();
    255//println!("JP === {:#?}",jp);
    256Ok(JointProbability::new(jp))
    257}
    258
    259   /// Extracts the marginal probability distribution value matching a specific index coordinate for $X_2$.
    260pub fn marginal_x2(&self,index:usize)
    261->CDHResult<f64>{
    262Ok(self.probability_matrix.matrix
    263.iter().map(|a| a[index]).sum::<f64>())
    264}
    265
    266   /// Extracts the marginal probability distribution value matching a specific index coordinate for $X_1$.
    267pub fn marginal_x1(&self,index:usize)
    268->CDHResult<f64>{
    269Ok(self.probability_matrix.matrix[index].iter().sum::<f64>())
    270}
    271
    272    /// Computes the conditional probability allocation metric context $P(X_1 \mid X_2)$.
    273pub fn conditional_x1(&self,
    274index_x1:usize,
    275index_x2:usize)->CDHResult<f64>{
    276
    277Ok(
    278self.probability_matrix
    279.matrix[index_x2][index_x1]/self
    280.variables[1].probability[index_x2]
    281)
    282}
    283
    284/// Computes the conditional probability allocation metric context $P(X_2 \mid X_1)$.
    285pub fn conditional_x2(&self,
    286index_x1:usize,
    287index_x2:usize)->CDHResult<f64>{
    288Ok(
    289self.probability_matrix.
    290matrix[index_x2][index_x1]/self.
    291variables[0].probability[index_x1]
    292)}
    293
    294/// Calculates the conditional expectation variable limit $E[h(X_1) \mid X_2 = x_2]$.
    295pub fn conditional_expectation_x1<H>(&self,
    296 index_x2: usize, h: H) -> CDHResult<f64>
    297    where
    298        H: Fn(f64) -> f64,
    299    {
    300        let x1_outcomes = &self.variables[0]
    301.variable;
    302// Access outcomes of X1
    303        let mut expected_value = 0.0;
    304
    305        // Sum over all possible values of X1
    306        for index_x1 in 0..x1_outcomes.len() {
    307            let p_cond = self.conditional_x1(
    308index_x1, index_x2)?;
    309            if p_cond > 0.0 {
    310                expected_value += h(
    311x1_outcomes[index_x1]) * p_cond;
    312            }
    313        }
    314
    315        Ok(expected_value)
    316    }
    317
    318
    319   /// Calculates the conditional expectation variable limit $E[h(X_2) \mid X_1 = x_1]$.
    320    pub fn conditional_expectation_x2<H>(&self,
    321index_x1: usize, h: H) -> CDHResult<f64>
    322    where
    323        H: Fn(f64) -> f64,
    324    {
    325        let x2_outcomes = &self.variables[1]
    326.variable;
    327// Access outcomes of X2
    328        let mut expected_value = 0.0;
    329
    330        // Sum over all possible values of X2
    331        for index_x2 in 0..x2_outcomes.len() {
    332            let p_cond = self.conditional_x2(
    333index_x1, index_x2)?;
    334            if p_cond > 0.0 {
    335                expected_value += h(
    336x2_outcomes[index_x2]) * p_cond;
    337            }
    338        }
    339
    340        Ok(expected_value)
    341    }
    342
    343
    344   /// Evaluates joint expectation transformations $E[g(X, Y)]$ over the combined sample domains.
    345pub fn joint_expectation<F>(&self, g: F)
    346 -> CDHResult<f64>
    347    where
    348        F: Fn(f64, f64) -> f64,
    349    {
    350        let x = &self.variables[0];
    351        let y = &self.variables[1];
    352        let joint_matrix = &self.probability_matrix.
    353matrix;
    354
    355        let mut expected_value = 0.0;
    356
    357        for i in 0..x.variable.len() {
    358            for j in 0..y.variable.len() {
    359                let p_joint = joint_matrix[i][j];
    360
    361                if p_joint > 0.0 {
    362                    // Accumulate: g(x, y) * P(x, y)
    363                    expected_value += g(
    364x.variable[i], y.variable[j]) * p_joint;
    365                }
    366            }
    367        }
    368
    369       Ok( expected_value)
    370    }
    371
    372
    373/// 2. THE COVARIANCE CALCULATOR
    374    /// Uses your exact definitional
    375///formula: E[(X1 - E(X1))(X2 - E(X2))]
    376   /// Computes the true covariance spatial scaling link metric between two random processes.
    377    ///
    378    /// $$\text{Cov}(X,Y) = E[(X - E[X])(Y - E[Y])]$$
    379 pub fn covariance(&self) -> CDHResult<f64> {
    380        // Step A: Find the individual means
    381// using the engine
    382        let e_x1 = self.joint_expectation(
    383|x, _y| x)?;
    384        let e_x2 = self.joint_expectation(
    385|_x, y| y)?;
    386
    387        // Step B: Pass the exact deviation
    388//formula into the engine
    389       Ok( self.joint_expectation(
    390|x, y| (x - e_x1) * (y - e_x2))?)
    391    }
    392
    393/// Evaluates Pearson's joint population correlation coefficient ($\rho$) containing zero-variance protections.
    394pub fn correlation(&self) -> CDHResult<f64> {
    395        let cov = self.covariance()?;
    396
    397        // 1. Calculate individual expected
    398//values (means)
    399        let e_x1 = self.joint_expectation(
    400|x, _y| x)?;
    401        let e_x2 = self.joint_expectation(
    402|_x, y| y)?;
    403
    404        // 2. Calculate pure definitional
    405//variances: E[(X - E[X])^2]
    406        let var_x1 = self.joint_expectation(
    407|x, _y| (x - e_x1).powi(2))?;
    408        let var_x2 = self.joint_expectation(
    409|_x, y| (y - e_x2).powi(2))?;
    410
    411        // 3. Compute Pearson's rho
    412// with zero-variance protection
    413
    414       Ok( if var_x1 > 0.0 && var_x2 > 0.0 {
    415            cov / (var_x1.sqrt() * var_x2.sqrt())
    416        } else {
    417            0.0
    418        })
    419    }
    420}
    421
    422
    423
    424impl Probability{
    425  /// Computes direct classical configurations mapping favorable events against the full sample spaces.
    426pub fn get_probability(sample_space_len: f64,
    427favourable_len: f64)->CDHResult<f64>{
    428Ok(
    429favourable_len/sample_space_len)
    430}
    431
    432/// Generates pure mathematical factorials ($n!$) protected by upper hardware bounds limits.
    433    ///
    434    /// # Errors
    435    /// Returns an `Err` if $n > 101$, as the calculation scales beyond maximum `f64` storage boundaries.
    436pub fn factorial(n:usize)->CDHResult<f64>{
    437match n{
    438a if a<1=> Ok(1f64),
    439a if a >101=>Err("Can't Calculate n greater than 101. n should be between 0 to 101".to_string()),
    440_=>{
    441Ok((1..=n).fold(1f64,|a,b|{
    442a*(b as f64)
    443}))
    444}
    445}
    446
    447}
    448
    449
    450  /// Computes analytical permutation counts ($P_r^n$) avoiding negative loops.
    451pub fn n_p_r(n:usize,r:usize)->CDHResult<f64>{
    452match (n,r){
    453(0,_) => Err("n cannot be 0".to_string()),
    454(_a,0)=>Ok(1f64),
    455(a,b) if a==b=>Self::factorial(a),
    456(_,_)=>{
    457Ok((0..r).fold(1f64,|a,b|{
    458a*(n as f64-b as f64)
    459}))
    460}
    461}
    462
    463
    464}
    465
    466   /// Evaluates combinations counts ($C_r^n$), often stated as "n choose r".
    467pub fn n_c_r(n:usize,r:usize)->CDHResult<f64>{
    468Ok(Self::n_p_r(n,r)?/Self::factorial(r)?)
    469}
    470
    471 /// Transforms raw baseline sequences mapping distribution sets across processing closures.
    472pub fn random_variable<F>(set: &[f64],
    473mut f:F)-> CDHResult<Vec<f64>>
    474where
    475F: FnMut(f64)->f64,
    476//T: Copy
    477{Ok(
    478set.into_iter().map(|elements|{
    479f(*elements)
    480}).collect::<Vec<f64>>())
    481}
    482
    483/// Converts probability vectors into their matching localized Cumulative Distribution Function (CDF) increments.
    484pub fn distribution_function(
    485probability_set:&[f64])->CDHResult<Vec<f64>>{
    486let mut distri: Vec<f64>= Vec::with_capacity(
    487probability_set.len());
    488let mut sum = 0f64;
    489for &prob in probability_set{
    490sum+= prob;
    491distri.push(sum);
    492}
    493Ok(
    494distri)
    495}
    496
    497}
    498
    499
    500/// Ingests context tracking parameters mapping independent Binomial distribution configurations.
    501pub struct Binomial {
    502    /// Number of independent trials ($n$).
    503    pub n: usize,
    504    /// Vector tracking target successes ($x$).
    505    pub x: Vec<usize>,
    506    /// Probability of success on an individual trial ($p$).
    507    pub p: f64,
    508}
    509
    510
    511impl Binomial{
    512pub fn new(n:usize,x:Vec<usize>,p:f64)->Self{
    513Self{
    514n,x,p
    515}
    516}
    517
    518/// Computes the complete array parameters mapped via the distribution PMF formula.
    519pub fn get_probability_set(&self)
    520->CDHResult<Vec<f64>>{
    521Ok(self.x.iter().map(|&i|{
    522let ncr = Probability::n_c_r(self.n,i).unwrap();
    523let ppx = self.p.powf(i as f64);
    524let qpnx = (1f64-self.p).powf((self.n-i) as f64);
    525ncr*ppx*qpnx
    526}).collect::<Vec<f64>>()
    527)}
    528
    529
    530pub fn mean(&self)->CDHResult<f64>{
    531Ok(self.n as f64 * self.p)
    532}
    533pub fn variance(&self)->CDHResult<f64>{
    534Ok(self.mean()?*(1f64-self.p))
    535}
    536}
    537
    538
    539/// Tracks observations processing structural patterns for Discrete Geometric configurations.
    540pub struct Geometric {
    541    /// Number of trials until the first success occurs ($x$).
    542    pub x: Vec<usize>,
    543    /// Probability of success on a single trial ($p$).
    544    pub p: f64,
    545}
    546
    547
    548impl Geometric{
    549pub fn new(x:Vec<usize>, p:f64)->Self{
    550Self{
    551x,p}
    552}
    553
    554/// Maps the structural parameters through the Geometric execution distribution tracking matrix.
    555pub fn get_probability_set(&self)
    556->CDHResult<Vec<f64>>{
    557Ok(self.x.iter().map(|&i|{
    558let qpnx = (1f64-self.p).powf(i as f64 -1f64);
    559self.p*qpnx
    560}).collect::<Vec<f64>>()
    561)}
    562pub fn mean(&self)->CDHResult<f64>{
    563Ok(1f64/ self.p)
    564}
    565pub fn variance(&self)->CDHResult<f64>{
    566Ok((1f64-self.p)/(self.p.powf(2f64)))
    567}
    568}
    569
    570/// Handles Negative Binomial (Pascal) distributions tracking total required iterations up until target success thresholds are passed.
    571pub struct Pascal {
    572    /// Target number of total successes required ($r$).
    573    pub r: usize,
    574    /// Vector tracking total numbers of executed trials ($x$).
    575    pub x: Vec<usize>,
    576    /// Probability of success on an isolated trial ($p$).
    577    pub p: f64,
    578}
    579
    580
    581impl Pascal{
    582pub fn new(r:usize,x:Vec<usize>,p:f64)->Self{
    583Self{r,x,p}
    584}
    585
    586/// Computes the structural parameters mapping points via the Negative Binomial equation engine.
    587pub fn get_probability_set(&self)
    588->CDHResult<Vec<f64>>{
    589Ok(self.x.iter().map(|&i|{
    590let ncr = Probability::n_c_r(i-1,self.r-1).unwrap();
    591let ppx = self.p.powf(i as f64);
    592let qpnx = (1f64-self.p).powf((i-self.r) as f64);
    593ncr*ppx*qpnx
    594}).collect::<Vec<f64>>()
    595)}
    596
    597pub fn mean(&self)->CDHResult<f64>{
    598Ok(self.r as f64/self.p)
    599}
    600
    601pub fn variance(&self)->CDHResult<f64>{
    602Ok(self.r as f64/(self.p.powf(2f64)))
    603}
    604}
    605
    606/// Tracks parameters mapping states across Hypergeometric sample space distributions where sampling occurs without replacement.
    607pub struct HyperGeometric {
    608    /// Total items present inside the master population base ($N$).
    609    pub big_n: usize,
    610    /// Total characteristic target elements tracked inside the population ($T$).
    611    pub big_t: usize,
    612    /// Number of elements drawn in the sample slice ($n$).
    613    pub n: usize,
    614    /// Tracked number of matching characteristics observed inside the sample ($x$).
    615    pub x: usize,
    616}
    617
    618
    619impl HyperGeometric{
    620pub fn new(big_n:usize,big_t: usize,
    621n:usize,x:usize)->Self{
    622Self{big_n,big_t,n,x}
    623}
    624
    625    /// Maps combination ratios to evaluate discrete target probability outputs.
    626pub fn get_probability(&self)->CDHResult<f64>{
    627
    628let big_t_x = Probability::n_c_r(self.big_t,
    629self.x)?;
    630let big_n_t = Probability::n_c_r(
    631self.big_n-self.big_t,
    632self.n-self.x)?;
    633let big_n_n = Probability::n_c_r(self.big_n,
    634self.n)?;
    635Ok(big_t_x*big_n_t/big_n_n)
    636}
    637
    638pub fn mean(&self)->CDHResult<f64>{
    639Ok(self.n as f64 * self.big_t as f64/self.big_n as f64)
    640}
    641
    642pub fn variance(&self)->CDHResult<f64>{
    643let dd = self.big_t as f64;
    644let nn= self.big_n as f64;
    645let n= self.n as f64;
    646Ok(self.mean()?*(1f64 - (dd/nn))*((nn-n)/(nn-1f64)))
    647}
    648}