1 /*
2  * Normaliz
3  * Copyright (C) 2007-2021  W. Bruns, B. Ichim, Ch. Soeger, U. v. d. Ohe
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  *
17  * As an exception, when this program is distributed through (i) the App Store
18  * by Apple Inc.; (ii) the Mac App Store by Apple Inc.; or (iii) Google Play
19  * by Google Inc., then that store may impose any digital rights management,
20  * device limits and/or redistribution restrictions that are required by its
21  * terms of service.
22  */
23 //---------------------------------------------------------------------------
24 #ifndef LIBNORMALIZ_VECTOR_OPERATIONS_H
25 #define LIBNORMALIZ_VECTOR_OPERATIONS_H
26 //---------------------------------------------------------------------------
27 
28 #include <vector>
29 #include <ostream>
30 #include <list>
31 
32 #include "libnormaliz/general.h"
33 #include "libnormaliz/integer.h"
34 // #include "libnormaliz/convert.h"
35 #include "libnormaliz/dynamic_bitset.h"
36 
37 
38 #ifdef NMZ_FLINT
39 #include "flint/flint.h"
40 #include "flint/fmpq_poly.h"
41 #endif
42 
43 namespace libnormaliz {
44 using std::vector;
45 
46 //---------------------------------------------------------------------------
47 //				Output
48 //---------------------------------------------------------------------------
49 
50 template <typename T>
51 std::ostream& operator<<(std::ostream& out, const vector<T>& vec) {
52     for (size_t i = 0; i < vec.size(); ++i) {
53         out << vec[i] << " ";
54     }
55     out << std::endl;
56     return out;
57 }
58 
59 //---------------------------------------------------------------------------
60 //          Prototypes for vector_operations.cpp
61 //---------------------------------------------------------------------------
62 
63 template <typename Integer>
64 Integer v_scalar_product(const vector<Integer>& a, const vector<Integer>& b);
65 
66 template <typename Integer>
67 Integer v_make_prime(vector<Integer>& v);
68 
69 nmz_float l1norm(vector<nmz_float>& v);
70 
71 template <typename Integer>
72 void v_scalar_division(vector<Integer>& v, const Integer scalar);
73 
74 // special version of order_by_perm (below) since special swap is needed
75 void order_by_perm_bool(vector<bool>& v, const vector<key_t>& permfix);
76 
77 template <typename Integer>
78 vector<Integer> v_select_coordinates(const vector<Integer>& v, const vector<key_t> projection_key);
79 template <typename Integer>
80 vector<Integer> v_insert_coordinates(const vector<Integer>& v, const vector<key_t> projection_key, const size_t nr_cols);
81 
82 //---------------------------------------------------------------------------
83 //         Templated functions
84 //---------------------------------------------------------------------------
85 
86 // returns the scalar product of the truncations of vectors a and b to minimum of lengths
87 // template<typename Integer>
88 template <typename Integer>
v_scalar_product_vectors_unequal_lungth(const vector<Integer> & a,const vector<Integer> & b)89 Integer v_scalar_product_vectors_unequal_lungth(const vector<Integer>& a, const vector<Integer>& b) {
90     size_t n = std::min(a.size(), b.size());
91     vector<Integer> trunc_a = a;
92     vector<Integer> trunc_b = b;
93     trunc_a.resize(n);
94     trunc_b.resize(n);
95     return v_scalar_product(trunc_a, trunc_b);
96 }
97 
98 // v = v * scalar
99 template <typename Integer>
v_scalar_multiplication(vector<Integer> & v,const Integer scalar)100 void v_scalar_multiplication(vector<Integer>& v, const Integer scalar) {
101     size_t i, size = v.size();
102     for (i = 0; i < size; i++) {
103         v[i] *= scalar;
104     }
105 }
106 
107 // make random vector of length n with entries between -m and m
108 template <typename Integer>
v_random(size_t n,long m)109 vector<Integer> v_random(size_t n, long m) {
110     vector<Integer> result(n);
111     for (size_t i = 0; i < n; ++i)
112         result[i] = rand() % (2 * m + 1) - m;
113     return result;
114 }
115 
116 template <typename Integer>
compare_last(const vector<Integer> & a,const vector<Integer> & b)117 bool compare_last(const vector<Integer>& a, const vector<Integer>& b) {
118     return a.back() < b.back();
119 }
120 
121 // swaps entry i and j of the vector<bool> v
122 void v_bool_entry_swap(vector<bool>& v, size_t i, size_t j);
123 
124 vector<key_t> identity_key(size_t n);
125 vector<key_t> reverse_key(size_t n);
126 vector<key_t> random_key(size_t n);
127 
128 template <typename T>
order_by_perm(vector<T> & v,const vector<key_t> & permfix)129 void order_by_perm(vector<T>& v, const vector<key_t>& permfix) {
130     // orders v "in place", v --> w such that
131     // w[i]=v[permfix[i]]
132     // if v is  the map i --> v[i], then the resulting map is v \circ permfix
133 
134     vector<key_t> perm = permfix;  // we may want to use permfix a second time
135     vector<key_t> inv(perm.size());
136     for (key_t i = 0; i < perm.size(); ++i)
137         inv[perm[i]] = i;
138     for (key_t i = 0; i < perm.size(); ++i) {
139         key_t j = perm[i];
140         std::swap(v[i], v[perm[i]]);
141         std::swap(perm[i], perm[inv[i]]);
142         std::swap(inv[i], inv[j]);
143     }
144 }
145 
conjugate_perm(const vector<key_t> & p,const vector<key_t> & k)146 inline vector<key_t> conjugate_perm(const vector<key_t>& p, const vector<key_t>& k) {
147     // p is a permutation of [0,n-1], i --> p[i]
148     // k is an injective map [0,m-1] --> [0,n-1]
149     // k^{-1} is the partially defined inverse
150     // computes   k^{-1} p k
151     // works only if Image(k) is stable under p.
152 
153     vector<int> inv_k(p.size(), -1);
154     for (size_t i = 0; i < k.size(); ++i) {
155         inv_k[k[i]] = i;
156     }
157     vector<key_t> conj(k.size());
158     for (size_t i = 0; i < k.size(); ++i) {
159         assert(inv_k[k[i]] != -1);
160         conj[i] = inv_k[p[k[i]]];
161     }
162     return conj;
163 }
164 
165 template <typename T>
sort_individual_vectors(vector<vector<T>> & vv)166 void sort_individual_vectors(vector<vector<T> >& vv) {
167     for (size_t i = 0; i < vv.size(); ++i)
168         sort(vv[i].begin(), vv[i].end());
169 }
170 
171 template <typename Integer>
v_scalar_mult_mod_inner(vector<Integer> & w,const vector<Integer> & v,const Integer & scalar,const Integer & modulus)172 bool v_scalar_mult_mod_inner(vector<Integer>& w, const vector<Integer>& v, const Integer& scalar, const Integer& modulus) {
173     size_t i, size = v.size();
174     Integer test;
175     for (i = 0; i < size; i++) {
176         test = v[i] * scalar;
177         if (!check_range(test)) {
178             return false;
179         }
180         w[i] = test % modulus;
181         if (w[i] < 0)
182             w[i] += modulus;
183     }
184     return true;
185 }
186 
187 template <typename Integer>
188 vector<Integer> v_scalar_mult_mod(const vector<Integer>& v, const Integer& scalar, const Integer& modulus);
189 
190 //---------------------------------------------------------------------------
191 
192 /*
193 template <typename Integer>
194 size_t v_nr_negative(const vector<Integer>& v) {
195     size_t tmp = 0;
196     for (size_t i = 0; i < v.size(); ++i) {
197         if (v[i] < 0)
198             tmp++;
199     }
200     return tmp;
201 }
202 */
203 //---------------------------------------------------------------------------
204 
205 template <typename Integer>
v_non_negative(const vector<Integer> & v)206 bool v_non_negative(const vector<Integer>& v) {
207     for (size_t i = 0; i < v.size(); ++i) {
208         if (v[i] < 0)
209             return false;
210     }
211     return true;
212 }
213 
214 //---------------------------------------------------------------------------
215 /*
216 // returns a key vector containing the positions of non-zero entrys of v
217 template <typename Integer>
218 vector<key_t> v_non_zero_pos(const vector<Integer>& v) {
219     vector<key_t> key;
220     size_t size = v.size();
221     key.reserve(size);
222     for (key_t i = 0; i < size; i++) {
223         if (v[i] != 0) {
224             key.push_back(i);
225         }
226     }
227     return key;
228 }
229 */
230 
231 //---------------------------------------------------------------------------
232 // returns the vector of absolute values, does not change the argument
233 template <typename Integer>
v_abs_value(vector<Integer> & v)234 vector<Integer> v_abs_value(vector<Integer>& v) {
235     size_t i, size = v.size();
236     vector<Integer> w = v;
237     for (i = 0; i < size; i++) {
238         if (v[i] < 0)
239             w[i] = Iabs(v[i]);
240     }
241     return w;
242 }
243 
244 //---------------------------------------------------------------------------
245 // returns gcd of the elements of v
246 template <typename Integer>
v_gcd(const vector<Integer> & v)247 inline Integer v_gcd(const vector<Integer>& v) {
248     size_t i, size = v.size();
249     Integer g = 0;
250     for (i = 0; i < size; i++) {
251         g = libnormaliz::gcd(g, v[i]);
252         if (g == 1) {
253             return 1;
254         }
255     }
256     return g;
257 }
258 
259 template <>
v_gcd(const vector<mpq_class> & v)260 inline mpq_class v_gcd(const vector<mpq_class>& v) {
261     size_t i, size = v.size();
262     mpz_class g = 0;
263     for (i = 0; i < size; i++) {
264         g = libnormaliz::gcd(g, v[i].get_num());
265         if (g == 1) {
266             return 1;
267         }
268     }
269     return mpq_class(g);
270 }
271 
272 #ifdef ENFNORMALIZ
273 
get_gcd_num(const renf_elem_class & x)274 inline mpz_class get_gcd_num(const renf_elem_class& x) {
275     vector<mpz_class> numerator = x.num_vector();
276     return v_gcd(numerator);
277 }
278 
279 template <>
v_gcd(const vector<renf_elem_class> & v)280 inline renf_elem_class v_gcd(const vector<renf_elem_class>& v) {
281     size_t i, size = v.size();
282     mpz_class g = 0;
283     mpz_class this_gcd;
284     for (i = 0; i < size; i++) {
285         // this_gcd=v[i].num_content();
286         this_gcd = get_gcd_num(v[i]);
287         g = libnormaliz::gcd(g, this_gcd);
288         if (g == 1) {
289             return 1;
290         }
291     }
292     return renf_elem_class(g);
293 }
294 #endif
295 
296 //---------------------------------------------------------------------------
297 // returns lcm of the elements of v
298 template <typename Integer>
v_lcm(const vector<Integer> & v)299 Integer v_lcm(const vector<Integer>& v) {
300     size_t i, size = v.size();
301     Integer g = 1;
302     for (i = 0; i < size; i++) {
303         g = libnormaliz::lcm(g, v[i]);
304         if (g == 0) {
305             return 0;
306         }
307     }
308     return g;
309 }
310 
311 
312 // returns lcm of the elements of v from index k up to index j
313 template <typename Integer>
v_lcm_to(const vector<Integer> & v,const size_t k,const size_t j)314 Integer v_lcm_to(const vector<Integer>& v, const size_t k, const size_t j) {
315     assert(k <= j);
316     size_t i;
317     Integer g = 1;
318     for (i = k; i <= j; i++) {
319         g = libnormaliz::lcm(g, v[i]);
320         if (g == 0) {
321             return 0;
322         }
323     }
324     return g;
325 }
326 
327 
328 //---------------------------------------------------------------------------
329 
330 template <typename Integer>
v_abs(vector<Integer> & v)331 vector<Integer>& v_abs(vector<Integer>& v) {
332     size_t i, size = v.size();
333     for (i = 0; i < size; i++) {
334         if (v[i] < 0)
335             v[i] = Iabs(v[i]);
336     }
337     return v;
338 }
339 
340 //---------------------------------------------------------------------------
341 // returns a new vector with the content of a extended by b
342 template <typename T>
v_merge(const vector<T> & a,const T & b)343 vector<T> v_merge(const vector<T>& a, const T& b) {
344     size_t s = a.size();
345     vector<T> c(s + 1);
346     for (size_t i = 0; i < s; i++) {
347         c[i] = a[i];
348     }
349     c[s] = b;
350     return c;
351 }
352 
353 //---------------------------------------------------------------------------
354 
355 template <typename T>
v_merge(const vector<T> & a,const vector<T> & b)356 vector<T> v_merge(const vector<T>& a, const vector<T>& b) {
357     size_t s1 = a.size(), s2 = b.size(), i;
358     vector<T> c(s1 + s2);
359     for (i = 0; i < s1; i++) {
360         c[i] = a[i];
361     }
362     for (i = 0; i < s2; i++) {
363         c[s1 + i] = b[i];
364     }
365     return c;
366 }
367 
368 //---------------------------------------------------------------------------
369 
370 template <typename Integer>
v_reduction_modulo(vector<Integer> & v,const Integer & modulo)371 void v_reduction_modulo(vector<Integer>& v, const Integer& modulo) {
372     size_t i, size = v.size();
373     for (i = 0; i < size; i++) {
374         v[i] = v[i] % modulo;
375         if (v[i] < 0) {
376             v[i] = v[i] + modulo;
377         }
378     }
379 }
380 
381 //---------------------------------------------------------------------------
382 
383 template <typename Integer>
v_add_to_mod(vector<Integer> & a,const vector<Integer> & b,const Integer & m)384 vector<Integer>& v_add_to_mod(vector<Integer>& a, const vector<Integer>& b, const Integer& m) {
385     //  assert(a.size() == b.size());
386     size_t i, s = a.size();
387     for (i = 0; i < s; i++) {
388         //      a[i] = (a[i]+b[i])%m;
389         if ((a[i] += b[i]) >= m) {
390             a[i] -= m;
391         }
392     }
393     return a;
394 }
395 
396 //---------------------------------------------------------------------------
397 
398 template <typename Integer>
v_is_zero(const vector<Integer> & v)399 bool v_is_zero(const vector<Integer>& v) {
400     for (size_t i = 0; i < v.size(); ++i) {
401         if (v[i] != 0)
402             return false;
403     }
404     return true;
405 }
406 
407 //---------------------------------------------------------------------------
408 
409 template <typename Integer>
v_add(const vector<Integer> & a,const vector<Integer> & b)410 vector<Integer> v_add(const vector<Integer>& a, const vector<Integer>& b) {
411     assert(a.size() == b.size());
412     size_t i, s = a.size();
413     vector<Integer> d(s);
414     for (i = 0; i < s; i++) {
415         d[i] = a[i] + b[i];
416     }
417     return d;
418 }
419 
420 //---------------------------------------------------------------------------
421 
422 template <typename Integer>
v_add_result(vector<Integer> & result,const size_t s,const vector<Integer> & a,const vector<Integer> & b)423 void v_add_result(vector<Integer>& result, const size_t s, const vector<Integer>& a, const vector<Integer>& b) {
424     assert(a.size() == b.size() && a.size() == result.size());
425     size_t i;
426     // vector<Integer> d(s);
427     for (i = 0; i < s; i++) {
428         result[i] = a[i] + b[i];
429     }
430     // return d;
431 }
432 
433 //---------------------------------------------------------------------------
434 /*
435 // returns a new vector with the last size entries of v
436 template <typename T>
437 vector<T> v_cut_front(const vector<T>& v, size_t size) {
438     size_t s, k;
439     vector<T> tmp(size);
440     s = v.size() - size;
441     for (k = 0; k < size; k++) {
442         tmp[k] = v[s + k];
443     }
444     return tmp;
445 }
446 */
447 
448 //---------------------------------------------------------------------------
449 
450 template <typename Integer>
v_is_symmetric(const vector<Integer> & v)451 bool v_is_symmetric(const vector<Integer>& v) {
452     for (size_t i = 0; i < v.size() / 2; ++i) {
453         if (v[i] != v[v.size() - 1 - i])
454             return false;
455     }
456     return true;
457 }
458 
459 //---------------------------------------------------------------------------
460 
461 template <typename Integer>
v_el_trans(const vector<Integer> & av,vector<Integer> & bv,const Integer & F,const size_t start)462 void v_el_trans(const vector<Integer>& av, vector<Integer>& bv, const Integer& F, const size_t start) {
463     size_t i, n = av.size();
464 
465     auto a = av.begin();
466     auto b = bv.begin();
467 
468     a += start;
469     b += start;
470     n -= start;
471 
472     if (n >= 8) {
473         for (i = 0; i < (n >> 3); ++i, a += 8, b += 8) {
474             b[0] += F * a[0];
475             b[1] += F * a[1];
476             b[2] += F * a[2];
477             b[3] += F * a[3];
478             b[4] += F * a[4];
479             b[5] += F * a[5];
480             b[6] += F * a[6];
481             b[7] += F * a[7];
482         }
483         n -= i << 3;
484     }
485 
486     if (n >= 4) {
487         b[0] += F * a[0];
488         b[1] += F * a[1];
489         b[2] += F * a[2];
490         b[3] += F * a[3];
491 
492         n -= 4;
493         a += 4;
494         b += 4;
495     }
496 
497     if (n >= 2) {
498         b[0] += F * a[0];
499         b[1] += F * a[1];
500 
501         n -= 2;
502         a += 2;
503         b += 2;
504     }
505 
506     if (n > 0)
507         b[0] += F * a[0];
508 
509     for (size_t i = 0; i < bv.size(); ++i)
510         if (!check_range(bv[i]))
511             throw ArithmeticException("Vector entry out of range. Imminent danger of arithmetic overflow.");
512 }
513 
514 /*
515 template <typename Integer>
516 Integer v_max_abs(const vector<Integer>& v) {
517     Integer tmp = 0;
518     for (size_t i = 0; i < v.size(); i++) {
519         if (Iabs(v[i]) > tmp)
520             tmp = Iabs(v[i]);
521     }
522     return tmp;
523 }
524 */
525 
526 template <typename Integer>
527 Integer v_standardize(vector<Integer>& v, const vector<Integer>& LF);
528 
529 template <typename Integer>
530 Integer v_standardize(vector<Integer>& v);
531 
532 vector<bool> bitset_to_bool(const dynamic_bitset& BS);
533 vector<key_t> bitset_to_key(const dynamic_bitset& BS);
534 dynamic_bitset bool_to_bitset(const vector<bool>& val);
535 dynamic_bitset key_to_bitset(const vector<key_t>& key, long size);
536 
537 template <typename Integer>
make_integral(vector<Integer> & vec)538 inline void make_integral(vector<Integer>& vec) {
539 }
540 
541 // from the old renfxx.h
542 
543 #ifdef ENFNORMALIZ
544 
vector2fmpq_poly(fmpq_poly_t flp,const std::vector<mpq_class> & poly_vector)545 inline void vector2fmpq_poly(fmpq_poly_t flp, const std::vector<mpq_class>& poly_vector) {
546     slong n = (slong)poly_vector.size();
547 
548     fmpq_poly_fit_length(flp, n);
549     for (size_t i = 0; i < poly_vector.size(); ++i) {
550         fmpq_poly_set_coeff_mpq(flp, (slong)i, poly_vector[i].get_mpq_t());
551     }
552 }
553 
fmpq_poly2vector(std::vector<mpq_class> & poly_vector,const fmpq_poly_t flp)554 inline void fmpq_poly2vector(std::vector<mpq_class>& poly_vector, const fmpq_poly_t flp) {
555     slong length = fmpq_poly_length(flp);
556     if (length == 0) {
557         poly_vector.push_back(mpz_class(0));
558         return;
559     }
560     poly_vector.resize(length);
561     for (slong i = 0; i < length; i++) {
562         mpq_t current_coeff;
563         mpq_init(current_coeff);
564         fmpq_poly_get_coeff_mpq(current_coeff, flp, (slong)i);
565         poly_vector[i] = mpq_class(current_coeff);
566     }
567 }
568 
569 template <>
make_integral(vector<renf_elem_class> & vec)570 inline void make_integral(vector<renf_elem_class>& vec) {
571     mpz_class denom = 1;
572     for (size_t i = 0; i < vec.size(); ++i) {
573         denom = libnormaliz::lcm(denom, vec[i].den());
574     }
575     renf_elem_class fact(denom);
576     if (fact != 1)
577         v_scalar_multiplication(vec, fact);
578 }
579 #endif
580 
581 template <>
make_integral(vector<mpq_class> & vec)582 inline void make_integral(vector<mpq_class>& vec) {
583     mpz_class denom = 1;
584     for (size_t i = 0; i < vec.size(); ++i) {
585         denom = libnormaliz::lcm(denom, vec[i].get_den());
586     }
587     mpq_class fact(denom);
588     if (fact != 1)
589         v_scalar_multiplication(vec, fact);
590 }
591 
592 //=============================================================
593 
594 // old vector_operations.cpp
595 
596 template <typename Integer>
v_scalar_product(const vector<Integer> & av,const vector<Integer> & bv)597 Integer v_scalar_product(const vector<Integer>& av, const vector<Integer>& bv) {
598     // loop stretching ; brings some small speed improvement
599 
600     Integer ans = 0;
601     size_t i, n = av.size();
602 
603 #if 0  // #ifdef __MIC__   // not for newer compiler versions
604     // this version seems to be better vectorizable on the mic
605     for (i=0; i<n; ++i)
606         ans += av[i]*bv[i];
607 
608 #else   // __MIC__
609     auto a = av.begin(), b = bv.begin();
610 
611     if (n >= 16) {
612         for (i = 0; i < (n >> 4); ++i, a += 16, b += 16) {
613             ans += a[0] * b[0];
614             ans += a[1] * b[1];
615             ans += a[2] * b[2];
616             ans += a[3] * b[3];
617             ans += a[4] * b[4];
618             ans += a[5] * b[5];
619             ans += a[6] * b[6];
620             ans += a[7] * b[7];
621             ans += a[8] * b[8];
622             ans += a[9] * b[9];
623             ans += a[10] * b[10];
624             ans += a[11] * b[11];
625             ans += a[12] * b[12];
626             ans += a[13] * b[13];
627             ans += a[14] * b[14];
628             ans += a[15] * b[15];
629         }
630 
631         n -= i << 4;
632     }
633 
634     if (n >= 8) {
635         ans += a[0] * b[0];
636         ans += a[1] * b[1];
637         ans += a[2] * b[2];
638         ans += a[3] * b[3];
639         ans += a[4] * b[4];
640         ans += a[5] * b[5];
641         ans += a[6] * b[6];
642         ans += a[7] * b[7];
643 
644         n -= 8;
645         a += 8;
646         b += 8;
647     }
648 
649     if (n >= 4) {
650         ans += a[0] * b[0];
651         ans += a[1] * b[1];
652         ans += a[2] * b[2];
653         ans += a[3] * b[3];
654 
655         n -= 4;
656         a += 4;
657         b += 4;
658     }
659 
660     if (n >= 2) {
661         ans += a[0] * b[0];
662         ans += a[1] * b[1];
663 
664         n -= 2;
665         a += 2;
666         b += 2;
667     }
668 
669     if (n > 0)
670         ans += a[0] * b[0];
671 #endif  // __MIC__
672 
673     if (!check_range(ans)) {
674 #pragma omp atomic
675         GMP_scal_prod++;
676 
677         // cout << "av " << av;
678         // cout << "bv " << bv;
679         vector<mpz_class> mpz_a(av.size()), mpz_b(bv.size());
680         convert(mpz_a, av);
681         convert(mpz_b, bv);
682         convert(ans, v_scalar_product(mpz_a, mpz_b));
683     }
684 
685     return ans;
686 }
687 
688 template <>
v_scalar_product(const vector<nmz_float> & av,const vector<nmz_float> & bv)689 inline nmz_float v_scalar_product(const vector<nmz_float>& av, const vector<nmz_float>& bv) {
690     // loop stretching ; brings some small speed improvement
691 
692     nmz_float ans = 0;
693     size_t i, n = av.size();
694 
695     auto a = av.begin(), b = bv.begin();
696 
697     if (n >= 16) {
698         for (i = 0; i < (n >> 4); ++i, a += 16, b += 16) {
699             ans += a[0] * b[0];
700             ans += a[1] * b[1];
701             ans += a[2] * b[2];
702             ans += a[3] * b[3];
703             ans += a[4] * b[4];
704             ans += a[5] * b[5];
705             ans += a[6] * b[6];
706             ans += a[7] * b[7];
707             ans += a[8] * b[8];
708             ans += a[9] * b[9];
709             ans += a[10] * b[10];
710             ans += a[11] * b[11];
711             ans += a[12] * b[12];
712             ans += a[13] * b[13];
713             ans += a[14] * b[14];
714             ans += a[15] * b[15];
715         }
716 
717         n -= i << 4;
718     }
719 
720     if (n >= 8) {
721         ans += a[0] * b[0];
722         ans += a[1] * b[1];
723         ans += a[2] * b[2];
724         ans += a[3] * b[3];
725         ans += a[4] * b[4];
726         ans += a[5] * b[5];
727         ans += a[6] * b[6];
728         ans += a[7] * b[7];
729 
730         n -= 8;
731         a += 8;
732         b += 8;
733     }
734 
735     if (n >= 4) {
736         ans += a[0] * b[0];
737         ans += a[1] * b[1];
738         ans += a[2] * b[2];
739         ans += a[3] * b[3];
740 
741         n -= 4;
742         a += 4;
743         b += 4;
744     }
745 
746     if (n >= 2) {
747         ans += a[0] * b[0];
748         ans += a[1] * b[1];
749 
750         n -= 2;
751         a += 2;
752         b += 2;
753     }
754 
755     if (n > 0)
756         ans += a[0] * b[0];
757 
758     return ans;
759 }
760 
761 #ifdef ENFNORMALIZ
762 
763 template <>
v_scalar_product(const vector<renf_elem_class> & av,const vector<renf_elem_class> & bv)764 inline renf_elem_class v_scalar_product(const vector<renf_elem_class>& av, const vector<renf_elem_class>& bv) {
765     // loop stretching ; brings some small speed improvement
766 
767     assert(av.size() == bv.size());
768 
769     renf_elem_class ans = 0;
770     size_t n = av.size();
771     renf_elem_class help;
772 
773     for (size_t i = 0; i < n; ++i) {
774         if (av[i] != 0 && bv[i] != 0){
775             ans += av[i] * bv[i];
776             /* help = av[i];
777             help *= bv[i]; // does not seem to help
778             ans += help;*/
779         }
780     }
781     return ans;
782 }
783 
784 #endif
785 
786 //---------------------------------------------------------------------------
787 
788 template <>
v_scalar_product(const vector<mpq_class> & av,const vector<mpq_class> & bv)789 inline mpq_class v_scalar_product(const vector<mpq_class>& av, const vector<mpq_class>& bv) {
790     // loop stretching ; brings some small speed improvement
791 
792     assert(false);
793     return 0;
794 
795 }
796 
797 /* body removed for the time being
798     mpq_class ans = 0;
799     size_t i, n = av.size();
800 
801 #if 0  // #ifdef __MIC__   // not for newer compiler versions
802     // this version seems to be better vectorizable on the mic
803     for (i=0; i<n; ++i)
804         ans += av[i]*bv[i];
805 
806 #else   // __MIC__
807     auto a = av.begin(), b = bv.begin();
808 
809     if (n >= 16) {
810         for (i = 0; i < (n >> 4); ++i, a += 16, b += 16) {
811             ans += a[0] * b[0];
812             ans += a[1] * b[1];
813             ans += a[2] * b[2];
814             ans += a[3] * b[3];
815             ans += a[4] * b[4];
816             ans += a[5] * b[5];
817             ans += a[6] * b[6];
818             ans += a[7] * b[7];
819             ans += a[8] * b[8];
820             ans += a[9] * b[9];
821             ans += a[10] * b[10];
822             ans += a[11] * b[11];
823             ans += a[12] * b[12];
824             ans += a[13] * b[13];
825             ans += a[14] * b[14];
826             ans += a[15] * b[15];
827         }
828 
829         n -= i << 4;
830     }
831 
832     if (n >= 8) {
833         ans += a[0] * b[0];
834         ans += a[1] * b[1];
835         ans += a[2] * b[2];
836         ans += a[3] * b[3];
837         ans += a[4] * b[4];
838         ans += a[5] * b[5];
839         ans += a[6] * b[6];
840         ans += a[7] * b[7];
841 
842         n -= 8;
843         a += 8;
844         b += 8;
845     }
846 
847     if (n >= 4) {
848         ans += a[0] * b[0];
849         ans += a[1] * b[1];
850         ans += a[2] * b[2];
851         ans += a[3] * b[3];
852 
853         n -= 4;
854         a += 4;
855         b += 4;
856     }
857 
858     if (n >= 2) {
859         ans += a[0] * b[0];
860         ans += a[1] * b[1];
861 
862         n -= 2;
863         a += 2;
864         b += 2;
865     }
866 
867     if (n > 0)
868         ans += a[0] * b[0];
869 #endif  // __MIC__
870 
871     return ans;
872 }
873 
874 */
875 
876 //---------------------------------------------------------------------------
877 
878 template <typename Integer>
v_select_coordinates(const vector<Integer> & v,const vector<key_t> projection_key)879 vector<Integer> v_select_coordinates(const vector<Integer>& v, const vector<key_t> projection_key) {
880     vector<Integer> w(projection_key.size());
881     for (size_t i = 0; i < w.size(); ++i)
882         w[i] = v[projection_key[i]];
883     return w;
884 }
885 
886 //---------------------------------------------------------------------------
887 
888 template <typename Integer>
v_insert_coordinates(const vector<Integer> & v,const vector<key_t> projection_key,const size_t nr_cols)889 vector<Integer> v_insert_coordinates(const vector<Integer>& v, const vector<key_t> projection_key, const size_t nr_cols) {
890     vector<Integer> w(nr_cols);
891     for (size_t i = 0; i < projection_key.size(); ++i) {
892         assert(projection_key[i] < nr_cols);
893         w[projection_key[i]] = v[i];
894     }
895     return w;
896 }
897 //---------------------------------------------------------------------------
898 
899 
l1norm(vector<nmz_float> & v)900 inline  nmz_float l1norm(vector<nmz_float>& v) {
901     size_t i, size = v.size();
902     nmz_float g = 0;
903     for (i = 0; i < size; i++) {
904         if (Iabs(v[i]) > nmz_epsilon)
905             g += Iabs(v[i]);
906         else
907             v[i] = 0;
908     }
909     return g;
910 }
911 
912 /*
913 mpq_class l1norm(vector<mpq_class>& v) {
914     size_t i, size = v.size();
915     mpq_class g = 0;
916     for (i = 0; i < size; i++) {
917         if (Iabs(v[i]) > 0)
918             g += Iabs(v[i]);
919         else
920             v[i] = 0;
921     }
922     return g;
923 }
924 */
925 
926 /* for nmz_float is norms the vector to l_1 norm 1.
927  *
928  * for mpq_class and renf_elem_class it makes the vector coefficients integral
929  *
930  * then it extracts the gcd of the coefficients
931  */
932 
933 template <typename Integer>
v_make_prime(vector<Integer> & v)934 Integer v_make_prime(vector<Integer>& v) {
935     size_t i, size = v.size();
936 
937 #ifdef ENFNORMALIZ
938     if (using_renf<Integer>()) {
939         v_standardize(v);
940         make_integral(v);
941         return (1);
942     }
943 #endif
944 
945     if (using_mpq_class<Integer>())
946         make_integral(v);
947     Integer g = v_gcd(v);
948     if (g != 0 && g != 1) {
949         for (i = 0; i < size; i++) {
950             v[i] /= g;
951         }
952     }
953     return g;
954 }
955 
956 
957 template <>
v_make_prime(vector<nmz_float> & v)958 inline nmz_float v_make_prime(vector<nmz_float>& v) {
959     size_t i, size = v.size();
960     nmz_float g = l1norm(v);
961     if (g != 0) {
962         for (i = 0; i < size; i++) {
963             v[i] /= g;
964         }
965     }
966     return g;
967 }
968 
969 
970 //---------------------------------------------------------------
971 
972 // swaps entry i and j of the vector<bool> v
v_bool_entry_swap(vector<bool> & v,size_t i,size_t j)973 inline  void v_bool_entry_swap(vector<bool>& v, size_t i, size_t j) {
974     if (v[i] != v[j]) {
975         v[i].flip();
976         v[j].flip();
977     }
978 }
979 
980 //---------------------------------------------------------------
981 
identity_key(size_t n)982 inline vector<key_t> identity_key(size_t n) {
983     vector<key_t> key(n);
984     for (size_t k = 0; k < n; ++k)
985         key[k] = k;
986     return key;
987 }
988 
reverse_key(size_t n)989 inline vector<key_t> reverse_key(size_t n) {
990     vector<key_t> key(n);
991     for (size_t k = 0; k < n; ++k)
992         key[k] = (n - 1) - k;
993     return key;
994 }
995 
random_key(size_t n)996 inline vector<key_t> random_key(size_t n) {
997     vector<key_t> key = identity_key(n);
998     for (size_t k = 0; k < 3*n; ++k)
999         std::swap(key[rand() % n], key[rand() % n]);
1000     return key;
1001 }
1002 
1003 // vector<bool> is special because ordinary swap is not defined for it
order_by_perm_bool(vector<bool> & v,const vector<key_t> & permfix)1004 inline void order_by_perm_bool(vector<bool>& v, const vector<key_t>& permfix) {
1005     vector<key_t> perm = permfix;  // we may want to use permfix a second time
1006     vector<key_t> inv(perm.size());
1007     for (key_t i = 0; i < perm.size(); ++i)
1008         inv[perm[i]] = i;
1009     for (key_t i = 0; i < perm.size(); ++i) {
1010         key_t j = perm[i];
1011         // v.swap(v[i],v[perm[i]]);
1012         v_bool_entry_swap(v, i, perm[i]);
1013         std::swap(perm[i], perm[inv[i]]);
1014         std::swap(inv[i], inv[j]);
1015     }
1016 }
1017 
1018 //---------------------------------------------------------------------------
1019 
1020 template <typename Integer>
v_scalar_division(vector<Integer> & v,const Integer scalar)1021 void v_scalar_division(vector<Integer>& v, const Integer scalar) {
1022     size_t i, size = v.size();
1023     assert(scalar != 0);
1024     for (i = 0; i < size; i++) {
1025         assert(v[i] % scalar == 0);
1026         v[i] /= scalar;
1027     }
1028 }
1029 
1030 template <>
v_scalar_division(vector<nmz_float> & v,const nmz_float scalar)1031 inline void v_scalar_division(vector<nmz_float>& v, const nmz_float scalar) {
1032     size_t i, size = v.size();
1033     assert(scalar != 0);
1034     for (i = 0; i < size; i++) {
1035         v[i] /= scalar;
1036     }
1037 }
1038 
1039 
1040 
1041 template <>
v_scalar_division(vector<mpq_class> & v,const mpq_class scalar)1042 inline void v_scalar_division(vector<mpq_class>& v, const mpq_class scalar) {
1043     size_t i, size = v.size();
1044     assert(scalar != 0);
1045     for (i = 0; i < size; i++) {
1046         v[i] /= scalar;
1047     }
1048 }
1049 
1050 
1051 #ifdef ENFNORMALIZ
1052 template <>
v_scalar_division(vector<renf_elem_class> & v,const renf_elem_class scalar)1053 inline void v_scalar_division(vector<renf_elem_class>& v, const renf_elem_class scalar) {
1054     size_t i, size = v.size();
1055     assert(scalar != 0);
1056     renf_elem_class fact = 1 / scalar;
1057     for (i = 0; i < size; i++) {
1058         v[i] *= fact;
1059     }
1060 }
1061 #endif
1062 
1063 /* v_standardize
1064  *
1065  * defined only for mpq_class, nmz_float and renf_elem_class
1066  *
1067  * makes the value under LF equal to 1 (checks for positivity of value)
1068  *
1069  * or the last component equal to +-1
1070  */
1071 
1072 template <typename Integer>
v_standardize(vector<Integer> & v,const vector<Integer> & LF)1073 Integer v_standardize(vector<Integer>& v, const vector<Integer>& LF) {
1074     assert(false);
1075     return 0;
1076 }
1077 
1078 template <typename Integer>
v_standardize(vector<Integer> & v)1079 Integer v_standardize(vector<Integer>& v) {
1080     vector<Integer> LF;
1081     return v_standardize(v, LF);
1082 }
1083 
1084 template <>
v_standardize(vector<nmz_float> & v,const vector<nmz_float> & LF)1085 inline nmz_float v_standardize(vector<nmz_float>& v, const vector<nmz_float>& LF) {
1086     nmz_float denom = 0;
1087     if (LF.size() == v.size()) {
1088         denom = v_scalar_product(v, LF);
1089     }
1090 
1091     if (denom == 0) {
1092         for (long i = (long)v.size() - 1; i >= 0; --i) {
1093             if (v[i] != 0) {
1094                 denom = v[i];
1095                 break;
1096             }
1097         }
1098     }
1099     denom = Iabs(denom);
1100 
1101     if (denom == 0)
1102         return denom;
1103     if (denom != 1)
1104         v_scalar_division(v, denom);
1105 
1106     return denom;
1107 }
1108 
1109 /*
1110 template <>
1111 mpq_class v_standardize(vector<mpq_class>& v, const vector<mpq_class>& LF) {
1112     mpq_class denom = 0;
1113     if (LF.size() == v.size()) {
1114         denom = v_scalar_product(v, LF);
1115     };
1116 
1117     if (denom == 0) {
1118         for (long i = (long)v.size() - 1; i >= 0; --i) {
1119             if (v[i] != 0) {
1120                 denom = v[i];
1121                 break;
1122             }
1123         }
1124     }
1125     denom = Iabs(denom);
1126 
1127     if (denom == 0)
1128         return denom;
1129     if (denom != 1)
1130         v_scalar_division(v, denom);
1131 
1132     return denom;
1133 }
1134 */
1135 
1136 #ifdef ENFNORMALIZ
1137 
1138 template <>
v_standardize(vector<renf_elem_class> & v,const vector<renf_elem_class> & LF)1139 inline renf_elem_class v_standardize(vector<renf_elem_class>& v, const vector<renf_elem_class>& LF) {
1140     renf_elem_class denom = 0;
1141     if (LF.size() == v.size()) {
1142         denom = v_scalar_product(v, LF);
1143     }
1144 
1145     if (denom == 0) {
1146         for (long i = (long)v.size() - 1; i >= 0; --i) {
1147             if (v[i] != 0) {
1148                 denom = v[i];
1149                 break;
1150             }
1151         }
1152     }
1153     denom = Iabs(denom);
1154 
1155     if (denom == 0)
1156         return denom;
1157     if (denom != 1)
1158         v_scalar_division(v, denom);
1159 
1160     return denom;
1161 }
1162 #endif
1163 
1164 
1165 /* Not used presently
1166 // the following function removes the denominators and then extracts the Gcd of the numerators
1167 mpq_class v_standardize(vector<mpq_class>& v, const vector<mpq_class>& LF){
1168     size_t size=v.size();
1169     mpz_class d=1;
1170     for (size_t i = 0; i < size; i++)
1171         //d=lcm(d,v[i].get_den());  // GMP C++ function only available in GMP >= 6.1
1172         mpz_lcm(d.get_mpz_t(), d.get_mpz_t(), v[i].get_den().get_mpz_t());
1173     for (size_t i = 0; i < size; i++)
1174         v[i]*=d;
1175     mpz_class g=0;
1176     for (size_t i = 0; i < size; i++)
1177         //g=gcd(g,v[i].get_num());  //  GMP C++ function only available in GMP >= 6.1
1178         mpz_gcd(g.get_mpz_t(), g.get_mpz_t(), v[i].get_num().get_mpz_t());
1179     if (g==0)
1180         return 0;
1181     for (size_t i = 0; i < size; i++)
1182         v[i]/=g;
1183     return 1;
1184 }
1185 */
1186 
1187 template <typename Integer>
v_scalar_mult_mod(const vector<Integer> & v,const Integer & scalar,const Integer & modulus)1188 vector<Integer> v_scalar_mult_mod(const vector<Integer>& v, const Integer& scalar, const Integer& modulus) {
1189     vector<Integer> w(v.size());
1190     if (v_scalar_mult_mod_inner(w, v, scalar, modulus))
1191         return w;
1192 
1193 #pragma omp atomic
1194     GMP_scal_prod++;
1195     vector<mpz_class> x, y(v.size());
1196     convert(x, v);
1197     v_scalar_mult_mod_inner(y, x, convertTo<mpz_class>(scalar), convertTo<mpz_class>(modulus));
1198     return convertTo<vector<Integer> >(y);
1199 }
1200 
bitset_to_bool(const dynamic_bitset & val)1201 inline vector<bool> bitset_to_bool(const dynamic_bitset& val) {
1202     vector<bool> ret(val.size());
1203     for (size_t i = 0; i < val.size(); ++i)
1204         ret[i] = val[i];
1205     return ret;
1206 }
1207 
bool_to_bitset(const vector<bool> & val)1208 inline dynamic_bitset bool_to_bitset(const vector<bool>& val) {
1209     dynamic_bitset ret(val.size());
1210     for (size_t i = 0; i < val.size(); ++i)
1211         ret[i] = val[i];
1212     return ret;
1213 }
1214 
bitset_to_key(const dynamic_bitset & val)1215 inline vector<key_t> bitset_to_key(const dynamic_bitset& val) {
1216     vector<key_t> ret;
1217     for (size_t i = 0; i < val.size(); ++i)
1218         if(val[i])
1219             ret.push_back(i);
1220     return ret;
1221 }
1222 
key_to_bitset(const vector<key_t> & key,long size)1223 inline dynamic_bitset key_to_bitset(const vector<key_t>& key, long size){
1224 
1225     dynamic_bitset bs(size);
1226     for(size_t i=0; i< key.size(); ++i){
1227         assert(key[i] < size);
1228         bs[key[i]] = 1;
1229     }
1230     return bs;
1231 }
1232 
1233 template<typename T>
binary_expansion(T n)1234 vector<bool> binary_expansion(T n){
1235     vector<bool> bin;
1236     while(n != 0){
1237         bin.push_back(n & 1);
1238         n = n >> 1;
1239     }
1240     return bin;
1241 }
1242 
1243 template <typename Integer>
vector_sum_cascade(vector<Integer> & summands)1244 Integer vector_sum_cascade(vector<Integer>& summands){
1245        size_t step =2;
1246     bool added = true;
1247     while(added){
1248         added = false;
1249 #pragma omp parallel for
1250         for(size_t k=0; k < summands.size(); k+=step){
1251             if(summands.size() > k + step/2){
1252                 summands[k] += summands[k+ step/2];
1253                 added = true;
1254             }
1255         }
1256         step *=2;
1257     }
1258     return summands[0];
1259 }
1260 
1261 //--------------------------------------------------------------
1262 
1263 template <typename Integer>
1264 class AdditionPyramid {
1265 
1266 public:
1267 
1268     vector<Integer> accumulator;
1269     vector<size_t> counter;
1270     size_t capacity;
1271     void add_inner(const Integer summand, const size_t level);
1272 
1273     AdditionPyramid();
1274     AdditionPyramid(const size_t& given_capacity);
1275     void add(const Integer& summand);
1276     Integer sum();
1277     void reset();
1278     void set_capacity(const size_t& given_capacity);
1279 };
1280 
1281 template <typename Integer>
add_inner(const Integer summand,const size_t level)1282 void AdditionPyramid<Integer>::add_inner(const Integer summand, const size_t level){
1283 
1284     // cout << "***** " << summand << " -- " << level << endl;
1285 
1286     assert(level <= counter.size());
1287 
1288     if(level == counter.size()){
1289         counter.resize(level+1);
1290         accumulator.resize(level+1);
1291         // cout << "$$$$$ " << accumulator[level] << " -- " << summand << endl;
1292         accumulator[level] = summand;
1293         // cout << "+++ " << accumulator[level] << endl;
1294         return;
1295     }
1296 
1297     counter[level]++;
1298 
1299     if(counter[level] < capacity){
1300         accumulator[level] += summand;
1301         return;
1302     }
1303 
1304     add_inner(accumulator[level], level+1);
1305     counter[level] = 0;
1306     accumulator[level] = summand;
1307 }
1308 
1309 template <typename Integer>
AdditionPyramid()1310 AdditionPyramid<Integer>::AdditionPyramid(){
1311 
1312 }
1313 
1314 template <typename Integer>
reset()1315 void AdditionPyramid<Integer>::reset(){
1316 
1317     counter.clear();
1318     accumulator.clear();
1319 }
1320 
1321 template <typename Integer>
AdditionPyramid(const size_t & given_capacity)1322 AdditionPyramid<Integer>::AdditionPyramid(const size_t& given_capacity){
1323     capacity = given_capacity;
1324     reset();
1325 }
1326 
1327 template <typename Integer>
set_capacity(const size_t & given_capacity)1328 void AdditionPyramid<Integer>::set_capacity(const size_t& given_capacity){
1329     capacity = given_capacity;
1330 }
1331 
1332 template <typename Integer>
sum()1333 Integer AdditionPyramid<Integer>::sum(){
1334     Integer our_sum; // this version works also for CoCoALib::Bigrat
1335     our_sum = 0;
1336     for(size_t i=0; i<accumulator.size();++i)
1337         our_sum += accumulator[i];
1338     return our_sum;
1339 }
1340 
1341 template <typename Integer>
add(const Integer & summand)1342 void AdditionPyramid<Integer>::add(const Integer& summand){
1343 
1344     if(counter.size()>0){
1345         if(counter[0] < capacity-1){
1346             counter[0]++;
1347             accumulator[0] += summand;
1348             return;
1349         }
1350     }
1351     add_inner(summand,0);
1352 }
1353 
1354 
1355 }  // namespace libnormaliz
1356 
1357 //---------------------------------------------------------------------------
1358 #endif
1359 //---------------------------------------------------------------------------
1360