pub type ColumnId = u32;
#[derive(Debug, Clone, PartialEq)]
pub enum Sizing {
FixedClusters {
n_clusters: u32,
},
FixedSize {
cluster_size: u32,
},
}
impl Sizing {
pub fn atom(&self) -> usize {
match self {
Sizing::FixedClusters { n_clusters } => (*n_clusters).max(1) as usize,
Sizing::FixedSize { cluster_size } => (*cluster_size).max(1) as usize,
}
}
pub fn n_clusters_at(&self, n: usize) -> usize {
match self {
Sizing::FixedClusters { n_clusters } => (*n_clusters).max(1) as usize,
Sizing::FixedSize { cluster_size } => n / (*cluster_size).max(1) as usize,
}
}
pub fn cluster_of_row(&self, i: usize) -> usize {
match self {
Sizing::FixedClusters { n_clusters } => i % (*n_clusters).max(1) as usize,
Sizing::FixedSize { cluster_size } => i / (*cluster_size).max(1) as usize,
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct Grouping {
pub relation: GroupingRelation,
pub slopes: Vec<ColumnId>,
}
#[derive(Debug, Clone, PartialEq)]
pub enum GroupingRelation {
Crossed {
n_clusters: u32,
},
NestedWithin {
n_per_parent: u32,
},
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Family {
Gaussian,
Binomial {
link: BinomialLink,
},
Poisson {
link: PoissonLink,
},
Gamma {
link: GammaLink,
},
NegativeBinomial {
link: NegBinomialLink,
},
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BinomialLink {
Logit,
Probit,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PoissonLink {
Log,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum GammaLink {
Log,
Inverse,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum NegBinomialLink {
Log,
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub enum WaldSe {
#[default]
Hessian,
Rx,
}
#[derive(Debug, Clone, PartialEq)]
pub struct ReStructure {
pub sizing: Sizing,
pub slopes: Vec<ColumnId>,
pub extra_groupings: Vec<Grouping>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct ModelSpec {
pub family: Family,
pub re: Option<ReStructure>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn model_spec_constructs_and_reports_q() {
let re = ReStructure {
sizing: Sizing::FixedClusters { n_clusters: 30 },
slopes: vec![1],
extra_groupings: vec![Grouping {
relation: GroupingRelation::Crossed { n_clusters: 12 },
slopes: vec![],
}],
};
let spec = ModelSpec {
family: Family::Gaussian,
re: Some(re),
};
let re = spec.re.as_ref().unwrap();
assert_eq!(re.sizing.atom(), 30);
}
#[test]
fn m3_families_construct_and_are_copy() {
fn assert_copy<T: Copy>(_: T) {}
let f = Family::Gamma {
link: GammaLink::Log,
};
assert_copy(f); let _ = Family::Poisson {
link: PoissonLink::Log,
};
let _ = Family::NegativeBinomial {
link: NegBinomialLink::Log,
};
let _ = Family::Binomial {
link: BinomialLink::Probit,
};
}
#[test]
#[should_panic(expected = "nagq")]
fn nagq_even_rejected() {
let model = ModelSpec {
family: Family::Binomial {
link: BinomialLink::Logit,
},
re: Some(ReStructure {
sizing: Sizing::FixedClusters { n_clusters: 4 },
slopes: vec![],
extra_groupings: vec![],
}),
};
crate::fit::assert_model_shape_pub(&model, 2, 4);
}
}