geometric_sequence_domain.hpp
Go to the documentation of this file.
1 //---------------------------------------------------------------------------//
2 // Copyright (c) 2020-2021 Mikhail Komarov <nemo@nil.foundation>
3 // Copyright (c) 2020-2021 Nikita Kaskov <nbering@nil.foundation>
4 //
5 // MIT License
6 //
7 // Permission is hereby granted, free of charge, to any person obtaining a copy
8 // of this software and associated documentation files (the "Software"), to deal
9 // in the Software without restriction, including without limitation the rights
10 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 // copies of the Software, and to permit persons to whom the Software is
12 // furnished to do so, subject to the following conditions:
13 //
14 // The above copyright notice and this permission notice shall be included in all
15 // copies or substantial portions of the Software.
16 //
17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 // SOFTWARE.
24 //---------------------------------------------------------------------------//
25 
26 #ifndef CRYPTO3_MATH_GEOMETRIC_SEQUENCE_DOMAIN_HPP
27 #define CRYPTO3_MATH_GEOMETRIC_SEQUENCE_DOMAIN_HPP
28 
29 #include <vector>
30 
32 
34 
35 #ifdef MULTICORE
36 #include <omp.h>
37 #endif
38 
39 namespace nil {
40  namespace crypto3 {
41  namespace math {
42 
43  using namespace nil::crypto3::algebra;
44 
45  template<typename FieldType>
46  class evaluation_domain;
47 
48  template<typename FieldType>
49  class geometric_sequence_domain : public evaluation_domain<FieldType> {
50  typedef typename FieldType::value_type value_type;
51 
52  public:
53  typedef FieldType field_type;
54 
56  std::vector<value_type> geometric_sequence;
57  std::vector<value_type> geometric_triangular_sequence;
58 
60  geometric_sequence = std::vector<value_type>(this->m, value_type::zero());
61  geometric_sequence[0] = value_type::one();
62 
63  geometric_triangular_sequence = std::vector<value_type>(this->m, value_type::zero());
64  geometric_triangular_sequence[0] = value_type::one();
65 
66  for (std::size_t i = 1; i < this->m; i++) {
67  geometric_sequence[i] =
69  geometric_triangular_sequence[i] =
70  geometric_triangular_sequence[i - 1] * geometric_sequence[i - 1];
71  }
72 
73  precomputation_sentinel = true;
74  }
75 
76  geometric_sequence_domain(const std::size_t m) : evaluation_domain<FieldType>(m) {
77  if (m <= 1) {
78  throw std::invalid_argument("geometric(): expected m > 1");
79  }
80 
82  throw std::invalid_argument(
83  "geometric(): expected "
84  "value_type(fields::arithmetic_params<FieldType>::geometric_generator).is_zero() != "
85  "true");
86  }
87 
88  precomputation_sentinel = false;
89  }
90 
91  void fft(std::vector<value_type> &a) {
92  if (a.size() != this->m) {
93  if (a.size() < this->m) {
94  a.resize(this->m, value_type(0));
95  } else {
96  throw std::invalid_argument("geometric: expected a.size() == this->m");
97  }
98  }
99 
100  if (!precomputation_sentinel)
101  do_precomputation();
102 
103  monomial_to_newton_basis_geometric<FieldType>(a, geometric_sequence, geometric_triangular_sequence,
104  this->m);
105 
106  /* Newton to Evaluation */
107  std::vector<value_type> T(this->m);
108  T[0] = value_type::one();
109 
110  std::vector<value_type> g(this->m);
111  g[0] = a[0];
112 
113  for (std::size_t i = 1; i < this->m; i++) {
114  T[i] = T[i - 1] * (geometric_sequence[i] - value_type::one()).inversed();
115  g[i] = geometric_triangular_sequence[i] * a[i];
116  }
117 
118  multiplication(a, g, T);
119  a.resize(this->m);
120 
121 #ifdef MULTICORE
122 #pragma omp parallel for
123 #endif
124  for (std::size_t i = 0; i < this->m; i++) {
125  a[i] *= T[i].inversed();
126  }
127  }
128  void inverse_fft(std::vector<value_type> &a) {
129  if (a.size() != this->m) {
130  if (a.size() < this->m) {
131  a.resize(this->m, value_type(0));
132  } else {
133  throw std::invalid_argument("geometric: expected a.size() == this->m");
134  }
135  }
136 
137  if (!precomputation_sentinel)
138  do_precomputation();
139 
140  /* Interpolation to Newton */
141  std::vector<value_type> T(this->m);
142  T[0] = value_type::one();
143 
144  std::vector<value_type> W(this->m);
145  W[0] = a[0] * T[0];
146 
147  value_type prev_T = T[0];
148  for (std::size_t i = 1; i < this->m; i++) {
149  prev_T *= (geometric_sequence[i] - value_type::one()).inversed();
150 
151  W[i] = a[i] * prev_T;
152  T[i] = geometric_triangular_sequence[i] * prev_T;
153  if (i % 2 == 1)
154  T[i] = -T[i];
155  }
156 
157  multiplication(a, W, T);
158  a.resize(this->m);
159 
160 #ifdef MULTICORE
161 #pragma omp parallel for
162 #endif
163  for (std::size_t i = 0; i < this->m; i++) {
164  a[i] *= geometric_triangular_sequence[i].inversed();
165  }
166 
167  newton_to_monomial_basis_geometric<FieldType>(a, geometric_sequence, geometric_triangular_sequence,
168  this->m);
169  }
170  std::vector<value_type> evaluate_all_lagrange_polynomials(const value_type &t) {
171  /* Compute Lagrange polynomial of size m, with m+1 points (x_0, y_0), ... ,(x_m, y_m) */
172  /* Evaluate for x = t */
173  /* Return coeffs for each l_j(x) = (l / l_i[j]) * w[j] */
174 
175  /* for all i: w[i] = (1 / r) * w[i-1] * (1 - a[i]^m-i+1) / (1 - a[i]^-i) */
176 
177  if (!precomputation_sentinel) {
178  do_precomputation();
179  }
180 
185  for (std::size_t i = 0; i < this->m; ++i) {
186  if (geometric_sequence[i] == t) // i.e., t equals a[i]
187  {
188  std::vector<value_type> res(this->m, value_type::zero());
189  res[i] = value_type::one();
190  return res;
191  }
192  }
193 
198  std::vector<value_type> l(this->m);
199  l[0] = t - geometric_sequence[0];
200 
201  std::vector<value_type> g(this->m);
202  g[0] = value_type::zero();
203 
204  value_type l_vanish = l[0];
205  value_type g_vanish = value_type::one();
206  for (std::size_t i = 1; i < this->m; i++) {
207  l[i] = t - geometric_sequence[i];
208  g[i] = value_type::one() - geometric_sequence[i];
209 
210  l_vanish *= l[i];
211  g_vanish *= g[i];
212  }
213 
214  value_type r = geometric_sequence[this->m - 1].inversed();
215  value_type r_i = r;
216 
217  std::vector<value_type> g_i(this->m);
218  g_i[0] = g_vanish.inversed();
219 
220  l[0] = l_vanish * l[0].inversed() * g_i[0];
221  for (std::size_t i = 1; i < this->m; i++) {
222  g_i[i] = g_i[i - 1] * g[this->m - i] * -g[i].inversed() * geometric_sequence[i];
223  l[i] = l_vanish * r_i * l[i].inversed() * g_i[i];
224  r_i *= r;
225  }
226 
227  return l;
228  }
229  value_type get_domain_element(const std::size_t idx) {
230  if (!precomputation_sentinel)
231  do_precomputation();
232 
233  return this->geometric_sequence[idx];
234  }
235  value_type compute_vanishing_polynomial(const value_type &t) {
236  if (!precomputation_sentinel)
237  do_precomputation();
238 
239  /* Notes: Z = prod_{i = 0 to m} (t - a[i]) */
240  /* Better approach: Montgomery Trick + Divide&Conquer/FFT */
241  value_type Z = value_type::one();
242  for (std::size_t i = 0; i < this->m; i++) {
243  Z *= (t - geometric_sequence[i]);
244  }
245  return Z;
246  }
247  void add_poly_z(const value_type &coeff, std::vector<value_type> &H) {
248  if (H.size() != this->m + 1)
249  throw std::invalid_argument("geometric: expected H.size() == this->m+1");
250 
251  if (!precomputation_sentinel)
252  do_precomputation();
253 
254  std::vector<value_type> x(2, value_type::zero());
255  x[0] = -geometric_sequence[0];
256  x[1] = value_type::one();
257 
258  std::vector<value_type> t(2, value_type::zero());
259 
260  for (std::size_t i = 1; i < this->m + 1; i++) {
261  t[0] = -geometric_sequence[i];
262  t[1] = value_type::one();
263 
264  multiplication(x, x, t);
265  }
266 
267 #ifdef MULTICORE
268 #pragma omp parallel for
269 #endif
270  for (std::size_t i = 0; i < this->m + 1; i++) {
271  H[i] += (x[i] * coeff);
272  }
273  }
274  void divide_by_z_on_coset(std::vector<value_type> &P) {
275  const value_type coset = value_type(
277  sequence? */
278  const value_type Z_inverse_at_coset = compute_vanishing_polynomial(coset).inversed();
279  for (std::size_t i = 0; i < this->m; ++i) {
280  P[i] *= Z_inverse_at_coset;
281  }
282  }
283  };
284  } // namespace math
285  } // namespace crypto3
286 } // namespace nil
287 
288 #endif // ALGEBRA_FFT_GEOMETRIC_SEQUENCE_DOMAIN_HPP
Definition: evaluation_domain.hpp:41
Definition: geometric_sequence_domain.hpp:49
std::vector< value_type > geometric_triangular_sequence
Definition: geometric_sequence_domain.hpp:57
value_type get_domain_element(const std::size_t idx)
Definition: geometric_sequence_domain.hpp:229
bool precomputation_sentinel
Definition: geometric_sequence_domain.hpp:55
geometric_sequence_domain(const std::size_t m)
Definition: geometric_sequence_domain.hpp:76
void add_poly_z(const value_type &coeff, std::vector< value_type > &H)
Definition: geometric_sequence_domain.hpp:247
void divide_by_z_on_coset(std::vector< value_type > &P)
Definition: geometric_sequence_domain.hpp:274
FieldType field_type
Definition: geometric_sequence_domain.hpp:53
void fft(std::vector< value_type > &a)
Definition: geometric_sequence_domain.hpp:91
void do_precomputation()
Definition: geometric_sequence_domain.hpp:59
std::vector< value_type > evaluate_all_lagrange_polynomials(const value_type &t)
Definition: geometric_sequence_domain.hpp:170
std::vector< value_type > geometric_sequence
Definition: geometric_sequence_domain.hpp:56
value_type compute_vanishing_polynomial(const value_type &t)
Definition: geometric_sequence_domain.hpp:235
void inverse_fft(std::vector< value_type > &a)
Definition: geometric_sequence_domain.hpp:128
Definition: pair.hpp:33
void multiplication(Range &c, const Range &a, const Range &b)
Definition: basic_operations.hpp:192
bool is_zero(const Range &a)
Definition: basic_operations.hpp:43
Definition: pair.hpp:31
Definition: fields/params.hpp:58