use crate::error::RankAdapterError;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct DiscreteRankLimits {
pub max_bit_vector_width: usize,
pub max_subset_size: usize,
pub max_combination_n: usize,
pub max_permutation_n: usize,
pub max_simple_graph_nodes: usize,
pub max_bounded_vector_len: usize,
pub max_radix: u64,
pub max_fwht_signal_len: usize,
pub max_fwht_alphabet: u64,
}
impl DiscreteRankLimits {
pub const DEFAULT: Self = Self {
max_bit_vector_width: 127,
max_subset_size: 127,
max_combination_n: 127,
max_permutation_n: 127,
max_simple_graph_nodes: 16,
max_bounded_vector_len: 127,
max_radix: 1_000_000,
max_fwht_signal_len: 127,
max_fwht_alphabet: 1_000_000,
};
pub fn check_bit_vector_width(&self, width: usize) -> Result<(), RankAdapterError> {
self.check_usize("bit-vector width", width, self.max_bit_vector_width)
}
pub fn check_subset_size(&self, n: usize) -> Result<(), RankAdapterError> {
self.check_usize("subset size", n, self.max_subset_size)
}
pub fn check_combination(&self, n: usize, k: usize) -> Result<(), RankAdapterError> {
self.check_usize("combination n", n, self.max_combination_n)?;
if k > n {
return Err(RankAdapterError::Invalid(format!(
"combination k={k} exceeds n={n}"
)));
}
Ok(())
}
pub fn check_permutation_size(&self, n: usize) -> Result<(), RankAdapterError> {
self.check_usize("permutation size", n, self.max_permutation_n)
}
pub fn check_simple_graph_nodes(&self, n: usize) -> Result<(), RankAdapterError> {
self.check_usize("simple-graph nodes", n, self.max_simple_graph_nodes)
}
pub fn check_radices(&self, radices: &[u64]) -> Result<(), RankAdapterError> {
self.check_usize(
"bounded-int-vector length",
radices.len(),
self.max_bounded_vector_len,
)?;
for (index, radix) in radices.iter().copied().enumerate() {
self.check_radix(index, radix)?;
}
Ok(())
}
pub fn check_fwht_signal(&self, len: usize, alphabet: u64) -> Result<(), RankAdapterError> {
self.check_usize("FWHT signal length", len, self.max_fwht_signal_len)?;
self.check_bounded_u64("FWHT alphabet", alphabet, self.max_fwht_alphabet)
}
fn check_radix(&self, index: usize, radix: u64) -> Result<(), RankAdapterError> {
if radix == 0 {
return Err(RankAdapterError::Invalid(format!("radix {index} is zero")));
}
self.check_bounded_u64("radix", radix, self.max_radix)
}
fn check_usize(
&self,
name: &str,
value: usize,
maximum: usize,
) -> Result<(), RankAdapterError> {
if value > maximum {
return Err(RankAdapterError::LimitExceeded(format!(
"{name} {value} exceeds {maximum}"
)));
}
Ok(())
}
fn check_bounded_u64(
&self,
name: &str,
value: u64,
maximum: u64,
) -> Result<(), RankAdapterError> {
if value == 0 {
return Err(RankAdapterError::Invalid(format!(
"{name} must be non-zero"
)));
}
if value > maximum {
return Err(RankAdapterError::LimitExceeded(format!(
"{name} {value} exceeds {maximum}"
)));
}
Ok(())
}
}
impl Default for DiscreteRankLimits {
fn default() -> Self {
Self::DEFAULT
}
}