1use crate::basis::Basis;
12use crate::rns::RnsInt;
13
14#[derive(Clone, Debug)]
16pub struct RnsBatch {
17 pub data: Vec<u32>,
19 pub batch_size: usize,
21 pub basis: Basis,
23}
24
25impl RnsBatch {
26 pub fn new(batch_size: usize, basis: Basis) -> Self {
28 Self::zeros(batch_size, basis)
29 }
30
31 pub fn zeros(batch_size: usize, basis: Basis) -> Self {
33 let k = basis.len();
34 RnsBatch { data: vec![0; batch_size * k], batch_size, basis }
35 }
36
37 #[inline]
39 pub fn channels_len(&self) -> usize {
40 self.basis.len()
41 }
42
43 #[inline]
45 pub fn get(&self, b: usize, c: usize) -> u32 {
46 self.data[b * self.basis.len() + c]
47 }
48
49 #[inline]
51 pub fn set(&mut self, b: usize, c: usize, val: u32) {
52 let k = self.basis.len();
53 self.data[b * k + c] = val;
54 }
55
56 pub fn from_rns_ints(items: &[RnsInt]) -> Self {
61 assert!(!items.is_empty(), "cannot build an RnsBatch from zero items");
62 let basis = items[0].basis.clone();
63 let k = basis.len();
64 let mut data = Vec::with_capacity(items.len() * k);
65 for item in items {
66 debug_assert_eq!(item.basis, basis, "all items must share the basis");
67 debug_assert_eq!(item.residues.len(), k);
68 data.extend_from_slice(&item.residues);
69 }
70 RnsBatch { data, batch_size: items.len(), basis }
71 }
72
73 pub fn to_rns_ints(&self) -> Vec<RnsInt> {
75 let k = self.basis.len();
76 (0..self.batch_size)
77 .map(|b| {
78 let residues = self.data[b * k..(b + 1) * k].to_vec();
79 RnsInt::from_residues(residues, self.basis.clone())
80 })
81 .collect()
82 }
83
84 pub fn as_u32_bytes(&self) -> Vec<u8> {
86 bytemuck::cast_slice(&self.data).to_vec()
87 }
88
89 pub fn from_u32(values: &[u32], batch_size: usize, basis: Basis) -> Self {
91 RnsBatch { data: values.to_vec(), batch_size, basis }
92 }
93}
94
95#[cfg(test)]
96mod tests {
97 use super::*;
98
99 #[test]
100 fn get_set_roundtrip() {
101 let b = Basis::standard();
102 let mut batch = RnsBatch::zeros(4, b);
103 batch.set(2, 3, 7);
104 assert_eq!(batch.get(2, 3), 7);
105 assert_eq!(batch.get(0, 0), 0);
106 }
107
108 #[test]
109 fn pack_unpack_roundtrip() {
110 let b = Basis::standard();
111 let items = vec![
112 RnsInt::from_i64(123, b.clone()),
113 RnsInt::from_i64(456, b.clone()),
114 RnsInt::from_i64(789, b.clone()),
115 ];
116 let batch = RnsBatch::from_rns_ints(&items);
117 assert_eq!(batch.batch_size, 3);
118 let back = batch.to_rns_ints();
119 for (a, bb) in items.iter().zip(back.iter()) {
120 assert_eq!(a.to_bigint(), bb.to_bigint());
121 }
122 }
123
124 #[test]
125 fn u32_byte_layout() {
126 let b = Basis::standard();
127 let mut batch = RnsBatch::zeros(1, b);
128 batch.set(0, 0, 1);
129 batch.set(0, 1, 2);
130 let bytes = batch.as_u32_bytes();
131 assert_eq!(bytes[0], 1);
132 assert_eq!(bytes[4], 2);
133 }
134}