pub struct Channels(pub Arc<Vec<u64>>);Expand description
A shared, immutable set of pairwise-coprime moduli (the RNS “channels”).
Cheap to clone — it is just an Arc<Vec<u64>> behind a newtype.
Tuple Fields§
§0: Arc<Vec<u64>>Implementations§
Source§impl Channels
impl Channels
Sourcepub fn new(moduli: Vec<u64>) -> Self
pub fn new(moduli: Vec<u64>) -> Self
Build channels from explicit moduli.
In debug builds this asserts the moduli are pairwise coprime (the CRT requirement); in release builds the check is skipped for speed.
Sourcepub fn standard(n: usize) -> Self
pub fn standard(n: usize) -> Self
The first n primes as channels — the standard configuration.
Examples found in repository?
examples/float_comparison.rs (line 23)
22fn main() {
23 let ch = Channels::standard(32);
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 = Channels::standard(32);
25 let has_gpu = exec.gpu().is_some();
26
27 println!("== adele-ring :: backend benchmark (32 channels) ==");
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_rns_add(&a, &b), iters);
46
47 let (gpu_str, winner) = if let Some(gpu) = exec.gpu() {
48 let gpu_us = time_backend(|| gpu.batch_rns_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 = Channels::standard(32);
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 signed_capacity(&self) -> BigInt
pub fn signed_capacity(&self) -> BigInt
Signed range bound ⌊M/2⌋: values in (-bound, bound] are representable.
Trait Implementations§
impl Eq for Channels
Auto Trait Implementations§
impl Freeze for Channels
impl RefUnwindSafe for Channels
impl Send for Channels
impl Sync for Channels
impl Unpin for Channels
impl UnsafeUnpin for Channels
impl UnwindSafe for Channels
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