arnaucube
arnaucube/poulpyPublic Self-hosted repository
poulpy/base2k/src/scalar_znx.rs
base2k/src/scalar_znx.rsRaw
  1use crate::znx_base::{ZnxAlloc, ZnxBase, ZnxInfos, ZnxLayout, ZnxSliceSize};
  2use crate::{Backend, GetZnxBase, Module, VecZnx};
  3use rand::seq::SliceRandom;
  4use rand_core::RngCore;
  5use rand_distr::{Distribution, weighted::WeightedIndex};
  6use sampling::source::Source;
  7
  8pub const SCALAR_ZNX_ROWS: usize = 1;
  9pub const SCALAR_ZNX_SIZE: usize = 1;
 10
 11pub struct Scalar {
 12    pub inner: ZnxBase,
 13}
 14
 15impl GetZnxBase for Scalar {
 16    fn znx(&self) -> &ZnxBase {
 17        &self.inner
 18    }
 19
 20    fn znx_mut(&mut self) -> &mut ZnxBase {
 21        &mut self.inner
 22    }
 23}
 24
 25impl ZnxInfos for Scalar {}
 26
 27impl<B: Backend> ZnxAlloc<B> for Scalar {
 28    type Scalar = i64;
 29
 30    fn from_bytes_borrow(module: &Module<B>, _rows: usize, cols: usize, _size: usize, bytes: &mut [u8]) -> Self {
 31        Self {
 32            inner: ZnxBase::from_bytes_borrow(module.n(), SCALAR_ZNX_ROWS, cols, SCALAR_ZNX_SIZE, bytes),
 33        }
 34    }
 35
 36    fn bytes_of(module: &Module<B>, _rows: usize, cols: usize, _size: usize) -> usize {
 37        debug_assert_eq!(
 38            _rows, SCALAR_ZNX_ROWS,
 39            "rows != {} not supported for Scalar",
 40            SCALAR_ZNX_ROWS
 41        );
 42        debug_assert_eq!(
 43            _size, SCALAR_ZNX_SIZE,
 44            "rows != {} not supported for Scalar",
 45            SCALAR_ZNX_SIZE
 46        );
 47        module.n() * cols * std::mem::size_of::<self::Scalar>()
 48    }
 49}
 50
 51impl ZnxLayout for Scalar {
 52    type Scalar = i64;
 53}
 54
 55impl ZnxSliceSize for Scalar {
 56    fn sl(&self) -> usize {
 57        self.n()
 58    }
 59}
 60
 61impl Scalar {
 62    pub fn fill_ternary_prob(&mut self, col: usize, prob: f64, source: &mut Source) {
 63        let choices: [i64; 3] = [-1, 0, 1];
 64        let weights: [f64; 3] = [prob / 2.0, 1.0 - prob, prob / 2.0];
 65        let dist: WeightedIndex<f64> = WeightedIndex::new(&weights).unwrap();
 66        self.at_mut(col, 0)
 67            .iter_mut()
 68            .for_each(|x: &mut i64| *x = choices[dist.sample(source)]);
 69    }
 70
 71    pub fn fill_ternary_hw(&mut self, col: usize, hw: usize, source: &mut Source) {
 72        assert!(hw <= self.n());
 73        self.at_mut(col, 0)[..hw]
 74            .iter_mut()
 75            .for_each(|x: &mut i64| *x = (((source.next_u32() & 1) as i64) << 1) - 1);
 76        self.at_mut(col, 0).shuffle(source);
 77    }
 78
 79    pub fn alias_as_vec_znx(&self) -> VecZnx {
 80        VecZnx {
 81            inner: ZnxBase {
 82                n: self.n(),
 83                rows: 1,
 84                cols: 1,
 85                size: 1,
 86                data: Vec::new(),
 87                ptr: self.ptr() as *mut u8,
 88            },
 89        }
 90    }
 91}
 92
 93pub trait ScalarOps {
 94    fn bytes_of_scalar(&self, cols: usize) -> usize;
 95    fn new_scalar(&self, cols: usize) -> Scalar;
 96    fn new_scalar_from_bytes(&self, cols: usize, bytes: Vec<u8>) -> Scalar;
 97    fn new_scalar_from_bytes_borrow(&self, cols: usize, bytes: &mut [u8]) -> Scalar;
 98}
 99
100impl<B: Backend> ScalarOps for Module<B> {
101    fn bytes_of_scalar(&self, cols: usize) -> usize {
102        Scalar::bytes_of(self, SCALAR_ZNX_ROWS, cols, SCALAR_ZNX_SIZE)
103    }
104    fn new_scalar(&self, cols: usize) -> Scalar {
105        Scalar::new(self, SCALAR_ZNX_ROWS, cols, SCALAR_ZNX_SIZE)
106    }
107    fn new_scalar_from_bytes(&self, cols: usize, bytes: Vec<u8>) -> Scalar {
108        Scalar::from_bytes(self, SCALAR_ZNX_ROWS, cols, SCALAR_ZNX_SIZE, bytes)
109    }
110    fn new_scalar_from_bytes_borrow(&self, cols: usize, bytes: &mut [u8]) -> Scalar {
111        Scalar::from_bytes_borrow(self, SCALAR_ZNX_ROWS, cols, SCALAR_ZNX_SIZE, bytes)
112    }
113}