basis_change.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_BASIS_CHANGE_HPP
27 #define CRYPTO3_MATH_BASIS_CHANGE_HPP
28 
29 #include <algorithm>
30 #include <vector>
31 
34 
35 namespace nil {
36  namespace crypto3 {
37  namespace math {
38 
45  template<typename FieldType>
46  void compute_subproduct_tree(std::vector<std::vector<std::vector<typename FieldType::value_type>>> &T,
47  std::size_t m) {
48 
49  typedef typename FieldType::value_type value_type;
50 
51  if (T.size() != m + 1)
52  T.resize(m + 1);
53 
54  /*
55  * Subproduct tree T is represented as a 2-dimensional array T_{i, j}.
56  * T_{i, j} = product_{l = [2^i * j] to [2^i * (j+1) - 1]} (x - x_l)
57  * Note: n = 2^m.
58  */
59 
60  /* Precompute the first row. */
61  T[0] = std::vector<std::vector<value_type>>(1u << m);
62  for (std::size_t j = 0; j < (1u << m); j++) {
63  T[0][j] = std::vector<value_type>(2, value_type::one());
64  T[0][j][0] = value_type(-j);
65  }
66 
67  std::vector<value_type> a;
68  std::vector<value_type> b;
69 
70  std::size_t index = 0;
71  for (std::size_t i = 1; i <= m; i++) {
72  T[i] = std::vector<std::vector<value_type>>(1u << (m - i));
73  for (std::size_t j = 0; j < (1u << (m - i)); j++) {
74  a = T[i - 1][index];
75  index++;
76 
77  b = T[i - 1][index];
78  index++;
79 
80  multiplication(T[i][j], a, b);
81  }
82  index = 0;
83  }
84  }
85 
92  template<typename FieldType>
93  void
94  monomial_to_newton_basis(std::vector<typename FieldType::value_type> &a,
95  const std::vector<std::vector<std::vector<typename FieldType::value_type>>> &T,
96  size_t n) {
97 
98  typedef typename FieldType::value_type value_type;
99 
100  std::size_t m = log2(n);
101  // if (T.size() != m + 1u)
102  // throw DomainSizeException("expected T.size() == m + 1");
103 
104  /* MonomialToNewton */
105  std::vector<value_type> I(T[m][0]);
106  reverse(I, n);
107 
108  std::vector<value_type> mod(n + 1, value_type::zero());
109  mod[n] = value_type::one();
110 
111  extended_euclidean(mod, I, mod, mod, I);
112 
113  I.resize(n);
114 
115  std::vector<value_type> Q(transpose_multiplication(n - 1, I, a));
116  reverse(Q, n);
117 
118  /* TNewtonToMonomial */
119  std::vector<std::vector<value_type>> c(n);
120  c[0] = Q;
121 
122  std::size_t row_length;
123  std::size_t c_vec;
124  /* NB: unsigned reverse iteration: cannot do i >= 0, but can do i < m
125  because unsigned integers are guaranteed to wrap around */
126  for (std::size_t i = m - 1; i < m; i--) {
127  row_length = T[i].size() - 1;
128  c_vec = 1u << i;
129 
130  /* NB: unsigned reverse iteration */
131  for (std::size_t j = (1u << (m - i - 1)) - 1; j < (1u << (m - i - 1)); j--) {
132  c[2 * j + 1] = transpose_multiplication((1u << i) - 1, T[i][row_length - 2 * j], c[j]);
133  c[2 * j] = c[j];
134  c[2 * j].resize(c_vec);
135  }
136  }
137 
138  /* Store Computed Newton Basis Coefficients */
139  std::size_t j = 0;
140  /* NB: unsigned reverse iteration */
141  for (std::size_t i = c.size() - 1; i < c.size(); i--) {
142  a[j++] = c[i][0];
143  }
144  }
145 
152  template<typename FieldType>
153  void
154  newton_to_monomial_basis(std::vector<typename FieldType::value_type> &a,
155  const std::vector<std::vector<std::vector<typename FieldType::value_type>>> &T,
156  size_t n) {
157 
158  typedef typename FieldType::value_type value_type;
159 
160  std::size_t m = log2(n);
161  // if (T.size() != m + 1u)
162  // throw DomainSizeException("expected T.size() == m + 1");
163 
164  std::vector<std::vector<value_type>> f(n);
165  for (std::size_t i = 0; i < n; i++) {
166  f[i] = std::vector<value_type>(1, a[i]);
167  }
168 
169  /* NewtonToMonomial */
170  std::vector<value_type> temp(1, value_type::zero());
171  for (std::size_t i = 0; i < m; i++) {
172  for (std::size_t j = 0; j < (1u << (m - i - 1)); j++) {
173  multiplication(temp, T[i][2 * j], f[2 * j + 1]);
174  addition(f[j], f[2 * j], temp);
175  }
176  }
177 
178  a = f[0];
179  }
180 
186  template<typename FieldType, typename Range1, typename Range2, typename Range3>
188  const Range2 &geometric_sequence,
189  const Range3 &geometric_triangular_sequence,
190  const std::size_t &n) {
191 
192  typedef typename FieldType::value_type value_type;
193 
194  std::vector<value_type> u(n, value_type::zero());
195  std::vector<value_type> w(n, value_type::zero());
196  std::vector<value_type> z(n, value_type::zero());
197  std::vector<value_type> f(n, value_type::zero());
198  u[0] = value_type::one();
199  w[0] = a[0];
200  z[0] = value_type::one();
201  f[0] = a[0];
202 
203  for (std::size_t i = 1; i < n; i++) {
204  u[i] = u[i - 1] * geometric_sequence[i] * (value_type::one() - geometric_sequence[i]).inversed();
205  w[i] = a[i] * (u[i].inversed());
206  z[i] = u[i] * geometric_triangular_sequence[i].inversed();
207  f[i] = w[i] * geometric_triangular_sequence[i];
208 
209  if (i % 2 == 1) {
210  z[i] = -z[i];
211  f[i] = -f[i];
212  }
213  }
214 
215  w = transpose_multiplication(n - 1, z, f);
216 
217 #ifdef MULTICORE
218 #pragma omp parallel for
219 #endif
220  for (std::size_t i = 0; i < n; i++) {
221  a[i] = w[i] * z[i];
222  }
223  }
224 
230  template<typename FieldType, typename Range1, typename Range2, typename Range3>
232  const Range2 &geometric_sequence,
233  const Range3 &geometric_triangular_sequence,
234  std::size_t n) {
235 
236  typedef typename FieldType::value_type value_type;
237 
238  std::vector<value_type> v(n, value_type::zero());
239  std::vector<value_type> u(n, value_type::zero());
240  std::vector<value_type> w(n, value_type::zero());
241  std::vector<value_type> z(n, value_type::zero());
242  v[0] = a[0];
243  u[0] = value_type::one();
244  w[0] = a[0];
245  z[0] = value_type::one();
246 
247  for (std::size_t i = 1; i < n; i++) {
248  v[i] = a[i] * geometric_triangular_sequence[i];
249  if (i % 2 == 1)
250  v[i] = -v[i];
251 
252  u[i] = u[i - 1] * geometric_sequence[i] * (value_type::one() - geometric_sequence[i]).inversed();
253  w[i] = v[i] * u[i].inversed();
254 
255  z[i] = u[i] * geometric_triangular_sequence[i].inversed();
256  if (i % 2 == 1)
257  z[i] = -z[i];
258  }
259 
260  w = transpose_multiplication(n - 1, u, w);
261 
262 #ifdef MULTICORE
263 #pragma omp parallel for
264 #endif
265  for (std::size_t i = 0; i < n; i++) {
266  a[i] = w[i] * z[i];
267  }
268  }
269  } // namespace math
270  } // namespace crypto3
271 } // namespace nil
272 
273 #endif // ALGEBRA_FFT_BASIS_CHANGE_HPP
vector(T, U...) -> vector< std::enable_if_t<(std::is_same_v< T, U > &&...), T >, 1+sizeof...(U)>
deduction guide for uniform initialization
void newton_to_monomial_basis_geometric(Range1 &a, const Range2 &geometric_sequence, const Range3 &geometric_triangular_sequence, std::size_t n)
Definition: basis_change.hpp:231
void addition(Range &c, const Range &a, const Range &b)
Definition: basic_operations.hpp:78
void extended_euclidean(const Range1 &a, const Range2 &b, Range3 &g, Range4 &u, Range5 &v)
Perform the standard Extended Euclidean Division algorithm. Input: Polynomial A, Polynomial B....
Definition: xgcd.hpp:48
void multiplication(Range &c, const Range &a, const Range &b)
Definition: basic_operations.hpp:192
Range transpose_multiplication(const std::size_t &n, const Range &a, const Range &c)
Definition: basic_operations.hpp:202
void monomial_to_newton_basis(std::vector< typename FieldType::value_type > &a, const std::vector< std::vector< std::vector< typename FieldType::value_type >>> &T, size_t n)
Definition: basis_change.hpp:94
void reverse(Range &a, std::size_t n)
Definition: basic_operations.hpp:54
void monomial_to_newton_basis_geometric(Range1 &a, const Range2 &geometric_sequence, const Range3 &geometric_triangular_sequence, const std::size_t &n)
Definition: basis_change.hpp:187
void newton_to_monomial_basis(std::vector< typename FieldType::value_type > &a, const std::vector< std::vector< std::vector< typename FieldType::value_type >>> &T, size_t n)
Definition: basis_change.hpp:154
void compute_subproduct_tree(std::vector< std::vector< std::vector< typename FieldType::value_type >>> &T, std::size_t m)
Definition: basis_change.hpp:46
Definition: pair.hpp:31