poulpy/poulpy-hal/src/layouts/mat_znx.rs
poulpy-hal/src/layouts/mat_znx.rsRaw
1use crate::{
2 alloc_aligned,
3 layouts::{
4 Data, DataMut, DataRef, DataView, DataViewMut, DigestU64, FillUniform, ReaderFrom, ToOwnedDeep, VecZnx, WriterTo,
5 ZnxInfos, ZnxSliceSize, ZnxView, ZnxViewMut, ZnxZero,
6 },
7 source::Source,
8};
9use std::{
10 fmt,
11 hash::{DefaultHasher, Hasher},
12};
13
14use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
15use rand::RngCore;
16
17#[repr(C)]
18#[derive(PartialEq, Eq, Clone, Hash)]
19pub struct MatZnx<D: Data> {
20 data: D,
21 n: usize,
22 size: usize,
23 rows: usize,
24 cols_in: usize,
25 cols_out: usize,
26}
27
28impl<D: DataRef> DigestU64 for MatZnx<D> {
29 fn digest_u64(&self) -> u64 {
30 let mut h: DefaultHasher = DefaultHasher::new();
31 h.write(self.data.as_ref());
32 h.write_usize(self.n);
33 h.write_usize(self.size);
34 h.write_usize(self.rows);
35 h.write_usize(self.cols_in);
36 h.write_usize(self.cols_out);
37 h.finish()
38 }
39}
40
41impl<D: DataRef> ToOwnedDeep for MatZnx<D> {
42 type Owned = MatZnx<Vec<u8>>;
43 fn to_owned_deep(&self) -> Self::Owned {
44 MatZnx {
45 data: self.data.as_ref().to_vec(),
46 n: self.n,
47 size: self.size,
48 rows: self.rows,
49 cols_in: self.cols_in,
50 cols_out: self.cols_out,
51 }
52 }
53}
54
55impl<D: DataRef> fmt::Debug for MatZnx<D> {
56 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
57 write!(f, "{self}")
58 }
59}
60
61impl<D: Data> ZnxInfos for MatZnx<D> {
62 fn cols(&self) -> usize {
63 self.cols_in
64 }
65
66 fn rows(&self) -> usize {
67 self.rows
68 }
69
70 fn n(&self) -> usize {
71 self.n
72 }
73
74 fn size(&self) -> usize {
75 self.size
76 }
77
78 fn poly_count(&self) -> usize {
79 self.rows() * self.cols_in() * self.cols_out() * self.size()
80 }
81}
82
83impl<D: Data> ZnxSliceSize for MatZnx<D> {
84 fn sl(&self) -> usize {
85 self.n() * self.cols_out()
86 }
87}
88
89impl<D: Data> DataView for MatZnx<D> {
90 type D = D;
91 fn data(&self) -> &Self::D {
92 &self.data
93 }
94}
95
96impl<D: Data> DataViewMut for MatZnx<D> {
97 fn data_mut(&mut self) -> &mut Self::D {
98 &mut self.data
99 }
100}
101
102impl<D: DataRef> ZnxView for MatZnx<D> {
103 type Scalar = i64;
104}
105
106impl<D: Data> MatZnx<D> {
107 pub fn cols_in(&self) -> usize {
108 self.cols_in
109 }
110
111 pub fn cols_out(&self) -> usize {
112 self.cols_out
113 }
114}
115
116impl MatZnx<Vec<u8>> {
117 pub fn bytes_of(n: usize, rows: usize, cols_in: usize, cols_out: usize, size: usize) -> usize {
118 rows * cols_in * VecZnx::<Vec<u8>>::bytes_of(n, cols_out, size)
119 }
120
121 pub fn alloc(n: usize, rows: usize, cols_in: usize, cols_out: usize, size: usize) -> Self {
122 let data: Vec<u8> = alloc_aligned(Self::bytes_of(n, rows, cols_in, cols_out, size));
123 Self {
124 data,
125 n,
126 size,
127 rows,
128 cols_in,
129 cols_out,
130 }
131 }
132
133 pub fn from_bytes(n: usize, rows: usize, cols_in: usize, cols_out: usize, size: usize, bytes: impl Into<Vec<u8>>) -> Self {
134 let data: Vec<u8> = bytes.into();
135 assert!(data.len() == Self::bytes_of(n, rows, cols_in, cols_out, size));
136 Self {
137 data,
138 n,
139 size,
140 rows,
141 cols_in,
142 cols_out,
143 }
144 }
145}
146
147impl<D: DataRef> MatZnx<D> {
148 pub fn at(&self, row: usize, col: usize) -> VecZnx<&[u8]> {
149 #[cfg(debug_assertions)]
150 {
151 assert!(row < self.rows(), "rows: {} >= {}", row, self.rows());
152 assert!(col < self.cols_in(), "cols: {} >= {}", col, self.cols_in());
153 }
154
155 let self_ref: MatZnx<&[u8]> = self.to_ref();
156 let nb_bytes: usize = VecZnx::<Vec<u8>>::bytes_of(self.n, self.cols_out, self.size);
157 let start: usize = nb_bytes * self.cols() * row + col * nb_bytes;
158 let end: usize = start + nb_bytes;
159
160 VecZnx {
161 data: &self_ref.data[start..end],
162 n: self.n,
163 cols: self.cols_out,
164 size: self.size,
165 max_size: self.size,
166 }
167 }
168}
169
170impl<D: DataMut> MatZnx<D> {
171 pub fn at_mut(&mut self, row: usize, col: usize) -> VecZnx<&mut [u8]> {
172 #[cfg(debug_assertions)]
173 {
174 assert!(row < self.rows(), "rows: {} >= {}", row, self.rows());
175 assert!(col < self.cols_in(), "cols: {} >= {}", col, self.cols_in());
176 }
177
178 let n: usize = self.n();
179 let cols_out: usize = self.cols_out();
180 let cols_in: usize = self.cols_in();
181 let size: usize = self.size();
182
183 let self_ref: MatZnx<&mut [u8]> = self.to_mut();
184 let nb_bytes: usize = VecZnx::<Vec<u8>>::bytes_of(n, cols_out, size);
185 let start: usize = nb_bytes * cols_in * row + col * nb_bytes;
186 let end: usize = start + nb_bytes;
187
188 VecZnx {
189 data: &mut self_ref.data[start..end],
190 n,
191 cols: cols_out,
192 size,
193 max_size: size,
194 }
195 }
196}
197
198impl<D: DataMut> FillUniform for MatZnx<D> {
199 fn fill_uniform(&mut self, log_bound: usize, source: &mut Source) {
200 match log_bound {
201 64 => source.fill_bytes(self.data.as_mut()),
202 0 => panic!("invalid log_bound, cannot be zero"),
203 _ => {
204 let mask: u64 = (1u64 << log_bound) - 1;
205 for x in self.raw_mut().iter_mut() {
206 let r = source.next_u64() & mask;
207 *x = ((r << (64 - log_bound)) as i64) >> (64 - log_bound);
208 }
209 }
210 }
211 }
212}
213
214pub type MatZnxOwned = MatZnx<Vec<u8>>;
215pub type MatZnxMut<'a> = MatZnx<&'a mut [u8]>;
216pub type MatZnxRef<'a> = MatZnx<&'a [u8]>;
217
218pub trait MatZnxToRef {
219 fn to_ref(&self) -> MatZnx<&[u8]>;
220}
221
222impl<D: DataRef> MatZnxToRef for MatZnx<D> {
223 fn to_ref(&self) -> MatZnx<&[u8]> {
224 MatZnx {
225 data: self.data.as_ref(),
226 n: self.n,
227 rows: self.rows,
228 cols_in: self.cols_in,
229 cols_out: self.cols_out,
230 size: self.size,
231 }
232 }
233}
234
235pub trait MatZnxToMut {
236 fn to_mut(&mut self) -> MatZnx<&mut [u8]>;
237}
238
239impl<D: DataMut> MatZnxToMut for MatZnx<D> {
240 fn to_mut(&mut self) -> MatZnx<&mut [u8]> {
241 MatZnx {
242 data: self.data.as_mut(),
243 n: self.n,
244 rows: self.rows,
245 cols_in: self.cols_in,
246 cols_out: self.cols_out,
247 size: self.size,
248 }
249 }
250}
251
252impl<D: Data> MatZnx<D> {
253 pub fn from_data(data: D, n: usize, rows: usize, cols_in: usize, cols_out: usize, size: usize) -> Self {
254 Self {
255 data,
256 n,
257 rows,
258 cols_in,
259 cols_out,
260 size,
261 }
262 }
263}
264
265impl<D: DataMut> ReaderFrom for MatZnx<D> {
266 fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
267 self.n = reader.read_u64::<LittleEndian>()? as usize;
268 self.size = reader.read_u64::<LittleEndian>()? as usize;
269 self.rows = reader.read_u64::<LittleEndian>()? as usize;
270 self.cols_in = reader.read_u64::<LittleEndian>()? as usize;
271 self.cols_out = reader.read_u64::<LittleEndian>()? as usize;
272 let len: usize = reader.read_u64::<LittleEndian>()? as usize;
273 let buf: &mut [u8] = self.data.as_mut();
274 if buf.len() != len {
275 return Err(std::io::Error::new(
276 std::io::ErrorKind::UnexpectedEof,
277 format!("self.data.len()={} != read len={}", buf.len(), len),
278 ));
279 }
280 reader.read_exact(&mut buf[..len])?;
281 Ok(())
282 }
283}
284
285impl<D: DataRef> WriterTo for MatZnx<D> {
286 fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
287 writer.write_u64::<LittleEndian>(self.n as u64)?;
288 writer.write_u64::<LittleEndian>(self.size as u64)?;
289 writer.write_u64::<LittleEndian>(self.rows as u64)?;
290 writer.write_u64::<LittleEndian>(self.cols_in as u64)?;
291 writer.write_u64::<LittleEndian>(self.cols_out as u64)?;
292 let buf: &[u8] = self.data.as_ref();
293 writer.write_u64::<LittleEndian>(buf.len() as u64)?;
294 writer.write_all(buf)?;
295 Ok(())
296 }
297}
298
299impl<D: DataRef> fmt::Display for MatZnx<D> {
300 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
301 writeln!(
302 f,
303 "MatZnx(n={}, rows={}, cols_in={}, cols_out={}, size={})",
304 self.n, self.rows, self.cols_in, self.cols_out, self.size
305 )?;
306
307 for row_i in 0..self.rows {
308 writeln!(f, "Row {row_i}:")?;
309 for col_i in 0..self.cols_in {
310 writeln!(f, "cols_in {col_i}:")?;
311 writeln!(f, "{}:", self.at(row_i, col_i))?;
312 }
313 }
314 Ok(())
315 }
316}
317
318impl<D: DataMut> ZnxZero for MatZnx<D> {
319 fn zero(&mut self) {
320 self.raw_mut().fill(0)
321 }
322
323 fn zero_at(&mut self, i: usize, j: usize) {
324 self.at_mut(i, j).zero();
325 }
326}