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