pub struct Basis { /* private fields */ }Expand description
An ordered, extensible set of pairwise-coprime moduli.
Implementations§
Source§impl Basis
impl Basis
Sourcepub fn from_count(n: usize) -> Self
pub fn from_count(n: usize) -> Self
Build directly from a prime count (mainly for tests / fixed-size needs).
Sourcepub fn standard() -> Self
pub fn standard() -> Self
A general-purpose default basis (~512 bits ≈ 32 channels). Useful for open-ended Level 0/1 work and as the seed the multimodular pipeline grows.
Examples found in repository?
examples/float_comparison.rs (line 23)
22fn main() {
23 let ch = Basis::standard();
24 println!("== adele-ring :: exact vs f64 ==\n");
25 println!(
26 "{:<16} | {:<10} | {:<22} | {:<12} | ULPs",
27 "expression", "exact", "f64 result", "abs error"
28 );
29 println!("{}", "-".repeat(78));
30
31 // 0.1 + 0.2 = 3/10
32 let exact = RnsRational::from_fraction(1, 10, ch.clone())
33 .add(&RnsRational::from_fraction(1, 5, ch.clone()));
34 row("0.1 + 0.2", &exact.display(), 0.1 + 0.2, exact.to_f64());
35
36 // 1/3 * 3 = 1
37 let one = RnsRational::from_fraction(1, 3, ch.clone()).mul(&RnsRational::from_int(3, ch.clone()));
38 row("1/3 * 3", &one.display(), (1.0 / 3.0) * 3.0, one.to_f64());
39
40 // sqrt(2) * sqrt(2) = 2 (drops to Integer through the tower)
41 let s2 = TowerValue::Algebraic(AlgebraicNumber::sqrt(2, ch.clone()));
42 let two = s2.mul(&s2);
43 let naive = 2f64.sqrt() * 2f64.sqrt();
44 row("sqrt2 * sqrt2", "2", naive, two.to_f64().unwrap());
45
46 // sin(pi) = 0 (exact identity; f64 gives ~1.2e-16)
47 let sin_pi = TowerValue::Symbolic(SymbolicExpr::Pi).sin();
48 row("sin(pi)", "0", std::f64::consts::PI.sin(), sin_pi.to_f64().unwrap());
49
50 // 1/7 * 7 = 1
51 let one7 = RnsRational::from_fraction(1, 7, ch.clone()).mul(&RnsRational::from_int(7, ch));
52 row("1/7 * 7", &one7.display(), (1.0 / 7.0) * 7.0, one7.to_f64());
53
54 println!("\nEvery `exact` column is bit-for-bit correct; the f64 column drifts.");
55}More examples
examples/benchmark_backends.rs (line 24)
22fn main() {
23 let exec = executor();
24 let ch = Basis::standard();
25 let has_gpu = exec.gpu().is_some();
26
27 println!("== adele-ring :: backend benchmark ({} channels) ==", ch.len());
28 println!(
29 "GPU available: {}\n",
30 if has_gpu {
31 exec.gpu().map(|g| g.adapter_name().to_string()).unwrap_or_default()
32 } else {
33 "no (CPU-only)".to_string()
34 }
35 );
36
37 println!("{:>10} | {:>14} | {:>12} | winner", "batch_size", "cpu_rayon_us", "gpu_us");
38 println!("{}", "-".repeat(56));
39
40 for &size in &[1usize, 16, 128, 1024, 16_384, 65_536] {
41 let a = RnsBatch::from_rns_ints(&vec![RnsInt::from_i64(123, ch.clone()); size]);
42 let b = RnsBatch::from_rns_ints(&vec![RnsInt::from_i64(456, ch.clone()); size]);
43
44 let iters = if size <= 128 { 2000 } else { 100 };
45 let cpu_us = time_backend(|| exec.cpu().batch_add(&a, &b), iters);
46
47 let (gpu_str, winner) = if let Some(gpu) = exec.gpu() {
48 let gpu_us = time_backend(|| gpu.batch_add(&a, &b), iters);
49 let w = if cpu_us <= gpu_us { "CPU" } else { "GPU" };
50 (format!("{gpu_us:>12.2}"), w)
51 } else {
52 (" n/a".to_string(), "CPU")
53 };
54
55 println!("{size:>10} | {cpu_us:>14.2} | {gpu_str} | {winner}");
56 }
57
58 println!(
59 "\nNote: CPU wins for small batches (GPU upload/dispatch overhead ~100us);\n\
60 GPU pulls ahead once the batch is large enough to amortize that fixed cost."
61 );
62}examples/engineering.rs (line 8)
7fn main() {
8 let ch = Basis::standard();
9 let f = |p: i64, q: i64| RnsRational::from_fraction(p, q, ch.clone());
10
11 println!("== adele-ring :: exact engineering arithmetic ==\n");
12
13 // Stacked plate thicknesses in inches: 3/8 + 1/4 + 5/16.
14 let stack = f(3, 8).add(&f(1, 4)).add(&f(5, 16));
15 println!("3/8 + 1/4 + 5/16 in = {} in (= {:.6} in)", stack, stack.to_f64());
16
17 // Safety factor 1/1.5 = 2/3 exactly.
18 let safety = f(1, 1).div(&f(3, 2));
19 println!("1 / 1.5 = {} (= {:.6})", safety, safety.to_f64());
20
21 // Load ratio: 47 kips / 70 kips — stays exact through combination checks.
22 let load_ratio = f(47, 70);
23 let with_margin = load_ratio.add(&f(1, 10)); // add a 0.1 utilization margin
24 println!(
25 "47/70 + 1/10 = {} (= {:.6})",
26 with_margin,
27 with_margin.to_f64()
28 );
29
30 // AISC-style web area: t_w * d = (5/16) * (24/1) in^2.
31 let t_w = f(5, 16);
32 let d = f(24, 1);
33 let web_area = t_w.mul(&d);
34 println!("(5/16) * 24 = {} in^2 (= {:.6} in^2)", web_area, web_area.to_f64());
35
36 println!("\n-- base awareness --");
37 for (p, q) in [(1, 6), (1, 8), (47, 70)] {
38 let r = f(p, q);
39 println!(
40 "{p}/{q}: natural base = {}, terminates in base 10 = {}, period in base 10 = {}",
41 r.natural_base(),
42 r.exact_in_base(10),
43 r.termination_period_in_base(10)
44 );
45 }
46
47 // Demonstrate the classic float failure that adele-ring avoids.
48 let exact = f(1, 10).add(&f(1, 5)); // 0.1 + 0.2
49 let naive = 0.1_f64 + 0.2_f64;
50 println!("\n0.1 + 0.2 exact = {} (f64 gives {:.17})", exact, naive);
51 assert_eq!(exact, f(3, 10));
52}Sourcepub fn len(&self) -> usize
pub fn len(&self) -> usize
Number of channels.
Examples found in repository?
examples/benchmark_backends.rs (line 27)
22fn main() {
23 let exec = executor();
24 let ch = Basis::standard();
25 let has_gpu = exec.gpu().is_some();
26
27 println!("== adele-ring :: backend benchmark ({} channels) ==", ch.len());
28 println!(
29 "GPU available: {}\n",
30 if has_gpu {
31 exec.gpu().map(|g| g.adapter_name().to_string()).unwrap_or_default()
32 } else {
33 "no (CPU-only)".to_string()
34 }
35 );
36
37 println!("{:>10} | {:>14} | {:>12} | winner", "batch_size", "cpu_rayon_us", "gpu_us");
38 println!("{}", "-".repeat(56));
39
40 for &size in &[1usize, 16, 128, 1024, 16_384, 65_536] {
41 let a = RnsBatch::from_rns_ints(&vec![RnsInt::from_i64(123, ch.clone()); size]);
42 let b = RnsBatch::from_rns_ints(&vec![RnsInt::from_i64(456, ch.clone()); size]);
43
44 let iters = if size <= 128 { 2000 } else { 100 };
45 let cpu_us = time_backend(|| exec.cpu().batch_add(&a, &b), iters);
46
47 let (gpu_str, winner) = if let Some(gpu) = exec.gpu() {
48 let gpu_us = time_backend(|| gpu.batch_add(&a, &b), iters);
49 let w = if cpu_us <= gpu_us { "CPU" } else { "GPU" };
50 (format!("{gpu_us:>12.2}"), w)
51 } else {
52 (" n/a".to_string(), "CPU")
53 };
54
55 println!("{size:>10} | {cpu_us:>14.2} | {gpu_str} | {winner}");
56 }
57
58 println!(
59 "\nNote: CPU wins for small batches (GPU upload/dispatch overhead ~100us);\n\
60 GPU pulls ahead once the batch is large enough to amortize that fixed cost."
61 );
62}Sourcepub fn capacity_bits(&self) -> u64
pub fn capacity_bits(&self) -> u64
floor(log2(∏ primes)) — the usable bit capacity.
Sourcepub fn modulus_product(&self) -> BigUint
pub fn modulus_product(&self) -> BigUint
The product M = ∏ primes.
Sourcepub fn capacity(&self) -> BigUint
pub fn capacity(&self) -> BigUint
Alias for Basis::modulus_product — total dynamic range M.
Sourcepub fn signed_capacity(&self) -> BigInt
pub fn signed_capacity(&self) -> BigInt
Signed range bound ⌊M/2⌋: balanced values live in (-bound, bound].
Sourcepub fn extend_to_bits(&self, bits: u64) -> Basis
pub fn extend_to_bits(&self, bits: u64) -> Basis
A basis with at least bits of capacity (extends with more primes if
needed; the returned basis shares no state but is cheap to build).
Trait Implementations§
impl Eq for Basis
Auto Trait Implementations§
impl Freeze for Basis
impl RefUnwindSafe for Basis
impl Send for Basis
impl Sync for Basis
impl Unpin for Basis
impl UnsafeUnpin for Basis
impl UnwindSafe for Basis
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
Compare self to
key and return true if they are equal.Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
Converts
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
Converts
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more