poulpy/poulpy-core/src/layouts/prepared/gglwe_tsk.rs
poulpy-core/src/layouts/prepared/gglwe_tsk.rsRaw
1use poulpy_hal::{
2 api::{VmpPMatAlloc, VmpPMatAllocBytes, VmpPrepare},
3 layouts::{Backend, Data, DataMut, DataRef, Module, Scratch},
4};
5
6use crate::layouts::{
7 Base2K, Degree, Dnum, Dsize, GGLWEInfos, GGLWETensorKey, GLWEInfos, LWEInfos, Rank, TorusPrecision,
8 prepared::{GGLWESwitchingKeyPrepared, Prepare, PrepareAlloc, PrepareScratchSpace},
9};
10
11#[derive(PartialEq, Eq)]
12pub struct GGLWETensorKeyPrepared<D: Data, B: Backend> {
13 pub(crate) keys: Vec<GGLWESwitchingKeyPrepared<D, B>>,
14}
15
16impl<D: Data, B: Backend> LWEInfos for GGLWETensorKeyPrepared<D, B> {
17 fn n(&self) -> Degree {
18 self.keys[0].n()
19 }
20
21 fn base2k(&self) -> Base2K {
22 self.keys[0].base2k()
23 }
24
25 fn k(&self) -> TorusPrecision {
26 self.keys[0].k()
27 }
28
29 fn size(&self) -> usize {
30 self.keys[0].size()
31 }
32}
33
34impl<D: Data, B: Backend> GLWEInfos for GGLWETensorKeyPrepared<D, B> {
35 fn rank(&self) -> Rank {
36 self.rank_out()
37 }
38}
39
40impl<D: Data, B: Backend> GGLWEInfos for GGLWETensorKeyPrepared<D, B> {
41 fn rank_in(&self) -> Rank {
42 self.rank_out()
43 }
44
45 fn rank_out(&self) -> Rank {
46 self.keys[0].rank_out()
47 }
48
49 fn dsize(&self) -> Dsize {
50 self.keys[0].dsize()
51 }
52
53 fn dnum(&self) -> Dnum {
54 self.keys[0].dnum()
55 }
56}
57
58impl<B: Backend> GGLWETensorKeyPrepared<Vec<u8>, B> {
59 pub fn alloc<A>(module: &Module<B>, infos: &A) -> Self
60 where
61 A: GGLWEInfos,
62 Module<B>: VmpPMatAlloc<B>,
63 {
64 assert_eq!(
65 infos.rank_in(),
66 infos.rank_out(),
67 "rank_in != rank_out is not supported for GGLWETensorKeyPrepared"
68 );
69 Self::alloc_with(
70 module,
71 infos.base2k(),
72 infos.k(),
73 infos.dnum(),
74 infos.dsize(),
75 infos.rank_out(),
76 )
77 }
78
79 pub fn alloc_with(module: &Module<B>, base2k: Base2K, k: TorusPrecision, dnum: Dnum, dsize: Dsize, rank: Rank) -> Self
80 where
81 Module<B>: VmpPMatAlloc<B>,
82 {
83 let mut keys: Vec<GGLWESwitchingKeyPrepared<Vec<u8>, B>> = Vec::new();
84 let pairs: u32 = (((rank.0 + 1) * rank.0) >> 1).max(1);
85 (0..pairs).for_each(|_| {
86 keys.push(GGLWESwitchingKeyPrepared::alloc_with(
87 module,
88 base2k,
89 k,
90 Rank(1),
91 rank,
92 dnum,
93 dsize,
94 ));
95 });
96 Self { keys }
97 }
98
99 pub fn alloc_bytes<A>(module: &Module<B>, infos: &A) -> usize
100 where
101 A: GGLWEInfos,
102 Module<B>: VmpPMatAllocBytes,
103 {
104 assert_eq!(
105 infos.rank_in(),
106 infos.rank_out(),
107 "rank_in != rank_out is not supported for GGLWETensorKey"
108 );
109 let rank_out: usize = infos.rank_out().into();
110 let pairs: usize = (((rank_out + 1) * rank_out) >> 1).max(1);
111 pairs
112 * GGLWESwitchingKeyPrepared::alloc_bytes_with(
113 module,
114 infos.base2k(),
115 infos.k(),
116 Rank(1),
117 infos.rank_out(),
118 infos.dnum(),
119 infos.dsize(),
120 )
121 }
122
123 pub fn alloc_bytes_with(module: &Module<B>, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> usize
124 where
125 Module<B>: VmpPMatAllocBytes,
126 {
127 let pairs: usize = (((rank.0 + 1) * rank.0) >> 1).max(1) as usize;
128 pairs * GGLWESwitchingKeyPrepared::alloc_bytes_with(module, base2k, k, Rank(1), rank, dnum, dsize)
129 }
130}
131
132impl<D: DataMut, B: Backend> GGLWETensorKeyPrepared<D, B> {
133 // Returns a mutable reference to GLWESwitchingKey_{s}(s[i] * s[j])
134 pub fn at_mut(&mut self, mut i: usize, mut j: usize) -> &mut GGLWESwitchingKeyPrepared<D, B> {
135 if i > j {
136 std::mem::swap(&mut i, &mut j);
137 };
138 let rank: usize = self.rank_out().into();
139 &mut self.keys[i * rank + j - (i * (i + 1) / 2)]
140 }
141}
142
143impl<D: DataRef, B: Backend> GGLWETensorKeyPrepared<D, B> {
144 // Returns a reference to GLWESwitchingKey_{s}(s[i] * s[j])
145 pub fn at(&self, mut i: usize, mut j: usize) -> &GGLWESwitchingKeyPrepared<D, B> {
146 if i > j {
147 std::mem::swap(&mut i, &mut j);
148 };
149 let rank: usize = self.rank_out().into();
150 &self.keys[i * rank + j - (i * (i + 1) / 2)]
151 }
152}
153
154impl<B: Backend, A: GGLWEInfos> PrepareScratchSpace<B, A> for GGLWETensorKeyPrepared<Vec<u8>, B>
155where
156 GGLWESwitchingKeyPrepared<Vec<u8>, B>: PrepareScratchSpace<B, A>,
157{
158 fn prepare_scratch_space(module: &Module<B>, infos: &A) -> usize {
159 GGLWESwitchingKeyPrepared::prepare_scratch_space(module, infos)
160 }
161}
162
163impl<D: DataMut, DR: DataRef, B: Backend> Prepare<B, GGLWETensorKey<DR>> for GGLWETensorKeyPrepared<D, B>
164where
165 Module<B>: VmpPrepare<B>,
166{
167 fn prepare(&mut self, module: &Module<B>, other: &GGLWETensorKey<DR>, scratch: &mut Scratch<B>) {
168 #[cfg(debug_assertions)]
169 {
170 assert_eq!(self.keys.len(), other.keys.len());
171 }
172 self.keys
173 .iter_mut()
174 .zip(other.keys.iter())
175 .for_each(|(a, b)| {
176 a.prepare(module, b, scratch);
177 });
178 }
179}
180
181impl<D: DataRef, B: Backend> PrepareAlloc<B, GGLWETensorKeyPrepared<Vec<u8>, B>> for GGLWETensorKey<D>
182where
183 Module<B>: VmpPMatAlloc<B> + VmpPrepare<B>,
184{
185 fn prepare_alloc(&self, module: &Module<B>, scratch: &mut Scratch<B>) -> GGLWETensorKeyPrepared<Vec<u8>, B> {
186 let mut tsk_prepared: GGLWETensorKeyPrepared<Vec<u8>, B> = GGLWETensorKeyPrepared::alloc(module, self);
187 tsk_prepared.prepare(module, self, scratch);
188 tsk_prepared
189 }
190}