poulpy/core/src/layouts/prepared/gglwe_tsk.rs
core/src/layouts/prepared/gglwe_tsk.rsRaw
1use backend::hal::{
2 api::{VmpPMatAlloc, VmpPMatAllocBytes, VmpPMatPrepare},
3 layouts::{Backend, Data, DataMut, DataRef, Module, Scratch, VmpPMat},
4};
5
6use crate::layouts::{GGLWETensorKey, Infos, prepared::GGLWESwitchingKeyExec};
7
8#[derive(PartialEq, Eq)]
9pub struct GGLWETensorKeyExec<D: Data, B: Backend> {
10 pub(crate) keys: Vec<GGLWESwitchingKeyExec<D, B>>,
11}
12
13impl<B: Backend> GGLWETensorKeyExec<Vec<u8>, B> {
14 pub fn alloc(module: &Module<B>, n: usize, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> Self
15 where
16 Module<B>: VmpPMatAlloc<B>,
17 {
18 let mut keys: Vec<GGLWESwitchingKeyExec<Vec<u8>, B>> = Vec::new();
19 let pairs: usize = (((rank + 1) * rank) >> 1).max(1);
20 (0..pairs).for_each(|_| {
21 keys.push(GGLWESwitchingKeyExec::alloc(
22 module, n, basek, k, rows, digits, 1, rank,
23 ));
24 });
25 Self { keys }
26 }
27
28 pub fn bytes_of(module: &Module<B>, n: usize, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> usize
29 where
30 Module<B>: VmpPMatAllocBytes,
31 {
32 let pairs: usize = (((rank + 1) * rank) >> 1).max(1);
33 pairs * GGLWESwitchingKeyExec::bytes_of(module, n, basek, k, rows, digits, 1, rank)
34 }
35
36 pub fn from<D: DataRef>(
37 module: &Module<B>,
38 other: &GGLWETensorKey<D>,
39 scratch: &mut Scratch<B>,
40 ) -> GGLWETensorKeyExec<Vec<u8>, B>
41 where
42 Module<B>: VmpPMatAlloc<B> + VmpPMatPrepare<B>,
43 {
44 let mut tsk_exec: GGLWETensorKeyExec<Vec<u8>, B> = Self::alloc(
45 module,
46 other.n(),
47 other.basek(),
48 other.k(),
49 other.rows(),
50 other.digits(),
51 other.rank(),
52 );
53 tsk_exec.prepare(module, other, scratch);
54 tsk_exec
55 }
56}
57
58impl<D: Data, B: Backend> Infos for GGLWETensorKeyExec<D, B> {
59 type Inner = VmpPMat<D, B>;
60
61 fn inner(&self) -> &Self::Inner {
62 &self.keys[0].inner()
63 }
64
65 fn basek(&self) -> usize {
66 self.keys[0].basek()
67 }
68
69 fn k(&self) -> usize {
70 self.keys[0].k()
71 }
72}
73
74impl<D: Data, B: Backend> GGLWETensorKeyExec<D, B> {
75 pub fn rank(&self) -> usize {
76 self.keys[0].rank()
77 }
78
79 pub fn rank_in(&self) -> usize {
80 self.keys[0].rank_in()
81 }
82
83 pub fn rank_out(&self) -> usize {
84 self.keys[0].rank_out()
85 }
86
87 pub fn digits(&self) -> usize {
88 self.keys[0].digits()
89 }
90}
91
92impl<D: DataMut, B: Backend> GGLWETensorKeyExec<D, B> {
93 // Returns a mutable reference to GLWESwitchingKey_{s}(s[i] * s[j])
94 pub fn at_mut(&mut self, mut i: usize, mut j: usize) -> &mut GGLWESwitchingKeyExec<D, B> {
95 if i > j {
96 std::mem::swap(&mut i, &mut j);
97 };
98 let rank: usize = self.rank();
99 &mut self.keys[i * rank + j - (i * (i + 1) / 2)]
100 }
101}
102
103impl<D: DataRef, B: Backend> GGLWETensorKeyExec<D, B> {
104 // Returns a reference to GLWESwitchingKey_{s}(s[i] * s[j])
105 pub fn at(&self, mut i: usize, mut j: usize) -> &GGLWESwitchingKeyExec<D, B> {
106 if i > j {
107 std::mem::swap(&mut i, &mut j);
108 };
109 let rank: usize = self.rank();
110 &self.keys[i * rank + j - (i * (i + 1) / 2)]
111 }
112}
113
114impl<D: DataMut, B: Backend> GGLWETensorKeyExec<D, B> {
115 pub fn prepare<DataOther>(&mut self, module: &Module<B>, other: &GGLWETensorKey<DataOther>, scratch: &mut Scratch<B>)
116 where
117 DataOther: DataRef,
118 Module<B>: VmpPMatPrepare<B>,
119 {
120 #[cfg(debug_assertions)]
121 {
122 assert_eq!(self.keys.len(), other.keys.len());
123 }
124 self.keys
125 .iter_mut()
126 .zip(other.keys.iter())
127 .for_each(|(a, b)| {
128 a.prepare(module, b, scratch);
129 });
130 }
131}