poulpy/core/src/gglwe/tensor_key.rs
core/src/gglwe/tensor_key.rsRaw
1use backend::hal::{
2 api::{MatZnxAlloc, MatZnxAllocBytes},
3 layouts::{Backend, Data, DataMut, DataRef, MatZnx, Module, ReaderFrom, Scratch, VmpPMat, WriterTo},
4};
5
6use crate::{GGLWEExecLayoutFamily, GLWESwitchingKey, GLWESwitchingKeyExec, Infos};
7
8#[derive(PartialEq, Eq)]
9pub struct GLWETensorKey<D: Data> {
10 pub(crate) keys: Vec<GLWESwitchingKey<D>>,
11}
12
13impl GLWETensorKey<Vec<u8>> {
14 pub fn alloc<B: Backend>(module: &Module<B>, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> Self
15 where
16 Module<B>: MatZnxAlloc,
17 {
18 let mut keys: Vec<GLWESwitchingKey<Vec<u8>>> = Vec::new();
19 let pairs: usize = (((rank + 1) * rank) >> 1).max(1);
20 (0..pairs).for_each(|_| {
21 keys.push(GLWESwitchingKey::alloc(
22 module, basek, k, rows, digits, 1, rank,
23 ));
24 });
25 Self { keys: keys }
26 }
27
28 pub fn bytes_of<B: Backend>(module: &Module<B>, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> usize
29 where
30 Module<B>: MatZnxAllocBytes,
31 {
32 let pairs: usize = (((rank + 1) * rank) >> 1).max(1);
33 pairs * GLWESwitchingKey::<Vec<u8>>::bytes_of(module, basek, k, rows, digits, 1, rank)
34 }
35}
36
37impl<D: Data> Infos for GLWETensorKey<D> {
38 type Inner = MatZnx<D>;
39
40 fn inner(&self) -> &Self::Inner {
41 &self.keys[0].inner()
42 }
43
44 fn basek(&self) -> usize {
45 self.keys[0].basek()
46 }
47
48 fn k(&self) -> usize {
49 self.keys[0].k()
50 }
51}
52
53impl<D: Data> GLWETensorKey<D> {
54 pub fn rank(&self) -> usize {
55 self.keys[0].rank()
56 }
57
58 pub fn rank_in(&self) -> usize {
59 self.keys[0].rank_in()
60 }
61
62 pub fn rank_out(&self) -> usize {
63 self.keys[0].rank_out()
64 }
65
66 pub fn digits(&self) -> usize {
67 self.keys[0].digits()
68 }
69}
70
71impl<D: DataMut> GLWETensorKey<D> {
72 // Returns a mutable reference to GLWESwitchingKey_{s}(s[i] * s[j])
73 pub fn at_mut(&mut self, mut i: usize, mut j: usize) -> &mut GLWESwitchingKey<D> {
74 if i > j {
75 std::mem::swap(&mut i, &mut j);
76 };
77 let rank: usize = self.rank();
78 &mut self.keys[i * rank + j - (i * (i + 1) / 2)]
79 }
80}
81
82impl<D: DataRef> GLWETensorKey<D> {
83 // Returns a reference to GLWESwitchingKey_{s}(s[i] * s[j])
84 pub fn at(&self, mut i: usize, mut j: usize) -> &GLWESwitchingKey<D> {
85 if i > j {
86 std::mem::swap(&mut i, &mut j);
87 };
88 let rank: usize = self.rank();
89 &self.keys[i * rank + j - (i * (i + 1) / 2)]
90 }
91}
92
93use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
94
95impl<D: DataMut> ReaderFrom for GLWETensorKey<D> {
96 fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
97 let len: usize = reader.read_u64::<LittleEndian>()? as usize;
98 if self.keys.len() != len {
99 return Err(std::io::Error::new(
100 std::io::ErrorKind::InvalidData,
101 format!("self.keys.len()={} != read len={}", self.keys.len(), len),
102 ));
103 }
104 for key in &mut self.keys {
105 key.read_from(reader)?;
106 }
107 Ok(())
108 }
109}
110
111impl<D: DataRef> WriterTo for GLWETensorKey<D> {
112 fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
113 writer.write_u64::<LittleEndian>(self.keys.len() as u64)?;
114 for key in &self.keys {
115 key.write_to(writer)?;
116 }
117 Ok(())
118 }
119}
120
121#[derive(PartialEq, Eq)]
122pub struct GLWETensorKeyExec<D: Data, B: Backend> {
123 pub(crate) keys: Vec<GLWESwitchingKeyExec<D, B>>,
124}
125
126impl<B: Backend> GLWETensorKeyExec<Vec<u8>, B> {
127 pub fn alloc(module: &Module<B>, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> Self
128 where
129 Module<B>: GGLWEExecLayoutFamily<B>,
130 {
131 let mut keys: Vec<GLWESwitchingKeyExec<Vec<u8>, B>> = Vec::new();
132 let pairs: usize = (((rank + 1) * rank) >> 1).max(1);
133 (0..pairs).for_each(|_| {
134 keys.push(GLWESwitchingKeyExec::alloc(
135 module, basek, k, rows, digits, 1, rank,
136 ));
137 });
138 Self { keys }
139 }
140
141 pub fn bytes_of(module: &Module<B>, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> usize
142 where
143 Module<B>: GGLWEExecLayoutFamily<B>,
144 {
145 let pairs: usize = (((rank + 1) * rank) >> 1).max(1);
146 pairs * GLWESwitchingKeyExec::<Vec<u8>, B>::bytes_of(module, basek, k, rows, digits, 1, rank)
147 }
148}
149
150impl<D: Data, B: Backend> Infos for GLWETensorKeyExec<D, B> {
151 type Inner = VmpPMat<D, B>;
152
153 fn inner(&self) -> &Self::Inner {
154 &self.keys[0].inner()
155 }
156
157 fn basek(&self) -> usize {
158 self.keys[0].basek()
159 }
160
161 fn k(&self) -> usize {
162 self.keys[0].k()
163 }
164}
165
166impl<D: Data, B: Backend> GLWETensorKeyExec<D, B> {
167 pub fn rank(&self) -> usize {
168 self.keys[0].rank()
169 }
170
171 pub fn rank_in(&self) -> usize {
172 self.keys[0].rank_in()
173 }
174
175 pub fn rank_out(&self) -> usize {
176 self.keys[0].rank_out()
177 }
178
179 pub fn digits(&self) -> usize {
180 self.keys[0].digits()
181 }
182}
183
184impl<D: DataMut, B: Backend> GLWETensorKeyExec<D, B> {
185 // Returns a mutable reference to GLWESwitchingKey_{s}(s[i] * s[j])
186 pub fn at_mut(&mut self, mut i: usize, mut j: usize) -> &mut GLWESwitchingKeyExec<D, B> {
187 if i > j {
188 std::mem::swap(&mut i, &mut j);
189 };
190 let rank: usize = self.rank();
191 &mut self.keys[i * rank + j - (i * (i + 1) / 2)]
192 }
193}
194
195impl<D: DataRef, B: Backend> GLWETensorKeyExec<D, B> {
196 // Returns a reference to GLWESwitchingKey_{s}(s[i] * s[j])
197 pub fn at(&self, mut i: usize, mut j: usize) -> &GLWESwitchingKeyExec<D, B> {
198 if i > j {
199 std::mem::swap(&mut i, &mut j);
200 };
201 let rank: usize = self.rank();
202 &self.keys[i * rank + j - (i * (i + 1) / 2)]
203 }
204}
205
206impl<D: DataMut, B: Backend> GLWETensorKeyExec<D, B> {
207 pub fn prepare<DataOther>(&mut self, module: &Module<B>, other: &GLWETensorKey<DataOther>, scratch: &mut Scratch<B>)
208 where
209 DataOther: DataRef,
210 Module<B>: GGLWEExecLayoutFamily<B>,
211 {
212 #[cfg(debug_assertions)]
213 {
214 assert_eq!(self.keys.len(), other.keys.len());
215 }
216 self.keys
217 .iter_mut()
218 .zip(other.keys.iter())
219 .for_each(|(a, b)| {
220 a.prepare(module, b, scratch);
221 });
222 }
223}