2 *****************************************************************************
4 Implementation of interfaces for:
5 - a variable (i.e., x_i),
6 - a linear term (i.e., a_i * x_i), and
7 - a linear combination (i.e., sum_i a_i * x_i).
11 *****************************************************************************
12 * @author This file is part of libsnark, developed by SCIPR Lab
13 * and contributors (see AUTHORS).
14 * @copyright MIT license (see LICENSE file)
15 *****************************************************************************/
22 #include <libff/algebra/fields/bigint.hpp>
27 template<typename FieldT>
28 linear_term<FieldT> variable<FieldT>::operator*(
29 const integer_coeff_t int_coeff) const
31 return linear_term<FieldT>(*this, int_coeff);
34 template<typename FieldT>
35 linear_term<FieldT> variable<FieldT>::operator*(const FieldT &field_coeff) const
37 return linear_term<FieldT>(*this, field_coeff);
40 template<typename FieldT>
41 linear_combination<FieldT> variable<FieldT>::operator+(
42 const linear_combination<FieldT> &other) const
44 linear_combination<FieldT> result;
46 result.add_term(*this);
48 result.terms.begin(), other.terms.begin(), other.terms.end());
53 template<typename FieldT>
54 linear_combination<FieldT> variable<FieldT>::operator-(
55 const linear_combination<FieldT> &other) const
57 return (*this) + (-other);
60 template<typename FieldT>
61 linear_term<FieldT> variable<FieldT>::operator-() const
63 return linear_term<FieldT>(*this, -FieldT::one());
66 template<typename FieldT>
67 bool variable<FieldT>::operator==(const variable<FieldT> &other) const
69 return (this->index == other.index);
72 template<typename FieldT>
73 linear_term<FieldT> operator*(
74 const integer_coeff_t int_coeff, const variable<FieldT> &var)
76 return linear_term<FieldT>(var, int_coeff);
79 template<typename FieldT>
80 linear_term<FieldT> operator*(
81 const FieldT &field_coeff, const variable<FieldT> &var)
83 return linear_term<FieldT>(var, field_coeff);
86 template<typename FieldT>
87 linear_combination<FieldT> operator+(
88 const integer_coeff_t int_coeff, const variable<FieldT> &var)
90 return linear_combination<FieldT>(int_coeff) + var;
93 template<typename FieldT>
94 linear_combination<FieldT> operator+(
95 const FieldT &field_coeff, const variable<FieldT> &var)
97 return linear_combination<FieldT>(field_coeff) + var;
100 template<typename FieldT>
101 linear_combination<FieldT> operator-(
102 const integer_coeff_t int_coeff, const variable<FieldT> &var)
104 return linear_combination<FieldT>(int_coeff) - var;
107 template<typename FieldT>
108 linear_combination<FieldT> operator-(
109 const FieldT &field_coeff, const variable<FieldT> &var)
111 return linear_combination<FieldT>(field_coeff) - var;
114 template<typename FieldT>
115 linear_term<FieldT>::linear_term(const variable<FieldT> &var)
116 : index(var.index), coeff(FieldT::one())
120 template<typename FieldT>
121 linear_term<FieldT>::linear_term(
122 const variable<FieldT> &var, const integer_coeff_t int_coeff)
123 : index(var.index), coeff(FieldT(int_coeff))
127 template<typename FieldT>
128 linear_term<FieldT>::linear_term(
129 const variable<FieldT> &var, const FieldT &coeff)
130 : index(var.index), coeff(coeff)
134 template<typename FieldT>
135 linear_term<FieldT> linear_term<FieldT>::operator*(
136 const integer_coeff_t int_coeff) const
138 return (this->operator*(FieldT(int_coeff)));
141 template<typename FieldT>
142 linear_term<FieldT> linear_term<FieldT>::operator*(
143 const FieldT &field_coeff) const
145 return linear_term<FieldT>(this->index, field_coeff * this->coeff);
148 template<typename FieldT>
149 linear_combination<FieldT> operator+(
150 const integer_coeff_t int_coeff, const linear_term<FieldT> <)
152 return linear_combination<FieldT>(int_coeff) + lt;
155 template<typename FieldT>
156 linear_combination<FieldT> operator+(
157 const FieldT &field_coeff, const linear_term<FieldT> <)
159 return linear_combination<FieldT>(field_coeff) + lt;
162 template<typename FieldT>
163 linear_combination<FieldT> operator-(
164 const integer_coeff_t int_coeff, const linear_term<FieldT> <)
166 return linear_combination<FieldT>(int_coeff) - lt;
169 template<typename FieldT>
170 linear_combination<FieldT> operator-(
171 const FieldT &field_coeff, const linear_term<FieldT> <)
173 return linear_combination<FieldT>(field_coeff) - lt;
176 template<typename FieldT>
177 linear_combination<FieldT> linear_term<FieldT>::operator+(
178 const linear_combination<FieldT> &other) const
180 return linear_combination<FieldT>(*this) + other;
183 template<typename FieldT>
184 linear_combination<FieldT> linear_term<FieldT>::operator-(
185 const linear_combination<FieldT> &other) const
187 return (*this) + (-other);
190 template<typename FieldT>
191 linear_term<FieldT> linear_term<FieldT>::operator-() const
193 return linear_term<FieldT>(this->index, -this->coeff);
196 template<typename FieldT>
197 bool linear_term<FieldT>::operator==(const linear_term<FieldT> &other) const
199 return (this->index == other.index && this->coeff == other.coeff);
202 template<typename FieldT>
203 linear_term<FieldT> operator*(
204 const integer_coeff_t int_coeff, const linear_term<FieldT> <)
206 return FieldT(int_coeff) * lt;
209 template<typename FieldT>
210 linear_term<FieldT> operator*(
211 const FieldT &field_coeff, const linear_term<FieldT> <)
213 return linear_term<FieldT>(lt.index, field_coeff * lt.coeff);
216 template<typename FieldT>
217 linear_combination<FieldT>::linear_combination(const integer_coeff_t int_coeff)
219 this->add_term(linear_term<FieldT>(0, int_coeff));
222 template<typename FieldT>
223 linear_combination<FieldT>::linear_combination(const FieldT &field_coeff)
225 this->add_term(linear_term<FieldT>(0, field_coeff));
228 template<typename FieldT>
229 linear_combination<FieldT>::linear_combination(const variable<FieldT> &var)
234 template<typename FieldT>
235 linear_combination<FieldT>::linear_combination(const linear_term<FieldT> <)
240 template<typename FieldT>
241 typename std::vector<linear_term<FieldT>>::const_iterator linear_combination<
242 FieldT>::begin() const
244 return terms.begin();
247 template<typename FieldT>
248 typename std::vector<linear_term<FieldT>>::const_iterator linear_combination<
254 template<typename FieldT>
255 void linear_combination<FieldT>::add_term(const variable<FieldT> &var)
257 this->terms.emplace_back(linear_term<FieldT>(var.index, FieldT::one()));
260 template<typename FieldT>
261 void linear_combination<FieldT>::add_term(
262 const variable<FieldT> &var, const integer_coeff_t int_coeff)
264 this->terms.emplace_back(linear_term<FieldT>(var.index, int_coeff));
267 template<typename FieldT>
268 void linear_combination<FieldT>::add_term(
269 const variable<FieldT> &var, const FieldT &coeff)
271 this->terms.emplace_back(linear_term<FieldT>(var.index, coeff));
274 template<typename FieldT>
275 void linear_combination<FieldT>::add_term(const linear_term<FieldT> &other)
277 this->terms.emplace_back(other);
280 template<typename FieldT>
281 linear_combination<FieldT> linear_combination<FieldT>::operator*(
282 const integer_coeff_t int_coeff) const
284 return (*this) * FieldT(int_coeff);
287 template<typename FieldT>
288 FieldT linear_combination<FieldT>::evaluate(
289 const std::vector<FieldT> &assignment) const
291 FieldT acc = FieldT::zero();
292 for (auto < : terms) {
293 acc += (lt.index == 0 ? FieldT::one() : assignment[lt.index - 1]) *
299 template<typename FieldT>
300 linear_combination<FieldT> linear_combination<FieldT>::operator*(
301 const FieldT &field_coeff) const
303 linear_combination<FieldT> result;
304 result.terms.reserve(this->terms.size());
305 for (const linear_term<FieldT> < : this->terms) {
306 result.terms.emplace_back(lt * field_coeff);
311 template<typename FieldT>
312 linear_combination<FieldT> linear_combination<FieldT>::operator+(
313 const linear_combination<FieldT> &other) const
315 linear_combination<FieldT> result;
317 auto it1 = this->terms.begin();
318 auto it2 = other.terms.begin();
320 /* invariant: it1 and it2 always point to unprocessed items in the
321 * corresponding linear combinations */
322 while (it1 != this->terms.end() && it2 != other.terms.end()) {
323 if (it1->index < it2->index) {
324 result.terms.emplace_back(*it1);
326 } else if (it1->index > it2->index) {
327 result.terms.emplace_back(*it2);
330 /* it1->index == it2->index */
331 result.terms.emplace_back(linear_term<FieldT>(
332 variable<FieldT>(it1->index), it1->coeff + it2->coeff));
338 if (it1 != this->terms.end()) {
339 result.terms.insert(result.terms.end(), it1, this->terms.end());
341 result.terms.insert(result.terms.end(), it2, other.terms.end());
347 template<typename FieldT>
348 linear_combination<FieldT> linear_combination<FieldT>::operator-(
349 const linear_combination<FieldT> &other) const
351 return (*this) + (-other);
354 template<typename FieldT>
355 linear_combination<FieldT> linear_combination<FieldT>::operator-() const
357 return (*this) * (-FieldT::one());
360 template<typename FieldT>
361 bool linear_combination<FieldT>::operator==(
362 const linear_combination<FieldT> &other) const
364 return (this->terms == other.terms);
367 template<typename FieldT>
368 bool linear_combination<FieldT>::is_valid(const size_t num_variables) const
370 /* check that all terms in linear combination are sorted */
371 for (size_t i = 1; i < terms.size(); ++i) {
372 if (terms[i - 1].index >= terms[i].index) {
377 /* check that the variables are in proper range. as the variables
378 are sorted, it suffices to check the last term */
379 if ((--terms.end())->index >= num_variables) {
386 template<typename FieldT>
387 void linear_combination<FieldT>::print(
388 const std::map<size_t, std::string> &variable_annotations) const
390 for (auto < : terms) {
395 auto it = variable_annotations.find(lt.index);
399 (it == variable_annotations.end() ? "no annotation"
400 : it->second.c_str()));
406 template<typename FieldT>
407 void linear_combination<FieldT>::print_with_assignment(
408 const std::vector<FieldT> &full_assignment,
409 const std::map<size_t, std::string> &variable_annotations) const
411 for (auto < : terms) {
416 printf(" x_%zu * ", lt.index);
419 auto it = variable_annotations.find(lt.index);
421 " where x_%zu (%s) was assigned value ",
423 (it == variable_annotations.end() ? "no annotation"
424 : it->second.c_str()));
425 full_assignment[lt.index - 1].print();
426 printf(" i.e. negative of ");
427 (-full_assignment[lt.index - 1]).print();
432 template<typename FieldT>
433 std::ostream &operator<<(
434 std::ostream &out, const linear_combination<FieldT> &lc)
436 out << lc.terms.size() << "\n";
437 for (const linear_term<FieldT> < : lc.terms) {
438 out << lt.index << "\n";
439 out << lt.coeff << OUTPUT_NEWLINE;
445 template<typename FieldT>
446 std::istream &operator>>(std::istream &in, linear_combination<FieldT> &lc)
453 libff::consume_newline(in);
457 for (size_t i = 0; i < s; ++i) {
458 linear_term<FieldT> lt;
460 libff::consume_newline(in);
462 libff::consume_OUTPUT_NEWLINE(in);
463 lc.terms.emplace_back(lt);
469 template<typename FieldT>
470 linear_combination<FieldT> operator*(
471 const integer_coeff_t int_coeff, const linear_combination<FieldT> &lc)
473 return lc * int_coeff;
476 template<typename FieldT>
477 linear_combination<FieldT> operator*(
478 const FieldT &field_coeff, const linear_combination<FieldT> &lc)
480 return lc * field_coeff;
483 template<typename FieldT>
484 linear_combination<FieldT> operator+(
485 const integer_coeff_t int_coeff, const linear_combination<FieldT> &lc)
487 return linear_combination<FieldT>(int_coeff) + lc;
490 template<typename FieldT>
491 linear_combination<FieldT> operator+(
492 const FieldT &field_coeff, const linear_combination<FieldT> &lc)
494 return linear_combination<FieldT>(field_coeff) + lc;
497 template<typename FieldT>
498 linear_combination<FieldT> operator-(
499 const integer_coeff_t int_coeff, const linear_combination<FieldT> &lc)
501 return linear_combination<FieldT>(int_coeff) - lc;
504 template<typename FieldT>
505 linear_combination<FieldT> operator-(
506 const FieldT &field_coeff, const linear_combination<FieldT> &lc)
508 return linear_combination<FieldT>(field_coeff) - lc;
511 template<typename FieldT>
512 linear_combination<FieldT>::linear_combination(
513 const std::vector<linear_term<FieldT>> &all_terms)
515 if (all_terms.empty()) {
523 [](linear_term<FieldT> a, linear_term<FieldT> b) {
524 return a.index < b.index;
527 auto result_it = terms.begin();
528 for (auto it = ++terms.begin(); it != terms.end(); ++it) {
529 if (it->index == result_it->index) {
530 result_it->coeff += it->coeff;
532 *(++result_it) = *it;
535 terms.resize((result_it - terms.begin()) + 1);
538 } // namespace libsnark
540 #endif // VARIABLE_TCC