use rkyv::{Archive, Deserialize, Serialize};
use std::sync::OnceLock;
#[repr(C, align(4))]
struct AlignedBytes<const N: usize>([u8; N]);
static SOBOL_DATA_ALIGNED: &AlignedBytes<{ include_bytes!("sobol_data.bin").len() }> =
&AlignedBytes(*include_bytes!("sobol_data.bin"));
#[inline]
fn sobol_data_bytes() -> &'static [u8] {
&SOBOL_DATA_ALIGNED.0
}
static SOBOL_DATA: OnceLock<&'static ArchivedSobolData> = OnceLock::new();
#[derive(Archive, Deserialize, Serialize, Debug)]
#[rkyv(crate = rkyv)]
pub struct SobolPolynomial {
pub degree: u8,
pub coeff: u32,
pub m_values: Vec<u32>,
}
#[derive(Archive, Deserialize, Serialize, Debug)]
#[rkyv(crate = rkyv)]
pub struct SobolData {
pub polynomials: Vec<SobolPolynomial>,
}
#[inline]
pub fn get_sobol_data() -> &'static ArchivedSobolData {
SOBOL_DATA.get_or_init(|| {
unsafe { rkyv::access_unchecked::<ArchivedSobolData>(sobol_data_bytes()) }
})
}
pub const MAX_SOBOL_DIMENSION: usize = 21201;
#[inline]
pub fn get_polynomial(dimension: usize) -> Option<&'static ArchivedSobolPolynomial> {
if dimension < 2 || dimension > MAX_SOBOL_DIMENSION {
return None;
}
let data = get_sobol_data();
data.polynomials.get(dimension - 2)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_load_sobol_data() {
let data = get_sobol_data();
assert_eq!(data.polynomials.len(), 21200);
}
#[test]
fn test_dimension_2() {
let poly = get_polynomial(2).unwrap();
assert_eq!(poly.degree, 1);
assert_eq!(poly.coeff, 0);
assert_eq!(poly.m_values.len(), 1);
assert_eq!(poly.m_values[0], 1);
}
#[test]
fn test_dimension_3() {
let poly = get_polynomial(3).unwrap();
assert_eq!(poly.degree, 2);
assert_eq!(poly.coeff, 1);
assert_eq!(poly.m_values.len(), 2);
assert_eq!(poly.m_values[0], 1);
assert_eq!(poly.m_values[1], 3);
}
#[test]
fn test_out_of_range() {
assert!(get_polynomial(0).is_none());
assert!(get_polynomial(1).is_none()); assert!(get_polynomial(21202).is_none());
}
}