use crate::domain::{Padic, PadicDomain};
use crate::{Error, Result};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SampleSet<T> {
pub source: String,
pub values: Vec<T>,
}
impl<T> SampleSet<T> {
pub fn new(source: impl Into<String>, values: Vec<T>) -> Result<Self> {
if values.is_empty() {
return Err(Error::verification("sample set must not be empty"));
}
Ok(Self {
source: source.into(),
values,
})
}
pub fn len(&self) -> usize {
self.values.len()
}
pub fn is_empty(&self) -> bool {
self.values.is_empty()
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct BinarySampleSet<T> {
pub source: String,
pub pairs: Vec<(T, T)>,
}
impl<T> BinarySampleSet<T> {
pub fn new(source: impl Into<String>, pairs: Vec<(T, T)>) -> Result<Self> {
if pairs.is_empty() {
return Err(Error::verification("binary sample set must not be empty"));
}
Ok(Self {
source: source.into(),
pairs,
})
}
pub fn len(&self) -> usize {
self.pairs.len()
}
pub fn is_empty(&self) -> bool {
self.pairs.is_empty()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PadicSampleProfile {
ContractSmoke,
ValuationStratified,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PadicSampleGenerator {
profile: PadicSampleProfile,
}
impl PadicSampleGenerator {
pub fn new(profile: PadicSampleProfile) -> Self {
Self { profile }
}
pub fn contract_smoke() -> Self {
Self::new(PadicSampleProfile::ContractSmoke)
}
pub fn valuation_stratified() -> Self {
Self::new(PadicSampleProfile::ValuationStratified)
}
pub fn binary_samples(&self, domain: &PadicDomain) -> Result<BinarySampleSet<Padic>> {
match self.profile {
PadicSampleProfile::ContractSmoke => BinarySampleSet::new(
"p-adic contract smoke samples",
vec![
(domain.element(1), domain.element(2)),
(domain.element(domain.meta.prime as u128), domain.element(2)),
(
domain.element((domain.meta.prime * domain.meta.prime) as u128),
domain.element(domain.meta.prime as u128),
),
],
),
PadicSampleProfile::ValuationStratified => {
let mut pairs = Vec::new();
let max_level = domain.meta.precision.min(4);
for lhs_level in 0..max_level {
for rhs_level in 0..max_level {
let lhs = domain.element(power(domain.meta.prime, lhs_level)?);
let rhs = domain.element(2 * power(domain.meta.prime, rhs_level)?);
pairs.push((lhs, rhs));
}
}
BinarySampleSet::new("p-adic valuation-stratified samples", pairs)
}
}
}
}
fn power(base: u64, exponent: u32) -> Result<u128> {
let mut value = 1u128;
for _ in 0..exponent {
value = value
.checked_mul(base as u128)
.ok_or_else(|| Error::verification("sample value does not fit in u128"))?;
}
Ok(value)
}