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