variable.hpp
Go to the documentation of this file.
1 //---------------------------------------------------------------------------//
2 // Copyright (c) 2018-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 // @file Declaration of interfaces for:
26 // - a variable (i.e., x_i),
27 // - a linear term (i.e., a_i * x_i), and
28 // - a linear combination (i.e., sum_i a_i * x_i).
29 //---------------------------------------------------------------------------//
30 
31 #ifndef CRYPTO3_ZK_VARIABLE_HPP
32 #define CRYPTO3_ZK_VARIABLE_HPP
33 
34 #include <cstddef>
35 #include <algorithm>
36 #include <vector>
37 
38 namespace nil {
39  namespace crypto3 {
40  namespace zk {
41  namespace snark {
42 
46  typedef long integer_coeff_t;
47 
51  template<typename FieldType>
52  struct linear_term;
53 
57  template<typename FieldType>
58  struct linear_combination;
59 
60  /********************************* Variable **********************************/
61 
65  template<typename FieldType>
66  struct variable {
67 
68  typedef std::size_t index_type;
70 
71  variable(const index_type index = 0) : index(index) {};
72 
74  return linear_term<FieldType>(*this, int_coeff);
75  }
76 
77  linear_term<FieldType> operator*(const typename FieldType::value_type &field_coeff) const {
78  return linear_term<FieldType>(*this, field_coeff);
79  }
80 
83 
84  result.add_term(*this);
85  result.terms.insert(result.terms.begin(), other.terms.begin(), other.terms.end());
86 
87  return result;
88  }
89 
91  return (*this) + (-other);
92  }
93 
95  return linear_term<FieldType>(*this, -FieldType::value_type::one());
96  }
97 
98  bool operator==(const variable<FieldType> &other) const {
99  return (this->index == other.index);
100  }
101  };
102 
103  template<typename FieldType>
105  return linear_term<FieldType>(var, int_coeff);
106  }
107 
108  template<typename FieldType>
109  linear_term<FieldType> operator*(const typename FieldType::value_type &field_coeff,
110  const variable<FieldType> &var) {
111  return linear_term<FieldType>(var, field_coeff);
112  }
113 
114  template<typename FieldType>
116  const variable<FieldType> &var) {
117  return linear_combination<FieldType>(int_coeff) + var;
118  }
119 
120  template<typename FieldType>
121  linear_combination<FieldType> operator+(const typename FieldType::value_type &field_coeff,
122  const variable<FieldType> &var) {
123  return linear_combination<FieldType>(field_coeff) + var;
124  }
125 
126  template<typename FieldType>
128  const variable<FieldType> &var) {
129  return linear_combination<FieldType>(int_coeff) - var;
130  }
131 
132  template<typename FieldType>
133  linear_combination<FieldType> operator-(const typename FieldType::value_type &field_coeff,
134  const variable<FieldType> &var) {
135  return linear_combination<FieldType>(field_coeff) - var;
136  }
137 
138  /****************************** Linear term **********************************/
139 
143  template<typename FieldType>
144  struct linear_term {
145  typedef FieldType field_type;
146  typedef typename field_type::value_type field_value_type;
147 
150 
153  }
154 
155  linear_term(const variable<field_type> &var, const integer_coeff_t int_coeff) :
156  index(var.index), coeff(field_value_type(int_coeff)) {
157  }
158 
159  linear_term(const variable<field_type> &var, const field_value_type &field_coeff) :
160  index(var.index), coeff(field_coeff) {
161  }
162 
164  return (this->operator*(field_value_type(int_coeff)));
165  }
166 
168  return linear_term<field_type>(this->index, field_coeff * this->coeff);
169  }
170 
172  return linear_combination<field_type>(*this) + other;
173  }
174 
176  return (*this) + (-other);
177  }
178 
180  return linear_term<field_type>(this->index, -this->coeff);
181  }
182 
183  bool operator==(const linear_term<field_type> &other) const {
184  return (this->index == other.index && this->coeff == other.coeff);
185  }
186  };
187 
188  template<typename FieldType>
190  return typename FieldType::value_type(int_coeff) * lt;
191  }
192 
193  template<typename FieldType>
194  linear_term<FieldType> operator*(const typename FieldType::value_type &field_coeff,
195  const linear_term<FieldType> &lt) {
196  return linear_term<FieldType>(lt.index, field_coeff * lt.coeff);
197  }
198 
199  template<typename FieldType>
201  const linear_term<FieldType> &lt) {
202  return linear_combination<FieldType>(int_coeff) + lt;
203  }
204 
205  template<typename FieldType>
206  linear_combination<FieldType> operator+(const typename FieldType::value_type &field_coeff,
207  const linear_term<FieldType> &lt) {
208  return linear_combination<FieldType>(field_coeff) + lt;
209  }
210 
211  template<typename FieldType>
213  const linear_term<FieldType> &lt) {
214  return linear_combination<FieldType>(int_coeff) - lt;
215  }
216 
217  template<typename FieldType>
218  linear_combination<FieldType> operator-(const typename FieldType::value_type &field_coeff,
219  const linear_term<FieldType> &lt) {
220  return linear_combination<FieldType>(field_coeff) - lt;
221  }
222 
223  /***************************** Linear combination ****************************/
224 
228  template<typename FieldType>
230  typedef FieldType field_type;
231  typedef typename field_type::value_type field_value_type;
232 
233  std::vector<linear_term<FieldType>> terms;
234 
237  this->add_term(linear_term<FieldType>(0, int_coeff));
238  }
239  linear_combination(const field_value_type &field_coeff) {
240  this->add_term(linear_term<FieldType>(0, field_coeff));
241  }
243  this->add_term(var);
244  }
246  this->add_term(lt);
247  }
249  if (all_terms.empty()) {
250  return;
251  }
252 
253  terms = all_terms;
254  std::sort(terms.begin(), terms.end(),
255  [](linear_term<FieldType> a, linear_term<FieldType> b) { return a.index < b.index; });
256 
257  auto result_it = terms.begin();
258  for (auto it = ++terms.begin(); it != terms.end(); ++it) {
259  if (it->index == result_it->index) {
260  result_it->coeff += it->coeff;
261  } else {
262  *(++result_it) = *it;
263  }
264  }
265  terms.resize((result_it - terms.begin()) + 1);
266  }
267 
268  /* for supporting range-based for loops over linear_combination */
269  typename std::vector<linear_term<FieldType>>::const_iterator begin() const {
270  return terms.begin();
271  }
272 
273  typename std::vector<linear_term<FieldType>>::const_iterator end() const {
274  return terms.end();
275  }
276 
277  void add_term(const variable<FieldType> &var) {
278  this->terms.emplace_back(linear_term<FieldType>(var.index, field_value_type::one()));
279  }
280  void add_term(const variable<FieldType> &var, integer_coeff_t int_coeff) {
281  this->terms.emplace_back(linear_term<FieldType>(var.index, int_coeff));
282  }
283  void add_term(const variable<FieldType> &var, const field_value_type &field_coeff) {
284  this->terms.emplace_back(linear_term<FieldType>(var.index, field_coeff));
285  }
287  this->terms.emplace_back(lt);
288  }
289 
290  field_value_type evaluate(const std::vector<field_value_type> &assignment) const {
291  field_value_type acc = field_value_type::zero();
292  for (auto &lt : terms) {
293  acc += (lt.index == 0 ? field_value_type::one() : assignment[lt.index - 1]) * lt.coeff;
294  }
295  return acc;
296  }
297 
299  return (*this) * field_value_type(int_coeff);
300  }
301  linear_combination operator*(const field_value_type &field_coeff) const {
302  linear_combination result;
303  result.terms.reserve(this->terms.size());
304  for (const linear_term<FieldType> &lt : this->terms) {
305  result.terms.emplace_back(lt * field_coeff);
306  }
307  return result;
308  }
310  linear_combination result;
311 
312  auto it1 = this->terms.begin();
313  auto it2 = other.terms.begin();
314 
315  /* invariant: it1 and it2 always point to unprocessed items in the corresponding linear
316  * combinations
317  */
318  while (it1 != this->terms.end() && it2 != other.terms.end()) {
319  if (it1->index < it2->index) {
320  result.terms.emplace_back(*it1);
321  ++it1;
322  } else if (it1->index > it2->index) {
323  result.terms.emplace_back(*it2);
324  ++it2;
325  } else {
326  /* it1->index == it2->index */
327  result.terms.emplace_back(
328  linear_term<FieldType>(variable<FieldType>(it1->index), it1->coeff + it2->coeff));
329  ++it1;
330  ++it2;
331  }
332  }
333 
334  if (it1 != this->terms.end()) {
335  result.terms.insert(result.terms.end(), it1, this->terms.end());
336  } else {
337  result.terms.insert(result.terms.end(), it2, other.terms.end());
338  }
339 
340  return result;
341  }
343  return (*this) + (-other);
344  }
346  return (*this) * (-field_value_type::one());
347  }
348 
349  bool operator==(const linear_combination &other) const {
350 
351  std::vector<linear_term<FieldType>> thisterms = this->terms;
352  std::sort(thisterms.begin(), thisterms.end(),
353  [](linear_term<FieldType> a, linear_term<FieldType> b) { return a.index < b.index; });
354 
355  std::vector<linear_term<FieldType>> otherterms = other.terms;
356  std::sort(otherterms.begin(), otherterms.end(),
357  [](linear_term<FieldType> a, linear_term<FieldType> b) { return a.index < b.index; });
358 
359  return (thisterms == otherterms);
360  }
361 
362  bool is_valid(size_t num_variables) const {
363  /* check that all terms in linear combination are sorted */
364  for (std::size_t i = 1; i < terms.size(); ++i) {
365  if (terms[i - 1].index >= terms[i].index) {
366  return false;
367  }
368  }
369 
370  /* check that the variables are in proper range. as the variables
371  are sorted, it suffices to check the last term */
372  if ((--terms.end())->index >= num_variables) {
373  return false;
374  }
375 
376  return true;
377  }
378  };
379 
380  template<typename FieldType>
382  const linear_combination<FieldType> &lc) {
383  return lc * int_coeff;
384  }
385 
386  template<typename FieldType>
387  linear_combination<FieldType> operator*(const typename FieldType::value_type &field_coeff,
388  const linear_combination<FieldType> &lc) {
389  return lc * field_coeff;
390  }
391 
392  template<typename FieldType>
394  const linear_combination<FieldType> &lc) {
395  return linear_combination<FieldType>(int_coeff) + lc;
396  }
397 
398  template<typename FieldType>
399  linear_combination<FieldType> operator+(const typename FieldType::value_type &field_coeff,
400  const linear_combination<FieldType> &lc) {
401  return linear_combination<FieldType>(field_coeff) + lc;
402  }
403 
404  template<typename FieldType>
406  const linear_combination<FieldType> &lc) {
407  return linear_combination<FieldType>(int_coeff) - lc;
408  }
409 
410  template<typename FieldType>
411  linear_combination<FieldType> operator-(const typename FieldType::value_type &field_coeff,
412  const linear_combination<FieldType> &lc) {
413  return linear_combination<FieldType>(field_coeff) - lc;
414  }
415  } // namespace snark
416  } // namespace zk
417  } // namespace crypto3
418 } // namespace nil
419 
420 #endif // CRYPTO3_ZK_VARIABLE_HPP
vector(T, U...) -> vector< std::enable_if_t<(std::is_same_v< T, U > &&...), T >, 1+sizeof...(U)>
deduction guide for uniform initialization
long integer_coeff_t
Definition: variable.hpp:46
linear_term< FieldType > operator*(const integer_coeff_t int_coeff, const variable< FieldType > &var)
Definition: variable.hpp:104
linear_combination< FieldType > operator+(const integer_coeff_t int_coeff, const variable< FieldType > &var)
Definition: variable.hpp:115
linear_combination< FieldType > operator-(const integer_coeff_t int_coeff, const variable< FieldType > &var)
Definition: variable.hpp:127
Definition: pair.hpp:31
linear_combination()
Definition: variable.hpp:235
std::vector< linear_term< FieldType > > terms
Definition: variable.hpp:233
std::vector< linear_term< FieldType > >::const_iterator end() const
Definition: variable.hpp:273
linear_combination(const integer_coeff_t int_coeff)
Definition: variable.hpp:236
void add_term(const linear_term< FieldType > &lt)
Definition: variable.hpp:286
field_value_type evaluate(const std::vector< field_value_type > &assignment) const
Definition: variable.hpp:290
bool is_valid(size_t num_variables) const
Definition: variable.hpp:362
FieldType field_type
Definition: variable.hpp:230
linear_combination operator-(const linear_combination &other) const
Definition: variable.hpp:342
linear_combination(const linear_term< FieldType > &lt)
Definition: variable.hpp:245
void add_term(const variable< FieldType > &var, integer_coeff_t int_coeff)
Definition: variable.hpp:280
bool operator==(const linear_combination &other) const
Definition: variable.hpp:349
void add_term(const variable< FieldType > &var, const field_value_type &field_coeff)
Definition: variable.hpp:283
void add_term(const variable< FieldType > &var)
Definition: variable.hpp:277
field_type::value_type field_value_type
Definition: variable.hpp:231
linear_combination operator*(integer_coeff_t int_coeff) const
Definition: variable.hpp:298
linear_combination operator+(const linear_combination &other) const
Definition: variable.hpp:309
linear_combination(const variable< FieldType > &var)
Definition: variable.hpp:242
linear_combination operator-() const
Definition: variable.hpp:345
linear_combination(const std::vector< linear_term< FieldType >> &all_terms)
Definition: variable.hpp:248
linear_combination operator*(const field_value_type &field_coeff) const
Definition: variable.hpp:301
linear_combination(const field_value_type &field_coeff)
Definition: variable.hpp:239
std::vector< linear_term< FieldType > >::const_iterator begin() const
Definition: variable.hpp:269
Definition: variable.hpp:144
bool operator==(const linear_term< field_type > &other) const
Definition: variable.hpp:183
linear_term< field_type > operator-() const
Definition: variable.hpp:179
linear_combination< field_type > operator-(const linear_combination< field_type > &other) const
Definition: variable.hpp:175
field_value_type coeff
Definition: variable.hpp:149
linear_term(const variable< field_type > &var, const field_value_type &field_coeff)
Definition: variable.hpp:159
linear_term(const variable< field_type > &var)
Definition: variable.hpp:152
variable< FieldType >::index_type index
Definition: variable.hpp:148
linear_term(const variable< field_type > &var, const integer_coeff_t int_coeff)
Definition: variable.hpp:155
field_type::value_type field_value_type
Definition: variable.hpp:146
linear_term< field_type > operator*(const field_value_type &field_coeff) const
Definition: variable.hpp:167
FieldType field_type
Definition: variable.hpp:145
linear_term()
Definition: variable.hpp:151
linear_term< field_type > operator*(const integer_coeff_t int_coeff) const
Definition: variable.hpp:163
linear_combination< field_type > operator+(const linear_combination< field_type > &other) const
Definition: variable.hpp:171
Definition: variable.hpp:66
linear_combination< FieldType > operator+(const linear_combination< FieldType > &other) const
Definition: variable.hpp:81
index_type index
Definition: variable.hpp:69
variable(const index_type index=0)
Definition: variable.hpp:71
linear_term< FieldType > operator*(const integer_coeff_t int_coeff) const
Definition: variable.hpp:73
std::size_t index_type
Definition: variable.hpp:68
bool operator==(const variable< FieldType > &other) const
Definition: variable.hpp:98
linear_term< FieldType > operator*(const typename FieldType::value_type &field_coeff) const
Definition: variable.hpp:77
linear_combination< FieldType > operator-(const linear_combination< FieldType > &other) const
Definition: variable.hpp:90
linear_term< FieldType > operator-() const
Definition: variable.hpp:94