poulpy/poulpy-hal/src/layouts/scalar_znx.rs
poulpy-hal/src/layouts/scalar_znx.rsRaw
1use rand::seq::SliceRandom;
2use rand_core::RngCore;
3use rand_distr::{Distribution, weighted::WeightedIndex};
4
5use crate::{
6 alloc_aligned,
7 layouts::{
8 Data, DataMut, DataRef, DataView, DataViewMut, FillUniform, ReaderFrom, Reset, ToOwnedDeep, VecZnx, WriterTo, ZnxInfos,
9 ZnxSliceSize, ZnxView, ZnxViewMut, ZnxZero,
10 },
11 source::Source,
12};
13
14#[derive(PartialEq, Eq, Debug, Clone)]
15pub struct ScalarZnx<D: Data> {
16 pub data: D,
17 pub n: usize,
18 pub cols: usize,
19}
20
21impl<D: DataRef> ToOwnedDeep for ScalarZnx<D> {
22 type Owned = ScalarZnx<Vec<u8>>;
23 fn to_owned_deep(&self) -> Self::Owned {
24 ScalarZnx {
25 data: self.data.as_ref().to_vec(),
26 n: self.n,
27 cols: self.cols,
28 }
29 }
30}
31
32impl<D: Data> ZnxInfos for ScalarZnx<D> {
33 fn cols(&self) -> usize {
34 self.cols
35 }
36
37 fn rows(&self) -> usize {
38 1
39 }
40
41 fn n(&self) -> usize {
42 self.n
43 }
44
45 fn size(&self) -> usize {
46 1
47 }
48}
49
50impl<D: Data> ZnxSliceSize for ScalarZnx<D> {
51 fn sl(&self) -> usize {
52 self.n()
53 }
54}
55
56impl<D: Data> DataView for ScalarZnx<D> {
57 type D = D;
58 fn data(&self) -> &Self::D {
59 &self.data
60 }
61}
62
63impl<D: Data> DataViewMut for ScalarZnx<D> {
64 fn data_mut(&mut self) -> &mut Self::D {
65 &mut self.data
66 }
67}
68
69impl<D: DataRef> ZnxView for ScalarZnx<D> {
70 type Scalar = i64;
71}
72
73impl<D: DataMut> ScalarZnx<D> {
74 pub fn fill_ternary_prob(&mut self, col: usize, prob: f64, source: &mut Source) {
75 let choices: [i64; 3] = [-1, 0, 1];
76 let weights: [f64; 3] = [prob / 2.0, 1.0 - prob, prob / 2.0];
77 let dist: WeightedIndex<f64> = WeightedIndex::new(weights).unwrap();
78 self.at_mut(col, 0)
79 .iter_mut()
80 .for_each(|x: &mut i64| *x = choices[dist.sample(source)]);
81 }
82
83 pub fn fill_ternary_hw(&mut self, col: usize, hw: usize, source: &mut Source) {
84 assert!(hw <= self.n());
85 self.at_mut(col, 0)[..hw]
86 .iter_mut()
87 .for_each(|x: &mut i64| *x = (((source.next_u32() & 1) as i64) << 1) - 1);
88 self.at_mut(col, 0).shuffle(source);
89 }
90
91 pub fn fill_binary_prob(&mut self, col: usize, prob: f64, source: &mut Source) {
92 let choices: [i64; 2] = [0, 1];
93 let weights: [f64; 2] = [1.0 - prob, prob];
94 let dist: WeightedIndex<f64> = WeightedIndex::new(weights).unwrap();
95 self.at_mut(col, 0)
96 .iter_mut()
97 .for_each(|x: &mut i64| *x = choices[dist.sample(source)]);
98 }
99
100 pub fn fill_binary_hw(&mut self, col: usize, hw: usize, source: &mut Source) {
101 assert!(hw <= self.n());
102 self.at_mut(col, 0)[..hw]
103 .iter_mut()
104 .for_each(|x: &mut i64| *x = (source.next_u32() & 1) as i64);
105 self.at_mut(col, 0).shuffle(source);
106 }
107
108 pub fn fill_binary_block(&mut self, col: usize, block_size: usize, source: &mut Source) {
109 assert!(self.n().is_multiple_of(block_size));
110 let max_idx: u64 = (block_size + 1) as u64;
111 let mask_idx: u64 = (1 << ((u64::BITS - max_idx.leading_zeros()) as u64)) - 1;
112 for block in self.at_mut(col, 0).chunks_mut(block_size) {
113 let idx: usize = source.next_u64n(max_idx, mask_idx) as usize;
114 if idx != block_size {
115 block[idx] = 1;
116 }
117 }
118 }
119}
120
121impl ScalarZnx<Vec<u8>> {
122 pub fn alloc_bytes(n: usize, cols: usize) -> usize {
123 n * cols * size_of::<i64>()
124 }
125
126 pub fn alloc(n: usize, cols: usize) -> Self {
127 let data: Vec<u8> = alloc_aligned::<u8>(Self::alloc_bytes(n, cols));
128 Self { data, n, cols }
129 }
130
131 pub fn from_bytes(n: usize, cols: usize, bytes: impl Into<Vec<u8>>) -> Self {
132 let data: Vec<u8> = bytes.into();
133 assert!(data.len() == Self::alloc_bytes(n, cols));
134 Self { data, n, cols }
135 }
136}
137
138impl<D: DataMut> ZnxZero for ScalarZnx<D> {
139 fn zero(&mut self) {
140 self.raw_mut().fill(0)
141 }
142 fn zero_at(&mut self, i: usize, j: usize) {
143 self.at_mut(i, j).fill(0);
144 }
145}
146
147impl<D: DataMut> FillUniform for ScalarZnx<D> {
148 fn fill_uniform(&mut self, source: &mut Source) {
149 source.fill_bytes(self.data.as_mut());
150 }
151}
152
153impl<D: DataMut> Reset for ScalarZnx<D> {
154 fn reset(&mut self) {
155 self.zero();
156 self.n = 0;
157 self.cols = 0;
158 }
159}
160
161pub type ScalarZnxOwned = ScalarZnx<Vec<u8>>;
162
163impl<D: Data> ScalarZnx<D> {
164 pub fn from_data(data: D, n: usize, cols: usize) -> Self {
165 Self { data, n, cols }
166 }
167}
168
169pub trait ScalarZnxToRef {
170 fn to_ref(&self) -> ScalarZnx<&[u8]>;
171}
172
173impl<D: DataRef> ScalarZnxToRef for ScalarZnx<D> {
174 fn to_ref(&self) -> ScalarZnx<&[u8]> {
175 ScalarZnx {
176 data: self.data.as_ref(),
177 n: self.n,
178 cols: self.cols,
179 }
180 }
181}
182
183pub trait ScalarZnxToMut {
184 fn to_mut(&mut self) -> ScalarZnx<&mut [u8]>;
185}
186
187impl<D: DataMut> ScalarZnxToMut for ScalarZnx<D> {
188 fn to_mut(&mut self) -> ScalarZnx<&mut [u8]> {
189 ScalarZnx {
190 data: self.data.as_mut(),
191 n: self.n,
192 cols: self.cols,
193 }
194 }
195}
196
197impl<D: DataRef> ScalarZnx<D> {
198 pub fn as_vec_znx(&self) -> VecZnx<&[u8]> {
199 VecZnx {
200 data: self.data.as_ref(),
201 n: self.n,
202 cols: self.cols,
203 size: 1,
204 max_size: 1,
205 }
206 }
207}
208
209impl<D: DataMut> ScalarZnx<D> {
210 pub fn as_vec_znx_mut(&mut self) -> VecZnx<&mut [u8]> {
211 VecZnx {
212 data: self.data.as_mut(),
213 n: self.n,
214 cols: self.cols,
215 size: 1,
216 max_size: 1,
217 }
218 }
219}
220
221use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
222
223impl<D: DataMut> ReaderFrom for ScalarZnx<D> {
224 fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
225 self.n = reader.read_u64::<LittleEndian>()? as usize;
226 self.cols = reader.read_u64::<LittleEndian>()? as usize;
227 let len: usize = reader.read_u64::<LittleEndian>()? as usize;
228 let buf: &mut [u8] = self.data.as_mut();
229 if buf.len() != len {
230 return Err(std::io::Error::new(
231 std::io::ErrorKind::UnexpectedEof,
232 format!("self.data.len()={} != read len={}", buf.len(), len),
233 ));
234 }
235 reader.read_exact(&mut buf[..len])?;
236 Ok(())
237 }
238}
239
240impl<D: DataRef> WriterTo for ScalarZnx<D> {
241 fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
242 writer.write_u64::<LittleEndian>(self.n as u64)?;
243 writer.write_u64::<LittleEndian>(self.cols as u64)?;
244 let buf: &[u8] = self.data.as_ref();
245 writer.write_u64::<LittleEndian>(buf.len() as u64)?;
246 writer.write_all(buf)?;
247 Ok(())
248 }
249}