1 /*++
2 Copyright (c) 2011 Microsoft Corporation
3 
4 Module Name:
5 
6     polynomial.cpp
7 
8 Abstract:
9 
10     Goodies for creating and handling polynomials.
11 
12 Author:
13 
14     Leonardo (leonardo) 2011-11-15
15 
16 Notes:
17 
18 --*/
19 #include "math/polynomial/polynomial.h"
20 #include "util/vector.h"
21 #include "util/chashtable.h"
22 #include "util/small_object_allocator.h"
23 #include "util/id_gen.h"
24 #include "util/buffer.h"
25 #include "util/scoped_ptr_vector.h"
26 #include "math/polynomial/upolynomial_factorization.h"
27 #include "math/polynomial/polynomial_primes.h"
28 #include "util/permutation.h"
29 #include "math/polynomial/algebraic_numbers.h"
30 #include "util/mpzzp.h"
31 #include "util/timeit.h"
32 #include "math/polynomial/linear_eq_solver.h"
33 #include "util/scoped_numeral_buffer.h"
34 #include "util/ref_buffer.h"
35 #include "util/common_msgs.h"
36 #include <memory>
37 
38 namespace polynomial {
39 
factor_params()40     factor_params::factor_params():
41         m_max_p(UINT_MAX),
42         m_p_trials(1),
43         m_max_search_size(UINT_MAX) {
44     }
45 
factor_params(unsigned max_p,unsigned p_trials,unsigned max_search_size)46     factor_params::factor_params(unsigned max_p, unsigned p_trials, unsigned max_search_size):
47         m_max_p(max_p),
48         m_p_trials(p_trials),
49         m_max_search_size(max_search_size) {
50     }
51 
updt_params(params_ref const & p)52     void factor_params::updt_params(params_ref const & p) {
53         m_max_p    = p.get_uint("max_prime", UINT_MAX);
54         m_p_trials = p.get_uint("num_primes", 1);
55         m_max_search_size = p.get_uint("max_search_size", UINT_MAX);
56     }
57 
get_param_descrs(param_descrs & r)58     void factor_params::get_param_descrs(param_descrs & r) {
59         r.insert("max_search_size", CPK_UINT, "(default: infty) Z3 polynomial factorization is composed of three steps: factorization in GF(p), lifting and search. This parameter can be used to limit the search space.");
60         r.insert("max_prime", CPK_UINT, "(default: infty) Z3 polynomial factorization is composed of three steps: factorization in GF(p), lifting and search. This parameter limits the maximum prime number p to be used in the first step.");
61         r.insert("num_primes", CPK_UINT, "(default: 1) Z3 polynomial factorization is composed of three steps: factorization in GF(p), lifting and search. The search space may be reduced by factoring the polynomial in different GF(p)'s. This parameter specify the maximum number of finite factorizations to be considered, before lifiting and searching.");
62     }
63 
64     typedef ptr_vector<monomial> monomial_vector;
65 
display(std::ostream & out) const66     void var2degree::display(std::ostream & out) const {
67         bool first = true;
68         out << "[";
69         for (unsigned i = 0; i < m_var2degree.size(); ++ i) {
70             if (!m_var2degree.empty()) {
71                 if (!first) {
72                     out << ",";
73                 }
74                 out << "x" << i << "^" << m_var2degree[i];
75                 if (first) {
76                     first = false;
77                 }
78             }
79         }
80         out << "]";
81     }
82 
83     // -----------------------------------
84     //
85     // Monomials
86     //
87     // -----------------------------------
88 
89     /**
90        \brief power: var + exponent
91     */
92     class power : public std::pair<var, unsigned> {
93     public:
power()94         power():std::pair<var, unsigned>() {}
power(var v,unsigned d)95         power(var v, unsigned d):std::pair<var, unsigned>(v, d) {}
get_var() const96         var get_var() const { return first; }
degree() const97         unsigned degree() const { return second; }
degree()98         unsigned & degree() { return second; }
set_var(var x)99         void set_var(var x) { first = x; }
100 
101         struct lt_var {
operator ()polynomial::power::lt_var102             bool operator()(power const & p1, power const & p2) {
103                 // CMW: The assertion below does not hold on macOS, because
104                 // their implementation of std::sort will try to compare
105                 // two items at the same index instead of comparing
106                 // the indices directly. I suspect that the purpose of
107                 // this assertion was to make sure that there are
108                 // no duplicates, so I replaced it with a new assertion at
109                 // the end of var_degrees(...).
110 
111                 // SASSERT(p1.get_var() != p2.get_var());
112 
113                 return p1.get_var() < p2.get_var();
114             }
115         };
116 
117         struct lt_degree {
operator ()polynomial::power::lt_degree118             bool operator()(power const & p1, power const & p2) {
119                 return p1.degree() < p2.degree();
120             }
121         };
122     };
123 
124 
operator <<(std::ostream & out,power const & p)125     std::ostream & operator<<(std::ostream & out, power const & p) {
126         out << "x" << p.get_var();
127         if (p.degree() != 1)
128             out << "^" << p.degree();
129         return out;
130     }
131 
132     /**
133        \brief Return true if the variables in pws are sorted in increasing order and are distinct.
134     */
is_valid_power_product(unsigned sz,power const * pws)135     bool is_valid_power_product(unsigned sz, power const * pws) {
136         for (unsigned i = 1; i < sz; i++) {
137             if (pws[i-1].get_var() >= pws[i].get_var())
138                 return false;
139         }
140         return true;
141     }
142 
143     /**
144        \brief Return total degree of the given power product.
145     */
power_product_total_degree(unsigned sz,power const * pws)146     unsigned power_product_total_degree(unsigned sz, power const * pws) {
147         unsigned r = 0;
148         for (unsigned i = 0; i < sz; i++)
149             r += pws[i].degree();
150         return r;
151     }
152 
153     /**
154        \brief Monomials (power products)
155     */
156     class monomial {
157         unsigned  m_ref_count;
158         unsigned  m_id;           //!< unique id
159         unsigned  m_total_degree; //!< total degree of the monomial
160         unsigned  m_size;         //!< number of powers
161         unsigned  m_hash;
162         power     m_powers[0];
163         friend class tmp_monomial;
164 
sort()165         void sort() {
166             std::sort(m_powers, m_powers + m_size, power::lt_var());
167         }
168     public:
hash_core(unsigned sz,power const * pws)169         static unsigned hash_core(unsigned sz, power const * pws) {
170             return string_hash(reinterpret_cast<char*>(const_cast<power*>(pws)), sz*sizeof(power), 11);
171         }
172 
173         struct hash_proc {
operator ()polynomial::monomial::hash_proc174             unsigned operator()(monomial const * m) const {
175                 return m->m_hash;
176             }
177         };
178 
179         struct eq_proc {
operator ()polynomial::monomial::eq_proc180             bool operator()(monomial const * m1, monomial const * m2) const {
181                 if (m1->size() != m2->size() || m1->hash() != m2->hash())
182                     return false;
183                 // m_total_degree must not be used as a filter, because it is not updated in temporary monomials.
184                 for (unsigned i = 0; i < m1->m_size; i++) {
185                     if (m1->get_power(i) != m2->get_power(i))
186                         return false;
187                 }
188 
189                 return true;
190             }
191         };
192 
get_obj_size(unsigned sz)193         static unsigned get_obj_size(unsigned sz) { return sizeof(monomial) + sz * sizeof(power); }
194 
monomial(unsigned id,unsigned sz,power const * pws,unsigned h)195         monomial(unsigned id, unsigned sz, power const * pws, unsigned h):
196             m_ref_count(0),
197             m_id(id),
198             m_total_degree(0),
199             m_size(sz),
200             m_hash(h) {
201             for (unsigned i = 0; i < sz; i ++) {
202                 power const & pw = pws[i];
203                 m_powers[i] = pw;
204                 SASSERT(i == 0 || get_var(i) > get_var(i-1));
205                 SASSERT(degree(i) > 0);
206                 m_total_degree += degree(i);
207             }
208         }
209 
hash() const210         unsigned hash() const { return m_hash; }
211 
ref_count() const212         unsigned ref_count() const { return m_ref_count; }
213 
inc_ref()214         void inc_ref() { m_ref_count++; }
215 
dec_ref()216         void dec_ref() { SASSERT(m_ref_count > 0); m_ref_count--; }
217 
is_valid() const218         bool is_valid() const {
219             return is_valid_power_product(m_size, m_powers) && power_product_total_degree(m_size, m_powers) == m_total_degree;
220         }
221 
id() const222         unsigned id() const { return m_id; }
223 
size() const224         unsigned size() const { return m_size; }
225 
total_degree() const226         unsigned total_degree() const { return m_total_degree; }
227 
get_power(unsigned idx) const228         power const & get_power(unsigned idx) const { SASSERT(idx < size()); return m_powers[idx]; }
229 
get_powers() const230         power const * get_powers() const { return m_powers; }
231 
get_var(unsigned idx) const232         var get_var(unsigned idx) const { return get_power(idx).get_var(); }
233 
degree(unsigned idx) const234         unsigned degree(unsigned idx) const { return get_power(idx).degree(); }
235 
max_var() const236         var max_var() const {
237             if (m_size == 0)
238                 return null_var;
239             return get_var(m_size - 1);
240         }
241 
max_var_degree() const242         unsigned max_var_degree() const {
243             if (m_size == 0)
244                 return 0;
245             return degree(m_size - 1);
246         }
247 
248 #define SMALL_MONOMIAL 8
249 
index_of(var x) const250         unsigned index_of(var x) const {
251             if (m_size == 0)
252                 return UINT_MAX;
253             unsigned last = m_size - 1;
254             if (get_var(last) == x)
255                 return last;
256             if (m_size < SMALL_MONOMIAL) {
257                 // use linear search for small monomials
258                 // search backwards since we usually ask for the degree of "big" variables
259                 for (unsigned i = last; i-- > 0; ) {
260                     if (get_var(i) == x)
261                         return i;
262                 }
263                 return UINT_MAX;
264             }
265             else {
266                 // use binary search for big monomials
267                 int low  = 0;
268                 int high = last;
269                 while (true) {
270                     int mid   = low + ((high - low)/2);
271                     var x_mid = get_var(mid);
272                     if (x > x_mid) {
273                         low = mid + 1;
274                     }
275                     else if (x < x_mid) {
276                         high = mid - 1;
277                     }
278                     else {
279                         return mid;
280                     }
281                     if (low > high)
282                         return UINT_MAX;
283                 }
284             }
285         }
286 
degree_of(var x) const287         unsigned degree_of(var x) const {
288             unsigned pos = index_of(x);
289             if (pos == UINT_MAX)
290                 return 0;
291             return degree(pos);
292         }
293 
294 
295         // Given the subset S of variables that are smaller than x,
296         // then return the maximal one.
max_smaller_than_core(var x) const297         var max_smaller_than_core(var x) const {
298             if (m_size == 0)
299                 return null_var;
300             if (m_size < SMALL_MONOMIAL) {
301                 // use linear search for small monomials
302                 // search backwards since we usually ask for the degree of "big" variables
303                 unsigned i = m_size;
304                 while (i > 0) {
305                     --i;
306                     if (get_var(i) < x)
307                         return get_var(i);
308                 }
309                 return null_var;
310             }
311             else {
312                 // use binary search for big monomials
313                 int low  = 0;
314                 int high = m_size-1;
315                 if (x <= get_var(low)) {
316                     return null_var;
317                 }
318                 if (x > get_var(high)) {
319                     return get_var(high);
320                 }
321                 if (x == get_var(high)) {
322                     SASSERT(high > 0);
323                     return get_var(high-1);
324                 }
325                 while (true) {
326                     SASSERT(0 <= low && high < static_cast<int>(m_size));
327                     SASSERT(get_var(low) < x);
328                     SASSERT(x < get_var(high));
329                     SASSERT(low < high);
330                     if (high == low + 1) {
331                         SASSERT(get_var(low) < x);
332                         SASSERT(x < get_var(low+1));
333                         return get_var(low);
334                     }
335                     SASSERT(high > low + 1);
336                     int mid   = low + ((high - low)/2);
337                     SASSERT(low < mid && mid < high);
338                     var x_mid = get_var(mid);
339                     if (x_mid == x) {
340                         SASSERT(low < mid && mid < high && high < static_cast<int>(m_size));
341                         SASSERT(get_var(mid-1) < x && x == get_var(mid));
342                         return get_var(mid-1);
343                     }
344                     if (x < x_mid) {
345                         high = mid;
346                     }
347                     else {
348                         SASSERT(x_mid < x);
349                         low  = mid;
350                     }
351                 }
352             }
353         }
354 
max_smaller_than(var x) const355         var max_smaller_than(var x) const {
356             SASSERT(x != null_var);
357             var y = max_smaller_than_core(x);
358             DEBUG_CODE({
359                 bool found = false;
360                 for (unsigned i = 0; i < m_size; i++) {
361                     if (get_var(i) < x) {
362                         CTRACE("poly_bug", !(y != null_var && get_var(i) <= y),
363                                tout << "m: "; display(tout); tout << "\n";
364                                tout << "x: " << x << "\n";
365                                tout << "y: " << y << "\n";
366                                tout << "i: " << i << "\n";
367                                tout << "get_var(i): " << get_var(i) << "\n";);
368                         SASSERT(y != null_var && get_var(i) <= y);
369                     }
370                     if (get_var(i) == y)
371                         found = true;
372                 }
373                 SASSERT(y == null_var || (y < x && found));
374             });
375             return y;
376         }
377 
display(std::ostream & out,display_var_proc const & proc=display_var_proc (),bool use_star=false) const378         std::ostream& display(std::ostream & out, display_var_proc const & proc = display_var_proc(), bool use_star = false) const {
379             if (m_size == 0) {
380                 out << "1";
381                 return out;
382             }
383             for (unsigned i = 0; i < m_size; i++) {
384                 if (i > 0) {
385                     if (use_star)
386                         out << "*";
387                     else
388                         out << " ";
389                 }
390                 proc(out, get_var(i));
391                 if (degree(i) > 1)
392                     out << "^" << degree(i);
393             }
394             return out;
395         }
396 
display_smt2(std::ostream & out,display_var_proc const & proc=display_var_proc ()) const397         void display_smt2(std::ostream & out, display_var_proc const & proc = display_var_proc()) const {
398             if (m_size == 0) {
399                 out << "1";
400             }
401             else if (m_size == 1 && degree(0) == 1) {
402                 proc(out, get_var(0));
403             }
404             else {
405                 out << "(*";
406                 for (unsigned i = 0; i < m_size; i++) {
407                     var x = get_var(i);
408                     unsigned k = degree(i);
409                     SASSERT(k > 0);
410                     for (unsigned j = 0; j < k; j++) {
411                         out << " ";
412                         proc(out, x);
413                     }
414                 }
415                 out << ")";
416             }
417         }
418 
is_unit() const419         bool is_unit() const { return m_size == 0; }
420 
421         /**
422            \brief Return true if the degree of every variable is even.
423         */
is_power_of_two() const424         bool is_power_of_two() const {
425             for (unsigned i = 0; i < m_size; i++) {
426                 if (degree(i) % 2 == 1)
427                     return false;
428             }
429             return true;
430         }
431 
is_square() const432         bool is_square() const {
433             for (unsigned i = 0; i < m_size; i++) {
434                 if (degree(i) % 2 != 0)
435                     return false;
436             }
437             return true;
438         }
439 
rename(unsigned sz,var const * xs)440         void rename(unsigned sz, var const * xs) {
441             for (unsigned i = 0; i < m_size; i++) {
442                 power & pw = m_powers[i];
443                 pw.set_var(xs[pw.get_var()]);
444             }
445             sort();
446             m_hash = hash_core(m_size, m_powers);
447         }
448     };
449 
swap(monomial * & m1,monomial * & m2)450     inline void swap(monomial * & m1, monomial * & m2) { std::swap(m1, m2); }
451 
452     typedef chashtable<monomial*, monomial::hash_proc, monomial::eq_proc> monomial_table;
453 
454     /**
455        \brief Mapping from monomials to positions.
456     */
457     class monomial2pos {
458         unsigned_vector          m_m2pos;
459     public:
get(monomial const * m)460         unsigned get(monomial const * m) {
461             unsigned id = m->id();
462             m_m2pos.reserve(id+1, UINT_MAX);
463             return m_m2pos[id];
464         }
465 
reset(monomial const * m)466         void reset(monomial const * m) {
467             unsigned id = m->id();
468             SASSERT(id < m_m2pos.size());
469             m_m2pos[id] = UINT_MAX;
470         }
471 
set(monomial const * m,unsigned pos)472         void set(monomial const * m, unsigned pos) {
473             unsigned id = m->id();
474             m_m2pos.reserve(id+1, UINT_MAX);
475             SASSERT(m_m2pos[id] == UINT_MAX);
476             m_m2pos[id] = pos;
477         }
478 
479         /**
480            \brief Save the position of the monomials in p.
481         */
482         template<typename Poly>
set(Poly const * p)483         void set(Poly const * p) {
484             unsigned sz = p->size();
485             for (unsigned i = 0; i < sz; i++) {
486                 set(p->m(i), i);
487             }
488         }
489 
490         /**
491            \brief Undo the effects of save_pos.
492         */
493         template<typename Poly>
reset(Poly const * p)494         void reset(Poly const * p) {
495             unsigned sz = p->size();
496             for (unsigned i = 0; i < sz; i++) {
497                 reset(p->m(i));
498             }
499         }
500     };
501 
502 
503 #define TMP_INITIAL_CAPACITY 128
504 
505     /**
506        \brief Wrapper for temporary monomials.
507     */
508     class tmp_monomial {
509         monomial *               m_ptr;
510         unsigned                 m_capacity; //!< maximum number of arguments supported by m_ptr;
511 
allocate(unsigned capacity)512         monomial * allocate(unsigned capacity) {
513             void * mem  = memory::allocate(monomial::get_obj_size(capacity));
514             return new (mem) monomial(UINT_MAX, 0, nullptr, 0);
515         }
516 
deallocate(monomial * ptr,unsigned capacity)517         void deallocate(monomial * ptr, unsigned capacity) {
518             memory::deallocate(ptr);
519         }
520 
increase_capacity(unsigned new_capacity)521         void increase_capacity(unsigned new_capacity) {
522             SASSERT(new_capacity > m_capacity);
523             deallocate(m_ptr, m_capacity);
524             m_ptr = allocate(new_capacity);
525             m_capacity = new_capacity;
526         }
527 
expand_capacity(unsigned new_capacity)528         void expand_capacity(unsigned new_capacity) {
529             SASSERT(new_capacity > m_capacity);
530             monomial * new_ptr  = allocate(new_capacity);
531             new_ptr->m_size = m_ptr->m_size;
532             std::uninitialized_copy(m_ptr->m_powers, m_ptr->m_powers + m_ptr->m_size, new_ptr->m_powers);
533             deallocate(m_ptr, m_capacity);
534             m_ptr      = new_ptr;
535             m_capacity = new_capacity;
536         }
537     public:
tmp_monomial()538         tmp_monomial():
539             m_ptr(allocate(TMP_INITIAL_CAPACITY)),
540             m_capacity(TMP_INITIAL_CAPACITY) {
541         }
542 
~tmp_monomial()543         ~tmp_monomial() {
544             deallocate(m_ptr, m_capacity);
545         }
546 
init(unsigned sz,power const * pws)547         void init(unsigned sz, power const * pws) {
548             if (sz > m_capacity)
549                 increase_capacity(sz * 2);
550             SASSERT(sz < m_capacity);
551             m_ptr->m_size = sz;
552             std::uninitialized_copy(pws, pws + sz, m_ptr->m_powers);
553         }
554 
reset()555         void reset() {
556             m_ptr->m_size = 0;
557         }
558 
size() const559         unsigned size() const {
560             return m_ptr->m_size;
561         }
562 
push_back(power const & pw)563         void push_back(power const & pw) {
564             if (m_ptr->m_size >= m_capacity)
565                 expand_capacity(m_ptr->m_size * 2);
566             m_ptr->m_powers[m_ptr->m_size] = pw;
567             m_ptr->m_size++;
568         }
569 
get_ptr()570         monomial * get_ptr() {
571             unsigned sz = m_ptr->m_size;
572             m_ptr->m_hash = monomial::hash_core(sz, m_ptr->m_powers);
573             return m_ptr;
574         }
575 
reserve(unsigned capacity)576         void reserve(unsigned capacity) {
577             if (capacity > m_capacity)
578                 increase_capacity(capacity * 2);
579         }
580 
set_size(unsigned sz)581         void set_size(unsigned sz) {
582             SASSERT(sz <= m_capacity);
583             m_ptr->m_size = sz;
584         }
585 
set_power(unsigned idx,power const & pw)586         void set_power(unsigned idx, power const & pw) {
587             SASSERT(idx < m_capacity);
588             m_ptr->m_powers[idx] = pw;
589         }
590 
get_power(unsigned idx) const591         power const & get_power(unsigned idx) const { return m_ptr->m_powers[idx]; }
592 
get_powers() const593         power const * get_powers() const { return m_ptr->m_powers; }
594     };
595 
596     /**
597        \brief Compare m1 and m2 using a lexicographical order
598 
599        Return
600             -   -1  if m1 <_lex m2,
601             -   0   if m1 = m2,
602             -   1   if m1 >_lex m2
603 
604        The biggest variable dominates
605        x3^3 > x3^2 x1^2 > x3 x2^2 x_1 > x1^3
606 
607        Remark: in out representation the biggest variable is in the last position.
608     */
lex_compare(monomial const * m1,monomial const * m2)609     int lex_compare(monomial const * m1, monomial const * m2) {
610         if (m1 == m2)
611             return 0;
612         int sz1  = m1->size();
613         int sz2  = m2->size();
614         int idx1 = sz1 - 1;
615         int idx2 = sz2 - 1;
616         while (idx1 >= 0 && idx2 >= 0) {
617             power const & pw1 = m1->get_power(idx1);
618             power const & pw2 = m2->get_power(idx2);
619             if (pw1.get_var() == pw2.get_var()) {
620                 if (pw1.degree() == pw2.degree()) {
621                     idx1--;
622                     idx2--;
623                     continue;
624                 }
625                 return pw1.degree() < pw2.degree() ? -1 : 1;
626             }
627             return pw1.get_var() > pw2.get_var() ? 1 : -1;
628         }
629         SASSERT(idx1 >= 0 || idx2 >= 0);
630         SASSERT(idx1 < 0  || idx2 < 0);
631         return idx1 < 0 ? -1 : 1;
632     }
633 
634     /**
635        Similar to lex_compare, but min_var is assumed to be the minimal variable.
636     */
lex_compare2(monomial const * m1,monomial const * m2,var min_var)637     int lex_compare2(monomial const * m1, monomial const * m2, var min_var) {
638         if (m1 == m2)
639             return 0;
640         int sz1  = m1->size();
641         int sz2  = m2->size();
642         int idx1 = sz1 - 1;
643         int idx2 = sz2 - 1;
644         unsigned min_var_degree1 = 0;
645         unsigned min_var_degree2 = 0;
646         while (idx1 >= 0 && idx2 >= 0) {
647             power const & pw1 = m1->get_power(idx1);
648             power const & pw2 = m2->get_power(idx2);
649             if (pw1.get_var() == min_var) {
650                 min_var_degree1 = pw1.degree();
651                 idx1--;
652                 if (pw2.get_var() == min_var) {
653                     min_var_degree2 = pw2.degree();
654                     idx2--;
655                 }
656                 continue;
657             }
658             if (pw2.get_var() == min_var) {
659                 min_var_degree2 = pw2.degree();
660                 idx2--;
661                 continue;
662             }
663             if (pw1.get_var() == pw2.get_var()) {
664                 if (pw1.degree() == pw2.degree()) {
665                     idx1--;
666                     idx2--;
667                     continue;
668                 }
669                 return pw1.degree() < pw2.degree() ? -1 : 1;
670             }
671             return pw1.get_var() > pw2.get_var() ? 1 : -1;
672         }
673         if (idx1 == idx2) {
674             SASSERT(min_var_degree1 != min_var_degree2);
675             return min_var_degree1 < min_var_degree2 ? -1 : 1;
676         }
677         return idx1 < 0 ? -1 : 1;
678     }
679 
680     struct lex_lt2 {
681         var m_min;
lex_lt2polynomial::lex_lt2682         lex_lt2(var m):m_min(m) {}
operator ()polynomial::lex_lt2683         bool operator()(monomial * m1, monomial * m2) const {
684             TRACE("lex_bug", tout << "min: x" << m_min << "\n"; m1->display(tout); tout << "\n"; m2->display(tout); tout << "\n";);
685             return lex_compare2(m1, m2, m_min) < 0;
686         }
687     };
688 
689     /**
690        \brief Compare m1 and m2 using a graded lexicographical order
691 
692        \see lex_compare
693     */
graded_lex_compare(monomial const * m1,monomial const * m2)694     int graded_lex_compare(monomial const * m1, monomial const * m2) {
695         unsigned t1 = m1->total_degree();
696         unsigned t2 = m2->total_degree();
697         if (t1 == t2)
698             return lex_compare(m1, m2);
699         else
700             return t1 < t2 ? -1 : 1;
701     }
702 
703     /**
704        \brief Compare submonomials m1[start1, end1) and m2[start2, end2) using reverse lexicographical order
705     */
rev_lex_compare(monomial const * m1,unsigned start1,unsigned end1,monomial const * m2,unsigned start2,unsigned end2)706     int rev_lex_compare(monomial const * m1, unsigned start1, unsigned end1, monomial const * m2, unsigned start2, unsigned end2) {
707         SASSERT(end1 >= start1);
708         SASSERT(end2 >= start2);
709         unsigned idx1 = end1;
710         unsigned idx2 = end2;
711         while(idx1 > start1 && idx2 > start2) {
712             --idx1;
713             --idx2;
714             power const & pw1 = m1->get_power(idx1);
715             power const & pw2 = m2->get_power(idx2);
716             if (pw1.get_var() == pw2.get_var()) {
717                 if (pw1.degree() == pw2.degree()) {
718                     // Remark: the submonomials have the same total degree, but they are not equal. So, idx1 > 0 and idx2 > 0.
719                     SASSERT(idx1 > start1 && idx2 > start2);
720                     continue;
721                 }
722                 return pw1.degree() > pw2.degree() ? -1 : 1;
723             }
724             return pw1.get_var() > pw2.get_var() ? -1 : 1;
725         }
726         SASSERT(idx1 == start1 || idx2 == start2);
727         if (idx1 == start1)
728             return idx2 == start2 ? 0 : -1;
729         SASSERT(idx2 == start2 && idx1 != start1);
730         return 1;
731     }
732 
733     /**
734        \brief Compare m1 and m2 using reverse lexicographical order.
735 
736        \see lex_compare
737     */
rev_lex_compare(monomial const * m1,monomial const * m2)738     int rev_lex_compare(monomial const * m1, monomial const * m2) {
739         if (m1 == m2)
740             return 0;
741         return rev_lex_compare(m1, 0, m1->size(), m2, 0, m2->size());
742     }
743 
744     /**
745        \brief Compare m1 and m2 using graded reverse lexicographical order.
746 
747        \see lex_compare
748     */
graded_rev_lex_compare(monomial const * m1,monomial const * m2)749     int graded_rev_lex_compare(monomial const * m1, monomial const * m2) {
750         unsigned t1 = m1->total_degree();
751         unsigned t2 = m2->total_degree();
752         if (t1 == t2)
753             return rev_lex_compare(m1, m2);
754         else
755             return t1 < t2 ? -1 : 1;
756     }
757 
758     struct graded_lex_gt {
operator ()polynomial::graded_lex_gt759         bool operator()(monomial const * m1, monomial const * m2) { return graded_lex_compare(m1, m2) < 0; }
760     };
761 
762     /**
763        \brief
764     */
765     class monomial_manager {
766         unsigned                 m_ref_count;
767         small_object_allocator * m_allocator;
768         bool                     m_own_allocator;
769         monomial_table           m_monomials;
770         id_gen                   m_mid_gen; // id generator for monomials
771         unsigned                 m_next_var;
772         monomial *               m_unit;
773         tmp_monomial             m_mk_tmp;
774         tmp_monomial             m_tmp1;
775         tmp_monomial             m_tmp2;
776         tmp_monomial             m_tmp3;
777         svector<power>           m_powers_tmp;
778     public:
monomial_manager(small_object_allocator * a=nullptr)779         monomial_manager(small_object_allocator * a = nullptr) {
780             m_ref_count = 0;
781             m_next_var  = 0;
782             if (a == nullptr) {
783                 m_allocator     = alloc(small_object_allocator, "polynomial");
784                 m_own_allocator = true;
785             }
786             else {
787                 m_allocator     = a;
788                 m_own_allocator = false;
789             }
790             m_unit = mk_monomial(0, static_cast<power const *>(nullptr));
791             inc_ref(m_unit);
792         }
793 
~monomial_manager()794         ~monomial_manager() {
795             dec_ref(m_unit);
796             CTRACE("polynomial", !m_monomials.empty(),
797                    tout << "monomials leaked (can happen during cancelation)\n";
798                    for (auto * m : m_monomials) {
799                        m->display(tout << m->id() << " " << m->ref_count() << " ") << "\n";
800                    });
801             for (monomial* m : m_monomials) {
802                 unsigned obj_sz = monomial::get_obj_size(m->size());
803                 m_allocator->deallocate(obj_sz, m);
804             }
805             m_monomials.reset();
806             if (m_own_allocator)
807                 dealloc(m_allocator);
808         }
809 
inc_ref()810         void inc_ref() {
811             m_ref_count++;
812         }
813 
dec_ref()814         void dec_ref() {
815             SASSERT(m_ref_count > 0);
816             m_ref_count--;
817             if (m_ref_count == 0)
818                 dealloc(this);
819         }
820 
allocator()821         small_object_allocator & allocator() { return *m_allocator; }
822 
mk_var()823         var mk_var() {
824             var r = m_next_var;
825             m_next_var++;
826             return r;
827         }
828 
num_vars() const829         unsigned num_vars() const {
830             return m_next_var;
831         }
832 
is_valid(var x) const833         bool is_valid(var x) const {
834             return x < m_next_var;
835         }
836 
del(monomial * m)837         void del(monomial * m) {
838             unsigned obj_sz = monomial::get_obj_size(m->size());
839             m_monomials.erase(m);
840             m_mid_gen.recycle(m->id());
841             m_allocator->deallocate(obj_sz, m);
842         }
843 
inc_ref(monomial * m)844         void inc_ref(monomial * m) {
845             m->inc_ref();
846         }
847 
dec_ref(monomial * m)848         void dec_ref(monomial * m) {
849             m->dec_ref();
850             if (m->ref_count() == 0)
851                 del(m);
852         }
853 
mk_unit()854         monomial * mk_unit() { return m_unit; }
855 
mk_monomial(tmp_monomial & tmp)856         monomial * mk_monomial(tmp_monomial & tmp) {
857             monomial * tmp_ptr = tmp.get_ptr();
858             monomial * & m = m_monomials.insert_if_not_there(tmp_ptr);
859             if (m != tmp_ptr)
860                 return m;
861             void * mem   = m_allocator->allocate(monomial::get_obj_size(tmp_ptr->size()));
862             unsigned id  = m_mid_gen.mk();
863             monomial * r = new (mem) monomial(id, tmp_ptr->size(), tmp_ptr->get_powers(), tmp_ptr->hash());
864             m            = r;
865             SASSERT(m_monomials.contains(r));
866             SASSERT(*(m_monomials.find_core(r)) == r);
867             return r;
868         }
869 
mk_monomial(unsigned sz,power const * pws)870         monomial * mk_monomial(unsigned sz, power const * pws) {
871             SASSERT(is_valid_power_product(sz, pws));
872             m_mk_tmp.init(sz, pws);
873             return mk_monomial(m_mk_tmp);
874         }
875 
convert(monomial const * src)876         monomial * convert(monomial const * src) {
877             unsigned sz = src->size();
878             for (unsigned i = 0; i < sz; i++) {
879                 var x = src->get_var(i);
880                 while (x >= num_vars()) {
881                     mk_var();
882                 }
883                 SASSERT(x < num_vars());
884             }
885             return mk_monomial(src->size(), src->get_powers());
886         }
887 
mk_monomial(var x)888         monomial * mk_monomial(var x) {
889             SASSERT(is_valid(x));
890             power pw(x, 1);
891             return mk_monomial(1, &pw);
892         }
893 
mk_monomial(var x,unsigned k)894         monomial * mk_monomial(var x, unsigned k) {
895             if (k == 0)
896                 return m_unit;
897             SASSERT(is_valid(x));
898             power pw(x, k);
899             return mk_monomial(1, &pw);
900         }
901 
mk_monomial(unsigned sz,var * xs)902         monomial * mk_monomial(unsigned sz, var * xs) {
903             if (sz == 0)
904                 return m_unit;
905             if (sz == 1)
906                 return mk_monomial(xs[0]);
907             m_powers_tmp.reset();
908             std::sort(xs, xs+sz);
909             SASSERT(is_valid(xs[0]));
910             m_powers_tmp.push_back(power(xs[0], 1));
911             for (unsigned i = 1; i < sz; i++) {
912                 var x = xs[i];
913                 SASSERT(is_valid(x));
914                 power & last = m_powers_tmp.back();
915                 if (x == last.get_var())
916                     last.degree()++;
917                 else
918                     m_powers_tmp.push_back(power(x, 1));
919             }
920             return mk_monomial(m_powers_tmp.size(), m_powers_tmp.c_ptr());
921         }
922 
mul(unsigned sz1,power const * pws1,unsigned sz2,power const * pws2)923         monomial * mul(unsigned sz1, power const * pws1, unsigned sz2, power const * pws2) {
924             SASSERT(is_valid_power_product(sz1, pws1));
925             SASSERT(is_valid_power_product(sz2, pws2));
926             tmp_monomial & product_tmp = m_tmp1;
927             product_tmp.reserve(sz1 + sz2); // product has at most sz1 + sz2 powers
928             unsigned i1 = 0, i2 = 0;
929             unsigned j  = 0;
930             while (true) {
931                 if (i1 == sz1) {
932                     // copy 2
933                     for (; i2 < sz2; i2++, j++)
934                         product_tmp.set_power(j, pws2[i2]);
935                     break;
936                 }
937                 if (i2 == sz2) {
938                     // copy 1
939                     for (; i1 < sz1; i1++, j++)
940                         product_tmp.set_power(j, pws1[i1]);
941                     break;
942                 }
943                 power const & pw1 = pws1[i1];
944                 power const & pw2 = pws2[i2];
945                 unsigned v1 = pw1.get_var();
946                 unsigned v2 = pw2.get_var();
947                 if (v1 == v2) {
948                     product_tmp.set_power(j, power(v1, pw1.degree() + pw2.degree()));
949                     i1++;
950                     i2++;
951                 }
952                 else if (v1 < v2) {
953                     product_tmp.set_power(j, pw1);
954                     i1++;
955                 }
956                 else {
957                     SASSERT(v1 > v2);
958                     product_tmp.set_power(j, pw2);
959                     i2++;
960                 }
961                 j++;
962             }
963             product_tmp.set_size(j);
964             TRACE("monomial_mul_bug",
965                   tout << "before mk_monomial\n";
966                   tout << "pws1: "; for (unsigned i = 0; i < sz1; i++) tout << pws1[i] << " "; tout << "\n";
967                   tout << "pws2: "; for (unsigned i = 0; i < sz2; i++) tout << pws2[i] << " "; tout << "\n";
968                   tout << "product_tmp: "; for (unsigned i = 0; i < product_tmp.size(); i++) tout << product_tmp.get_power(i) << " ";
969                   tout << "\n";);
970             monomial * r = mk_monomial(product_tmp);
971             TRACE("monomial_mul_bug",
972                   tout << "j: " << j << "\n";
973                   tout << "r: "; r->display(tout); tout << "\n";
974                   tout << "pws1: "; for (unsigned i = 0; i < sz1; i++) tout << pws1[i] << " "; tout << "\n";
975                   tout << "pws2: "; for (unsigned i = 0; i < sz2; i++) tout << pws2[i] << " "; tout << "\n";
976                   tout << "product_tmp: "; for (unsigned i = 0; i < product_tmp.size(); i++) tout << product_tmp.get_power(i) << " ";
977                   tout << "\n";);
978             SASSERT(r->is_valid());
979             SASSERT(r->total_degree() == power_product_total_degree(sz1, pws1) + power_product_total_degree(sz2, pws2));
980             return r;
981         }
982 
mul(monomial const * m1,monomial const * m2)983         monomial * mul(monomial const * m1, monomial const * m2) {
984             if (m1 == m_unit)
985                 return const_cast<monomial*>(m2);
986             if (m2 == m_unit)
987                 return const_cast<monomial*>(m1);
988             return mul(m1->size(), m1->get_powers(), m2->size(), m2->get_powers());
989         }
990 
991 
992         template<bool STORE_RESULT>
div_core(unsigned sz1,power const * pws1,unsigned sz2,power const * pws2,tmp_monomial & r)993         bool div_core(unsigned sz1, power const * pws1, unsigned sz2, power const * pws2, tmp_monomial & r) {
994             if (STORE_RESULT)
995                 r.reserve(sz1); // r has at most sz1 arguments.
996             unsigned i1  = 0;
997             unsigned i2  = 0;
998             unsigned j   = 0;
999             if (sz1 < sz2)
1000                 return false; // pws2 does not divide pws1
1001             while (true) {
1002                 if (i2 == sz2) {
1003                     if (STORE_RESULT) {
1004                         for (; i1 < sz1; i1++, j++)
1005                             r.set_power(j, pws1[i1]);
1006                         r.set_size(j);
1007                     }
1008                     return true;
1009                 }
1010                 if (i1 == sz1)
1011                     return false; // pws2 does not divide pws1
1012                 power const & pw1 = pws1[i1];
1013                 power const & pw2 = pws2[i2];
1014                 unsigned v1 = pw1.get_var();
1015                 unsigned v2 = pw2.get_var();
1016                 if (v1 == v2) {
1017                     unsigned d1 = pw1.degree();
1018                     unsigned d2 = pw2.degree();
1019                     if (d1 < d2)
1020                         return false; // pws2 does not divide pws1
1021                     if (STORE_RESULT) {
1022                         if (d1 > d2) {
1023                             r.set_power(j, power(v1, d1 - d2));
1024                             j++;
1025                         }
1026                     }
1027                     i1++;
1028                     i2++;
1029                 }
1030                 else if (v1 < v2) {
1031                     if (STORE_RESULT) {
1032                         r.set_power(j, pw1);
1033                         j++;
1034                     }
1035                     i1++;
1036                 }
1037                 else {
1038                     SASSERT(v1 > v2);
1039                     return false; // pws2 does not divide pws1
1040                 }
1041             }
1042         }
1043 
div(monomial const * m1,monomial const * m2)1044         bool div(monomial const * m1, monomial const * m2) {
1045             if (m1->total_degree() < m2->total_degree())
1046                 return false;
1047             if (m1 == m2)
1048                 return true;
1049             return div_core<false>(m1->size(), m1->get_powers(), m2->size(), m2->get_powers(), m_tmp1);
1050         }
1051 
div(monomial const * m1,monomial const * m2,monomial_ref & r)1052         bool div(monomial const * m1, monomial const * m2, monomial_ref & r) {
1053             if (m1->total_degree() < m2->total_degree())
1054                 return false;
1055             if (m1 == m2) {
1056                 r = m_unit;
1057                 return true;
1058             }
1059             tmp_monomial & div_tmp = m_tmp1;
1060             if (div_core<true>(m1->size(), m1->get_powers(), m2->size(), m2->get_powers(), div_tmp)) {
1061                 r = mk_monomial(div_tmp);
1062                 return true;
1063             }
1064             return false;
1065         }
1066 
1067         /**
1068             \brief Compute the gcd of pws1 and pws2, store it in g, and pws1/g in r1, and pws2/g in r2
1069             Return true if the gcd is not 1. If the result is false, then g, r1 and r2 should not be used.
1070         */
gcd_core(unsigned sz1,power const * pws1,unsigned sz2,power const * pws2,tmp_monomial & g,tmp_monomial & r1,tmp_monomial & r2)1071         bool gcd_core(unsigned sz1, power const * pws1, unsigned sz2, power const * pws2, tmp_monomial & g, tmp_monomial & r1, tmp_monomial & r2) {
1072             g.reserve(std::min(sz1, sz2));
1073             r1.reserve(sz2); // r1 has at most num_args2 arguments
1074             r2.reserve(sz1); // r2 has at most num_args1 arguments
1075             bool found  = false;
1076             unsigned i1 = 0;
1077             unsigned i2 = 0;
1078             unsigned j1 = 0;
1079             unsigned j2 = 0;
1080             unsigned j3 = 0;
1081             while (true) {
1082                 if (i1 == sz1) {
1083                     if (found) {
1084                         for (; i2 < sz2; i2++, j2++)
1085                             r2.set_power(j2, pws2[i2]);
1086                         r1.set_size(j1);
1087                         r2.set_size(j2);
1088                         g.set_size(j3);
1089                         return true;
1090                     }
1091                     return false;
1092                 }
1093                 if (i2 == sz2) {
1094                     if (found) {
1095                         for (; i1 < sz1; i1++, j1++)
1096                             r1.set_power(j1, pws1[i1]);
1097                         r1.set_size(j1);
1098                         r2.set_size(j2);
1099                         g.set_size(j3);
1100                         return true;
1101                     }
1102                     return false;
1103                 }
1104                 power const & pw1 = pws1[i1];
1105                 power const & pw2 = pws2[i2];
1106                 unsigned v1 = pw1.get_var();
1107                 unsigned v2 = pw2.get_var();
1108                 if (v1 == v2) {
1109                     found = true;
1110                     unsigned d1 = pw1.degree();
1111                     unsigned d2 = pw2.degree();
1112                     if (d1 > d2) {
1113                         r1.set_power(j1, power(v1, d1 - d2));
1114                         g.set_power(j3, pw2);
1115                         j1++;
1116                         j3++;
1117                     }
1118                     else if (d2 > d1) {
1119                         r2.set_power(j2, power(v2, d2 - d1));
1120                         g.set_power(j3, pw1);
1121                         j2++;
1122                         j3++;
1123                     }
1124                     else {
1125                         SASSERT(d1 == d2);
1126                         g.set_power(j3, pw1);
1127                         j3++;
1128                     }
1129                     i1++;
1130                     i2++;
1131                 }
1132                 else if (v1 < v2) {
1133                     r1.set_power(j1, pw1);
1134                     j1++;
1135                     i1++;
1136                 }
1137                 else {
1138                     SASSERT(v1 > v2);
1139                     r2.set_power(j2, pw2);
1140                     j2++;
1141                     i2++;
1142                 }
1143             }
1144         }
1145 
gcd(monomial const * m1,monomial const * m2,monomial * & q1,monomial * & q2)1146         monomial * gcd(monomial const * m1, monomial const * m2, monomial * & q1, monomial * & q2) {
1147             if (gcd_core(m1->size(), m1->get_powers(), m2->size(), m2->get_powers(), m_tmp1, m_tmp2, m_tmp3)) {
1148                 q1 = mk_monomial(m_tmp2);
1149                 q2 = mk_monomial(m_tmp3);
1150                 return mk_monomial(m_tmp1);
1151             }
1152             else {
1153                 // gcd is one
1154                 q1 = const_cast<monomial*>(m2);
1155                 q2 = const_cast<monomial*>(m1);
1156                 return m_unit;
1157             }
1158         }
1159 
unify(monomial const * m1,monomial const * m2,monomial * & q1,monomial * & q2)1160         bool unify(monomial const * m1, monomial const * m2, monomial * & q1, monomial * & q2) {
1161             if (gcd_core(m1->size(), m1->get_powers(), m2->size(), m2->get_powers(), m_tmp1, m_tmp2, m_tmp3)) {
1162                 q1 = mk_monomial(m_tmp2);
1163                 q2 = mk_monomial(m_tmp3);
1164                 return true;
1165             }
1166             return false;
1167         }
1168 
pw(monomial const * m,unsigned k)1169         monomial * pw(monomial const * m, unsigned k) {
1170             if (k == 0)
1171                 return m_unit;
1172             if (k == 1)
1173                 return const_cast<monomial*>(m);
1174             unsigned sz = m->size();
1175             tmp_monomial & pw_tmp = m_tmp1;
1176             pw_tmp.reserve(sz);
1177             for (unsigned i = 0; i < sz; i++)
1178                 pw_tmp.set_power(i, power(m->get_var(i), m->degree(i)*k));
1179             pw_tmp.set_size(sz);
1180             return mk_monomial(pw_tmp);
1181         }
1182 
sqrt(monomial const * m)1183         monomial * sqrt(monomial const * m) {
1184             SASSERT(m_unit != 0);
1185             if (m == m_unit)
1186                 return m_unit;
1187             unsigned sz = m->size();
1188             tmp_monomial & sqrt_tmp = m_tmp1;
1189             sqrt_tmp.reserve(sz);
1190             for (unsigned i = 0; i < sz; i++) {
1191                 if (m->degree(i) % 2 == 1)
1192                     return nullptr;
1193                 sqrt_tmp.set_power(i, power(m->get_var(i), m->degree(i) / 2));
1194             }
1195             sqrt_tmp.set_size(sz);
1196             return mk_monomial(sqrt_tmp);
1197         }
1198 
1199         /**
1200            \brief Return m/x^k
1201         */
div_x_k(monomial const * m,var x,unsigned k)1202         monomial * div_x_k(monomial const * m, var x, unsigned k) {
1203             SASSERT(is_valid(x));
1204             unsigned sz = m->size();
1205             tmp_monomial & elim_tmp = m_tmp1;
1206             elim_tmp.reserve(sz);
1207             unsigned j = 0;
1208             for (unsigned i = 0; i < sz; i++) {
1209                 power const & pw = m->get_power(i);
1210                 var y = pw.get_var();
1211                 if (x != y) {
1212                     elim_tmp.set_power(j, pw);
1213                     j++;
1214                 }
1215                 else {
1216                     SASSERT(k <= pw.degree());
1217                     unsigned d = pw.degree();
1218                     if (k < d) {
1219                         elim_tmp.set_power(j, power(y, d - k));
1220                         j++;
1221                     }
1222                 }
1223             }
1224             elim_tmp.set_size(j);
1225             return mk_monomial(elim_tmp);
1226         }
1227 
1228         /**
1229            \brief Return m/x^n  where n == m->degree_of(x)
1230         */
div_x(monomial const * m,var x)1231         monomial * div_x(monomial const * m, var x) {
1232             SASSERT(is_valid(x));
1233             unsigned sz = m->size();
1234             tmp_monomial & elim_tmp = m_tmp1;
1235             elim_tmp.reserve(sz);
1236             unsigned j = 0;
1237             for (unsigned i = 0; i < sz; i++) {
1238                 power const & pw = m->get_power(i);
1239                 var y = pw.get_var();
1240                 if (x != y) {
1241                     elim_tmp.set_power(j, pw);
1242                     j++;
1243                 }
1244             }
1245             elim_tmp.set_size(j);
1246             return mk_monomial(elim_tmp);
1247         }
1248 
derivative(monomial const * m,var x)1249         monomial * derivative(monomial const * m, var x) {
1250             SASSERT(is_valid(x));
1251             unsigned sz = m->size();
1252             tmp_monomial & derivative_tmp = m_tmp1;
1253             derivative_tmp.reserve(sz);
1254             unsigned j = 0;
1255             for (unsigned i = 0; i < sz; i++) {
1256                 power const & pw = m->get_power(i);
1257                 var y = pw.get_var();
1258                 if (x == y) {
1259                     unsigned d = pw.degree();
1260                     if (d > 1) {
1261                         derivative_tmp.set_power(j, power(y, d-1));
1262                         j++;
1263                     }
1264                 }
1265                 else {
1266                     derivative_tmp.set_power(j, pw);
1267                     j++;
1268                 }
1269             }
1270             derivative_tmp.set_size(j);
1271             return mk_monomial(derivative_tmp);
1272         }
1273 
rename(unsigned sz,var const * xs)1274         void rename(unsigned sz, var const * xs) {
1275             SASSERT(m_ref_count <= 1);
1276             SASSERT(sz == num_vars());
1277             DEBUG_CODE({
1278                 // check whether xs is really a permutation
1279                 bool_vector found;
1280                 found.resize(num_vars(), false);
1281                 for (unsigned i = 0; i < sz; i++) {
1282                     SASSERT(xs[i] < num_vars());
1283                     SASSERT(!found[xs[i]]);
1284                     found[xs[i]] = true;
1285                 }
1286             });
1287             monomial_table new_table;
1288             monomial_table::iterator it  = m_monomials.begin();
1289             monomial_table::iterator end = m_monomials.end();
1290             for (; it != end; ++it) {
1291                 monomial * m = *it;
1292                 m->rename(sz, xs);
1293                 SASSERT(!new_table.contains(m));
1294                 new_table.insert(m);
1295             }
1296             m_monomials.swap(new_table);
1297         }
1298 
1299     };
1300 
1301 
1302     /**
1303        We maintain the following invariant:
1304        The first monomial m of every non-zero polynomial p contains:
1305           1) the maximal variable x of p,
1306           2) and the degree of x in m is maximal in p.
1307     */
1308     class polynomial {
1309     public:
1310         typedef manager::numeral    numeral;
1311     private:
1312         unsigned     m_ref_count;
1313         unsigned     m_id:31;
1314         unsigned     m_lex_sorted:1;
1315         unsigned     m_size;
1316         numeral *    m_as;
1317         monomial **  m_ms;
1318 
lex_sort(unsigned start,unsigned end,var x,vector<unsigned_vector> & buckets,unsigned_vector & p)1319         void lex_sort(unsigned start, unsigned end, var x, vector<unsigned_vector> & buckets, unsigned_vector & p) {
1320             SASSERT(end > start);
1321             unsigned max_degree = 0;
1322             for (unsigned i = start, j = 0; i < end; i++, j++) {
1323                 monomial * m = m_ms[i];
1324                 unsigned d = m->degree_of(x);
1325                 buckets.reserve(d+1);
1326                 buckets[d].push_back(j);
1327                 if (d > max_degree)
1328                     max_degree = d;
1329             }
1330             p.reset();
1331             unsigned i = max_degree + 1;
1332             while (i > 0) {
1333                 --i;
1334                 p.append(buckets[i]);
1335                 buckets[i].reset();
1336             }
1337             SASSERT(p.size() == end - start);
1338             apply_permutation(p.size(), m_as + start, p.c_ptr());
1339             apply_permutation_core(p.size(), m_ms + start, p.c_ptr()); // p is not needed anymore after this command
1340             i = start;
1341             while (i < end) {
1342                 monomial * m = m_ms[i];
1343                 unsigned d   = m->degree_of(x);
1344                 if (d == 0) {
1345                     // x does not occur in m
1346                     // since we sorted, x should not in the rest
1347                     // we should find the maximal variable variable smaller than x in [i, end)
1348                     var y = max_smaller_than(i, end, x);
1349                     if (y != null_var)
1350                         lex_sort(i, end, y, buckets, p);
1351                     return;
1352                 }
1353                 unsigned j = i + 1;
1354                 for (; j < end; j++) {
1355                     unsigned d_j   = m_ms[j]->degree_of(x);
1356                     SASSERT(d_j <= d); // it is sorted
1357                     if (d_j < d)
1358                         break;
1359                 }
1360                 SASSERT(j == end || m_ms[j]->degree_of(x) < d);
1361                 // sort interval [i, j) using the maximal variable y smaller than x
1362                 if (j > i + 1) {
1363                     // only need to sort if the interval has more than one element.
1364                     var y = max_smaller_than(i, j, x);
1365                     if (y != null_var)
1366                         lex_sort(i, j, y, buckets, p);
1367                 }
1368                 i = j;
1369             }
1370         }
1371 
1372     public:
ref_count() const1373         unsigned ref_count() const { return m_ref_count; }
inc_ref()1374         void inc_ref() { m_ref_count++; }
dec_ref()1375         void dec_ref() { SASSERT(m_ref_count > 0); m_ref_count--; }
1376 
get_obj_size(unsigned n)1377         static unsigned get_obj_size(unsigned n) { return sizeof(polynomial) + n * (sizeof(numeral) + sizeof(monomial*)); }
1378 
1379         /**
1380            \brief Partial order used to implement the polynomial invariant that guarantees
1381            that the first monomial contains the maximal variable in the polynomial, and it
1382            occurs with maximal degree.
1383 
1384            Return true if m1 > m2 in this partial order.
1385         */
po_gt(monomial const * m1,monomial const * m2)1386         static bool po_gt(monomial const * m1, monomial const * m2) {
1387             if (m1->size() == 0)
1388                 return false;
1389             if (m2->size() == 0)
1390                 return true;
1391             if (m1->max_var() < m2->max_var())
1392                 return false;
1393             if (m1->max_var() > m2->max_var())
1394                 return true;
1395             SASSERT(m1->max_var() == m2->max_var());
1396             return m1->max_var_degree() > m2->max_var_degree();
1397         }
1398 
1399         // swap monomials at positions 0 and pos
swap_0_pos(unsigned pos)1400         void swap_0_pos(unsigned pos) {
1401             if (pos != 0) {
1402                 swap(m_as[0], m_as[pos]);
1403                 std::swap(m_ms[0], m_ms[pos]);
1404             }
1405         }
1406 
polynomial(mpzzp_manager & nm,unsigned id,unsigned sz,numeral * as,monomial * const * ms,numeral * as_mem,monomial ** ms_mem)1407         polynomial(mpzzp_manager & nm, unsigned id, unsigned sz, numeral * as, monomial * const * ms, numeral * as_mem, monomial ** ms_mem):
1408             m_ref_count(0),
1409             m_id(id),
1410             m_lex_sorted(false),
1411             m_size(sz),
1412             m_as(as_mem),
1413             m_ms(ms_mem) {
1414             if (sz > 0) {
1415                 unsigned max_pos = 0;
1416                 for (unsigned i = 0; i < sz; i++) {
1417                     new (m_as + i) numeral(); // initialize the big number at m_as[i]
1418                     swap(m_as[i], as[i]);
1419                     SASSERT(ms[i]->ref_count() > 0);
1420                     m_ms[i] = ms[i];
1421                     if (i > 0 && po_gt(m_ms[i], m_ms[max_pos]))
1422                         max_pos = i;
1423                 }
1424                 swap_0_pos(max_pos);
1425             }
1426         }
1427 
1428         // Return the maximal variable y occurring in [m_ms + start, m_ms + end) that is smaller than x
max_smaller_than(unsigned start,unsigned end,var x)1429         var max_smaller_than(unsigned start, unsigned end, var x) {
1430             var max = null_var;
1431             for (unsigned i = start; i < end; i++) {
1432                 var y = m_ms[i]->max_smaller_than(x);
1433                 if (y != null_var && (max == null_var || y > max))
1434                     max = y;
1435             }
1436             return max;
1437         }
1438 
lex_sorted() const1439         bool lex_sorted() const {
1440             return m_lex_sorted;
1441         }
1442 
1443         // Put monomials in lexicographical order
lex_sort(vector<unsigned_vector> & buckets,unsigned_vector & p,mpzzp_manager & nm)1444         void lex_sort(vector<unsigned_vector> & buckets, unsigned_vector & p, mpzzp_manager & nm) {
1445             if (m_lex_sorted)
1446                 return;
1447             if (size() <= 1) {
1448                 m_lex_sorted = true;
1449                 return;
1450             }
1451             lex_sort(0, size(), m(0)->max_var(), buckets, p);
1452             m_lex_sorted = true;
1453             DEBUG_CODE({
1454                 for (unsigned i = 0; i < m_size - 1; i++) {
1455                     CTRACE("poly_bug", lex_compare(m_ms[i], m_ms[i+1]) <= 0,
1456                            tout << "i: " << i << "\npoly: "; display(tout, nm); tout << "\n";);
1457                     SASSERT(lex_compare(m_ms[i], m_ms[i+1]) > 0);
1458                 }
1459             });
1460         }
1461 
1462         /**
1463            \brief Make sure that the first monomial contains the maximal variable x occurring in the polynomial,
1464            and x occurs with maximal degree.
1465         */
make_first_maximal()1466         void make_first_maximal() {
1467             if (m_size <= 1)
1468                 return;
1469             unsigned max_pos = 0;
1470             for (unsigned i = 1; i < m_size; i++) {
1471                 if (po_gt(m_ms[i], m_ms[max_pos]))
1472                     max_pos = i;
1473             }
1474             swap_0_pos(max_pos);
1475             m_lex_sorted = false;
1476         }
1477 
1478         /**
1479            \brief Return the position of the maximal monomial with
1480            respect to graded lexicographical order.  Return UINT_MAX
1481            if polynomial is zero.
1482         */
graded_lex_max_pos() const1483         unsigned graded_lex_max_pos() const {
1484             if (m_size == 0)
1485                 return UINT_MAX;
1486             unsigned max_pos = 0;
1487             for (unsigned i = 1; i < m_size; i++) {
1488                 if (graded_lex_compare(m_ms[i], m_ms[max_pos]) > 0)
1489                     max_pos = i;
1490             }
1491             return max_pos;
1492         }
1493 
1494         /**
1495            \brief Return the position of the minimal monomial with
1496            respect to graded lexicographical order.  Return UINT_MAX
1497            if polynomial is zero.
1498         */
graded_lex_min_pos() const1499         unsigned graded_lex_min_pos() const {
1500             if (m_size == 0)
1501                 return UINT_MAX;
1502             unsigned min_pos = 0;
1503             for (unsigned i = 1; i < m_size; i++) {
1504                 if (graded_lex_compare(m_ms[i], m_ms[min_pos]) < 0)
1505                     min_pos = i;
1506             }
1507             return min_pos;
1508         }
1509 
id() const1510         unsigned id() const { return m_id; }
size() const1511         unsigned size() const { return m_size; }
m(unsigned idx) const1512         monomial * m(unsigned idx) const { SASSERT(idx < size()); return m_ms[idx]; }
begin() const1513         monomial *const* begin() const { return m_ms; }
end() const1514         monomial *const* end() const { return m_ms + size(); }
a(unsigned idx) const1515         numeral const & a(unsigned idx) const { SASSERT(idx < size()); return m_as[idx]; }
a(unsigned idx)1516         numeral & a(unsigned idx) { SASSERT(idx < size()); return m_as[idx]; }
as() const1517         numeral const * as() const { return m_as; }
1518 
is_zero() const1519         bool is_zero() const { return m_size == 0; }
1520 
display(std::ostream & out,mpzzp_manager & nm,display_var_proc const & proc=display_var_proc (),bool use_star=false) const1521         std::ostream& display(std::ostream & out, mpzzp_manager & nm, display_var_proc const & proc = display_var_proc(), bool use_star = false) const {
1522             if (is_zero()) {
1523                 out << "0";
1524                 return out;
1525             }
1526 
1527             for (unsigned i = 0; i < m_size; i++) {
1528                 numeral const & a_i = a(i);
1529                 _scoped_numeral<mpzzp_manager> abs_a_i(nm);
1530                 nm.set(abs_a_i, a_i);
1531                 nm.abs(abs_a_i);
1532 
1533                 numeral const & a_prime = abs_a_i;
1534                 if (i > 0) {
1535                     if (nm.is_neg(a_i))
1536                         out << " - ";
1537                     else
1538                         out << " + ";
1539                 }
1540                 else {
1541                     if (nm.is_neg(a_i))
1542                         out << "- ";
1543                 }
1544 
1545                 if (m(i)->is_unit()) {
1546                     out << nm.to_string(a_prime);
1547                 }
1548                 else if (nm.is_one(a_prime)) {
1549                     m(i)->display(out, proc, use_star);
1550                 }
1551                 else {
1552                     out << nm.to_string(a_prime);
1553                     if (use_star)
1554                         out << "*";
1555                     else
1556                         out << " ";
1557                     m(i)->display(out, proc, use_star);
1558                 }
1559             }
1560             return out;
1561         }
1562 
display_num_smt2(std::ostream & out,mpzzp_manager & nm,numeral const & a)1563         static void display_num_smt2(std::ostream & out, mpzzp_manager & nm, numeral const & a) {
1564             if (nm.is_neg(a)) {
1565                 out << "(- ";
1566                 _scoped_numeral<mpzzp_manager> abs_a(nm);
1567                 nm.set(abs_a, a);
1568                 nm.neg(abs_a);
1569                 nm.display(out, abs_a);
1570                 out << ")";
1571             }
1572             else {
1573                 nm.display(out, a);
1574             }
1575         }
1576 
display_mon_smt2(std::ostream & out,mpzzp_manager & nm,display_var_proc const & proc,unsigned i) const1577         void display_mon_smt2(std::ostream & out, mpzzp_manager & nm, display_var_proc const & proc, unsigned i) const {
1578             SASSERT(i < m_size);
1579             monomial const * m_i = m(i);
1580             numeral const &  a_i = a(i);
1581             if (m_i->size() == 0) {
1582                 display_num_smt2(out, nm, a_i);
1583             }
1584             else if (nm.is_one(a_i)) {
1585                 if (m_i->size() == 1) {
1586                     m_i->display_smt2(out, proc);
1587                 }
1588                 else {
1589                     out << "(* ";
1590                     m_i->display_smt2(out, proc);
1591                     out << ")";
1592                 }
1593             }
1594             else {
1595                 out << "(* ";
1596                 display_num_smt2(out, nm, a_i);
1597                 out << " ";
1598                 m_i->display_smt2(out, proc);
1599                 out << ")";
1600             }
1601         }
1602 
display_smt2(std::ostream & out,mpzzp_manager & nm,display_var_proc const & proc=display_var_proc ()) const1603         void display_smt2(std::ostream & out, mpzzp_manager & nm, display_var_proc const & proc = display_var_proc()) const {
1604             if (m_size == 0) {
1605                 out << "0";
1606             }
1607             else if (m_size == 1) {
1608                 display_mon_smt2(out, nm, proc, 0);
1609             }
1610             else {
1611                 out << "(+";
1612                 for (unsigned i = 0; i < m_size; i++) {
1613                     out << " ";
1614                     display_mon_smt2(out, nm, proc, i);
1615                 }
1616                 out << ")";
1617             }
1618         }
1619 
display(std::ostream & out,mpzzp_manager & nm,bool use_star) const1620         void display(std::ostream & out, mpzzp_manager & nm, bool use_star) const {
1621             display(out, nm, display_var_proc(), use_star);
1622         }
1623 
1624     };
1625 
factors(manager & _m)1626     manager::factors::factors(manager & _m):m_manager(_m), m_total_factors(0) {
1627         m().m().set(m_constant, 1);
1628     }
1629 
~factors()1630     manager::factors::~factors() {
1631         reset();
1632         m().m().del(m_constant);
1633     }
1634 
reset()1635     void manager::factors::reset() {
1636         for (unsigned i = 0; i < m_factors.size(); ++ i) {
1637             m().dec_ref(m_factors[i]);
1638         }
1639         m_factors.reset();
1640         m_degrees.reset();
1641         m_total_factors = 0;
1642         m().m().set(m_constant, 1);
1643     }
1644 
push_back(polynomial * p,unsigned degree)1645     void manager::factors::push_back(polynomial * p, unsigned degree) {
1646         SASSERT(p != 0 && degree > 0);
1647         m_factors.push_back(p);
1648         m_degrees.push_back(degree);
1649         m_total_factors += degree;
1650         m().inc_ref(p);
1651     }
1652 
multiply(polynomial_ref & out) const1653     void manager::factors::multiply(polynomial_ref & out) const {
1654         if (m_factors.empty()) {
1655             out = m().mk_const(m_constant);
1656         }
1657         else {
1658             // multiply the factors
1659             for (unsigned i = 0; i < m_factors.size(); ++ i) {
1660                 polynomial_ref current(m_factors[i], m());
1661                 if (m_degrees[i] > 1) {
1662                     m().pw(current, m_degrees[i], current);
1663                 }
1664                 if (i == 0) {
1665                     out = current;
1666                 } else {
1667                     out = m().mul(out, current);
1668                 }
1669             }
1670             // multiply the constant
1671             out = m().mul(m_constant, out);
1672         }
1673     }
1674 
display(std::ostream & out) const1675     void manager::factors::display(std::ostream & out) const {
1676         out << m().m().to_string(get_constant());
1677         for (unsigned i = 0; i < m_factors.size(); ++ i) {
1678             out << " * (";
1679             m_manager.display(out, m_factors[i]);
1680             out << ")^" << m_degrees[i];
1681         }
1682     }
1683 
set_constant(numeral const & constant)1684     void manager::factors::set_constant(numeral const & constant) {
1685         m().m().set(m_constant, constant);
1686     }
1687 
set_degree(unsigned i,unsigned degree)1688     void manager::factors::set_degree(unsigned i, unsigned degree) {
1689         SASSERT(i > 0);
1690         m_total_factors -= m_degrees[i];
1691         m_total_factors += m_degrees[i] = degree;
1692     }
1693 
operator [](unsigned i) const1694     polynomial_ref manager::factors::operator[](unsigned i) const {
1695         return polynomial_ref(m_factors[i], m());
1696     }
1697 
id(monomial const * m)1698     unsigned manager::id(monomial const * m) {
1699         return m->id();
1700     }
1701 
id(polynomial const * p)1702     unsigned manager::id(polynomial const * p) {
1703         return p->id();
1704     }
1705 
is_unit(monomial const * m)1706     bool manager::is_unit(monomial const * m) {
1707         return m->size() == 0;
1708     }
1709 
is_zero(polynomial const * p)1710     bool manager::is_zero(polynomial const * p) {
1711         return p->size() == 0;
1712     }
1713 
is_const(polynomial const * p)1714     bool manager::is_const(polynomial const * p) {
1715         return is_zero(p) || (p->size() == 1 && is_unit(p->m(0)));
1716     }
1717 
is_univariate(monomial const * m)1718     bool manager::is_univariate(monomial const * m) {
1719         return m->size() <= 1;
1720     }
1721 
is_univariate(polynomial const * p)1722     bool manager::is_univariate(polynomial const * p) {
1723         unsigned sz = p->size();
1724         if (is_const(p))
1725             return true;
1726         monomial * m = p->m(0);
1727         var x = max_var(p);
1728         for (unsigned i = 0; i < sz; i++) {
1729             m = p->m(i);
1730             if (m->size() == 1 && m->get_var(0) == x)
1731                 continue;
1732             if (m->size() == 0)
1733                 continue;
1734             return false;
1735         }
1736         return true;
1737     }
1738 
size(polynomial const * p)1739     unsigned manager::size(polynomial const * p) {
1740         return p->size();
1741     }
1742 
coeff(polynomial const * p,unsigned i)1743     polynomial::numeral const & manager::coeff(polynomial const * p, unsigned i) {
1744         return p->a(i);
1745     }
1746 
univ_coeff(polynomial const * p,unsigned k)1747     polynomial::numeral const & manager::univ_coeff(polynomial const * p, unsigned k) {
1748         static numeral zero(0);
1749         SASSERT(is_univariate(p));
1750         unsigned sz = p->size();
1751         for (unsigned i = 0; i < sz; i++) {
1752             if (p->m(i)->total_degree() == k)
1753                 return p->a(i);
1754         }
1755         return zero;
1756     }
1757 
get_monomial(polynomial const * p,unsigned i)1758     monomial * manager::get_monomial(polynomial const * p, unsigned i) {
1759         return p->m(i);
1760     }
1761 
total_degree(monomial const * m)1762     unsigned manager::total_degree(monomial const * m) {
1763         return m->total_degree();
1764     }
1765 
size(monomial const * m)1766     unsigned manager::size(monomial const * m) {
1767         return m->size();
1768     }
1769 
get_var(monomial const * m,unsigned i)1770     var manager::get_var(monomial const * m, unsigned i) {
1771         return m->get_var(i);
1772     }
1773 
degree(monomial const * m,unsigned i)1774     unsigned manager::degree(monomial const * m, unsigned i) {
1775         return m->degree(i);
1776     }
1777 
degree_of(monomial const * m,var x)1778     unsigned manager::degree_of(monomial const * m, var x) {
1779         return m->degree_of(x);
1780     }
1781 
is_linear(monomial const * m)1782     bool manager::is_linear(monomial const * m) {
1783         return m->size() == 0 || (m->size() == 1 && m->degree(0) == 1);
1784     }
1785 
is_linear(polynomial const * p)1786     bool manager::is_linear(polynomial const * p) {
1787         for (monomial* m : *p)
1788             if (!is_linear(m))
1789                 return false;
1790         return true;
1791     }
1792 
degree(polynomial const * p,var x)1793     unsigned manager::degree(polynomial const * p, var x) {
1794         unsigned sz = p->size();
1795         if (sz == 0)
1796             return 0;
1797         monomial * m  = p->m(0);
1798         unsigned msz = m->size();
1799         if (msz == 0)
1800             return 0; // see polynomial invariant.
1801         if (m->get_var(msz - 1) == x) {
1802             // x is the maximal variable in p
1803             return m->degree(msz - 1);
1804         }
1805         unsigned r = 0;
1806         // use slow (linear) scan.
1807         for (unsigned i = 0; i < sz; i++) {
1808             unsigned d = p->m(i)->degree_of(x);
1809             if (d > r)
1810                 r = d;
1811         }
1812         return r;
1813     }
1814 
max_var(polynomial const * p)1815     var manager::max_var(polynomial const * p) {
1816         if (p->size() == 0)
1817             return null_var;
1818         monomial * m  = p->m(0);
1819         return m->max_var();
1820     }
1821 
total_degree(polynomial const * p)1822     unsigned manager::total_degree(polynomial const * p) {
1823         // use linear scan... if it turns out to be too slow, I should cache total_degree in polynomial
1824         unsigned r = 0;
1825         unsigned sz = p->size();
1826         for (unsigned i = 0; i < sz; i++) {
1827             unsigned t = p->m(i)->total_degree();
1828             if (t > r)
1829                 r = t;
1830         }
1831         return r;
1832     }
1833 
1834     struct manager::imp {
1835         typedef upolynomial::manager up_manager;
1836         typedef mpzzp_manager    numeral_manager; // refine numeral_manager
1837 
1838         typedef _scoped_numeral<numeral_manager> scoped_numeral;
1839         typedef _scoped_numeral_vector<numeral_manager> scoped_numeral_vector;
1840 
1841         reslimit&                m_limit;
1842         manager &                m_wrapper;
1843         numeral_manager          m_manager;
1844         up_manager               m_upm;
1845         monomial_manager *       m_monomial_manager;
1846         polynomial_vector        m_polynomials;
1847         id_gen                   m_pid_gen; // id generator for polynomials
1848         del_eh *                 m_del_eh;
1849         polynomial *             m_zero;
1850         numeral                  m_zero_numeral;
1851         polynomial *             m_unit_poly;
1852         monomial2pos             m_m2pos;
1853         tmp_monomial             m_tmp1;
1854         numeral_vector           m_rat2numeral;
1855         numeral_vector           m_tmp_linear_as;
1856         monomial_vector          m_tmp_linear_ms;
1857         unsigned_vector          m_degree2pos;
1858         bool                     m_use_sparse_gcd;
1859         bool                     m_use_prs_gcd;
1860 
1861         // Debugging method: check if the coefficients of p are in the numeral_manager.
consistent_coeffspolynomial::manager::imp1862         bool consistent_coeffs(polynomial const * p) {
1863             scoped_numeral a(m_manager);
1864             unsigned sz = p->size();
1865             for (unsigned i = 0; i < sz; i++) {
1866                 m_manager.set(a, p->a(i));
1867                 SASSERT(m_manager.eq(a, p->a(i)));
1868             }
1869             return true;
1870         }
1871 
1872          /**
1873             \brief Divide as by the GCD of as.
1874             Return true, if the GCD is not 1.
1875          */
normalize_numeralspolynomial::manager::imp1876          static bool normalize_numerals(numeral_manager & m, numeral_vector & as) {
1877              unsigned sz = as.size();
1878              if (sz == 0)
1879                  return false;
1880              scoped_numeral g(m);
1881              m.gcd(as.size(), as.c_ptr(), g);
1882              if (m.is_one(g))
1883                  return false;
1884              SASSERT(m.is_pos(g));
1885              for (unsigned i = 0; i < sz; i++) {
1886                  m.div(as[i], g, as[i]);
1887              }
1888              return true;
1889          }
1890 
1891         /**
1892            \brief Som-of-monomials buffer.
1893            This a temporary datastructure for building polynomials.
1894 
1895            The following idiom should be used:
1896            Invoke add(...), addmul(...) several times, and then invoke mk() to obtain the final polynomial.
1897         */
1898         class som_buffer {
1899             imp *              m_owner;
1900             monomial2pos       m_m2pos;
1901             numeral_vector     m_tmp_as;
1902             monomial_vector    m_tmp_ms;
1903 
1904             /**
1905                \brief Remove zeros from m_tmp_as & m_tmp_ms.
1906                The reference counters of eliminated m_tmp_ms are decremented.
1907                m_m2pos is reset. That is for every m in m_tmp_ms, m_m2pos[m->id()] == UINT_MAX
1908             */
remove_zeros(bool normalize)1909             void remove_zeros(bool normalize) {
1910                 numeral_manager & mng = m_owner->m_manager;
1911                 SASSERT(m_tmp_ms.size() == m_tmp_as.size());
1912                 unsigned sz = m_tmp_ms.size();
1913                 unsigned j = 0;
1914                 for (unsigned i = 0; i < sz; i++) {
1915                     monomial * m = m_tmp_ms[i];
1916                     m_m2pos.reset(m);
1917                     if (mng.is_zero(m_tmp_as[i])) {
1918                         mng.reset(m_tmp_as[i]);
1919                         m_owner->dec_ref(m_tmp_ms[i]);
1920                     }
1921                     else {
1922                         if (i != j) {
1923                             SASSERT(m_tmp_ms[j] != m);
1924                             m_tmp_ms[j] = m;
1925                             swap(m_tmp_as[j], m_tmp_as[i]);
1926                         }
1927                         j++;
1928                     }
1929                 }
1930                 DEBUG_CODE({
1931                     for (unsigned i = j; i < sz; i++) {
1932                         SASSERT(mng.is_zero(m_tmp_as[i]));
1933                     }
1934                 });
1935                 m_tmp_as.shrink(j);
1936                 m_tmp_ms.shrink(j);
1937                 if (normalize) {
1938                     normalize_numerals(mng, m_tmp_as);
1939                 }
1940             }
1941 
1942         public:
som_buffer()1943             som_buffer():m_owner(nullptr) {}
1944 
reset()1945             void reset() {
1946                 if (empty())
1947                     return;
1948                 numeral_manager & mng = m_owner->m_manager;
1949                 SASSERT(m_tmp_ms.size() == m_tmp_as.size());
1950                 unsigned sz = m_tmp_ms.size();
1951                 for (unsigned i = 0; i < sz; i++) {
1952                     monomial * m = m_tmp_ms[i];
1953                     m_m2pos.reset(m);
1954                     mng.reset(m_tmp_as[i]);
1955                     m_owner->dec_ref(m_tmp_ms[i]);
1956                 }
1957                 m_tmp_as.reset();
1958                 m_tmp_ms.reset();
1959             }
1960 
set_owner(imp * o)1961             void set_owner(imp * o) { m_owner = o; }
1962 
size() const1963             unsigned size() const { return m_tmp_ms.size(); }
1964 
empty() const1965             bool empty() const { return m_tmp_ms.empty(); }
1966 
m(unsigned i) const1967             monomial * m(unsigned i) const { return m_tmp_ms[i]; }
1968 
a(unsigned i) const1969             numeral const & a(unsigned i) const { return m_tmp_as[i]; }
1970 
1971             /**
1972                \brief Return the position of the maximal monomial with
1973                respect to graded lexicographical order.
1974 
1975                Return UINT_MAX if empty.
1976             */
graded_lex_max_pos() const1977             unsigned graded_lex_max_pos() const {
1978                 numeral_manager & mng = m_owner->m_manager;
1979                 unsigned max_pos = UINT_MAX;
1980                 unsigned sz = m_tmp_as.size();
1981                 for (unsigned i = 0; i < sz; i++) {
1982                     if (!mng.is_zero(m_tmp_as[i])) {
1983                         if (max_pos == UINT_MAX) {
1984                             max_pos = i;
1985                         }
1986                         else {
1987                             if (graded_lex_compare(m_tmp_ms[i], m_tmp_ms[max_pos]) > 0)
1988                                 max_pos = i;
1989                         }
1990                     }
1991                 }
1992                 return max_pos;
1993             }
1994 
1995             /**
1996                \brief Store a*m*p into the buffer.
1997                m_m2pos is updated with the position of the monomials in m_tmp_ms.
1998 
1999                The reference counter of new monomials added into the buffer is increased.
2000             */
2001             template<typename PolyType, bool CheckZeros>
addmul_core(numeral const & a,monomial const * m,PolyType const * p)2002             void addmul_core(numeral const & a, monomial const * m, PolyType const * p) {
2003                 numeral_manager & mng = m_owner->m_manager;
2004                 if (mng.is_zero(a))
2005                     return;
2006                 unsigned sz = p->size();
2007                 for (unsigned i = 0; i < sz; i++) {
2008                     if (CheckZeros && mng.is_zero(p->a(i)))
2009                         continue;
2010                     monomial * m2 = p->m(i);
2011                     m2 = m_owner->mul(m, m2);
2012                     unsigned pos  = m_m2pos.get(m2);
2013                     if (pos == UINT_MAX) {
2014                         m_m2pos.set(m2, m_tmp_ms.size());
2015                         m_tmp_ms.push_back(m2);
2016                         m_owner->inc_ref(m2);
2017                         m_tmp_as.push_back(numeral());
2018                         mng.mul(a, p->a(i), m_tmp_as.back());
2019                     }
2020                     else {
2021                         mng.addmul(m_tmp_as[pos], a, p->a(i), m_tmp_as[pos]);
2022                     }
2023                 }
2024             }
2025 
addmul(numeral const & a,monomial const * m,polynomial const * p)2026             void addmul(numeral const & a, monomial const * m, polynomial const * p) {
2027                 return addmul_core<polynomial, false>(a, m, p);
2028             }
2029 
addmul(numeral const & a,monomial const * m,som_buffer const * p)2030             void addmul(numeral const & a, monomial const * m, som_buffer const * p) {
2031                 return addmul_core<som_buffer, false>(a, m, p);
2032             }
2033 
addmul(numeral const & a,monomial const * m,som_buffer const & p)2034             void addmul(numeral const & a, monomial const * m, som_buffer const & p) {
2035                 return addmul(a, m, &p);
2036             }
2037 
addmul(numeral const & a,som_buffer const * p)2038             void addmul(numeral const & a, som_buffer const * p) {
2039                 return addmul(a, m_owner->mk_unit(), p);
2040             }
2041 
addmul(numeral const & a,som_buffer const & p)2042             void addmul(numeral const & a, som_buffer const & p) {
2043                 return addmul(a, &p);
2044             }
2045 
addmul(monomial const * m,som_buffer const * p)2046             void addmul(monomial const * m, som_buffer const * p) {
2047                 numeral one(1);
2048                 return addmul(one, m, p);
2049             }
2050 
addmul(monomial const * m,som_buffer const & p)2051             void addmul(monomial const * m, som_buffer const & p) {
2052                 return addmul(m, &p);
2053             }
2054 
2055             /**
2056                \brief Store p into the buffer.
2057                m_m2pos is updated with the position of the monomials in m_tmp_ms.
2058 
2059                The reference counter of new monomials added into the buffer is increased.
2060             */
add(polynomial const * p)2061             void add(polynomial const * p) {
2062                 numeral_manager & mng = m_owner->m_manager;
2063                 unsigned sz = p->size();
2064                 for (unsigned i = 0; i < sz; i++) {
2065                     monomial * m2 = p->m(i);
2066                     unsigned pos  = m_m2pos.get(m2);
2067                     if (pos == UINT_MAX) {
2068                         m_m2pos.set(m2, m_tmp_ms.size());
2069                         m_tmp_ms.push_back(m2);
2070                         m_owner->inc_ref(m2);
2071                         m_tmp_as.push_back(numeral());
2072                         mng.set(m_tmp_as.back(), p->a(i));
2073                     }
2074                     else {
2075                         mng.add(m_tmp_as[pos], p->a(i), m_tmp_as[pos]);
2076                     }
2077                 }
2078             }
2079 
2080             /**
2081                \brief Add 'a*m' into m_tmp_as and m_tmp_ms.
2082                m_m2pos is updated with the position of the monomials in m_tmp_ms.
2083 
2084                The reference counter of m is increased.
2085             */
add(numeral const & a,monomial * m)2086             void add(numeral const & a, monomial * m) {
2087                 numeral_manager & mng = m_owner->m_manager;
2088                 if (mng.is_zero(a))
2089                     return;
2090                 unsigned pos  = m_m2pos.get(m);
2091                 if (pos == UINT_MAX) {
2092                     m_m2pos.set(m, m_tmp_ms.size());
2093                     m_owner->inc_ref(m);
2094                     m_tmp_ms.push_back(m);
2095                     m_tmp_as.push_back(numeral());
2096                     mng.set(m_tmp_as.back(), a);
2097                 }
2098                 else {
2099                     mng.add(m_tmp_as[pos], a, m_tmp_as[pos]);
2100                 }
2101             }
2102 
2103             /**
2104                \brief Add 'a' (that is, a*m_unit) into m_tmp_as and m_tmp_ms.
2105                m_m2pos is updated with the position of the monomials in m_tmp_ms.
2106 
2107                The reference counter of m_unit is increased.
2108             */
add(numeral const & a)2109             void add(numeral const & a) {
2110                 add(a, m_owner->mk_unit());
2111             }
2112 
sort_graded_lex()2113             void sort_graded_lex() {
2114                 std::sort(m_tmp_ms.begin(), m_tmp_ms.end(), graded_lex_gt());
2115                 numeral_vector new_as;
2116                 unsigned sz = m_tmp_ms.size();
2117                 for (unsigned i = 0; i < sz; i++) {
2118                     monomial * m = m_tmp_ms[i];
2119                     unsigned pos = m_m2pos.get(m);
2120                     new_as.push_back(numeral());
2121                     swap(new_as.back(), m_tmp_as[pos]);
2122                     m_m2pos.reset(m);
2123                     m_m2pos.set(m, i);
2124                 }
2125                 m_tmp_as.swap(new_as);
2126             }
2127 
2128             // For each monomial m
2129             //   If m contains x^k and k >= x2d[x] and x2d[x] != 0, then set coefficient of m to 0.
mod_d(var2degree const & x2d)2130             void mod_d(var2degree const & x2d) {
2131                 numeral_manager & mng = m_owner->m_manager;
2132                 unsigned sz = m_tmp_ms.size();
2133                 for (unsigned i = 0; i < sz; i++) {
2134                     if (mng.is_zero(m_tmp_as[i]))
2135                         continue;
2136                     monomial * m = m_tmp_ms[i];
2137                     unsigned msz = m->size();
2138                     unsigned j;
2139                     for (j = 0; j < msz; j++) {
2140                         var x = m->get_var(j);
2141                         unsigned dx = x2d.degree(x);
2142                         if (dx == 0)
2143                             continue;
2144                         if (m->degree(j) >= dx)
2145                             break;
2146                     }
2147                     if (j < msz) {
2148                         mng.reset(m_tmp_as[i]);
2149                     }
2150                 }
2151             }
2152 
mk(bool normalize=false)2153             polynomial * mk(bool normalize = false) {
2154                 remove_zeros(normalize);
2155                 polynomial * p = m_owner->mk_polynomial_core(m_tmp_as.size(), m_tmp_as.c_ptr(), m_tmp_ms.c_ptr());
2156                 m_tmp_as.reset();
2157                 m_tmp_ms.reset();
2158                 return p;
2159             }
2160 
display(std::ostream & out) const2161             void display(std::ostream & out) const {
2162                 SASSERT(m_tmp_ms.size() == m_tmp_as.size());
2163                 numeral_manager & mng = m_owner->m_manager;
2164                 for (unsigned i = 0; i < m_tmp_as.size(); i++) {
2165                     if (i > 0) out << " + ";
2166                     out << mng.to_string(m_tmp_as[i]) << "*"; m_tmp_ms[i]->display(out);
2167                 }
2168                 out << "\n";
2169             }
2170         };
2171 
2172         class som_buffer_vector {
2173             imp *                  m_owner;
2174             ptr_vector<som_buffer> m_buffers;
2175 
ensure_capacity(unsigned sz)2176             void ensure_capacity(unsigned sz) {
2177                 unsigned old_sz = m_buffers.size();
2178                 for (unsigned i = old_sz; i < sz; i++) {
2179                     som_buffer * new_buffer = alloc(som_buffer);
2180                     if (m_owner)
2181                         new_buffer->set_owner(m_owner);
2182                     m_buffers.push_back(new_buffer);
2183                 }
2184                 SASSERT(m_buffers.size() >= sz);
2185             }
2186 
2187         public:
som_buffer_vector()2188             som_buffer_vector() {
2189                 m_owner = nullptr;
2190             }
2191 
~som_buffer_vector()2192             ~som_buffer_vector() {
2193                 clear();
2194             }
2195 
clear()2196             void clear() {
2197                 reset();
2198                 unsigned sz = m_buffers.size();
2199                 for (unsigned i = 0; i < sz; i++) {
2200                     dealloc(m_buffers[i]);
2201                 }
2202                 m_buffers.reset();
2203             }
2204 
set_owner(imp * owner)2205             void set_owner(imp * owner) {
2206                 SASSERT(m_owner == owner || m_owner == 0);
2207                 if (m_owner == nullptr) {
2208                     m_owner = owner;
2209                     unsigned sz = m_buffers.size();
2210                     for (unsigned i = 0; i < sz; i++) {
2211                         m_buffers[i]->set_owner(m_owner);
2212                     }
2213                 }
2214             }
2215 
operator [](unsigned idx)2216             som_buffer * operator[](unsigned idx) {
2217                 ensure_capacity(idx+1);
2218                 return m_buffers[idx];
2219             }
2220 
reset(unsigned sz)2221             void reset(unsigned sz) {
2222                 if (sz > m_buffers.size())
2223                     sz = m_buffers.size();
2224                 for (unsigned i = 0; i < sz; i++) {
2225                     m_buffers[i]->reset();
2226                 }
2227             }
2228 
reset()2229             void reset() {
2230                 reset(m_buffers.size());
2231             }
2232 
2233         };
2234 
2235         /**
2236            \brief Cheap version of som_buffer.
2237            In this buffer, each monomial can be added at most once.
2238         */
2239         class cheap_som_buffer {
2240             imp *              m_owner;
2241             numeral_vector     m_tmp_as;
2242             monomial_vector    m_tmp_ms;
2243         public:
cheap_som_buffer()2244             cheap_som_buffer():m_owner(nullptr) {}
2245 
set_owner(imp * o)2246             void set_owner(imp * o) { m_owner = o; }
empty() const2247             bool empty() const { return m_tmp_ms.empty(); }
2248 
2249             /**
2250                \brief Add a*m to the buffer, the content of a is reset.
2251             */
add_reset(numeral & a,monomial * m)2252             void add_reset(numeral & a, monomial * m) {
2253                 SASSERT(std::find(m_tmp_ms.begin(), m_tmp_ms.end(), m) == m_tmp_ms.end());
2254                 numeral_manager & mng = m_owner->m_manager;
2255                 if (mng.is_zero(a))
2256                     return;
2257                 m_tmp_as.push_back(numeral());
2258                 swap(m_tmp_as.back(), a);
2259                 m_owner->inc_ref(m);
2260                 m_tmp_ms.push_back(m);
2261             }
2262 
2263             /**
2264                \brief Add a*m to the buffer.
2265             */
add(numeral const & a,monomial * m)2266             void add(numeral const & a, monomial * m) {
2267                 SASSERT(std::find(m_tmp_ms.begin(), m_tmp_ms.end(), m) == m_tmp_ms.end());
2268                 numeral_manager & mng = m_owner->m_manager;
2269                 if (mng.is_zero(a))
2270                     return;
2271                 m_tmp_as.push_back(numeral());
2272                 mng.set(m_tmp_as.back(), a);
2273                 m_owner->inc_ref(m);
2274                 m_tmp_ms.push_back(m);
2275             }
2276 
2277             /**
2278                \brief Add a*m*p to the buffer.
2279             */
addmul(numeral const & a,monomial const * m,polynomial const * p)2280             void addmul(numeral const & a, monomial const * m, polynomial const * p) {
2281                 numeral_manager & mng = m_owner->m_manager;
2282                 if (mng.is_zero(a))
2283                     return;
2284                 unsigned sz = p->size();
2285                 for (unsigned i = 0; i < sz; i++) {
2286                     monomial * m2 = p->m(i);
2287                     m2 = m_owner->mul(m, m2);
2288                     // m2 is not in m_tmp_ms
2289                     SASSERT(std::find(m_tmp_ms.begin(), m_tmp_ms.end(), m2) == m_tmp_ms.end());
2290                     m_owner->inc_ref(m2);
2291                     m_tmp_ms.push_back(m2);
2292                     m_tmp_as.push_back(numeral());
2293                     mng.mul(a, p->a(i), m_tmp_as.back());
2294                 }
2295             }
2296 
normalize()2297             bool normalize() {
2298                 return normalize_numerals(m_owner->m_manager, m_tmp_as);
2299             }
2300 
reset()2301             void reset() {
2302                 if (empty())
2303                     return;
2304                 numeral_manager & mng = m_owner->m_manager;
2305                 unsigned sz = m_tmp_ms.size();
2306                 for (unsigned i = 0; i < sz; i++) {
2307                     mng.del(m_tmp_as[i]);
2308                     m_owner->dec_ref(m_tmp_ms[i]);
2309                 }
2310                 m_tmp_as.reset();
2311                 m_tmp_ms.reset();
2312             }
2313 
mk()2314             polynomial * mk() {
2315                 polynomial * new_p = m_owner->mk_polynomial_core(m_tmp_as.size(), m_tmp_as.c_ptr(), m_tmp_ms.c_ptr());
2316                 m_tmp_as.reset();
2317                 m_tmp_ms.reset();
2318                 return new_p;
2319             }
2320         };
2321 
2322         som_buffer       m_som_buffer;
2323         som_buffer       m_som_buffer2;
2324         cheap_som_buffer m_cheap_som_buffer;
2325         cheap_som_buffer m_cheap_som_buffer2;
2326 
initpolynomial::manager::imp2327         void init() {
2328             m_del_eh = nullptr;
2329             m_som_buffer.set_owner(this);
2330             m_som_buffer2.set_owner(this);
2331             m_cheap_som_buffer.set_owner(this);
2332             m_cheap_som_buffer2.set_owner(this);
2333             m_zero = mk_polynomial_core(0, nullptr, nullptr);
2334             m().set(m_zero_numeral, 0);
2335             inc_ref(m_zero);
2336             numeral one(1);
2337             m_unit_poly = mk_const_core(one);
2338             inc_ref(m_unit_poly);
2339             m_use_sparse_gcd = true;
2340             m_use_prs_gcd = false;
2341         }
2342 
imppolynomial::manager::imp2343         imp(reslimit& lim, manager & w, unsynch_mpz_manager & m, monomial_manager * mm):
2344             m_limit(lim),
2345             m_wrapper(w),
2346             m_manager(m),
2347             m_upm(lim, m) {
2348             if (mm == nullptr)
2349                 mm = alloc(monomial_manager);
2350             m_monomial_manager = mm;
2351             m_monomial_manager->inc_ref();
2352             init();
2353         }
2354 
imppolynomial::manager::imp2355         imp(reslimit& lim, manager & w, unsynch_mpz_manager & m, small_object_allocator * a):
2356             m_limit(lim),
2357             m_wrapper(w),
2358             m_manager(m),
2359             m_upm(lim, m) {
2360             m_monomial_manager = alloc(monomial_manager, a);
2361             m_monomial_manager->inc_ref();
2362             init();
2363         }
2364 
~imppolynomial::manager::imp2365         ~imp() {
2366             dec_ref(m_zero);
2367             dec_ref(m_unit_poly);
2368             m_som_buffer.reset();
2369             m_som_buffer2.reset();
2370             m_cheap_som_buffer.reset();
2371             m_cheap_som_buffer2.reset();
2372             m_manager.del(m_zero_numeral);
2373             m_mgcd_iterpolators.flush();
2374             m_mgcd_skeletons.reset();
2375             CTRACE("polynomial", !m_polynomials.empty(),
2376                    tout << "leaked polynomials\n";
2377                    for (auto* p : m_polynomials) {
2378                        if (p) p->display(tout, m_manager) << "\n";
2379                    });
2380             m_polynomials.reset();
2381             SASSERT(m_polynomials.empty());
2382             m_iccp_ZpX_buffers.clear();
2383             m_monomial_manager->dec_ref();
2384         }
2385 
checkpointpolynomial::manager::imp2386         void checkpoint() {
2387             if (!m_limit.inc()) {
2388                 throw polynomial_exception(Z3_CANCELED_MSG);
2389             }
2390         }
2391 
mpolynomial::manager::imp2392         mpzzp_manager & m() const { return const_cast<imp*>(this)->m_manager; }
pmpolynomial::manager::imp2393         manager & pm() const { return m_wrapper; }
upmpolynomial::manager::imp2394         up_manager & upm() { return m_upm; }
mmpolynomial::manager::imp2395         monomial_manager & mm() const { return *m_monomial_manager; }
2396 
mk_varpolynomial::manager::imp2397         var mk_var() {
2398             return mm().mk_var();
2399         }
2400 
num_varspolynomial::manager::imp2401         unsigned num_vars() const {
2402             return mm().num_vars();
2403         }
2404 
is_validpolynomial::manager::imp2405         bool is_valid(var x) const {
2406             return mm().is_valid(x);
2407         }
2408 
2409 
add_del_ehpolynomial::manager::imp2410         void add_del_eh(del_eh * eh) {
2411             eh->m_next = m_del_eh;
2412             m_del_eh = eh;
2413         }
2414 
remove_del_ehpolynomial::manager::imp2415         void remove_del_eh(del_eh * eh) {
2416             SASSERT(eh != 0);
2417             SASSERT(m_del_eh != 0);
2418             if (m_del_eh == eh) {
2419                 m_del_eh = m_del_eh->m_next;
2420             }
2421             else {
2422                 del_eh * curr = m_del_eh;
2423                 while (curr) {
2424                     if (curr->m_next == eh) {
2425                         curr->m_next = curr->m_next->m_next;
2426                         return;
2427                     }
2428                     curr = curr->m_next;
2429                 }
2430                 UNREACHABLE();
2431             }
2432         }
2433 
delpolynomial::manager::imp2434         void del(polynomial * p) {
2435             TRACE("polynomial", tout << "deleting: "; p->display(tout, m_manager); tout << "\n";);
2436             if (m_del_eh != nullptr) {
2437                 del_eh * curr = m_del_eh;
2438                 do {
2439                     (*curr)(p);
2440                     curr = curr->m_next;
2441                 }
2442                 while (curr != nullptr);
2443             }
2444             unsigned sz     = p->size();
2445             unsigned obj_sz = polynomial::get_obj_size(sz);
2446             for (unsigned i = 0; i < sz; i++) {
2447                 m_manager.del(p->a(i));
2448                 dec_ref(p->m(i));
2449             }
2450             unsigned id = p->id();
2451             m_pid_gen.recycle(id);
2452             m_polynomials[id] = 0;
2453             mm().allocator().deallocate(obj_sz, p);
2454         }
2455 
inc_refpolynomial::manager::imp2456         void inc_ref(monomial * m) {
2457             mm().inc_ref(m);
2458         }
2459 
dec_refpolynomial::manager::imp2460         void dec_ref(monomial * m) {
2461             mm().dec_ref(m);
2462         }
2463 
inc_refpolynomial::manager::imp2464         void inc_ref(polynomial * p) {
2465             p->inc_ref();
2466         }
2467 
dec_refpolynomial::manager::imp2468         void dec_ref(polynomial * p) {
2469             p->dec_ref();
2470             if (p->ref_count() == 0)
2471                 del(p);
2472         }
2473 
2474         vector<unsigned_vector> m_lex_sort_buckets;
2475         unsigned_vector         m_lex_sort_permutation;
lex_sortpolynomial::manager::imp2476         void lex_sort(polynomial const * p) {
2477             const_cast<polynomial*>(p)->lex_sort(m_lex_sort_buckets, m_lex_sort_permutation, m_manager);
2478         }
2479 
operator ()polynomial::manager::imp::poly_khasher2480         struct poly_khasher { unsigned operator()(polynomial const * p) const { return 17; } };
2481 
2482         struct poly_chasher {
operator ()polynomial::manager::imp::poly_chasher2483             unsigned operator()(polynomial const * p, unsigned idx) const {
2484                 return hash_u_u(p->m(idx)->hash(), numeral_manager::hash(p->a(idx)));
2485             }
2486         };
2487 
hashpolynomial::manager::imp2488         unsigned hash(polynomial const * p) {
2489             if (p->size() == 0)
2490                 return 31;
2491             lex_sort(const_cast<polynomial*>(p));
2492             return get_composite_hash(p, p->size(), poly_khasher(), poly_chasher());
2493         }
2494 
mk_polynomial_corepolynomial::manager::imp2495         polynomial * mk_polynomial_core(unsigned sz, numeral * as, monomial * const * ms) {
2496             unsigned obj_sz = polynomial::get_obj_size(sz);
2497             void * mem      = mm().allocator().allocate(obj_sz);
2498             void * as_mem   = static_cast<char*>(mem) + sizeof(polynomial);
2499             void * ms_mem   = static_cast<char*>(as_mem) + sizeof(numeral)*sz;
2500             unsigned id     = m_pid_gen.mk();
2501             polynomial * p  = new (mem) polynomial(m_manager, id, sz, as, ms, static_cast<numeral*>(as_mem), static_cast<monomial**>(ms_mem));
2502             m_polynomials.reserve(id+1);
2503             SASSERT(m_polynomials[id] == 0);
2504             m_polynomials[id] = p;
2505             return p;
2506         }
2507 
gcd_simplifypolynomial::manager::imp2508         void gcd_simplify(polynomial * p) {
2509             if (m_manager.finite()) return;
2510             auto& m = m_manager.m();
2511             unsigned sz = p->size();
2512             if (sz == 0)
2513                 return;
2514             unsigned g = 0;
2515             for (unsigned i = 0; i < sz; i++) {
2516                 if (!m.is_int(p->a(i))) {
2517                     return;
2518                 }
2519                 int j = m.get_int(p->a(i));
2520                 if (j == INT_MIN || j == 1 || j == -1)
2521                     return;
2522                 g = u_gcd(abs(j), g);
2523                 if (g == 1)
2524                     return;
2525             }
2526             scoped_mpz r(m), gg(m);
2527             m.set(gg, g);
2528             for (unsigned i = 0; i < sz; ++i) {
2529                 m.div_gcd(p->a(i), gg, r);
2530                 m.set(p->a(i), r);
2531             }
2532         }
2533 
mk_zeropolynomial::manager::imp2534         polynomial * mk_zero() {
2535             return m_zero;
2536         }
2537 
mk_onepolynomial::manager::imp2538         polynomial * mk_one() {
2539             return m_unit_poly;
2540         }
2541 
mk_unitpolynomial::manager::imp2542         monomial * mk_unit() { return mm().mk_unit(); }
2543 
mk_monomialpolynomial::manager::imp2544         monomial * mk_monomial(tmp_monomial & tmp) { return mm().mk_monomial(tmp); }
2545 
mk_monomialpolynomial::manager::imp2546         monomial * mk_monomial(var x) { return mm().mk_monomial(x); }
2547 
mk_monomialpolynomial::manager::imp2548         monomial * mk_monomial(var x, unsigned k) { return mm().mk_monomial(x, k); }
2549 
mk_monomialpolynomial::manager::imp2550         monomial * mk_monomial(unsigned sz, var * xs) { return mm().mk_monomial(sz, xs); }
2551 
mk_monomialpolynomial::manager::imp2552         monomial * mk_monomial(unsigned sz, power const * pws) { return mm().mk_monomial(sz, pws); }
2553 
convertpolynomial::manager::imp2554         monomial * convert(monomial const * src) { return mm().convert(src); }
2555 
mk_const_corepolynomial::manager::imp2556         polynomial * mk_const_core(numeral & a) {
2557             monomial * u = mk_unit();
2558             inc_ref(u);
2559             return mk_polynomial_core(1, &a, &u);
2560         }
2561 
mk_constpolynomial::manager::imp2562         polynomial * mk_const(numeral & a) {
2563             if (m_manager.is_zero(a))
2564                 return mk_zero();
2565             if (m_manager.is_one(a))
2566                 return mk_one();
2567             return mk_const_core(a);
2568         }
2569 
mk_constpolynomial::manager::imp2570         polynomial * mk_const(rational const & a) {
2571             SASSERT(a.is_int());
2572             scoped_numeral tmp(m_manager);
2573             m_manager.set(tmp, a.to_mpq().numerator());
2574             polynomial * p = mk_const(tmp);
2575             return p;
2576         }
2577 
mk_polynomialpolynomial::manager::imp2578         polynomial * mk_polynomial(var x, unsigned k) {
2579             SASSERT(is_valid(x));
2580             numeral one(1);
2581             monomial * m = mk_monomial(x, k);
2582             inc_ref(m);
2583             return mk_polynomial_core(1, &one, &m);
2584         }
2585 
mk_polynomialpolynomial::manager::imp2586         polynomial * mk_polynomial(unsigned sz, numeral * as, monomial * const * ms) {
2587             m_som_buffer.reset();
2588             for (unsigned i = 0; i < sz; i++) {
2589                 m_som_buffer.add(as[i], ms[i]);
2590             }
2591             return m_som_buffer.mk();
2592         }
2593 
2594         /**
2595            \brief Convert rationals into numerals at m_rat2numeral
2596         */
rational2numeralpolynomial::manager::imp2597         void rational2numeral(unsigned sz, rational const * as) {
2598             SASSERT(m_rat2numeral.empty());
2599             for (unsigned i = 0; i < sz; i++) {
2600                 SASSERT(as[i].is_int());
2601                 m_rat2numeral.push_back(numeral());
2602                 m_manager.set(m_rat2numeral.back(), as[i].to_mpq().numerator());
2603             }
2604         }
2605 
reset_tmp_as2polynomial::manager::imp2606         void reset_tmp_as2() {
2607             DEBUG_CODE({
2608                 for (unsigned i = 0; i < m_rat2numeral.size(); i++) {
2609                     SASSERT(m_manager.is_zero(m_rat2numeral[i]));
2610                 }
2611             });
2612             m_rat2numeral.reset();
2613         }
2614 
mk_polynomialpolynomial::manager::imp2615         polynomial * mk_polynomial(unsigned sz, rational const * as, monomial * const * ms) {
2616             rational2numeral(sz, as);
2617             polynomial * p = mk_polynomial(sz, m_rat2numeral.c_ptr(), ms);
2618             reset_tmp_as2();
2619             return p;
2620         }
2621 
mk_univariatepolynomial::manager::imp2622         polynomial * mk_univariate(var x, unsigned n, numeral * as) {
2623             SASSERT(m_cheap_som_buffer.empty());
2624             unsigned k = n+1;
2625             while (k > 0) {
2626                 --k;
2627                 if (m_manager.is_zero(as[k])) {
2628                     m_manager.del(as[k]);
2629                     continue;
2630                 }
2631                 m_cheap_som_buffer.add_reset(as[k], mk_monomial(x, k));
2632             }
2633             return m_cheap_som_buffer.mk();
2634         }
2635 
mk_univariatepolynomial::manager::imp2636         polynomial * mk_univariate(var x, unsigned n, rational const * as) {
2637             SASSERT(is_valid(x));
2638             rational2numeral(n+1, as);
2639             polynomial * p = mk_univariate(x, n, m_rat2numeral.c_ptr());
2640             reset_tmp_as2();
2641             return p;
2642         }
2643 
mk_linearpolynomial::manager::imp2644         polynomial * mk_linear(unsigned sz, numeral * as, var const * xs, numeral & c) {
2645             SASSERT(m_tmp_linear_as.empty());
2646             SASSERT(m_tmp_linear_ms.empty());
2647             for (unsigned i = 0; i < sz; i++) {
2648                 if (m_manager.is_zero(as[i]))
2649                     continue;
2650                 m_tmp_linear_as.push_back(numeral());
2651                 swap(m_tmp_linear_as.back(), as[i]);
2652                 m_tmp_linear_ms.push_back(mk_monomial(xs[i]));
2653             }
2654             if (!m_manager.is_zero(c)) {
2655                 m_tmp_linear_as.push_back(numeral());
2656                 swap(m_tmp_linear_as.back(), c);
2657                 m_tmp_linear_ms.push_back(mk_unit());
2658             }
2659             polynomial * p = mk_polynomial(m_tmp_linear_as.size(), m_tmp_linear_as.c_ptr(), m_tmp_linear_ms.c_ptr());
2660             for (auto& a : m_tmp_linear_as) {
2661                 m_manager.del(a);
2662             }
2663             m_tmp_linear_as.reset();
2664             m_tmp_linear_ms.reset();
2665             return p;
2666         }
2667 
mk_linearpolynomial::manager::imp2668         polynomial * mk_linear(unsigned sz, rational const * as, var const * xs, rational const & c) {
2669             SASSERT(c.is_int());
2670             rational2numeral(sz, as);
2671             numeral tmp_c;
2672             m_manager.set(tmp_c, c.to_mpq().numerator());
2673             polynomial * p = mk_linear(sz, m_rat2numeral.c_ptr(), xs, tmp_c);
2674             SASSERT(m_manager.is_zero(tmp_c));
2675             reset_tmp_as2();
2676             return p;
2677         }
2678 
2679 
mulpolynomial::manager::imp2680         monomial * mul(monomial const * m1, monomial const * m2) {
2681             return mm().mul(m1, m2);
2682         }
2683 
divpolynomial::manager::imp2684         bool div(monomial const * m1, monomial const * m2) {
2685             return mm().div(m1, m2);
2686         }
2687 
divpolynomial::manager::imp2688         bool div(monomial const * m1, monomial const * m2, monomial_ref & r) {
2689             return mm().div(m1, m2, r);
2690         }
2691 
gcdpolynomial::manager::imp2692         monomial * gcd(monomial const * m1, monomial const * m2, monomial * & q1, monomial * & q2) {
2693             return mm().gcd(m1, m2, q1, q2);
2694         }
2695 
unifypolynomial::manager::imp2696         bool unify(monomial const * m1, monomial const * m2, monomial * & q1, monomial * & q2) {
2697             return mm().unify(m1, m2, q1, q2);
2698         }
2699 
pwpolynomial::manager::imp2700         monomial * pw(monomial const * m, unsigned k) {
2701             return mm().pw(m, k);
2702         }
2703 
sqrtpolynomial::manager::imp2704         monomial * sqrt(monomial const * m) {
2705             return mm().sqrt(m);
2706         }
2707 
addmulpolynomial::manager::imp2708         polynomial * addmul(numeral const & a1, monomial const * m1, polynomial const * p1, numeral const & a2, monomial const * m2, polynomial const * p2) {
2709             m_som_buffer.reset();
2710             m_som_buffer.addmul(a1, m1, p1);
2711             m_som_buffer.addmul(a2, m2, p2);
2712             return m_som_buffer.mk();
2713         }
2714 
addmulpolynomial::manager::imp2715         polynomial * addmul(polynomial const * p1, numeral const & a2, monomial const * m2, polynomial const * p2) {
2716             numeral one(1);
2717             return addmul(one, mk_unit(), p1, a2, m2, p2);
2718         }
2719 
addmulpolynomial::manager::imp2720         polynomial * addmul(polynomial const * p1, numeral const & a2, polynomial const * p2) {
2721             return addmul(p1, a2, mk_unit(), p2);
2722         }
2723 
addpolynomial::manager::imp2724         polynomial * add(polynomial const * p1, polynomial const * p2) {
2725             numeral one(1);
2726             return addmul(one, mk_unit(), p1, one, mk_unit(), p2);
2727         }
2728 
subpolynomial::manager::imp2729         polynomial * sub(polynomial const * p1, polynomial const * p2) {
2730             numeral one(1);
2731             numeral minus_one; // It is incorrect to initialize with -1 when numeral_manager is GF_2
2732             m_manager.set(minus_one, -1);
2733             return addmul(one, mk_unit(), p1, minus_one, mk_unit(), p2);
2734         }
2735 
2736         /**
2737            \brief Return p1*p2 + a
2738         */
muladdpolynomial::manager::imp2739         polynomial * muladd(polynomial const * p1, polynomial const * p2, numeral const & a) {
2740             if (is_zero(p1) || is_zero(p2)) {
2741                 return mk_const(a);
2742             }
2743             m_som_buffer.reset();
2744             unsigned sz1 = p1->size();
2745             for (unsigned i = 0; i < sz1; i++) {
2746                 checkpoint();
2747                 numeral const & a1 = p1->a(i);
2748                 monomial * m1      = p1->m(i);
2749                 m_som_buffer.addmul(a1, m1, p2);
2750             }
2751             m_som_buffer.add(a);
2752             return m_som_buffer.mk();
2753         }
2754 
mulpolynomial::manager::imp2755         polynomial * mul(polynomial const * p1, polynomial const * p2) {
2756             numeral zero(0);
2757             return muladd(p1, p2, zero);
2758         }
2759 
mulpolynomial::manager::imp2760         polynomial * mul(numeral const & a, monomial const * m, polynomial const * p) {
2761             if (m_manager.is_zero(a))
2762                 return m_zero;
2763             if (m_manager.is_one(a) && m == mk_unit())
2764                 return const_cast<polynomial*>(p);
2765             SASSERT(m_cheap_som_buffer.empty());
2766             m_cheap_som_buffer.addmul(a, m, p);
2767             return m_cheap_som_buffer.mk();
2768         }
2769 
mulpolynomial::manager::imp2770         polynomial * mul(monomial const * m, polynomial const * p) {
2771             numeral one(1);
2772             return mul(one, m, p);
2773         }
2774 
mulpolynomial::manager::imp2775         polynomial * mul(numeral const & a, polynomial const * p) {
2776             return mul(a, mk_unit(), p);
2777         }
2778 
2779         /**
2780            \brief Return a*p1*p2
2781         */
mulpolynomial::manager::imp2782         polynomial * mul(numeral const & a, polynomial const * p1, polynomial const * p2) {
2783             if (m_manager.is_zero(a) || is_zero(p1) || is_zero(p2))
2784                 return mk_zero();
2785             scoped_numeral new_a1(m_manager);
2786             m_som_buffer.reset();
2787             unsigned sz1 = p1->size();
2788             for (unsigned i = 0; i < sz1; i++) {
2789                 checkpoint();
2790                 numeral const & a1 = p1->a(i);
2791                 m_manager.mul(a, a1, new_a1);
2792                 monomial * m1      = p1->m(i);
2793                 m_som_buffer.addmul(new_a1, m1, p2);
2794             }
2795             return m_som_buffer.mk();
2796         }
2797 
2798         // Divide coefficients of p by d.
2799         // This methods assumes that all coefficients of p are divisible by d.
divpolynomial::manager::imp2800         polynomial * div(polynomial * p, numeral const & d) {
2801             SASSERT(m_cheap_som_buffer.empty());
2802             unsigned sz = p->size();
2803             scoped_numeral a(m_manager);
2804             for (unsigned i = 0; i < sz; i++) {
2805                 m_manager.div(p->a(i), d, a);
2806                 m_cheap_som_buffer.add(a, p->m(i));
2807             }
2808             return m_cheap_som_buffer.mk();
2809         }
2810 
mulpolynomial::manager::imp2811         polynomial * mul(rational const & a, polynomial const * p) {
2812             SASSERT(a.is_int());
2813             scoped_numeral tmp(m_manager);
2814             m_manager.set(tmp, a.to_mpq().numerator());
2815             polynomial * new_p = mul(tmp, p);
2816             return new_p;
2817         }
2818 
2819         /**
2820            \brief Return m/x^k
2821         */
div_x_kpolynomial::manager::imp2822         monomial * div_x_k(monomial const * m, var x, unsigned k) {
2823             return mm().div_x_k(m, x, k);
2824         }
2825 
2826         /**
2827            \brief Return m/x^n  where n == m->degree_of(x)
2828         */
div_xpolynomial::manager::imp2829         monomial * div_x(monomial const * m, var x) {
2830             return mm().div_x(m, x);
2831         }
2832 
is_p_normalizedpolynomial::manager::imp2833         bool is_p_normalized(polynomial const * p) const {
2834             for (unsigned i = 0; i < p->size(); i++) {
2835                 SASSERT(m().is_p_normalized(p->a(i)));
2836             }
2837             return true;
2838         }
2839 
2840         /**
2841            \brief (Incremental) Newton interpolation for multivariate polynomials.
2842            Creates a polynomial on x of degree at most d with coefficients in Z[y1, ..., ym],
2843            using d+1 sample points.
2844            Sample points are provided using the method add, and the interpolating polynomial
2845            is created using mk() method.
2846 
2847            \pre manager must be configured in Zp (modular) mode.
2848            We need this requeriment because we use the inverse operation.
2849         */
2850         class newton_interpolator {
2851             imp &                 pm;
2852             scoped_numeral_vector m_inputs;
2853             scoped_numeral_vector m_invs;
2854             polynomial_ref_vector m_vs;
m() const2855             mpzzp_manager & m() const { return pm.m(); }
2856         public:
newton_interpolator(imp & _pm)2857             newton_interpolator(imp & _pm):pm(_pm), m_inputs(m()), m_invs(m()), m_vs(pm.m_wrapper) {
2858                 m_invs.push_back(numeral(0));
2859             }
2860 
reset()2861             void reset() {
2862                 m_inputs.reset();
2863                 m_invs.shrink(1);
2864                 m_vs.reset();
2865                 SASSERT(m().is_zero(m_invs[0]));
2866             }
2867 
inputs() const2868             scoped_numeral_vector const & inputs() const { return m_inputs; }
2869 
num_sample_points() const2870             unsigned num_sample_points() const { return m_inputs.size(); }
2871 
2872             /**
2873                \brief Add a new datapoint
2874             */
add(numeral const & input,polynomial const * output)2875             void add(numeral const & input, polynomial const * output) {
2876                 TRACE("newton", tout << m().to_string(input) << " -> "; output->display(tout, m()); tout << "\n";);
2877                 SASSERT(m().modular());
2878                 unsigned sz = num_sample_points();
2879                 if (sz > 0) {
2880                     unsigned k = sz;
2881                     // add new inverse
2882                     scoped_numeral product(m());
2883                     scoped_numeral aux(m());
2884                     SASSERT(!m().eq(input, m_inputs[0]));
2885                     m().sub(input, m_inputs[0], product);
2886                     for (unsigned i = 1; i <= k - 1; i++) {
2887                         SASSERT(!m().eq(input, m_inputs[i]));
2888                         m().sub(input, m_inputs[i], aux);
2889                         m().mul(product, aux, product);
2890                     }
2891                     m().inv(product);
2892                     m_inputs.push_back(input);
2893                     m_invs.push_back(product);
2894                     TRACE("newton", tout << "invs[" << k << "]: " << product << "\n";);
2895                     SASSERT(m().eq(m_inputs[k], input));
2896                     // Compute newton's coefficient
2897                     polynomial_ref temp(pm.m_wrapper);
2898                     polynomial_ref aux_poly(pm.m_wrapper);
2899                     temp = m_vs.get(k-1);
2900                     for (int j = k - 2; j >= 0; j--) {
2901                         // temp <- temp*(input - m_inputs[j]) + vs[j]
2902                         m().sub(input, m_inputs[j], aux);
2903                         SASSERT(m().is_p_normalized(aux));
2904                         aux_poly = pm.mul(aux, temp);
2905                         temp     = pm.add(aux_poly, m_vs.get(j));
2906                         SASSERT(pm.is_p_normalized(temp));
2907                     }
2908                     // new vs <- (output - temp)*invs[sz]
2909                     aux_poly = pm.sub(output, temp);
2910                     SASSERT(pm.is_p_normalized(aux_poly));
2911                     aux_poly = pm.mul(m_invs[sz], aux_poly);
2912                     SASSERT(pm.is_p_normalized(aux_poly));
2913                     m_vs.push_back(aux_poly);
2914                     TRACE("newton", tout << "vs[" << k << "]: " << aux_poly << "\n";);
2915                 }
2916                 else {
2917                     m_inputs.push_back(input);
2918                     m_vs.push_back(const_cast<polynomial*>(output));
2919                 }
2920             }
2921 
2922             // Convert newton form to standard form
mk(var x,polynomial_ref & r)2923             void mk(var x, polynomial_ref & r) {
2924                 SASSERT(m().modular());
2925                 polynomial_ref u(pm.m_wrapper);
2926                 polynomial_ref aux_poly(pm.m_wrapper);
2927                 int num = num_sample_points();
2928                 int d   = num - 1;
2929                 SASSERT(num > 0);
2930                 u = m_vs.get(d);
2931                 scoped_numeral c(m());
2932                 for (int k = d - 1; k >= 0; k--) {
2933                     TRACE("newton", tout << "u: " << u << "\n";);
2934                     // create polynomial (x - inputs[k])
2935                     m().set(c, m_inputs[k]);
2936                     m().neg(c);
2937                     numeral one(1);
2938                     aux_poly = pm.mk_linear(1, &one, &x, c);
2939                     TRACE("newton", tout << "(x - inputs[k]): " << aux_poly << "\n";);
2940                     // u <- u * (x - inputs[k]) + vs[k]
2941                     aux_poly = pm.mul(u, aux_poly);
2942                     u        = pm.add(aux_poly, m_vs.get(k));
2943                 }
2944                 TRACE("newton", tout << "result u: " << u << "\n";);
2945                 r = u;
2946             }
2947         };
2948 
2949         /**
2950            \brief Newton interpolation for multivariate polynomials.
2951            Creates a polynomial on x of degree at most d with coefficients in Z[y1, ..., ym],
2952            using d+1 sample points.
2953            The sample points are store in the vectors inputs and outputs. Both must have size d+1.
2954 
2955            \pre manager must be configured in Zp (modular) mode.
2956            We need this requeriment because we use the inverse operation.
2957         */
newton_interpolationpolynomial::manager::imp2958         void newton_interpolation(var x, unsigned d, numeral const * inputs, polynomial * const * outputs, polynomial_ref & r) {
2959             SASSERT(m().modular());
2960             newton_interpolator interpolator(*this);
2961             for (unsigned i = 0; i <= d; i++)
2962                 interpolator.add(inputs[i], outputs[i]);
2963             interpolator.mk(x, r);
2964         }
2965 
2966         class newton_interpolator_vector {
2967             imp *                           m_imp;
2968             ptr_vector<newton_interpolator> m_data;
2969         public:
newton_interpolator_vector()2970             newton_interpolator_vector():m_imp(nullptr) {}
2971 
~newton_interpolator_vector()2972             ~newton_interpolator_vector() {
2973                 flush();
2974             }
2975 
flush()2976             void flush() {
2977                 unsigned sz = m_data.size();
2978                 for (unsigned i = 0; i < sz; i++)
2979                     dealloc(m_data[i]);
2980                 m_data.reset();
2981             }
2982 
set_owner(imp * owner)2983             void set_owner(imp * owner) {
2984                 SASSERT(m_imp == 0 || m_imp == owner);
2985                 m_imp = owner;
2986             }
2987 
operator [](unsigned idx)2988             newton_interpolator & operator[](unsigned idx) {
2989                 SASSERT(m_imp);
2990                 while (idx >= m_data.size()) {
2991                     m_data.push_back(alloc(newton_interpolator, *m_imp));
2992                 }
2993                 return *(m_data[idx]);
2994             }
2995         };
2996 
2997         /**
2998            \brief Represents a polynomial skeleton of a multivariate polynomial Z[Y1, ..., Yn]
2999            with coefficients in Z[X]
3000         */
3001         struct skeleton {
3002             struct entry {
3003                 monomial * m_monomial; // a monomial in Z[Y1, ..., Y1]
3004                 unsigned   m_first_power_idx; // position (in m_powers) of the powers of X that are the coefficient of this monomial
3005                 unsigned   m_num_powers; // size of the coefficient of this monomial.
entrypolynomial::manager::imp::skeleton::entry3006                 entry(monomial * m, unsigned first_idx):
3007                     m_monomial(m),
3008                     m_first_power_idx(first_idx),
3009                     m_num_powers(1) {
3010                 }
num_powerspolynomial::manager::imp::skeleton::entry3011                 unsigned num_powers() const { return m_num_powers; }
mpolynomial::manager::imp::skeleton::entry3012                 monomial * m() const { return m_monomial; }
3013             };
3014             imp &                pm;
3015             var                  m_x;
3016             svector<entry>       m_entries;
3017             unsigned_vector      m_powers;
3018             ptr_vector<monomial> m_orig_monomials;
3019             unsigned             m_max_powers; // maximal number of powers associated with an entry
3020 
skeletonpolynomial::manager::imp::skeleton3021             skeleton(imp & _pm, polynomial * p, var x):pm(_pm), m_x(x) {
3022                 m_max_powers = 0;
3023                 ptr_buffer<monomial, 128> ms;
3024                 unsigned sz = p->size();
3025                 for (unsigned i = 0; i < sz; i++) {
3026                     ms.push_back(p->m(i));
3027                 }
3028                 std::sort(ms.begin(), ms.end(), lex_lt2(x));
3029                 monomial * prev = nullptr;
3030                 for (unsigned i = 0; i < sz; i++) {
3031                     monomial * orig_m = ms[i];
3032                     monomial * m;
3033                     unsigned   k = orig_m->degree_of(x);
3034                     if (k > 0)
3035                         m = pm.div_x(orig_m, x);
3036                     else
3037                         m = orig_m;
3038                     if (m == prev) {
3039                         unsigned & num_powers = m_entries.back().m_num_powers;
3040                         num_powers++;
3041                         if (num_powers > m_max_powers)
3042                             m_max_powers = num_powers;
3043                     }
3044                     else {
3045                         prev = m;
3046                         pm.inc_ref(m);
3047                         m_entries.push_back(entry(m, m_powers.size()));
3048                         if (m_max_powers == 0)
3049                             m_max_powers = 1;
3050                     }
3051                     pm.inc_ref(orig_m);
3052                     m_orig_monomials.push_back(orig_m);
3053                     m_powers.push_back(k);
3054                 }
3055                 TRACE("skeleton",
3056                       tout << "x: x" << m_x << "\n";
3057                       tout << "max: " << m_max_powers << "\n";
3058                       tout << "p: "; p->display(tout, pm.m()); tout << "\n";
3059                       tout << "skeleton: "; display(tout); tout << "\n";);
3060                 DEBUG_CODE({
3061                     unsigned sz = m_entries.size();
3062                     for (unsigned i = 1; i < sz; i++) {
3063                         SASSERT(lex_compare(m_entries[i-1].m_monomial, m_entries[i].m_monomial) < 0);
3064                     }
3065                 });
3066             }
3067 
~skeletonpolynomial::manager::imp::skeleton3068             ~skeleton() {
3069                 unsigned sz = m_entries.size();
3070                 for (unsigned i = 0; i < sz; i++) {
3071                     pm.dec_ref(m_entries[i].m_monomial);
3072                 }
3073                 sz = m_orig_monomials.size();
3074                 for (unsigned i = 0; i < sz; i++) {
3075                     pm.dec_ref(m_orig_monomials[i]);
3076                 }
3077             }
3078 
get_entry_idxpolynomial::manager::imp::skeleton3079             unsigned get_entry_idx(monomial * m) {
3080                 unsigned sz = m_entries.size();
3081                 for (unsigned i = 0; i < sz; i++) {
3082                     if (m_entries[i].m_monomial == m)
3083                         return i;
3084                 }
3085                 return UINT_MAX;
3086             }
3087 
num_entriespolynomial::manager::imp::skeleton3088             unsigned num_entries() const { return m_entries.size(); }
3089 
operator []polynomial::manager::imp::skeleton3090             entry const & operator[](unsigned idx) const { return m_entries[idx]; }
3091 
ith_powerpolynomial::manager::imp::skeleton3092             unsigned ith_power(entry const & e, unsigned i) const { SASSERT(i < e.m_num_powers); return m_powers[e.m_first_power_idx + i]; }
3093 
ith_orig_monomialpolynomial::manager::imp::skeleton3094             monomial * ith_orig_monomial(entry const & e, unsigned i) const { SASSERT(i < e.m_num_powers); return m_orig_monomials[e.m_first_power_idx + i]; }
3095 
max_num_powerspolynomial::manager::imp::skeleton3096             unsigned max_num_powers() const { return m_max_powers; }
3097 
displaypolynomial::manager::imp::skeleton3098             void display(std::ostream & out) {
3099                 unsigned sz = m_entries.size();
3100                 for (unsigned i = 0; i < sz; i++) {
3101                     entry & e = m_entries[i];
3102                     if (i > 0) out << " ";
3103                     out << "(";
3104                     for (unsigned j = 0; j < e.m_num_powers; j++) {
3105                         if (j > 0) out << " ";
3106                         out << "x" << m_x << "^";
3107                         out << m_powers[e.m_first_power_idx + j];
3108                     }
3109                     out << ")*";
3110                     e.m_monomial->display(out);
3111                 }
3112             }
3113         };
3114 
3115         class sparse_interpolator {
3116             skeleton *      m_skeleton;
3117             numeral_vector  m_inputs;
3118             numeral_vector  m_outputs;
3119         public:
sparse_interpolator(skeleton * sk)3120             sparse_interpolator(skeleton * sk):m_skeleton(sk) {
3121                 // reserve space output values associated with each entry
3122                 if (sk) {
3123                     unsigned sz = sk->num_entries();
3124                     for (unsigned i = 0; i < sz; i++) {
3125                         unsigned num_powers = (*sk)[i].num_powers();
3126                         for (unsigned j = 0; j < num_powers; j++) {
3127                             m_outputs.push_back(numeral());
3128                         }
3129                     }
3130                 }
3131             }
3132 
~sparse_interpolator()3133             ~sparse_interpolator() {
3134                 if (m_skeleton) {
3135                     numeral_manager & m = m_skeleton->pm.m();
3136                     for (unsigned i = 0; i < m_inputs.size(); i++)
3137                         m.del(m_inputs[i]);
3138                     for (unsigned i = 0; i < m_outputs.size(); i++)
3139                         m.del(m_outputs[i]);
3140                 }
3141             }
3142 
reset()3143             void reset() {
3144                 numeral_manager & m = m_skeleton->pm.m();
3145                 for (unsigned i = 0; i < m_inputs.size(); i++) {
3146                     m.del(m_inputs[i]);
3147                 }
3148                 m_inputs.reset();
3149             }
3150 
ready() const3151             bool ready() const {
3152                 return m_inputs.size() == m_skeleton->max_num_powers();
3153             }
3154 
add(numeral const & in,polynomial const * q)3155             bool add(numeral const & in, polynomial const * q) {
3156                 SASSERT(m_skeleton);
3157                 SASSERT(m_inputs.size() < m_skeleton->max_num_powers());
3158                 numeral_manager & m = m_skeleton->pm.m();
3159                 unsigned input_idx = m_inputs.size();
3160                 m_inputs.push_back(numeral());
3161                 m.set(m_inputs.back(), in);
3162                 unsigned sz = q->size();
3163                 for (unsigned i = 0; i < sz; i++) {
3164                     monomial * mon = q->m(i);
3165                     unsigned entry_idx = m_skeleton->get_entry_idx(mon);
3166                     if (entry_idx == UINT_MAX)
3167                         return false;
3168                     skeleton::entry const & e = (*m_skeleton)[entry_idx];
3169                     if (input_idx >= e.num_powers())
3170                         continue;
3171                     unsigned output_idx = e.m_first_power_idx + input_idx;
3172                     m.set(m_outputs[output_idx], q->a(i));
3173                 }
3174                 return true;
3175             }
3176 
mk(polynomial_ref & r)3177             bool mk(polynomial_ref & r) {
3178                 SASSERT(m_skeleton);
3179                 numeral_manager & m = m_skeleton->pm.m();
3180                 scoped_numeral_vector           cs(m);
3181                 scoped_numeral_vector           new_as(m);
3182                 scoped_numeral_vector           as(m);
3183                 ptr_buffer<monomial,128>        mons;
3184                 scoped_numeral                  aux(m);
3185                 linear_eq_solver<mpzzp_manager> solver(m);
3186                 unsigned sz = m_skeleton->num_entries();
3187                 for (unsigned k = 0; k < sz; k++) {
3188                     skeleton::entry const & e = (*m_skeleton)[k];
3189                     unsigned num_pws = e.num_powers();
3190                     solver.resize(num_pws);
3191                     new_as.resize(num_pws);
3192                     for (unsigned i = 0; i < num_pws; i++) {
3193                         numeral & in = m_inputs[i];
3194                         cs.reset();
3195                         for (unsigned j = 0; j < num_pws; j++) {
3196                             m.power(in, m_skeleton->ith_power(e, j), aux);
3197                             cs.push_back(aux);
3198                         }
3199                         unsigned output_idx = e.m_first_power_idx + i;
3200                         TRACE("sparse_interpolator", tout << "adding new equation:\n";
3201                               for (unsigned i = 0; i < num_pws; i++) {
3202                                   tout << m.to_string(cs[i]) << " ";
3203                               }
3204                               tout << "\n";);
3205                         solver.add(i, cs.c_ptr(), m_outputs[output_idx]);
3206                     }
3207                     TRACE("sparse_interpolator",
3208                           tout << "find coefficients of:\n";
3209                           for (unsigned i = 0; i < num_pws; i++) {
3210                               m_skeleton->ith_orig_monomial(e, i)->display(tout); tout << "\n";
3211                           }
3212                           tout << "system of equations:\n";
3213                           solver.display(tout););
3214                     if (!solver.solve(new_as.c_ptr()))
3215                         return false;
3216                     for (unsigned i = 0; i < num_pws; i++) {
3217                         if (!m.is_zero(new_as[i])) {
3218                             as.push_back(new_as[i]);
3219                             mons.push_back(m_skeleton->ith_orig_monomial(e, i));
3220                         }
3221                     }
3222                 }
3223                 r = m_skeleton->pm.mk_polynomial(as.size(), as.c_ptr(), mons.c_ptr());
3224                 return true;
3225             }
3226         };
3227 
3228         bool_vector  m_found_vars;
varspolynomial::manager::imp3229         void vars(polynomial const * p, var_vector & xs) {
3230             xs.reset();
3231             m_found_vars.reserve(num_vars(), false);
3232             unsigned sz = p->size();
3233             for (unsigned i = 0; i < sz; i++) {
3234                 monomial * m = p->m(i);
3235                 unsigned msz = m->size();
3236                 for (unsigned j = 0; j < msz; j++) {
3237                     var x = m->get_var(j);
3238                     if (!m_found_vars[x]) {
3239                         m_found_vars[x] = true;
3240                         xs.push_back(x);
3241                     }
3242                 }
3243             }
3244             // reset m_found_vars
3245             sz = xs.size();
3246             for (unsigned i = 0; i < sz; i++)
3247                 m_found_vars[xs[i]] = false;
3248         }
3249 
3250         typedef sbuffer<power, 32>    power_buffer;
3251         typedef sbuffer<unsigned, 32> unsigned_buffer;
3252         typedef sbuffer<var, 32>      var_buffer;
3253 
3254         /**
3255            Store in pws the variables occurring in p and their (minimal or maximal) degrees.
3256         */
3257         unsigned_vector m_var_degrees_tmp;
3258         template<bool Max>
var_degreespolynomial::manager::imp3259         void var_degrees(polynomial const * p, power_buffer & pws) {
3260             pws.reset();
3261             unsigned_vector & var2pos = m_var_degrees_tmp;
3262             var2pos.reserve(num_vars(), UINT_MAX);
3263 
3264             unsigned sz = p->size();
3265             for (unsigned i = 0; i < sz; i++) {
3266                 monomial * m = p->m(i);
3267                 unsigned msz = m->size();
3268                 for (unsigned j = 0; j < msz; j++) {
3269                     var x        = m->get_var(j);
3270                     unsigned k   = m->degree(j);
3271                     unsigned pos = var2pos[x];
3272                     if (pos == UINT_MAX) {
3273                         var2pos[x] = pws.size();
3274                         pws.push_back(power(x, k));
3275                     }
3276                     else if (Max && k > pws[pos].degree()) {
3277                         pws[pos].degree() = k;
3278                     }
3279                     else if (!Max && k < pws[pos].degree()) {
3280                         pws[pos].degree() = k;
3281                     }
3282                 }
3283             }
3284 
3285             sz = pws.size();
3286             for (unsigned i = 0; i < sz; i++) {
3287                 SASSERT(var2pos[pws[i].get_var()] != UINT_MAX);
3288                 var2pos[pws[i].get_var()] = UINT_MAX;
3289             }
3290 
3291             DEBUG_CODE({
3292                 for (unsigned i = 0; i < pws.size(); i++) {
3293                     for (unsigned j = i + 1; j < pws.size(); j++)
3294                         SASSERT(pws[i].first != pws[j].first);
3295                 }
3296             });
3297         }
3298 
var_max_degreespolynomial::manager::imp3299         void var_max_degrees(polynomial const * p, power_buffer & pws) {
3300             var_degrees<true>(p, pws);
3301         }
3302 
var_min_degreespolynomial::manager::imp3303         void var_min_degrees(polynomial const * p, power_buffer & pws) {
3304             var_degrees<false>(p, pws);
3305         }
3306 
coeffpolynomial::manager::imp3307         polynomial * coeff(polynomial const * p, var x, unsigned k) {
3308             SASSERT(is_valid(x));
3309             SASSERT(m_cheap_som_buffer.empty());
3310             TRACE("coeff_bug", tout << "p: "; p->display(tout, m_manager); tout << "\nx: " << x << ", k: " << k << "\n";);
3311             unsigned sz = p->size();
3312             for (unsigned i = 0; i < sz; i++) {
3313                 monomial * m = p->m(i);
3314                 unsigned   d = m->degree_of(x);
3315                 if (d == k)
3316                     m_cheap_som_buffer.add(p->a(i), div_x(m, x));
3317             }
3318             return m_cheap_som_buffer.mk();
3319         }
3320 
3321         /**
3322            Let p be of the form q_k(yvec)*x^k +  ...+ q_0(yvec)
3323            Store the polynomials q_k(yvec), ..., q_0(yvec) in the som_buffer_vector.
3324         */
coeffspolynomial::manager::imp3325         void coeffs(polynomial const * p, var x, som_buffer_vector & cs) {
3326             cs.set_owner(this);
3327             unsigned sz = p->size();
3328             for (unsigned i = 0; i < sz; i++) {
3329                 monomial * m   = p->m(i);
3330                 unsigned     d = m->degree_of(x);
3331                 som_buffer * c = cs[d];
3332                 c->add(p->a(i), div_x(m, x));
3333             }
3334         }
3335 
3336         /**
3337            \brief Return a polynomial h that is the coefficient of x^k in p.
3338            Store the reduct (p - h x^k) into \c reduct.
3339         */
coeffpolynomial::manager::imp3340         polynomial * coeff(polynomial const * p, var x, unsigned k, polynomial_ref & reduct) {
3341             SASSERT(is_valid(x));
3342             SASSERT(m_cheap_som_buffer.empty());
3343             SASSERT(m_cheap_som_buffer2.empty());
3344             unsigned sz = p->size();
3345             for (unsigned i = 0; i < sz; i++) {
3346                 monomial * m = p->m(i);
3347                 unsigned   d = m->degree_of(x);
3348                 if (d == k)
3349                     m_cheap_som_buffer.add(p->a(i), div_x(m, x));
3350                 else
3351                     m_cheap_som_buffer2.add(p->a(i), m);
3352             }
3353             reduct = m_cheap_som_buffer2.mk();
3354             return m_cheap_som_buffer.mk();
3355         }
3356 
3357         /**
3358            \brief Return true if the coefficient of x^k is just a constant.
3359            Store it in c.
3360          */
const_coeffpolynomial::manager::imp3361         bool const_coeff(polynomial const * p, var x, unsigned k, numeral & c) {
3362             SASSERT(is_valid(x));
3363             m_manager.reset(c);
3364             unsigned sz = p->size();
3365             for (unsigned i = 0; i < sz; i++) {
3366                 monomial * m = p->m(i);
3367                 unsigned   d = m->degree_of(x);
3368                 if (d == k) {
3369                     unsigned msz = m->size();
3370                     if ((k > 0 && msz > 1) || (k == 0 && msz > 0))
3371                         return false;
3372                     m_manager.set(c, p->a(i));
3373                 }
3374             }
3375             return true;
3376         }
3377 
nonzero_const_coeffpolynomial::manager::imp3378         bool nonzero_const_coeff(polynomial const * p, var x, unsigned k) {
3379             scoped_numeral c(m_manager);
3380             return const_coeff(p, x, k, c) && !m_manager.is_zero(c);
3381         }
3382 
3383         /**
3384            \brief Extract the integer content of p.
3385         */
icpolynomial::manager::imp3386         void ic(polynomial const * p, numeral & a) {
3387             if (is_zero(p)) {
3388                 m_manager.reset(a);
3389                 return;
3390             }
3391             if (is_const(p)) {
3392                 m_manager.set(a, p->a(0));
3393                 return;
3394             }
3395             m_manager.set(a, p->a(0));
3396             unsigned sz = p->size();
3397             for (unsigned i = 1; i < sz; i++) {
3398                 if (m_manager.is_one(a))
3399                     return;
3400                 m_manager.gcd(a, p->a(i), a);
3401             }
3402         }
3403 
3404         /**
3405            \brief Sum of the absolute values of the coefficients.
3406         */
abs_normpolynomial::manager::imp3407         void abs_norm(polynomial const * p, numeral & norm) {
3408             m_manager.reset(norm);
3409             scoped_numeral tmp(m_manager);
3410             unsigned sz = p->size();
3411             for (unsigned i = 0; i < sz; ++ i) {
3412                 m_manager.set(tmp, p->a(i));
3413                 m_manager.abs(tmp);
3414                 m_manager.add(norm, tmp, norm);
3415             }
3416         }
3417 
3418         /**
3419            \brief Arbitrary leading integer coefficient.
3420         */
numeral_lcpolynomial::manager::imp3421         numeral const & numeral_lc(polynomial const * p, var x) {
3422             int sz = p->size();
3423             if (sz == 0) {
3424                 return m_zero_numeral;
3425             } else {
3426                 return p->a(0);
3427             }
3428         }
3429 
numeral_tcpolynomial::manager::imp3430         numeral const & numeral_tc(polynomial const * p) {
3431             int sz = p->size();
3432             if (sz == 0) {
3433                 return m_zero_numeral;
3434             }
3435             else {
3436                 monomial * u = mk_unit();
3437                 for (int i = 0; i < sz; ++ i) {
3438                     if (p->m(i) == u)
3439                         return p->a(i);
3440                 }
3441                 return m_zero_numeral;
3442             }
3443         }
3444 
3445         /**
3446            \brief Extract the integer content of p.
3447            p = a*c s.t. the GCD of the coefficients of c is one.
3448         */
icpolynomial::manager::imp3449         void ic(polynomial const * p, numeral & a, polynomial_ref & c) {
3450             if (is_zero(p)) {
3451                 m_manager.reset(a);
3452                 c = const_cast<polynomial*>(p);
3453                 return;
3454             }
3455             if (is_const(p)) {
3456                 m_manager.set(a, p->a(0));
3457                 c = mk_one();
3458                 return;
3459             }
3460             unsigned sz = p->size();
3461             m_manager.gcd(sz, p->as(), a);
3462             if (m_manager.is_one(a)) {
3463                 c = const_cast<polynomial*>(p);
3464                 return;
3465             }
3466             m_cheap_som_buffer.reset();
3467             scoped_numeral ai(m_manager);
3468             for (unsigned i = 0; i < sz; i++) {
3469                 monomial * m = p->m(i);
3470                 m_manager.div(p->a(i), a, ai);
3471                 m_cheap_som_buffer.add_reset(ai, m);
3472             }
3473             c = m_cheap_som_buffer.mk();
3474         }
3475 
3476         // Flip the sign of p, if the leading monomial is negative
flip_sign_if_lm_neg_corepolynomial::manager::imp3477         polynomial * flip_sign_if_lm_neg_core(polynomial const * p) {
3478             if (is_zero(p))
3479                 return const_cast<polynomial*>(p);
3480             unsigned glex_max_pos = p->graded_lex_max_pos();
3481             SASSERT(glex_max_pos != UINT_MAX);
3482             if (m_manager.is_neg(p->a(glex_max_pos)))
3483                 return neg(p);
3484             else
3485                 return const_cast<polynomial*>(p);
3486         }
3487 
flip_sign_if_lm_negpolynomial::manager::imp3488         void flip_sign_if_lm_neg(polynomial_ref & p) {
3489             p = flip_sign_if_lm_neg_core(p);
3490         }
3491 
3492         /**
3493            \brief Extract the integer content, content and primitive part of p with respect to
3494            variable x.
3495         */
iccppolynomial::manager::imp3496         void iccp(polynomial const * p, var x, numeral & i, polynomial_ref & c, polynomial_ref & pp) {
3497             TRACE("polynomial", tout << "iccp x" << x << "\n"; p->display(tout, m_manager); tout << "\n";);
3498             if (is_zero(p)) {
3499                 m_manager.set(i, 0);
3500                 c  = mk_one();
3501                 pp = const_cast<polynomial*>(p);
3502                 return;
3503             }
3504             if (is_const(p)) {
3505                 m_manager.set(i, p->a(0));
3506                 c  = mk_one();
3507                 pp = mk_one();
3508                 return;
3509             }
3510             unsigned d = degree(p, x);
3511             if (d == 0) {
3512                 ic(p, i, c);
3513                 pp = mk_one();
3514                 return;
3515             }
3516             // Apply filter and collect powers of x occurring in p
3517             // The quick filter is the following:
3518             //   If p contains a monomial x^k and no monomial of the form m*x^k m != 1, then
3519             //      c = m_unit_poly
3520             //   To detect that we use a map (iccp_powers) from k to counters.
3521             //   We traverse p and update the map using the following rules:
3522             //      - found monomial x^k then iccp_powers[k]++;
3523             //      - found monomial m*x^k then iccp_powers[k]+=2;
3524             //   If after traversing p, there is a k s.t. iccp_powers[k] == 1, we know c == 1
3525             // We store iccp_powers the powers of x occurring in p.
3526             sbuffer<unsigned, 128> iccp_filter;
3527             sbuffer<unsigned, 128> iccp_powers;
3528             iccp_filter.resize(d+1, 0);
3529             iccp_powers.reset();
3530             for (unsigned j = 0; j <= d; j++)
3531                 iccp_filter[j] = 0;
3532             unsigned sz = p->size();
3533             for (unsigned j = 0; j < sz; j++) {
3534                 monomial * m = p->m(j);
3535                 unsigned   k = m->degree_of(x);
3536                 TRACE("polynomial", tout << "degree of x" << x << " at "; m->display(tout); tout << " is " << k << "\n";);
3537                 if (iccp_filter[k] == 0)
3538                     iccp_powers.push_back(k);
3539                 if (m->size() == (k > 0 ? 1 : 0))
3540                     iccp_filter[k]++;
3541                 else
3542                     iccp_filter[k]+=2;
3543             }
3544             SASSERT(!iccp_powers.empty());
3545             unsigned num_powers = iccp_powers.size();
3546             for (unsigned j = 0; j < num_powers; j++) {
3547                 SASSERT(iccp_filter[iccp_powers[j]] > 0);
3548                 if (iccp_filter[iccp_powers[j]] == 1) {
3549                     ic(p, i, pp);
3550                     c = mk_one();
3551                     return;
3552                 }
3553             }
3554             // Extract integer content
3555             ic(p, i, pp);
3556             TRACE("polynomial", tout << "p: "; p->display(tout, m_manager); tout << "\ni: " << m_manager.to_string(i) << "\npp: " << pp << "\n";);
3557             // Compute c using the gcd of coeffs of x^k for k's in iccp_powers
3558             polynomial_ref ci(pm());
3559             c = coeff(pp, x, iccp_powers[0]);
3560             for (unsigned j = 1; j < num_powers; j++) {
3561                 ci = coeff(pp, x, iccp_powers[j]);
3562                 gcd(c, ci, c);
3563                 if (is_const(c)) {
3564                     c = mk_one();
3565                     return;
3566                 }
3567             }
3568             SASSERT(!is_const(c));
3569             // make sure the sign of the leading monomial is positive
3570             flip_sign_if_lm_neg(c);
3571             TRACE("polynomial", tout << "pp: " << pp << "\nc: " << c << "\n";);
3572             pp = exact_div(pp, c);
3573         }
3574 
iccppolynomial::manager::imp3575         void iccp(polynomial const * p, numeral & i, polynomial_ref & c, polynomial_ref & pp) {
3576             iccp(p, max_var(p), i, c, pp);
3577         }
3578 
pppolynomial::manager::imp3579         polynomial_ref pp(polynomial const * p, var x) {
3580             scoped_numeral i(m_manager);
3581             polynomial_ref c(pm()), result(pm());
3582             iccp(p, x, i, c, result);
3583             return result;
3584         }
3585 
is_primitivepolynomial::manager::imp3586         bool is_primitive(polynomial const * p, var x) {
3587             scoped_numeral i(m_manager);
3588             polynomial_ref c(pm());
3589             polynomial_ref pp(pm());
3590             iccp(p, x, i, c, pp);
3591             return eq(p, pp);
3592         }
3593 
lcpolynomial::manager::imp3594         polynomial * lc(polynomial const * p, var x) {
3595             return coeff(p, x, degree(p, x));
3596         }
3597 
gcd_prspolynomial::manager::imp3598         void gcd_prs(polynomial const * u, polynomial const * v, var x, polynomial_ref & r) {
3599             TRACE("polynomial_gcd", tout << "gcd prs with x" << x << " for\nu: ";
3600                   u->display(tout, m_manager); tout << "\nv: "; v->display(tout, m_manager); tout << "\n";);
3601             if (degree(u, x) < degree(v, x))
3602                 std::swap(u, v);
3603             scoped_numeral i_u(m_manager), i_v(m_manager);
3604             polynomial_ref c_u(pm()), c_v(pm());
3605             polynomial_ref pp_u(pm()), pp_v(pm());
3606             scoped_numeral d_a(m_manager);
3607             polynomial_ref d_r(pm());
3608             polynomial_ref g(pm()), h(pm()), rem(pm()), new_h(pm());
3609 
3610             iccp(u, x, i_u, c_u, pp_u);
3611             iccp(v, x, i_v, c_v, pp_v);
3612 
3613             gcd(c_u, c_v, d_r);
3614             m_manager.gcd(i_u, i_v, d_a);
3615             TRACE("polynomial_gcd_detail",
3616                   tout << "After GCD of the content\n";
3617                   tout << "u: "; u->display(tout, m_manager); tout << "\n";
3618                   tout << "v: "; v->display(tout, m_manager); tout << "\n";
3619                   tout << "i_u: " << i_u << "\n";
3620                   tout << "i_v: " << i_v << "\n";
3621                   tout << "c_u: " << c_u << "\n";
3622                   tout << "c_v: " << c_v << "\n";
3623                   tout << "pp_u: " << pp_u << "\n";
3624                   tout << "pp_v: " << pp_v << "\n";
3625                   tout << "d_r: " << d_r << "\nd_a: " << d_a << "\n";);
3626 
3627             g = mk_one();
3628             h = mk_one();
3629 
3630             unsigned counter = 0;
3631             while (true) {
3632                 SASSERT(degree(pp_u, x) >= degree(pp_v, x));
3633                 unsigned delta = degree(pp_u, x) - degree(pp_v, x);
3634                 TRACE("polynomial_gcd_detail",
3635                       tout << "iteration: " << counter << "\n";
3636                       tout << "gcd loop\npp_u: " << pp_u << "\npp_v: " << pp_v << "\ndelta: " << delta << "\n";);
3637                 counter++;
3638                 exact_pseudo_remainder(pp_u, pp_v, x, rem);
3639                 if (is_zero(rem)) {
3640                     TRACE("polynomial", tout << "rem is zero...\npp_v: " << pp_v << "\n";);
3641                     flip_sign_if_lm_neg(pp_v);
3642                     r = pp(pp_v, x);
3643                     r = mul(d_a, d_r, r);
3644                     return;
3645                 }
3646                 if (is_const(rem)) {
3647                     TRACE("polynomial", tout << "rem is a constant: " << rem << "\nr: " << d_r << "\nd_a: " << d_a << "\n";);
3648                     r = mul(d_a, d_r);
3649                     return;
3650                 }
3651                 pp_u = pp_v;
3652                 // pp_v <- rem/g*h^{delta}
3653                 pp_v = exact_div(rem, g);
3654                 // delta is usually a small number, so I do not compute h^delta
3655                 for (unsigned i = 0; i < delta; i++)
3656                     pp_v = exact_div(pp_v, h);
3657                 g   = lc(pp_u, x);
3658                 // h <- h^{1-delta}*g^{delta}
3659                 new_h = mk_one();
3660                 for (unsigned i = 0; i < delta; i++)
3661                     new_h = mul(new_h, g);
3662                 if (delta > 1) {
3663                     for (unsigned i = 0; i < delta - 1; i++)
3664                         new_h = exact_div(new_h, h);
3665                 }
3666                 h = new_h;
3667             }
3668         }
3669 
3670         // Store in r <- gcd(content(u, x), v)
gcd_contentpolynomial::manager::imp3671         void gcd_content(polynomial const * u, var x, polynomial const * v, polynomial_ref & r) {
3672             scoped_numeral i_u(m_manager);
3673             polynomial_ref c_u(pm());
3674             polynomial_ref pp_u(pm());
3675 
3676             iccp(u, x, i_u, c_u, pp_u);
3677             c_u = mul(i_u, c_u);
3678             gcd(c_u, v, r);
3679         }
3680 
3681         // TODO: implement euclid algorithm when m_manager in Zp mode
euclid_gcdpolynomial::manager::imp3682         void euclid_gcd(polynomial const * u, polynomial const * v, polynomial_ref & r) {
3683             SASSERT(m().modular());
3684             CTRACE("mgcd", !is_univariate(u) || !is_univariate(v),
3685                    tout << "euclid_gcd, polynomials are not univariate\n"; u->display(tout, m()); tout << "\n"; v->display(tout, m()); tout << "\n";);
3686             SASSERT(is_univariate(u));
3687             SASSERT(is_univariate(v));
3688             if (is_zero(u)) {
3689                 r = const_cast<polynomial*>(v);
3690                 flip_sign_if_lm_neg(r);
3691                 return;
3692             }
3693             if (is_zero(v)) {
3694                 r = const_cast<polynomial*>(u);
3695                 flip_sign_if_lm_neg(r);
3696                 return;
3697             }
3698             if (u == v) {
3699                 r = const_cast<polynomial*>(u);
3700                 flip_sign_if_lm_neg(r);
3701                 return;
3702             }
3703             if (is_const(u) || is_const(v)) {
3704                 scoped_numeral i_u(m_manager), i_v(m_manager);
3705                 ic(v, i_v);
3706                 ic(u, i_u);
3707                 scoped_numeral a(m_manager);
3708                 m_manager.gcd(i_v, i_u, a);
3709                 r = mk_const(a);
3710                 return;
3711             }
3712            // Maybe map it to univariate case
3713             gcd_prs(u, v, max_var(u), r);
3714         }
3715 
3716         // Combine two different modular images using Chinese Remainder theorem
3717         // The new bound is stored in b2
CRA_combine_imagespolynomial::manager::imp3718         void CRA_combine_images(polynomial const * C1, scoped_numeral const & b1, polynomial const * C2, scoped_numeral & b2, polynomial_ref & r) {
3719             lex_sort(C1);
3720             lex_sort(C2);
3721             TRACE("CRA", tout << "C1: "; C1->display(tout, m()); tout << "\nC2: "; C2->display(tout, m()); tout << "\n";);
3722             SASSERT(m_cheap_som_buffer.empty());
3723             SASSERT(!m().m().is_even(b1));
3724             SASSERT(!m().m().is_even(b2));
3725             cheap_som_buffer & R = m_cheap_som_buffer;
3726             scoped_numeral inv1(m());
3727             scoped_numeral inv2(m());
3728             scoped_numeral g(m());
3729             m().gcd(b1, b2, inv1, inv2, g);
3730             SASSERT(m().is_one(g));
3731             TRACE("CRA", tout << "b1: " << b1 << ", b2: " << b2 << ", inv1: " << inv1 << ", inv2: " << inv2 << "\n";);
3732             // b1*inv1 + b2.inv2 = 1
3733             // inv1 is the inverse of b1 mod b2
3734             // inv2 is the inverse of b2 mod b1
3735             m().m().mod(inv1, b2, inv1);
3736             m().m().mod(inv2, b1, inv2);
3737             TRACE("CRA", tout << "inv1: " << inv1 << ", inv2: " << inv2 << "\n";);
3738             scoped_numeral a1(m());
3739             scoped_numeral a2(m());
3740             m().mul(b2, inv2, a1); // a1 is the multiplicator for coefficients of C1
3741             m().mul(b1, inv1, a2); // a2 is the multiplicator for coefficients of C2
3742             TRACE("CRA", tout << "a1: " << a1 << ", a2: " << a2 << "\n";);
3743             // new bound
3744             scoped_numeral new_bound(m());
3745             m().mul(b1, b2, new_bound);
3746             scoped_numeral lower(m());
3747             scoped_numeral upper(m());
3748             scoped_numeral new_a(m()), tmp1(m()), tmp2(m()), tmp3(m());
3749             m().div(new_bound, 2, upper);
3750             m().set(lower, upper);
3751             m().neg(lower);
3752             TRACE("CRA", tout << "lower: " << lower << ", upper: " << upper << "\n";);
3753 
3754             #define ADD(A1, A2, M) {                    \
3755                 m().mul(A1, a1, tmp1);                  \
3756                 m().mul(A2, a2, tmp2);                  \
3757                 m().add(tmp1, tmp2, tmp3);              \
3758                 m().m().mod(tmp3, new_bound, new_a);    \
3759                 if (m().gt(new_a, upper))               \
3760                     m().sub(new_a, new_bound, new_a);   \
3761                 R.add(new_a, M);                        \
3762             }
3763 
3764             numeral zero(0);
3765             unsigned i1  = 0;
3766             unsigned i2  = 0;
3767             unsigned sz1 = C1->size();
3768             unsigned sz2 = C2->size();
3769             while (true) {
3770                 if (i1 == sz1) {
3771                     while (i2 < sz2) {
3772                         TRACE("CRA", tout << "adding C2 rest\n";);
3773                         ADD(zero, C2->a(i2), C2->m(i2));
3774                         i2++;
3775                     }
3776                     break;
3777                 }
3778                 if (i2 == sz2) {
3779                     while (i1 < sz1) {
3780                         TRACE("CRA", tout << "adding C1 rest\n";);
3781                         ADD(C1->a(i1), zero, C1->m(i1));
3782                         i1++;
3783                     }
3784                     break;
3785                 }
3786                 monomial * m1 = C1->m(i1);
3787                 monomial * m2 = C2->m(i2);
3788                 int s = lex_compare(m1, m2);
3789                 if (s == 0) {
3790                     ADD(C1->a(i1), C2->a(i2), m1);
3791                     TRACE("CRA",
3792                           tout << "C1->a(i1): " << m().to_string(C1->a(i1)) << ", C2->a(i2): " << m().to_string(C2->a(i2)) << ", new_a: " << new_a << "\n";
3793                           tout << "tmp1: " << tmp1 << ", tmp2: " << tmp2 << ", tmp3: " << tmp3 << "\n";);
3794                     i1++;
3795                     i2++;
3796                 }
3797                 else if (s > 0) {
3798                     TRACE("CRA", tout << "C1 mon biggerr, adding it...\n";);
3799                     ADD(C1->a(i1), zero, m1);
3800                     i1++;
3801                 }
3802                 else {
3803                     TRACE("CRA", tout << "C2 mon bigger, adding it...\n";);
3804                     ADD(zero, C2->a(i2), m2);
3805                     i2++;
3806                 }
3807             }
3808             m().set(b2, new_bound);
3809             r  = R.mk();
3810         }
3811 
uni_mod_gcdpolynomial::manager::imp3812         void uni_mod_gcd(polynomial const * u, polynomial const * v, polynomial_ref & r) {
3813             TRACE("mgcd", tout << "univ_modular_gcd\nu: "; u->display(tout, m_manager); tout << "\nv: "; v->display(tout, m_manager); tout << "\n";);
3814             SASSERT(!m().modular());
3815             SASSERT(is_univariate(u));
3816             SASSERT(!is_const(u) && !is_const(v));
3817             SASSERT(max_var(u) == max_var(v));
3818             var x = max_var(u);
3819             scoped_numeral c_u(m()), c_v(m());
3820             polynomial_ref pp_u(pm()), pp_v(pm());
3821             ic(u, c_u, pp_u);
3822             ic(v, c_v, pp_v);
3823 
3824             scoped_numeral d_a(m());
3825             m_manager.gcd(c_u, c_v, d_a);
3826 
3827             scoped_numeral lc_u(m());
3828             scoped_numeral lc_v(m());
3829             unsigned d_u = degree(pp_u, x);
3830             unsigned d_v = degree(pp_v, x);
3831             lc_u = univ_coeff(pp_u, d_u);
3832             lc_v = univ_coeff(pp_v, d_v);
3833             scoped_numeral lc_g(m());
3834             m().gcd(lc_u, lc_v, lc_g);
3835 
3836             polynomial_ref u_Zp(m_wrapper);
3837             polynomial_ref v_Zp(m_wrapper);
3838 
3839             polynomial_ref C_star(m_wrapper);
3840             scoped_numeral bound(m());
3841             polynomial_ref q(m_wrapper);
3842 
3843             polynomial_ref candidate(m_wrapper);
3844 
3845             scoped_numeral p(m());
3846             for (unsigned i = 0; i < NUM_BIG_PRIMES; i++) {
3847                 m().set(p, g_big_primes[i]);
3848                 TRACE("mgcd", tout << "trying prime: " << p << "\n";);
3849                 {
3850                     scoped_set_zp setZp(m_wrapper, p);
3851                     u_Zp = normalize(pp_u);
3852                     v_Zp = normalize(pp_v);
3853                     if (degree(u_Zp, x) < d_u) {
3854                         TRACE("mgcd", tout << "bad prime, leading coefficient vanished\n";);
3855                         continue; // bad prime
3856                     }
3857                     if (degree(v_Zp, x) < d_v) {
3858                         TRACE("mgcd", tout << "bad prime, leading coefficient vanished\n";);
3859                         continue; // bad prime
3860                     }
3861                     euclid_gcd(u_Zp, v_Zp, q);
3862                     // normalize so that lc_g is leading coefficient of q
3863                     q = mk_glex_monic(q);
3864                     scoped_numeral c(m());
3865                     m().set(c, lc_g);
3866                     q = mul(c, q);
3867                 }
3868                 TRACE("mgcd", tout << "new q:\n" << q << "\n";);
3869                 if (is_const(q)) {
3870                     TRACE("mgcd", tout << "done, modular gcd is one\n";);
3871                     if (m().is_one(d_a))
3872                         r = q; // GCD is one
3873                     else
3874                         r = mk_const(d_a);
3875                     return;
3876                 }
3877                 if (C_star.get() == nullptr) {
3878                     C_star = q;
3879                     m().set(bound, p);
3880                 }
3881                 else {
3882                     if (degree(q, x) < degree(C_star, x)) {
3883                         // discard accumulated image, it was affected by unlucky primes
3884                         TRACE("mgcd", tout << "discarding image\n";);
3885                         C_star = q;
3886                         m().set(bound, p);
3887                     }
3888                     else {
3889                         CRA_combine_images(q, p, C_star, bound, C_star);
3890                         TRACE("mgcd", tout << "new combined:\n" << C_star << "\n";);
3891                     }
3892                 }
3893                 candidate = pp(C_star, x);
3894                 TRACE("mgcd", tout << "candidate:\n" << candidate << "\n";);
3895                 scoped_numeral lc_candidate(m());
3896                 lc_candidate = univ_coeff(candidate, degree(candidate, x));
3897                 if (m().divides(lc_candidate, lc_g) &&
3898                     divides(candidate, pp_u) &&
3899                     divides(candidate, pp_v)) {
3900                     TRACE("mgcd", tout << "found GCD\n";);
3901                     r = mul(d_a, candidate);
3902                     flip_sign_if_lm_neg(r);
3903                     TRACE("mgcd", tout << "r: " << r << "\n";);
3904                     return;
3905                 }
3906             }
3907             // Oops, modular GCD failed, not enough primes
3908             // fallback to prs
3909             gcd_prs(u, v, x, r);
3910         }
3911 
3912         typedef ref_buffer<polynomial, manager> polynomial_ref_buffer;
3913 
3914         /**
3915            Compute the content and primitive parts of p, when p is viewed as a multivariate polynomial Zp[y_1, ..., y_n]
3916            with coefficients in Zp[x].
3917         */
3918         som_buffer_vector m_iccp_ZpX_buffers;
iccp_ZpXpolynomial::manager::imp3919         void iccp_ZpX(polynomial const * p, var x, numeral & ci, polynomial_ref & c, polynomial_ref & pp) {
3920             SASSERT(m().modular());
3921             TRACE("mgcd_detail", tout << "iccp_ZpX, p: "; p->display(tout, m()); tout << "\nvar x" << x << "\n";);
3922             if (is_zero(p)) {
3923                 TRACE("mgcd_detail", tout << "iccp_ZpX, p is zero\n";);
3924                 m_manager.set(ci, 0);
3925                 c  = mk_one();
3926                 pp = const_cast<polynomial*>(p);
3927                 return;
3928             }
3929             if (is_const(p)) {
3930                 TRACE("mgcd_detail", tout << "iccp_ZpX, p is constant\n";);
3931                 m_manager.set(ci, p->a(0));
3932                 c  = mk_one();
3933                 pp = mk_one();
3934                 return;
3935             }
3936             unsigned d = degree(p, x);
3937             if (d == 0) {
3938                 TRACE("mgcd_detail", tout << "iccp_ZpX, degree(p, x) == 0\n";);
3939                 ic(p, ci, pp);
3940                 c = mk_one();
3941                 return;
3942             }
3943             // 1) traverse monomials of p, and mark the monomials that contain p, also compute the minimal degree of x in p.
3944             ref_buffer<monomial, manager> no_x_ms(m_wrapper); // monomials that do not contains x
3945             unsigned min_degree = UINT_MAX;    // min degree of x in p
3946             unsigned sz = p->size();
3947             for (unsigned i = 0; i < sz; i++) {
3948                 monomial * m = p->m(i);
3949                 unsigned   k = m->degree_of(x);
3950                 if (k == 0) {
3951                     // if m is not marked
3952                     if (m_m2pos.get(m) == UINT_MAX) {
3953                         no_x_ms.push_back(m);
3954                         m_m2pos.set(m, 1); // it is just a mark
3955                     }
3956                 }
3957                 if (k < min_degree)
3958                     min_degree = k;
3959             }
3960             SASSERT(min_degree == 0 || no_x_ms.empty());
3961             if (min_degree > 0) {
3962                 SASSERT(no_x_ms.empty());
3963                 // nothing was marked.
3964                 // divide by x^min_degree
3965                 TRACE("mgcd_detail", tout << "iccp_ZpX, all monomials contain x" << x << ", dividing by x" << x << "^" << min_degree << "\n";);
3966                 polynomial_ref xmin(m_wrapper);
3967                 polynomial_ref new_p(m_wrapper);
3968                 xmin  = mk_polynomial(x, min_degree);
3969                 new_p = exact_div(p, xmin);
3970                 iccp_ZpX(new_p, x, ci, c, pp);
3971                 c     = mul(xmin, c);
3972                 return;
3973             }
3974             // 2) if for some marked monomial m (i.e., the ones that do not contain x), there is no monomial m*x^k in p,
3975             //    then c = 1
3976             unsigned num_marked = no_x_ms.size();
3977             unsigned num_unmarked = 0;
3978             monomial_ref tmp_m(m_wrapper);
3979             for (unsigned i = 0; i < sz; i++) {
3980                 monomial * m = p->m(i);
3981                 unsigned   k = m->degree_of(x);
3982                 if (k == 0)
3983                     continue;
3984                 tmp_m = div_x(m, x);
3985                 SASSERT(tmp_m != m); // since x is in m, but not in tmp_m
3986                 if (m_m2pos.get(tmp_m) == 1) {
3987                     num_unmarked++;
3988                     m_m2pos.reset(tmp_m);
3989                     SASSERT(m_m2pos.get(tmp_m) == UINT_MAX);
3990                 }
3991             }
3992             SASSERT(num_unmarked <= num_marked);
3993             if (num_unmarked < num_marked) {
3994                 // reset remaining marks
3995                 for (unsigned i = 0; i < num_marked; i++)
3996                     m_m2pos.reset(no_x_ms[i]);
3997                 TRACE("mgcd_detail", tout << "iccp_ZpX, cheap case... invoking ic\n";);
3998                 ic(p, ci, pp);
3999                 c  = mk_one();
4000                 return;
4001             }
4002             // 3) expensive case
4003             // Basic idea: separate a*m*x^k into a*x^k and m, put a*x^k into the som_buffer associated with m.
4004             // The mapping between m is som_buffers is given by m_m2pos
4005 
4006             // Extract integer content
4007             ic(p, ci, pp);
4008             no_x_ms.reset();
4009             som_buffer_vector & som_buffers = m_iccp_ZpX_buffers;
4010             som_buffers.set_owner(this);
4011             for (unsigned i = 0; i < sz; i++) {
4012                 monomial * m = pp->m(i);
4013                 unsigned   k = m->degree_of(x);
4014                 if (k != 0) {
4015                     tmp_m = div_x(m, x);
4016                     m = tmp_m.get();
4017                 }
4018                 unsigned pos = m_m2pos.get(m);
4019                 if (pos == UINT_MAX) {
4020                     pos = no_x_ms.size();
4021                     no_x_ms.push_back(m);
4022                     m_m2pos.set(m, pos);
4023                 }
4024                 som_buffer * som = som_buffers[pos];
4025                 som->add(pp->a(i), mk_monomial(x, k));
4026             }
4027             unsigned num_ms = no_x_ms.size();
4028             for (unsigned i = 0; i < num_ms; i++)
4029                 m_m2pos.reset(no_x_ms[i]);
4030             SASSERT(num_ms > 0);
4031             // Compute GCD of all som_buffers
4032             polynomial_ref g(m_wrapper);
4033             polynomial_ref new_g(m_wrapper);
4034             g = som_buffers[0]->mk();
4035             for (unsigned i = 1; i < num_ms; i++) {
4036                 polynomial_ref a(m_wrapper);
4037                 a = som_buffers[i]->mk();
4038                 SASSERT(is_univariate(a));
4039                 euclid_gcd(g, a, new_g);
4040                 g = new_g;
4041                 if (is_const(g))
4042                     break;
4043             }
4044             if (!is_const(g)) {
4045                 CTRACE("content_bug", !divides(g, pp),
4046                        tout << "GF(" << m().m().to_string(m().p()) << ")\n";
4047                        tout << "pp: "; pp->display(tout, m()); tout << "\n"; tout << "var: x" << x << "\n";
4048                        tout << "content: " << g << "\n";);
4049                 c  = g;
4050                 pp = exact_div(pp, c);
4051             }
4052             else {
4053                 c  = mk_one();
4054             }
4055             som_buffers.reset(num_ms);
4056         }
4057 
4058         // Return the leading coefficient (with respect to glex) of p when
4059         // p is viewed as a multivariate polynomial Zp[y_1, ..., y_n] with coefficients in Zp[x].
lc_glex_ZpXpolynomial::manager::imp4060         polynomial * lc_glex_ZpX(polynomial const * p, var x) {
4061             // collect a*x^k of maximal monomial with respect to glex
4062             m_som_buffer.reset();
4063             monomial_ref max_m(m_wrapper);
4064             monomial_ref tmp_m(m_wrapper);
4065             unsigned sz = p->size();
4066             for (unsigned i = 0; i < sz; i++) {
4067                 monomial * m = p->m(i);
4068                 unsigned   k = m->degree_of(x);
4069                 if (k != 0) {
4070                     tmp_m = div_x(m, x);
4071                     m = tmp_m.get();
4072                 }
4073                 if (max_m == 0 || graded_lex_compare(m, max_m) > 0) {
4074                     // found new maximal monomial
4075                     m_som_buffer.reset();
4076                     max_m = m;
4077                     m_som_buffer.add(p->a(i), mk_monomial(x, k));
4078                 }
4079                 else if (max_m == m) {
4080                     // found another a*x^k of max_m
4081                     m_som_buffer.add(p->a(i), mk_monomial(x, k));
4082                 }
4083             }
4084             SASSERT(!m_som_buffer.empty());
4085             TRACE("mgcd_detail", tout << "maximal monomial: "; max_m->display(tout); tout << "\n";);
4086             return m_som_buffer.mk();
4087         }
4088 
4089         // Wrapper for iccp_ZpX
primitive_ZpXpolynomial::manager::imp4090         void primitive_ZpX(polynomial const * p, var x, polynomial_ref & pp) {
4091             scoped_numeral ci(m());
4092             polynomial_ref c(m_wrapper);
4093             iccp_ZpX(p, x, ci, c, pp);
4094         }
4095 
4096         // select a new random value in GF(p) that is not in vals, and store it in r
peek_freshpolynomial::manager::imp4097         void peek_fresh(scoped_numeral_vector const & vals, unsigned p, scoped_numeral & r) {
4098             SASSERT(vals.size() < p); // otherwise we can't keep the fresh value
4099             unsigned sz = vals.size();
4100             while (true) {
4101                 m().set(r, rand() % p);
4102                 // check if fresh value...
4103                 unsigned k = 0;
4104                 for (; k < sz; k++) {
4105                     if (m().eq(vals[k], r))
4106                         break;
4107                 }
4108                 if (k == sz)
4109                     return; // value is fresh
4110             }
4111         }
4112 
4113         newton_interpolator_vector   m_mgcd_iterpolators;
4114         scoped_ptr_vector<skeleton>  m_mgcd_skeletons;
4115 
4116         struct sparse_mgcd_failed {};
4117 
4118         // Auxiliary recursive function used in multivariate modular GCD
mod_gcd_recpolynomial::manager::imp4119         void mod_gcd_rec(polynomial const * u, polynomial const * v, unsigned p,
4120                          unsigned idx, var_buffer const & vars, polynomial_ref & r) {
4121             TRACE("mgcd", tout << "mod_gcd_rec\nu: "; u->display(tout, m_manager, true); tout << "\nv: "; v->display(tout, m_manager, true); tout << "\n";);
4122             unsigned num_vars = vars.size();
4123             SASSERT(num_vars > 0);
4124             if (idx == num_vars - 1) {
4125                 SASSERT(is_univariate(u));
4126                 SASSERT(is_univariate(v));
4127                 euclid_gcd(u, v, r);
4128                 TRACE("mgcd", tout << "mod_gcd_rec result: "; r->display(tout, m_manager, true); tout << "\n";);
4129                 return;
4130             }
4131 
4132             var x = vars[idx];
4133             scoped_numeral ci_u(m()), ci_v(m());
4134             polynomial_ref c_u(m_wrapper),  pp_u(m_wrapper), lc_u(m_wrapper);
4135             polynomial_ref c_v(m_wrapper),  pp_v(m_wrapper), lc_v(m_wrapper);
4136             iccp_ZpX(u, x, ci_u, c_u, pp_u);
4137             iccp_ZpX(v, x, ci_v, c_v, pp_v);
4138             lc_u = lc_glex_ZpX(pp_u, x);
4139             lc_v = lc_glex_ZpX(pp_v, x);
4140             scoped_numeral ci_g(m());
4141             polynomial_ref c_g(m_wrapper);
4142             polynomial_ref lc_g(m_wrapper);
4143             TRACE("mgcd_detail",
4144                   tout << "idx: " << idx << "\n";
4145                   tout << "x" << x << "\n";
4146                   tout << "pp_u = "; pp_u->display(tout, m_manager, true); tout << "\n";
4147                   tout << "pp_v = "; pp_v->display(tout, m_manager, true); tout << "\n";
4148                   tout << "c_u = "; c_u->display(tout, m_manager, true); tout << "\n";
4149                   tout << "c_v = "; c_v->display(tout, m_manager, true); tout << "\n";
4150                   tout << "lc_u = "; lc_u->display(tout, m_manager, true); tout << "\n";
4151                   tout << "lc_v = "; lc_v->display(tout, m_manager, true); tout << "\n";
4152                   tout << "ci_u = " << ci_u << "\n";
4153                   tout << "ci_v = " << ci_v << "\n";);
4154             m().gcd(ci_u, ci_v, ci_g);
4155             euclid_gcd(c_u, c_v, c_g);
4156             euclid_gcd(lc_u, lc_v, lc_g);
4157             TRACE("mgcd_detail",
4158                   tout << "c_g = "; c_g->display(tout, m_manager, true); tout << "\n";
4159                   tout << "lc_g = "; lc_g->display(tout, m_manager, true); tout << "\n";
4160                   tout << "ci_g = " << ci_g << "\n";);
4161 
4162             skeleton * sk = m_mgcd_skeletons[idx];
4163 
4164             // use dense interpolation if skeleton is not available
4165             newton_interpolator & interpolator = m_mgcd_iterpolators[idx];
4166             sparse_interpolator sinterpolator(sk);
4167 
4168             polynomial_ref u1(m_wrapper), v1(m_wrapper), q(m_wrapper);
4169             scoped_numeral val(m());
4170             scoped_numeral lc_g_val(m());
4171             polynomial_ref H(m_wrapper), C(m_wrapper);
4172             polynomial_ref lc_H(m_wrapper);
4173             unsigned min_deg_q = UINT_MAX;
4174             unsigned counter   = 0;
4175 
4176             for (;; counter++) {
4177                 while (true) {
4178                     peek_fresh(interpolator.inputs(), p, val);
4179                     // the selected value must satisfy lc_g(val) != 0
4180                     univ_eval(lc_g, x, val, lc_g_val);
4181                     if (!m().is_zero(lc_g_val))
4182                         break;
4183                 }
4184                 TRACE("mgcd", tout << "x" << x << " -> " << val << "\n";);
4185                 u1 = substitute(pp_u, 1, &x, &(val.get()));
4186                 v1 = substitute(pp_v, 1, &x, &(val.get()));
4187                 mod_gcd_rec(u1, v1, p, idx+1, vars, q);
4188                 q = mk_glex_monic(q);
4189                 q = mul(lc_g_val, q);
4190                 var q_var      = max_var(q);
4191                 unsigned deg_q = q_var == null_var ? 0 : degree(q, q_var);
4192                 TRACE("mgcd_detail", tout << "counter: " << counter << "\nidx: " << idx << "\nq: " << q << "\ndeg_q: " << deg_q << "\nmin_deg_q: " <<
4193                       min_deg_q << "\nnext_x: x" << vars[idx+1] << "\nmax_var(q): " << q_var << "\n";);
4194                 if (deg_q < min_deg_q) {
4195                     TRACE("mgcd_detail", tout << "resetting...\n";);
4196                     counter   = 0;
4197                     min_deg_q = deg_q;
4198                     // start from scratch
4199                     if (sk == nullptr) {
4200                         interpolator.reset();
4201                         interpolator.add(val, q);
4202                     }
4203                     else {
4204                         sinterpolator.reset();
4205                         if (!sinterpolator.add(val, q))
4206                             throw sparse_mgcd_failed();
4207                     }
4208                 }
4209                 else if (deg_q == min_deg_q) {
4210                     TRACE("mgcd_detail", tout << "adding sample point...\n";);
4211                     if (sk == nullptr) {
4212                         interpolator.add(val, q);
4213                     }
4214                     else {
4215                         if (!sinterpolator.add(val, q))
4216                             throw sparse_mgcd_failed();
4217                     }
4218                 }
4219                 else {
4220                     TRACE("mgcd", tout << "skipping q...\n";);
4221                     continue;
4222                 }
4223                 bool found_candidate = false;
4224                 if (sk == nullptr) {
4225                     SASSERT(interpolator.num_sample_points() > 0);
4226                     interpolator.mk(x, H);
4227                     TRACE("mgcd_detail", tout << "idx: " << idx << "\ncandidate H: " << H << "\n";);
4228                     lc_H = lc_glex_ZpX(H, x);
4229                     TRACE("mgcd_detail", tout << "idx: " << idx << "\nlc_H: " << lc_H << "\nlc_g: " << lc_g << "\n";);
4230                     if (eq(lc_H, lc_g)) {
4231                         found_candidate = true;
4232                     }
4233                 }
4234                 else {
4235                     if (sinterpolator.ready()) {
4236                         if (!sinterpolator.mk(H))
4237                             throw sparse_mgcd_failed();
4238                         found_candidate = true;
4239                     }
4240                 }
4241 
4242                 bool done = false;
4243                 if (found_candidate) {
4244                     if (degree(H, x) > 0)
4245                         primitive_ZpX(H, x, C);
4246                     else
4247                         C = normalize(H);
4248                     TRACE("mgcd_detail", tout << "C: " << C << "\npp_u: " << pp_u << "\npp_v: " << pp_v << "\ndivides(C, pp_u): " <<
4249                           divides(C, pp_u) << "\ndivides(C, pp_v): " << divides(C, pp_v) << "\n";);
4250                     if (divides(C, pp_u) && divides(C, pp_v)) {
4251                         r = mul(c_g, C);
4252                         r = mul(ci_g, r);
4253                         done = true;
4254                     }
4255                     else if (min_deg_q == 0) {
4256                         r = c_g;
4257                         r = mul(ci_g, r);
4258                         done = true;
4259                     }
4260                     else if (sk != nullptr) {
4261                         throw sparse_mgcd_failed();
4262                     }
4263                 }
4264 
4265                 if (done) {
4266                     TRACE("mgcd", tout << "idx: " << idx << "\nresult: " << r << "\n";);
4267                     if (sk == nullptr && m_use_sparse_gcd) {
4268                         // save skeleton
4269                         skeleton * new_sk = alloc(skeleton, *this, H, x);
4270                         m_mgcd_skeletons.set(idx, new_sk);
4271                     }
4272                     return;
4273                 }
4274             }
4275         }
4276 
4277         // Multivariate modular GCD algorithm
mod_gcdpolynomial::manager::imp4278         void mod_gcd(polynomial const * u, polynomial const * v,
4279                      power_buffer const & u_var_degrees, power_buffer const & v_var_degrees,
4280                      polynomial_ref & r) {
4281             m_mgcd_iterpolators.set_owner(this);
4282             TRACE("mgcd", tout << "mod_gcd\nu: "; u->display(tout, m_manager, true); tout << "\nv: "; v->display(tout, m_manager, true); tout << "\n";);
4283             TRACE("mgcd_call", tout << "mod_gcd\nu: "; u->display(tout, m_manager, true); tout << "\nv: "; v->display(tout, m_manager, true); tout << "\n";);
4284             SASSERT(!m().modular());
4285             // u and v contain the same set of variables
4286             SASSERT(u_var_degrees.size() == v_var_degrees.size());
4287             unsigned num_vars = u_var_degrees.size();
4288             SASSERT(num_vars > 1); // should use uni_mod_gcd if univariate
4289             var_buffer      vars;
4290             power_buffer var_min_degrees;
4291             for (unsigned i = 0; i < num_vars; i++) {
4292                 SASSERT(u_var_degrees[i].get_var() == v_var_degrees[i].get_var());
4293                 var x = u_var_degrees[i].get_var();
4294                 unsigned d = std::min(u_var_degrees[i].degree(), v_var_degrees[i].degree());
4295                 var_min_degrees.push_back(power(x, d));
4296             }
4297             std::sort(var_min_degrees.begin(), var_min_degrees.end(), power::lt_degree());
4298             m_mgcd_skeletons.reset();
4299             for (unsigned i = 0; i < num_vars; i++) {
4300                 vars.push_back(var_min_degrees[i].get_var());
4301                 m_mgcd_skeletons.push_back(nullptr);
4302             }
4303 
4304             scoped_numeral c_u(m()), c_v(m());
4305             polynomial_ref pp_u(pm()), pp_v(pm());
4306             ic(u, c_u, pp_u);
4307             ic(v, c_v, pp_v);
4308 
4309             scoped_numeral d_a(m());
4310             m_manager.gcd(c_u, c_v, d_a);
4311 
4312             unsigned mm_u_pos = pp_u->graded_lex_max_pos(); // position of the maximal monomial in u
4313             unsigned mm_v_pos = pp_v->graded_lex_max_pos(); // position of the maximal monomial in v
4314             scoped_numeral lc_u(m());
4315             scoped_numeral lc_v(m());
4316             lc_u = pp_u->a(mm_u_pos);
4317             lc_v = pp_v->a(mm_v_pos);
4318             scoped_numeral lc_g(m());
4319             m().gcd(lc_u, lc_v, lc_g);
4320 
4321             polynomial_ref u_Zp(m_wrapper);
4322             polynomial_ref v_Zp(m_wrapper);
4323             polynomial_ref C_star(m_wrapper);
4324             scoped_numeral bound(m());
4325             polynomial_ref q(m_wrapper);
4326             polynomial_ref candidate(m_wrapper);
4327             scoped_numeral p(m());
4328 
4329             for (unsigned i = 0; i < NUM_BIG_PRIMES; i++) {
4330                 m().set(p, g_big_primes[i]);
4331                 TRACE("mgcd", tout << "trying prime: " << p << "\n";);
4332                 {
4333                     scoped_set_zp setZp(m_wrapper, p);
4334                     u_Zp = normalize(pp_u);
4335                     if (u_Zp->size() != pp_u->size()) {
4336                         TRACE("mgcd", tout << "bad prime, coefficient(s) vanished\n";);
4337                         continue; // bad prime some monomial vanished
4338                     }
4339                     v_Zp = normalize(pp_v);
4340                     if (v_Zp->size() != pp_v->size()) {
4341                         TRACE("mgcd", tout << "bad prime, coefficient(s) vanished\n";);
4342                         continue; // bad prime some monomial vanished
4343                     }
4344                     TRACE("mgcd", tout << "u_Zp: " << u_Zp << "\nv_Zp: " << v_Zp << "\n";);
4345                     mod_gcd_rec(u_Zp, v_Zp, g_big_primes[i], 0, vars, q);
4346                     q = mk_glex_monic(q);
4347                     scoped_numeral c(m());
4348                     m().set(c, lc_g);
4349                     q = mul(c, q);
4350                 }
4351                 TRACE("mgcd", tout << "new q:\n" << q << "\n";);
4352                 if (is_const(q)) {
4353                     TRACE("mgcd", tout << "done, modular gcd is one\n";);
4354                     r = mk_const(d_a);
4355                     return;
4356                 }
4357                 if (C_star.get() == nullptr) {
4358                     C_star = q;
4359                     m().set(bound, p);
4360                 }
4361                 else {
4362                     monomial * max_C_star = C_star->m(C_star->graded_lex_max_pos());
4363                     monomial * max_q      = q->m(q->graded_lex_max_pos());
4364                     if (graded_lex_compare(max_q, max_C_star) < 0) {
4365                         // Discard accumulated image, it was affected by unlucky primes
4366                         // maximal monomial of q is smaller than maximal monomial of C_star
4367                         TRACE("mgcd", tout << "discarding image\n";);
4368                         C_star = q;
4369                         m().set(bound, p);
4370                     }
4371                     else {
4372                         CRA_combine_images(q, p, C_star, bound, C_star);
4373                         TRACE("mgcd", tout << "new combined:\n" << C_star << "\n";);
4374                     }
4375                 }
4376                 candidate = normalize(C_star);
4377                 TRACE("mgcd", tout << "candidate:\n" << candidate << "\n";);
4378                 scoped_numeral lc_candidate(m());
4379                 lc_candidate = candidate->a(candidate->graded_lex_max_pos());
4380                 if (m().divides(lc_candidate, lc_g) &&
4381                     divides(candidate, pp_u) &&
4382                     divides(candidate, pp_v)) {
4383                     TRACE("mgcd", tout << "found GCD\n";);
4384                     r = mul(d_a, candidate);
4385                     flip_sign_if_lm_neg(r);
4386                     TRACE("mgcd", tout << "r: " << r << "\n";);
4387                     return;
4388                 }
4389             }
4390             // Oops, modular GCD failed, not enough primes
4391             // fallback to prs
4392             gcd_prs(u, v, max_var(u), r);
4393         }
4394 
gcdpolynomial::manager::imp4395         void gcd(polynomial const * u, polynomial const * v, polynomial_ref & r) {
4396             power_buffer u_var_degrees;
4397             power_buffer v_var_degrees;
4398             TRACE("gcd_calls", tout << "gcd\nu: "; u->display(tout, m_manager); tout << "\nv: "; v->display(tout, m_manager); tout << "\n";);
4399             TRACE("polynomial_gcd",
4400                   tout << "gcd\nu: "; u->display(tout, m_manager); tout << "\nv: "; v->display(tout, m_manager);
4401                   tout << "\nis_zero(u): " << is_zero(u) << ", is_const(u): " << is_const(u) << "\n";
4402                   tout << "is_zero(v): " << is_zero(v) << ", is_const(v): " << is_const(v) << "\n";
4403                   tout << "modular: " << m().modular() << "\n";);
4404             if (is_zero(u)) {
4405                 r = const_cast<polynomial*>(v);
4406                 flip_sign_if_lm_neg(r);
4407                 return;
4408             }
4409             if (is_zero(v)) {
4410                 r = const_cast<polynomial*>(u);
4411                 flip_sign_if_lm_neg(r);
4412                 return;
4413             }
4414             if (u == v) {
4415                 r = const_cast<polynomial*>(u);
4416                 flip_sign_if_lm_neg(r);
4417                 return;
4418             }
4419             if (is_const(u) || is_const(v)) {
4420                 scoped_numeral i_u(m_manager), i_v(m_manager);
4421                 ic(v, i_v);
4422                 ic(u, i_u);
4423                 scoped_numeral a(m_manager);
4424                 m_manager.gcd(i_v, i_u, a);
4425                 r = mk_const(a);
4426                 return;
4427             }
4428 
4429             // Search for a variable x that occurs only in u or v.
4430             var_max_degrees(u, u_var_degrees); std::sort(u_var_degrees.begin(), u_var_degrees.end(), power::lt_var());
4431             var_max_degrees(v, v_var_degrees); std::sort(v_var_degrees.begin(), v_var_degrees.end(), power::lt_var());
4432 
4433             TRACE("polynomial_gcd",
4434                   tout << "u var info\n"; for (unsigned i = 0; i < u_var_degrees.size(); i++) tout << u_var_degrees[i] << " "; tout << "\n";
4435                   tout << "v var info\n"; for (unsigned i = 0; i < v_var_degrees.size(); i++) tout << v_var_degrees[i] << " "; tout << "\n";);
4436             var x        = null_var;
4437             bool u_found = false;
4438             bool v_found = false;
4439             unsigned i    = 0;
4440             unsigned u_sz = u_var_degrees.size();
4441             unsigned v_sz = v_var_degrees.size();
4442             unsigned sz   = std::min(u_sz, v_sz);
4443             for (; i < sz; i++) {
4444                 var xu = u_var_degrees[i].get_var();
4445                 var xv = v_var_degrees[i].get_var();
4446                 if (xu < xv) {
4447                     x = xu;
4448                     u_found = true;
4449                     break;
4450                 }
4451                 if (xu > xv) {
4452                     x = xv;
4453                     v_found = true;
4454                     break;
4455                 }
4456             }
4457             if (!u_found && !v_found && i < u_sz) {
4458                 x = u_var_degrees[i].get_var();
4459                 u_found = true;
4460             }
4461             if (!u_found && !v_found && i < v_sz) {
4462                 x = v_var_degrees[i].get_var();
4463                 v_found = true;
4464             }
4465 
4466             if (u_found) {
4467                 // u has a variable x that v doesn't have.
4468                 // Thus, gcd(u, v) = gcd(content(u, x), v)
4469                 gcd_content(u, x, v, r);
4470                 return;
4471             }
4472 
4473             if (v_found) {
4474                 // v has a variable x that u doesn't have.
4475                 // Thus, gcd(u, v) = gcd(u, content(v, x))
4476                 gcd_content(v, x, u, r);
4477                 return;
4478             }
4479 
4480             // TODO:
4481             // Try to find a variable x that occurs linearly in u or v
4482             // In this case, the GCD is linear or constant in x.
4483             // Assume x occurs linearly in u. Then,
4484             // gcd(u, v) = gcd(content(u, x), content(v, x))         if pp(u, x) does not divide pp(v, x)
4485             // gcd(u, v) = gcd(content(u, x), content(v, x))*pp(u,x) if pp(u, x) divides pp(v, x)
4486             //
4487 
4488             // select variable with minimal degree
4489             x = u_var_degrees[sz - 1].get_var(); // give preference to maximal variable
4490             SASSERT(u_var_degrees[sz - 1].get_var() == v_var_degrees[sz - 1].get_var());
4491             SASSERT(max_var(u) == max_var(v));
4492             SASSERT(max_var(u) == x);
4493 #if 0
4494             unsigned min_k = std::max(m_u_var_degrees[sz - 1].degree(), m_v_var_degrees[sz - 1].degree());
4495             unsigned max_var_bias = 2; // the basic procedures are optimized for operating on the maximal variable. So, we have a bias to select the maximal one
4496             if (min_k > max_var_bias) {
4497                 min_k -= max_var_bias;
4498                 i = sz - 1;
4499                 while (i > 0) {
4500                     --i;
4501                     SASSERT(m_u_var_degrees[i].get_var() == m_v_var_degrees[i].get_var());
4502                     unsigned k = std::max(m_u_var_degrees[i].degree(), m_v_var_degrees[i].degree());
4503                     if (k < min_k) {
4504                         x     = m_u_var_degrees[i].get_var();
4505                         min_k = k;
4506                     }
4507                 }
4508             }
4509 #endif
4510             if (!m().modular() && !m_use_prs_gcd) {
4511                 SASSERT(max_var(u) == max_var(v));
4512                 if (is_univariate(u)) {
4513                     SASSERT(is_univariate(v));
4514                     uni_mod_gcd(u, v, r);
4515                 }
4516                 else {
4517                     try {
4518                         #ifdef Z3DEBUG
4519                         polynomial_ref orig_u(m_wrapper);
4520                         polynomial_ref orig_v(m_wrapper);
4521                         if (is_debug_enabled("mgcd_check")) {
4522                             orig_u = const_cast<polynomial*>(u);
4523                             orig_v = const_cast<polynomial*>(v);
4524                         }
4525                         #endif
4526 
4527                         mod_gcd(u, v, u_var_degrees, v_var_degrees, r);
4528 
4529                         #ifdef Z3DEBUG
4530                         if (is_debug_enabled("mgcd_check")) {
4531                             polynomial_ref r2(m_wrapper);
4532                             flet<bool> use_prs(m_use_prs_gcd, false);
4533                             gcd_prs(orig_u, orig_v, x, r2);
4534                             CTRACE("mgcd_bug", !eq(r, r2), tout << "u: " << orig_u << "\nv: " << orig_v << "\nr1: " << r << "\nr2: " << r2 << "\n";);
4535                             SASSERT(eq(r, r2));
4536                         }
4537                         #endif
4538                     }
4539                     catch (const sparse_mgcd_failed &) {
4540                         flet<bool> use_prs(m_use_prs_gcd, false);
4541                         gcd_prs(u, v, x, r);
4542                     }
4543                 }
4544             }
4545             else {
4546                 gcd_prs(u, v, x, r);
4547             }
4548         }
4549 
derivativepolynomial::manager::imp4550         monomial * derivative(monomial const * m, var x) {
4551             return mm().derivative(m, x);
4552         }
4553 
derivativepolynomial::manager::imp4554         polynomial * derivative(polynomial const * p, var x) {
4555             SASSERT(is_valid(x));
4556             SASSERT(m_cheap_som_buffer.empty());
4557             unsigned sz = p->size();
4558             for (unsigned i = 0; i < sz; i++) {
4559                 monomial * m = p->m(i);
4560                 unsigned   d = m->degree_of(x);
4561                 TRACE("polynomial", m->display(tout); tout << " degree_of x" << x << ": " << d << "\n";);
4562                 if (d > 0) {
4563                     scoped_numeral n(m_manager);
4564                     m_manager.set(n, d);
4565                     scoped_numeral a(m_manager);
4566                     m_manager.mul(p->a(i), n, a);
4567                     m_cheap_som_buffer.add_reset(a, derivative(m, x));
4568                 }
4569             }
4570             return m_cheap_som_buffer.mk();
4571         }
4572 
square_freepolynomial::manager::imp4573         void square_free(polynomial const * p, polynomial_ref & r) {
4574             if (is_zero(p)) {
4575                 r = mk_zero();
4576                 return;
4577             }
4578             if (is_const(p)) {
4579                 r = const_cast<polynomial*>(p);
4580                 return;
4581             }
4582 
4583             var x = max_var(p);
4584             scoped_numeral i(m_manager);
4585             polynomial_ref c(pm()), pp(pm());
4586             iccp(p, x, i, c, pp);
4587             polynomial_ref sqf_c(pm());
4588             square_free(c, sqf_c);
4589 
4590             polynomial_ref pp_prime(pm());
4591             pp_prime = derivative(pp, x);
4592             polynomial_ref g(pm());
4593             gcd(pp, pp_prime, g);
4594             if (is_const(g)) {
4595                 if (eq(sqf_c, c)) {
4596                     r = const_cast<polynomial*>(p);
4597                     return;
4598                 }
4599             }
4600             else {
4601                 pp = exact_div(pp, g);
4602             }
4603             r = mul(i, sqf_c);
4604             r = mul(r, pp);
4605         }
4606 
is_square_freepolynomial::manager::imp4607         bool is_square_free(polynomial const * p) {
4608             polynomial_ref r(pm());
4609             square_free(p, r);
4610             SASSERT(!eq(p, r) || p == r.get()); // this is a property of the square_free procedure
4611             return p == r.get();
4612         }
4613 
square_freepolynomial::manager::imp4614         void square_free(polynomial const * p, var x, polynomial_ref & r) {
4615             if (is_zero(p)) {
4616                 r = mk_zero();
4617                 return;
4618             }
4619             if (is_const(p)) {
4620                 r = const_cast<polynomial*>(p);
4621                 return;
4622             }
4623 
4624             polynomial_ref p_prime(pm());
4625             p_prime = derivative(p, x);
4626             polynomial_ref g(pm());
4627             gcd(p, p_prime, g);
4628             if (is_const(g)) {
4629                 r = const_cast<polynomial*>(p);
4630             }
4631             else {
4632                 r = exact_div(p, g);
4633             }
4634         }
4635 
is_square_freepolynomial::manager::imp4636         bool is_square_free(polynomial const * p, var x) {
4637             polynomial_ref r(pm());
4638             square_free(p, x, r);
4639             SASSERT(!eq(p, r) || p == r.get()); // this is a property of the square_free procedure
4640             return p == r.get();
4641         }
4642 
pwpolynomial::manager::imp4643         void pw(polynomial const * p, unsigned k, polynomial_ref & r) {
4644             if (k == 0) {
4645                 r = mk_one();
4646                 return;
4647             }
4648             if (k == 1) {
4649                 r = const_cast<polynomial*>(p);
4650                 return;
4651             }
4652             polynomial_ref result(pm());
4653             result = const_cast<polynomial*>(p);
4654             for (unsigned i = 1; i < k; i++)
4655                 result = mul(result, const_cast<polynomial*>(p));
4656             r = result;
4657 #if 0
4658             SASSERT(k >= 2);
4659             unsigned mask  = 1;
4660             polynomial_ref p2(pm());
4661             p2 = const_cast<polynomial*>(p);
4662             r  = mk_one();
4663             while (true) {
4664                 if (mask & k)
4665                     r = mul(r, p2);
4666                 mask = mask << 1;
4667                 if (mask > k)
4668                     return;
4669                 p2 = mul(p2, p2);
4670             }
4671 #endif
4672         }
4673 
eqpolynomial::manager::imp4674         bool eq(polynomial const * p1, polynomial const * p2) {
4675             if (p1 == p2)
4676                 return true;
4677             unsigned sz1 = p1->size();
4678             unsigned sz2 = p2->size();
4679             if (sz1 != sz2)
4680                 return false;
4681             if (sz1 == 0)
4682                 return true;
4683             if (max_var(p1) != max_var(p2))
4684                 return false;
4685             m_m2pos.set(p1);
4686             for (unsigned i = 0; i < sz2; i++) {
4687                 unsigned pos1 = m_m2pos.get(p2->m(i));
4688                 if (pos1 == UINT_MAX || !m_manager.eq(p1->a(pos1), p2->a(i))) {
4689                     m_m2pos.reset(p1);
4690                     return false;
4691                 }
4692             }
4693             m_m2pos.reset(p1);
4694             return true;
4695         }
4696 
compose_1_div_xpolynomial::manager::imp4697         polynomial * compose_1_div_x(polynomial const * p) {
4698             SASSERT(is_univariate(p));
4699             if (is_const(p))
4700                 return const_cast<polynomial*>(p);
4701             SASSERT(m_cheap_som_buffer.empty());
4702             var x       = max_var(p);
4703             unsigned n  = degree(p, x);
4704             unsigned sz = p->size();
4705             for (unsigned i = 0; i < sz; i++) {
4706                 monomial * m = p->m(i);
4707                 SASSERT(m->size() <= 1);
4708                 monomial * new_m = mk_monomial(x, n - m->degree_of(x));
4709                 m_cheap_som_buffer.add(p->a(i), new_m);
4710             }
4711             return m_cheap_som_buffer.mk();
4712         }
4713 
push_powerpolynomial::manager::imp4714         void push_power(sbuffer<power> & pws, var x, unsigned d) {
4715             if (d > 0)
4716                 pws.push_back(power(x, d));
4717         }
4718 
compose_x_div_ypolynomial::manager::imp4719         polynomial * compose_x_div_y(polynomial const * p, var y) {
4720             SASSERT(is_univariate(p));
4721             SASSERT(max_var(p) != y);
4722             if (is_const(p))
4723                 return const_cast<polynomial*>(p);
4724             SASSERT(m_cheap_som_buffer.empty());
4725             var x       = max_var(p);
4726             unsigned n  = degree(p, x);
4727             unsigned sz = p->size();
4728             sbuffer<power> pws;
4729             for (unsigned i = 0; i < sz; i++) {
4730                 unsigned   k = p->m(i)->degree_of(x);
4731                 pws.reset();
4732                 if (x < y) {
4733                     push_power(pws, x, k);
4734                     push_power(pws, y, n - k);
4735                 }
4736                 else {
4737                     push_power(pws, y, n - k);
4738                     push_power(pws, x, k);
4739                 }
4740                 monomial * new_m = mk_monomial(pws.size(), pws.c_ptr());
4741                 m_cheap_som_buffer.add(p->a(i), new_m);
4742             }
4743             return m_cheap_som_buffer.mk();
4744         }
4745 
compose_ypolynomial::manager::imp4746         polynomial * compose_y(polynomial const * p, var y) {
4747             SASSERT(is_valid(y));
4748             SASSERT(is_univariate(p));
4749             if (y == max_var(p) || is_const(p))
4750                 return const_cast<polynomial*>(p);
4751             SASSERT(m_cheap_som_buffer.empty());
4752             unsigned sz = p->size();
4753             for (unsigned i = 0; i < sz; i++) {
4754                 monomial * m = p->m(i);
4755                 SASSERT(m->size() <= 1);
4756                 monomial * new_m;
4757                 if (m->size() == 0)
4758                     new_m = m;
4759                 else
4760                     new_m = mk_monomial(y, m->degree(0));
4761                 m_cheap_som_buffer.add(p->a(i), new_m);
4762             }
4763             return m_cheap_som_buffer.mk();
4764         }
4765 
compose_minus_xpolynomial::manager::imp4766         polynomial * compose_minus_x(polynomial const * p) {
4767             SASSERT(is_univariate(p));
4768             if (is_const(p))
4769                 return const_cast<polynomial*>(p);
4770             SASSERT(m_cheap_som_buffer.empty());
4771             scoped_numeral a(m_manager);
4772             unsigned sz = p->size();
4773             for (unsigned i = 0; i < sz; i++) {
4774                 monomial * m = p->m(i);
4775                 if (m->total_degree() % 2 == 0) {
4776                     m_cheap_som_buffer.add(p->a(i), p->m(i));
4777                 }
4778                 else {
4779                     m_manager.set(a, p->a(i));
4780                     m_manager.neg(a);
4781                     m_cheap_som_buffer.add(a, p->m(i));
4782                 }
4783             }
4784             return m_cheap_som_buffer.mk();
4785         }
4786 
4787         /**
4788            \brief Store the positions (in m_degree2pos) of the monomials of an univariate polynomial.
4789         */
save_degree2pospolynomial::manager::imp4790         void save_degree2pos(polynomial const * p) {
4791             SASSERT(is_univariate(p));
4792             var x = max_var(p);
4793             unsigned n  = degree(p, x);
4794             m_degree2pos.reserve(n+1, UINT_MAX);
4795             unsigned sz = p->size();
4796             for (unsigned i = 0; i < sz; i++) {
4797                 monomial * m = p->m(i);
4798                 SASSERT(m->size() <= 1);
4799                 SASSERT(m_degree2pos[m->total_degree()] == UINT_MAX);
4800                 m_degree2pos[m->total_degree()] = i;
4801             }
4802         }
4803 
4804         /**
4805            \brief Undo the modifications in m_degree2pos performed by save_degree2pos.
4806         */
reset_degree2pospolynomial::manager::imp4807         void reset_degree2pos(polynomial const * p) {
4808             SASSERT(is_univariate(p));
4809             unsigned sz = p->size();
4810             for (unsigned i = 0; i < sz; i++) {
4811                 monomial * m = p->m(i);
4812                 SASSERT(m->size() <= 1);
4813                 SASSERT(m_degree2pos[m->total_degree()] == i);
4814                 m_degree2pos[m->total_degree()] = UINT_MAX;
4815             }
4816         }
4817 
4818         // muladd may throw if the cancel flag is set.
4819         // So we wrap the degree2pos set and reset
4820         // in a scoped class to ensure the state is clean
4821         // on exit.
4822         struct scoped_degree2pos {
4823             imp& pm;
4824             polynomial const* p;
scoped_degree2pospolynomial::manager::imp::scoped_degree2pos4825             scoped_degree2pos(imp& pm, polynomial const* p):
4826                 pm(pm),
4827                 p(p)
4828             {
4829                 pm.save_degree2pos(p);
4830             }
4831 
~scoped_degree2pospolynomial::manager::imp::scoped_degree2pos4832             ~scoped_degree2pos() {
4833                 pm.reset_degree2pos(p);
4834             }
4835         };
4836 
4837         /**
4838            \brief Given an univariate polynomial p(x) and a polynomial q(y_1, ..., y_n),
4839            return a polynomial r(y_1, ..., y_n) = p(q(y_1, ..., y_n)).
4840         */
composepolynomial::manager::imp4841         void compose(polynomial const * p, polynomial const * q, polynomial_ref & r) {
4842             SASSERT(is_univariate(p));
4843             if (is_const(p)) {
4844                 r = const_cast<polynomial*>(p);
4845                 return;
4846             }
4847             var x      = max_var(p);
4848             unsigned d = degree(p, x);
4849             scoped_degree2pos _sd2pos(*this, p);
4850             scoped_numeral a(m());
4851             m_manager.set(a, p->a(m_degree2pos[d]));
4852             r = mk_const(a);
4853             for (unsigned i = 1; i <= d; i++) {
4854                 unsigned pos = m_degree2pos[d-i];
4855                 if (pos != UINT_MAX)
4856                     m_manager.set(a, p->a(pos));
4857                 else
4858                     m_manager.reset(a);
4859                 r = muladd(q, r, a);
4860             }
4861         }
4862 
mk_x_minus_ypolynomial::manager::imp4863         polynomial * mk_x_minus_y(var x, var y) {
4864             numeral zero(0);
4865             numeral minus_one; // It is not safe to initialize with -1 when numeral_manager is GF_2
4866             m_manager.set(minus_one, -1);
4867             numeral as[2] = { numeral(1), std::move(minus_one) };
4868             var     xs[2] = { x, y };
4869             return mk_linear(2, as, xs, zero);
4870         }
4871 
compose_x_minus_ypolynomial::manager::imp4872         void compose_x_minus_y(polynomial const * p, var y, polynomial_ref & r) {
4873             SASSERT(is_valid(y));
4874             SASSERT(is_univariate(p));
4875             var x = max_var(p);
4876             if (y == max_var(p)) {
4877                 r = coeff(p, x, 0);
4878                 return;
4879             }
4880             polynomial_ref x_minus_y(pm());
4881             x_minus_y = mk_x_minus_y(x, y);
4882             return compose(p, x_minus_y, r);
4883         }
4884 
mk_x_plus_ypolynomial::manager::imp4885         polynomial * mk_x_plus_y(var x, var y) {
4886             numeral zero(0);
4887             numeral as[2] = { numeral(1), numeral(1) };
4888             var     xs[2] = { x, y };
4889             return mk_linear(2, as, xs, zero);
4890         }
4891 
compose_x_plus_ypolynomial::manager::imp4892         void compose_x_plus_y(polynomial const * p, var y, polynomial_ref & r) {
4893             SASSERT(is_valid(y));
4894             SASSERT(is_univariate(p));
4895             var x = max_var(p);
4896             polynomial_ref x_plus_y(pm());
4897             x_plus_y = mk_x_plus_y(x, y);
4898             return compose(p, x_plus_y, r);
4899         }
4900 
4901         // Return the polynomial x - c
mk_x_minus_cpolynomial::manager::imp4902         polynomial * mk_x_minus_c(var x, numeral const & c) {
4903             numeral as[2];
4904             m_manager.set(as[0], c);
4905             m_manager.set(as[1], 1);
4906             m_manager.neg(as[0]);
4907             polynomial * p = mk_univariate(x, 1, as);
4908             TRACE("polynomial", tout << "x - c: "; p->display(tout, m_manager); tout << "\n";);
4909             m_manager.del(as[0]);
4910             m_manager.del(as[1]);
4911             return p;
4912         }
4913 
compose_x_minus_cpolynomial::manager::imp4914         void compose_x_minus_c(polynomial const * p, numeral const & c, polynomial_ref & r) {
4915             SASSERT(is_univariate(p));
4916             if (m_manager.is_zero(c)) {
4917                 r = const_cast<polynomial*>(p);
4918                 return;
4919             }
4920             var x = max_var(p);
4921             polynomial_ref x_minus_c(pm());
4922             x_minus_c = mk_x_minus_c(x, c);
4923             return compose(p, x_minus_c, r);
4924         }
4925 
4926         /**
4927            \brief Template for computing several variations of pseudo division algorithm.
4928            If degree(p) < degree(q) -->  Q = m_zero, d = 0, R = p
4929 
4930            The following property is guaranteed by this method
4931 
4932            l(q)^d * p = Q * q + R
4933 
4934            where l(q) is coeff(q, x, degree(q, x))
4935 
4936            Possible configurations:
4937            Exact_d == true, then d = degree(p) - degree(q) + 1.
4938            If Exact_d == false, then d <= degree(p) - degree(q) + 1.
4939 
4940            If Quotient == false, Q is not computed.
4941 
4942            If ModD == true, then x2d must be different from 0.
4943            Moreover, p and q are assumed to be normalized modulo x2d.
4944            For all x, x2d->degree(x) > 0 implies  degree(p, x) < x2d->degree(x) and degree(q, x) < x2d->degree(x)
4945            Moreover, the division algorithm will compute Q and R modulo x2d.
4946         */
4947         template<bool Exact_d, bool Quotient, bool ModD>
pseudo_division_corepolynomial::manager::imp4948         void pseudo_division_core(polynomial const * p, polynomial const * q, var x, unsigned & d, polynomial_ref & Q, polynomial_ref & R,
4949                                   var2degree const * x2d = nullptr) {
4950             SASSERT(is_valid(x));
4951             SASSERT(!ModD || x2d != 0);
4952             TRACE("polynomial", tout << "pseudo_division\np: "; p->display(tout, m_manager);
4953                   tout << "\nq: "; q->display(tout, m_manager); tout << "\nx: " << x << "\n";);
4954             polynomial * A = const_cast<polynomial*>(p);
4955             polynomial * B = const_cast<polynomial*>(q);
4956             unsigned deg_A = degree(A, x);
4957             unsigned deg_B = degree(B, x);
4958             if (deg_B == 0) {
4959                 R = m_zero;
4960                 if (Quotient) {
4961                     if (Exact_d) {
4962                         d = deg_A /* - deg_B */ + 1;
4963                         // Since degree(B) = 0, lc(B) == B
4964                         // lc(B)^d * A = Q * B + R  -->  (using R == 0, lc(B) == B)
4965                         // B^d * A = Q * B
4966                         // Thus, Q = A * B^{d-1}
4967                         if (d == 1) {
4968                             Q = A;
4969                             return;
4970                         }
4971                         polynomial_ref Bdm1(pm());
4972                         pw(B, d - 1, Bdm1);
4973                         Q = mul(A, Bdm1);
4974                         if (ModD)
4975                             Q = mod_d(Q, *x2d);
4976                     }
4977                     else {
4978                         d = 1;
4979                         Q = A;
4980                     }
4981                 }
4982                 return;
4983             }
4984             if (deg_B > deg_A) {
4985                 Q = m_zero;
4986                 R = A;
4987                 d = 0;
4988             }
4989             scoped_numeral minus_a(m_manager);
4990             polynomial_ref l_B(pm()); // leading coefficient of B (that is, coefficient of x^(deg_B))
4991             polynomial_ref r_B(pm()); // reduct of B (that is, B without leading coefficient)
4992             l_B = coeff(B, x, deg_B, r_B);
4993             d = 0;
4994             R = A;
4995             Q = m_zero;
4996             while (true) {
4997                 checkpoint();
4998                 TRACE("polynomial",
4999                       tout << "A: "; A->display(tout, m_manager); tout << "\n";
5000                       tout << "B: "; B->display(tout, m_manager); tout << "\n";
5001                       tout << "l_B: "; l_B->display(tout, m_manager); tout << "\n";
5002                       tout << "r_B: "; r_B->display(tout, m_manager); tout << "\n";
5003                       tout << "Q: "; Q->display(tout, m_manager); tout << "\n";
5004                       tout << "R: "; R->display(tout, m_manager); tout << "\n";
5005                       tout << "d: " << d << "\n";);
5006                 unsigned deg_R = degree(R, x);
5007                 if (deg_B > deg_R) {
5008                     if (Exact_d) {
5009                         // Adjust Q and R
5010                         unsigned exact_d = deg_A - deg_B + 1;
5011                         SASSERT(d <= exact_d);
5012                         if (d < exact_d) {
5013                             unsigned e = exact_d - d;
5014                             polynomial_ref l_B_e(pm());
5015                             pw(l_B, e, l_B_e);
5016                             TRACE("polynomial", tout << "l_B_e: " << l_B_e << "\n";);
5017                             if (Quotient) {
5018                                 Q = mul(l_B_e, Q);
5019                                 if (ModD)
5020                                     Q = mod_d(Q, *x2d);
5021                             }
5022                             R = mul(l_B_e, R);
5023                             if (ModD)
5024                                 R = mod_d(R, *x2d);
5025                         }
5026                     }
5027                     return;
5028                 }
5029                 // S <- l_R * x^(deg_R - deg_B)
5030                 // R <- l_B * R - S * B
5031                 // Note that the goal is to cancel x^deg_R in R.
5032                 // m_som_buffer will contain the new monomials of R.
5033                 m_som_buffer.reset();
5034                 // We can accomplish that by traversing the current R, and
5035                 //  - For each monomial a * m * x^deg_R --> m_som_buffer.addmul(-a, m * x^(deg_R - deg_B), r_B)
5036                 //               Note that m*x^(deg_R - deg_B) is div_x_k(m*x^deg_R, deg_B)
5037                 //  - For other monomials a*m,  --->   m_som_buffer.addmul(a, m, l_B)
5038                 // Note that, with this trick and don't need to create the temporary polynomials l_B * R and S * B
5039                 //
5040                 // If the quotient needs to be computed, we have that
5041                 // S <- l_R * x^(deg_R - deg_B)
5042                 // Q <- l_B * Q + S
5043                 // The new monomials of Q are stored in m_som_buffer2
5044                 // When traversing R, for each monomial a*m*x^deg_R  we add m_som_buffer2.add(a, m*x^(deg_R - deg_B))
5045                 m_som_buffer2.reset();
5046                 //
5047                 unsigned sz = R->size();
5048                 for (unsigned i = 0; i < sz; i++) {
5049                     monomial * m      = R->m(i);
5050                     numeral const & a = R->a(i);
5051                     if (m->degree_of(x) == deg_R) {
5052                         monomial_ref m_prime(pm());
5053                         m_prime = div_x_k(m, x, deg_B);
5054                         CTRACE("polynomial", m->degree_of(x) != deg_R - deg_B,
5055                                tout << "deg_R: " << deg_R << ", deg_B: " << deg_B << ", x: " << x << "\n";
5056                                m->display(tout); tout << ", "; m_prime->display(tout); tout << "\n";);
5057                         SASSERT(m->degree_of(x) == deg_R);
5058                         SASSERT(m_prime->degree_of(x) == deg_R - deg_B);
5059                         if (Quotient) {
5060                             m_som_buffer2.add(a, m_prime);
5061                         }
5062                         m_manager.set(minus_a, a);
5063                         m_manager.neg(minus_a);
5064                         m_som_buffer.addmul(minus_a, m_prime, r_B);
5065                     }
5066                     else {
5067                         m_som_buffer.addmul(a, m, l_B);
5068                     }
5069                 }
5070                 if (ModD)
5071                     m_som_buffer.mod_d(*x2d);
5072                 R = m_som_buffer.mk();
5073                 if (Quotient) {
5074                     // m_som_buffer2 contains new monomials of Q <- l_B Q + S
5075                     // We have already copied S to m_som_buffer2.
5076                     // To add l_B * Q, we just traverse Q executing addmul(Q->a(i), Q->m(i), l_B)
5077                     unsigned sz = Q->size();
5078                     for (unsigned i = 0; i < sz; i++) {
5079                         m_som_buffer2.addmul(Q->a(i), Q->m(i), l_B);
5080                     }
5081                     if (ModD)
5082                         m_som_buffer2.mod_d(*x2d);
5083                     Q = m_som_buffer2.mk();
5084                 }
5085                 d++;
5086             }
5087         }
5088 
exact_pseudo_remainderpolynomial::manager::imp5089         void exact_pseudo_remainder(polynomial const * p, polynomial const * q, var x, polynomial_ref & R) {
5090             unsigned d;
5091             polynomial_ref Q(pm());
5092             pseudo_division_core<true, false, false>(p, q, x, d, Q, R);
5093         }
5094 
pseudo_remainderpolynomial::manager::imp5095         void pseudo_remainder(polynomial const * p, polynomial const * q, var x, unsigned & d, polynomial_ref & R) {
5096 #ifdef Z3DEBUG
5097             polynomial_ref old_p(pm());
5098             polynomial_ref old_q(pm());
5099             old_p = const_cast<polynomial*>(p); // R may be aliasing p and q
5100             old_q = const_cast<polynomial*>(q);
5101             polynomial_ref Q(pm());
5102             pseudo_division_core<false, true, false>(p, q, x, d, Q, R);
5103             // debugging code
5104             // check if lc(q)^d * p = Q * q + R
5105             polynomial_ref l(pm());
5106             l = coeff(old_q, x, degree(q, x));
5107             polynomial_ref ld(pm());
5108             pw(l, d, ld);
5109             polynomial_ref lhs(pm());
5110             lhs = mul(ld, old_p);
5111             polynomial_ref rhs(pm());
5112             rhs = mul(Q, old_q);
5113             rhs = add(rhs, R);
5114             bool is_eq = eq(lhs, rhs);
5115             TRACE("pseudo_remainder",
5116                   tout << "pseudo_division bug\n";
5117                   tout << "p:   "; old_p->display(tout, m_manager); tout << "\n";
5118                   tout << "q:   "; old_q->display(tout, m_manager); tout << "\n";
5119                   tout << "Q:   " << Q << "\nR:   " << R << "\n";
5120                   tout << "l^d: " << ld << "\nlhs: " << lhs << "\nrhs: " << rhs << "\n";);
5121             SASSERT(is_eq);
5122 #else
5123             polynomial_ref Q(pm());
5124             pseudo_division_core<false, false, false>(p, q, x, d, Q, R);
5125 #endif
5126         }
5127 
exact_pseudo_divisionpolynomial::manager::imp5128         void exact_pseudo_division(polynomial const * p, polynomial const * q, var x, polynomial_ref & Q, polynomial_ref & R) {
5129             unsigned d;
5130             pseudo_division_core<true, true, false>(p, q, x, d, Q, R);
5131         }
5132 
pseudo_divisionpolynomial::manager::imp5133         void pseudo_division(polynomial const * p, polynomial const * q, var x, unsigned & d, polynomial_ref & Q, polynomial_ref & R) {
5134             pseudo_division_core<false, true, false>(p, q, x, d, Q, R);
5135         }
5136 
exact_divpolynomial::manager::imp5137         polynomial * exact_div(polynomial const * p, numeral const & c) {
5138             SASSERT(!m().is_zero(c));
5139 
5140             som_buffer & R = m_som_buffer;
5141             R.reset();
5142 
5143             numeral tmp;
5144 
5145             unsigned sz = p->size();
5146             for (unsigned i = 0; i < sz; ++ i) {
5147                 SASSERT(m().divides(c, p->a(i)));
5148                 m().div(p->a(i), c, tmp);
5149                 if (!m().is_zero(tmp)) {
5150                     R.add(tmp, p->m(i));
5151                 }
5152             }
5153 
5154             m().del(tmp);
5155 
5156             return R.mk();
5157         }
5158 
exact_divpolynomial::manager::imp5159         polynomial * exact_div(polynomial const * p, polynomial const * q) {
5160             TRACE("polynomial", tout << "exact division\np: "; p->display(tout, m_manager); tout << "\nq: "; q->display(tout, m_manager); tout << "\n";);
5161             if (is_zero(p))
5162                 return const_cast<polynomial*>(p);
5163             SASSERT(!is_zero(q));
5164             m_som_buffer.reset();
5165             m_som_buffer2.reset();
5166             som_buffer & R = m_som_buffer;
5167             som_buffer & C = m_som_buffer2;
5168             R.add(p);
5169             unsigned max_q = q->graded_lex_max_pos();
5170             monomial * m_q = q->m(max_q);
5171             numeral const & a_q = q->a(max_q);
5172             monomial_ref m_r_q_ref(pm());
5173             scoped_numeral a_r_q(m_manager);
5174             while (true) {
5175                 checkpoint();
5176                 unsigned max_R = R.graded_lex_max_pos();
5177                 if (max_R == UINT_MAX) {
5178                     // R is empty
5179                     R.reset();
5180                     return C.mk();
5181                 }
5182                 monomial const * m_r = R.m(max_R);
5183                 numeral const & a_r  = R.a(max_R);
5184                 monomial_ref m_r_q(pm());
5185                 VERIFY(div(m_r, m_q, m_r_q));
5186                 TRACE("polynomial", tout << "m_r: "; m_r->display(tout); tout << "\nm_q: "; m_q->display(tout); tout << "\n";
5187                       if (m_r_q) { tout << "m_r_q: "; m_r_q->display(tout); tout << "\n"; });
5188                 m_r_q_ref = m_r_q;
5189                 m_manager.div(a_r, a_q, a_r_q);
5190                 C.add(a_r_q, m_r_q);       // C <- C + (a_r/a_q)*(m_r/m_q)
5191                 m_manager.neg(a_r_q);
5192                 R.addmul(a_r_q, m_r_q, q); // R <- R - (a_r/a_q)*(m_r/m_q)*Q
5193             }
5194         }
5195 
5196         // Return true if q divides p.
dividespolynomial::manager::imp5197         bool divides(polynomial const * q, polynomial const * p) {
5198             TRACE("polynomial", tout << "divides\nq: "; q->display(tout, m_manager); tout << "\np: "; p->display(tout, m_manager); tout << "\n";);
5199             TRACE("divides", tout << "divides\nq: "; q->display(tout, m_manager); tout << "\np: "; p->display(tout, m_manager); tout << "\n";);
5200             if (is_zero(p))
5201                 return true;
5202             SASSERT(!is_zero(q));
5203             m_som_buffer.reset();
5204             m_som_buffer2.reset();
5205             som_buffer & R = m_som_buffer;
5206             R.add(p);
5207             unsigned max_q = q->graded_lex_max_pos();
5208             monomial * m_q = q->m(max_q);
5209             numeral const & a_q = q->a(max_q);
5210             monomial_ref m_r_q_ref(pm());
5211             scoped_numeral a_r_q(m_manager);
5212             while (true) {
5213                 checkpoint();
5214                 unsigned max_R = R.graded_lex_max_pos();
5215                 if (max_R == UINT_MAX) {
5216                     // R is empty
5217                     return true;
5218                 }
5219                 monomial const * m_r = R.m(max_R);
5220                 numeral const & a_r  = R.a(max_R);
5221                 monomial_ref m_r_q(pm());
5222                 bool q_div_r = div(m_r, m_q, m_r_q);
5223                 m_r_q_ref = m_r_q;
5224                 TRACE("polynomial", tout << "m_r: "; m_r->display(tout); tout << "\nm_q: "; m_q->display(tout); tout << "\n";
5225                       if (m_r_q) { tout << "m_r_q: "; m_r_q->display(tout); tout << "\n"; });
5226                 if (!q_div_r)
5227                     return false;
5228                 if (!m_manager.divides(a_q, a_r))
5229                     return false;
5230                 m_manager.div(a_r, a_q, a_r_q);
5231                 m_manager.neg(a_r_q);
5232                 R.addmul(a_r_q, m_r_q, q); // R <- R - (a_r/a_q)*(m_r/m_q)*Q
5233             }
5234         }
5235 
quasi_resultantpolynomial::manager::imp5236         void quasi_resultant(polynomial const * p, polynomial const * q, var x, polynomial_ref & r) {
5237             // For h_0 = p and h_1 = q, we compute the following sequence
5238             // using the pseudo remainder procedure
5239             //
5240             // l(h_1)^d_1 * h_0     = q_1 * h_1 + h_2
5241             // l(h_2)^d_2 * h_1     = q_2 * h_2 + h_3
5242             // l(h_3)^d_3 * h_2     = q_3 * h_3 + h_4
5243             // ...
5244             // l(h_n)^d_n * h_{n-1} = q_n * h_n + h_{n+1}
5245             //
5246             // where
5247             // degree(h_i, x) > 0 for all i in [0, n], and
5248             // degree(h_{n+1}, x) == 0
5249             //
5250             // l(h_i) is the leading coefficient of h_i with respect to variable x.
5251             // l(h_i) is in general a polynomial.
5252             // For example, l( y*x^2 + x^2 + y^2 x + 1 ) = y + 1
5253             //
5254             // d^i is an unsigned integer. It is introduce by the pseudo remainder procedure
5255             // because the coefficients of x^k do not form a field. That is, they are elements of a polynomial ring Q[y_1, ..., y_n].
5256             // Their values are irrelevant for the correctness of this procedure.
5257             //
5258             // Observation 1:
5259             //   If h_0 and h_1 are polynomials in Q[y_1, ..., y_n, x],
5260             //   then h_{n+1} is a polynomial in Q[y_1, ..., y_n].
5261             //
5262             // Observation 2:
5263             //   For any (complex values) a_1, ..., a_n, b,
5264             //   if h_0(a_1, ..., a_n, b) = h_1(a_1, ..., a_n, b) = 0
5265             //   then for any h_i in the sequence, h_i(a_1, ..., a_n, b) = 0.
5266             //   In particular, h_{n+1}(a_1, ..., a_n) = 0
5267             //
5268             // Observation 3:
5269             //   The procedure terminates because degree(h_i, x) > degree(h_{i+1}, x)
5270             //   for all i >= 1
5271             //
5272             // Observation 4:
5273             //   If h_{n+1} is the zero polynomial, then
5274             //   For any complex numbers a_1, ..., a_n
5275             //   the univariate polynomials p(a_1, ..., a_n, x) and q(a_1, ..., a_n, x) in C[x]
5276             //   have a common root.
5277             //   Reason:
5278             //      If h_n(a_1, ..., a_n, x) is not the zero polynomial, then it is the GCD of p(a_1, ..., a_n, x) and q(a_1, ..., a_n, x),
5279             //      and it contains the common roots.
5280             //      If h_n(a_1, ..., a_n, x) is the zero polynomial, then
5281             //      we consider h_{n-1}(a_1, ..., a_n, x). If it is not the zero polynomial then it is the GCD and we are done,
5282             //      otherwise we consider h_{n-2}(a_1, ..., a_n, x), and we continue the same process.
5283             //      Thus, eventually we find a h_i(a_1, ..., a_n, x) for i > 1 that is the GCD, or q(a_1, ..., a_n, x) is the zero polynomial,
5284             //      and any polynomial p(a_1, ..., a_n, x) has a common root with the zero polynomial.
5285             //
5286             SASSERT(degree(p, x) > 0);
5287             SASSERT(degree(q, x) > 0);
5288             polynomial_ref h_0(pm());
5289             polynomial_ref h_1(pm());
5290             polynomial_ref h_2(pm());
5291             if (degree(p, x) < degree(q, x))
5292                 std::swap(p, q);
5293             h_0 = const_cast<polynomial*>(p);
5294             h_1 = const_cast<polynomial*>(q);
5295             unsigned d;
5296             while (true) {
5297                 SASSERT(degree(h_1, x) <= degree(h_0, x));
5298                 pseudo_remainder(h_0, h_1, x, d, h_2);
5299                 TRACE("polynomial", tout << "h_0: " << h_0 << "\nh_1: " << h_1 << "\nh_2: " << h_2 << "\n";);
5300                 SASSERT(degree(h_2, x) < degree(h_1, x));
5301                 // We have that
5302                 // l(h_1)^d h_0 = Q h_1 + h_2.
5303                 // Q is the quotient of the division.
5304                 // l(h_1) is the leading coefficient of h_1.
5305                 // From this equation, we have that any zero of h_0 and h_1 is also a zero of h_2
5306                 if (degree(h_2, x) == 0) {
5307                     r = h_2;
5308                     return;
5309                 }
5310                 h_0 = h_1;
5311                 h_1 = h_2;
5312                 // this computation will terminate since the pseudo_remainder guarantees that
5313                 // degree(h_2, x) < degree(h_1, x)
5314             }
5315         }
5316 
5317         // sign = sign * (-1)^(deg_A * deg_B)
update_signpolynomial::manager::imp5318         static void update_sign(unsigned deg_A, unsigned deg_B, bool & sign) {
5319             if (deg_A % 2 == 0 || deg_B % 2 == 0)
5320                 return;
5321             sign = !sign;
5322         }
5323 
5324         /**
5325            \brief Compute the resultant of p and q with respect to r.
5326 
5327            The Resultant is usually defined as the determinant of the
5328            Sylvester matrix for p and q. This matrix is built using
5329            the coefficients of p and q with respect to x.
5330 
5331            Given p and q polynomials in Q[y_1, ..., y_n, x], r is a polynomial in Q[y_1, ..., y_n].
5332 
5333            Property 1)
5334             If p and q can be written as
5335                  p = a_m * (x - alpha_1) * ... * (x - alpha_m)
5336                  q = b_n * (x - beta_1)  * ... * (x - beta_n)
5337             Then,
5338               Res(p, q, x) = a_m^n * b_n^m * Product_{i in [1,m], j in [1, n]} (alpha_i - beta_j)
5339 
5340             Remark: if p and q are univariate polynomials, then alpha_i's and beta_j's are the roots
5341             of p and q, then Res(p, q, x) is the product of the differences of their roots modulo
5342             a constant.
5343 
5344            Property 2)
5345            For any (complex values) a_1, ..., a_n, b,
5346            if p(a_1, ..., a_n, b) = q(a_1, ..., a_n, b) = 0, then r(a_1, ..., b_n) = 0
5347 
5348            Property 3)
5349            There are polynomials U and V in Q[y_1, ..., y_n, x] s.t.
5350            p*U + q*V = r
5351            s.t.
5352            deg(U, x) < deg(q, x)
5353            and
5354            deg(V, x) < deg(p, x)
5355 
5356            We use Res(p, q, x) to denote the resultant of p and q.
5357 
5358            Property 4) (follows from 1)
5359            If Res(p, q, x) = 0, then p and q have a common divisor.
5360 
5361            Resultant Calculus:
5362              Let A and B be two polynomials of degree m and n on variable x.
5363              Let c and d be numerals.
5364 
5365              Res(A, B, x)  = (-1)^(m*n) * Res(B, A, x)
5366              Res(cA, B, x) = c^n * Res(A, B, x)
5367              Res(c, B, x)  = c^n
5368              Res(0, B, x)  = 0 if n > 0
5369              Res(c, d, x)  = 1
5370              Res(A, B1*B2, x) = Res(A, B1, x)*Res(A, B2, x)
5371              Res(A, A*Q + B, x)  = coeff(A, x)^(l-n) * Res(A, B, x)   where l = deg(A*Q + R)
5372 
5373              The last equation suggests an approach for computing the Resultant using
5374              pseudo-division instead of determinants.
5375 
5376              Given A and B s.t. degree(A, x) = m >= n = degree(B, x)
5377              Then  lc^d * A = Q * B + R
5378              where lc = coeff(B, x), and
5379                    pseudo_division(A, B, x, d, Q, R);
5380                    r = degree(R)
5381              Then we have:
5382              (lc^d)^n * Res(A, B) = Res(A * l^d, B) = Res(Q * B + R, B) = (-1)^(m*n) * Res(B, Q * B + R) = (-1)^(m*n) * lc^(m-r) * Res(B, R)
5383 
5384              So,
5385              lc^(d*n) * Res(A, B) = (-1)^(m*n) * lc^(m-r) * Res(B, R)
5386 
5387              From the pseudo-division algorithm, we have that:
5388                  1) 1 <= d <= m - n + 1
5389                  2) 0 <= r <  n <= m
5390 
5391                  d*n >= m >= m-r
5392 
5393              So, if d*n == m-r
5394                     Res(A, B) = (-1)^(m*n) * Res(R, B)
5395                  if d*n >  m-r
5396                     Res(A, B) = (-1)^(m*n) * exact_div(Res(R, B), lc^(d*n - m + r))
5397                  if d*n <  m-r
5398                     Res(A, B) = (-1)^(m*n) * mul(Res(R, B), lc^(m - r - d * n))
5399         */
resultantpolynomial::manager::imp5400         void resultant(polynomial const * p, polynomial const * q, var x, polynomial_ref & result) {
5401             polynomial_ref A(pm());
5402             polynomial_ref B(pm());
5403             A = const_cast<polynomial*>(p);
5404             B = const_cast<polynomial*>(q);
5405             TRACE("resultant", tout << "resultant(A, B, x)\nA: " << A << "\nB: " << B << "\nx: " << x << "\n";);
5406             // Res(0, B) = Res(A, 0) = 0
5407             if (is_zero(A) || is_zero(B)) {
5408                 result = mk_zero();
5409                 return;
5410             }
5411             // Res(c, d, x)  = 1             c and d are constants
5412             // Res(c, B, x)  = c^{deg(B)}
5413             if (is_const(A)) {
5414                 if (is_const(B))
5415                     result = mk_one();
5416                 else
5417                     pw(A, degree(B, x), result);
5418                 return;
5419             }
5420             // Res(A, d, x)  = d^{deg(A)}
5421             if (is_const(B)) {
5422                 pw(B, degree(A, x), result);
5423                 return;
5424             }
5425 
5426             // decompose A and B into
5427             //   A = iA*cA*ppA
5428             //   B = iB*cB*ppB
5429             scoped_numeral iA(m_manager), iB(m_manager);
5430             polynomial_ref cA(pm()), cB(pm());
5431             polynomial_ref ppA(pm()), ppB(pm());
5432             iccp(A, x, iA, cA, ppA);
5433             iccp(B, x, iB, cB, ppB);
5434             cA = mul(iA, cA);
5435             cB = mul(iB, cB);
5436             // At this point, A = cA*ppA and B = cB*ppB,  where cA and cB are the content of A and B, and ppA and ppB the primitive polynomials
5437             polynomial_ref t(pm());
5438             // t <- cA^{deg(B)}*cB^{deg(A)}
5439             pw(cA, degree(B, x), cA);
5440             pw(cB, degree(A, x), cB);
5441             t = mul(cA, cB);
5442             A = ppA;
5443             B = ppB;
5444             //
5445             TRACE("resultant", tout << "resultant(A, B, x) after normalization\nA: " << A << "\nB: " << B << "\nx: " << x << "\n";
5446                   tout << "t: " << t << "\n";);
5447 
5448             int s = 1;
5449             unsigned degA = degree(A, x);
5450             unsigned degB = degree(B, x);
5451             if (degA < degB) {
5452                 A.swap(B);
5453                 if (degA % 2 == 1 && degB % 2 == 1)
5454                     s = -1;
5455             }
5456 
5457             polynomial_ref R(pm());
5458             polynomial_ref g(pm());
5459             polynomial_ref h(pm());
5460             polynomial_ref new_h(pm());
5461             // g <- 1
5462             g = mk_one();
5463             // h <- 1
5464             h = mk_one();
5465 
5466             while (true) {
5467                 TRACE("resultant", tout << "A: " << A << "\nB: " << B << "\n";);
5468                 degA = degree(A, x);
5469                 degB = degree(B, x);
5470                 SASSERT(degA >= degB);
5471                 unsigned delta = degA - degB;
5472                 if (degA % 2 == 1 && degB % 2 == 1)
5473                     s = -s;
5474                 // lc(B)^delta+1 A = BQ + R
5475                 exact_pseudo_remainder(A, B, x, R);
5476                 A = B;
5477                 // B <- R/g*h^{delta}
5478                 B = exact_div(R, g);
5479                 for (unsigned i = 0; i < delta; i++)
5480                     B = exact_div(B, h);
5481                 // g <- lc(A)
5482                 g = lc(A, x);
5483                 // h <- g^delta * h^{1-delta}
5484                 new_h = mk_one();
5485                 pw(g, delta, new_h);
5486                 if (delta > 1) {
5487                     for (unsigned i = 0; i < delta - 1; i++)
5488                         new_h = exact_div(new_h, h);
5489                 }
5490                 h = new_h;
5491                 if (degree(B, x) == 0) {
5492                     unsigned degA = degree(A, x);
5493                     // h <- lc(B)^{deg(A)} * h^{1-deg(A)}
5494                     new_h = lc(B, x);
5495                     pw(new_h, degA, new_h);
5496                     if (degA > 1) {
5497                         for (unsigned i = 0; i < degA - 1; i++)
5498                             new_h = exact_div(new_h, h);
5499                     }
5500                     h = new_h;
5501                     // result <- s*t*h
5502                     result = mul(t, h);
5503                     if (s < 0)
5504                         result = neg(result);
5505                     return;
5506                 }
5507             }
5508         }
5509 
5510         /**
5511            \brief Return the discriminant of p with respect to x.
5512 
5513            Disc(p, x) = (-1)^(m * (m-1)/2) * Resultant(p, dp/dx, x) / coeff(p, x)
5514            dp/dx is the derivative of p with respect to x.
5515         */
discriminantpolynomial::manager::imp5516         void discriminant(polynomial const * p, var x, polynomial_ref & r) {
5517             polynomial_ref p_prime(pm());
5518             unsigned m = degree(p, x);
5519             if (m == 0) {
5520                 r = m_zero;
5521                 return;
5522             }
5523             p_prime = derivative(p, x);
5524             resultant(p, p_prime, x, r);
5525             bool sign = (static_cast<uint64_t>(m) * static_cast<uint64_t>(m-1))%4 != 0;
5526             TRACE("resultant", tout << "discriminant sign: " << sign << "\n";);
5527             scoped_numeral lc(m_manager);
5528             if (const_coeff(p, x, m, lc)) {
5529                 if (sign)
5530                     m_manager.neg(lc);
5531                 r = div(r, lc);
5532             }
5533             else {
5534                 if (sign)
5535                     r = neg(r);
5536                 polynomial_ref c(pm());
5537                 c = coeff(p, x, m);
5538                 r = exact_div(r, c);
5539             }
5540         }
5541 
subresultant_chainpolynomial::manager::imp5542         void subresultant_chain(polynomial const * p, polynomial const * q, var x, polynomial_ref_vector & sRes) {
5543             // REMARK: the code does not work if deg_p == deg_q
5544             unsigned deg_p = degree(p, x);
5545             unsigned deg_q = degree(q, x);
5546             if (deg_p < deg_q) {
5547                 std::swap(p, q);
5548                 std::swap(deg_p, deg_q);
5549             }
5550             SASSERT(deg_p > 0);
5551             unsigned n = deg_p;
5552             sRes.reset();
5553             sRes.resize(n + 1); // the sequence is from 0 ... n
5554             sRes.set(n, const_cast<polynomial*>(p));
5555             sRes.set(n - 1, const_cast<polynomial*>(q));
5556 
5557             polynomial_ref R_j_plus_1(pm());
5558             polynomial_ref prem(pm());
5559             polynomial_ref newS(pm());
5560 
5561             unsigned j = n - 1;
5562             while (j > 0) {
5563                 SASSERT(degree(sRes.get(j+1), x) == j+1); // sRes_{j+1} is regular
5564                 if (j == n-1)
5565                     R_j_plus_1 = mk_one(); // by definition of PSC chain
5566                 else
5567                     R_j_plus_1 = coeff(sRes.get(j+1), x, j+1);
5568                 unsigned r = degree(sRes.get(j), x);
5569                 if (r == j) {
5570                     // sRes_j is regular
5571 
5572                     exact_pseudo_remainder(sRes.get(j+1), sRes.get(j), x, prem);
5573                     TRACE("psc", tout << "j: " << j << "\nsRes_j+1: "; sRes.get(j+1)->display(tout, m_manager);
5574                           tout << "\nsRes_j: "; sRes.get(j)->display(tout, m_manager);
5575                           tout << "\nprem: " << prem << "\n";);
5576                     // sRes_{j-1} = prem/R_j_plus_1^2
5577                     newS = exact_div(prem, R_j_plus_1);
5578                     newS = exact_div(newS, R_j_plus_1);
5579                     sRes.set(j-1, newS);
5580                     j--;
5581                 }
5582                 else {
5583                     SASSERT(r < j);
5584                     // sRes_j is defective
5585 
5586                     // sRes_{j-1} = sRes_{j-2} = ... = sRes_{r+1} = 0
5587                     for (int i = j-1; i >= static_cast<int>(r+1); i--)
5588                         sRes.set(i, mk_zero());
5589 
5590                     // sRes_r = lc(sRes_j)^{j-r} * sRes_j / R_j_plus_1^{j-r}
5591                     newS = lc(sRes.get(j), x);
5592                     pw(newS, j-r, newS);
5593                     newS = mul(newS, sRes.get(j));
5594                     for (unsigned i = 0; i < j-r; i++)
5595                         newS = exact_div(newS, R_j_plus_1);
5596                     sRes.set(r, newS);
5597 
5598                     // If r > 0, we also compute sRes_{r-1}
5599                     if (r > 0) {
5600                         exact_pseudo_remainder(sRes.get(j+1), sRes.get(j), x, prem);
5601                         // sRes_{r-1} = prem/(-R_j_plus_1)^{j-r+2}
5602                         newS = prem;
5603                         for (unsigned i = 0; i < j-r+2; i++)
5604                             newS = exact_div(newS, R_j_plus_1);
5605                         if ((j-r+2)%2 == 1)
5606                             newS = neg(newS);
5607                         sRes.set(r-1, newS);
5608                         j = r - 1;
5609                     }
5610                     else {
5611                         j = 0;
5612                     }
5613                 }
5614             }
5615         }
5616 
psc_chain1polynomial::manager::imp5617         void psc_chain1(polynomial const * p, polynomial const * q, var x, polynomial_ref_vector & S) {
5618             subresultant_chain(p, q, x, S);
5619             unsigned sz = S.size();
5620             TRACE("psc", tout << "subresultant_chain\n";
5621                   for (unsigned i = 0; i < sz; i++) { tout << "i: " << i << " "; S.get(i)->display(tout, m_manager); tout << "\n"; });
5622             for (unsigned i = 0; i < sz - 1; i++) {
5623                 S.set(i, coeff(S.get(i), x, i));
5624             }
5625             S.set(sz-1, mk_one());
5626         }
5627 
5628         // Store in S a list of the non-zero principal subresultant coefficients of A and B
5629         // If i < j then psc_{i}(A,B) precedes psc_{j}(A,B) in S.
5630         // The leading coefficients of A and B are not included in S.
psc_chain2polynomial::manager::imp5631         void psc_chain2(polynomial const * A, polynomial const * B, var x, polynomial_ref_vector & S) {
5632             polynomial_ref G1(pm());
5633             polynomial_ref G2(pm());
5634             polynomial_ref G3(pm());
5635             polynomial_ref Gh3(pm());
5636             polynomial_ref g1(pm()), h0(pm()), hs0(pm()), h1(pm()), hs1(pm());
5637             unsigned n1 = degree(A, x);
5638             unsigned n2 = degree(B, x);
5639             if (n1 > n2) {
5640                 G1 = const_cast<polynomial*>(A);
5641                 G2 = const_cast<polynomial*>(B);
5642             }
5643             else {
5644                 G1 = const_cast<polynomial*>(B);
5645                 G2 = const_cast<polynomial*>(A);
5646                 std::swap(n1, n2);
5647             }
5648             unsigned d0 = 0;
5649             unsigned d1 = n1 - n2;
5650             unsigned i  = 1;
5651             unsigned n3;
5652             S.reset();
5653             while (true) {
5654                 // Compute Gh_{i+2}
5655                 if (!is_zero(G2)) {
5656                     exact_pseudo_remainder(G1, G2, x, Gh3);
5657                     n3 = degree(Gh3, x);
5658                     if (!is_zero(Gh3) && d1%2 == 0)
5659                         Gh3 = neg(Gh3);
5660                 }
5661 
5662                 // Compute hi
5663                 if (i > 1) {
5664                     g1 = lc(G1, x);
5665                     pw(g1, d0, h1);
5666                     if (i > 2) {
5667                         pw(h0, d0 - 1, hs0);
5668                         h1 = exact_div(h1, hs0);
5669                         S.push_back(h1);
5670                         if (is_zero(G2)) {
5671                             std::reverse(S.c_ptr(), S.c_ptr() + S.size());
5672                             return;
5673                         }
5674                     }
5675                 }
5676 
5677                 // Compute G_{i+2}
5678                 if (i == 1 || is_zero(Gh3)) {
5679                     G3 = Gh3;
5680                 }
5681                 else {
5682                     pw(h1, d1, hs1);
5683                     hs1 = mul(g1, hs1);
5684                     G3  = exact_div(Gh3, hs1);
5685                     hs1 = nullptr;
5686                 }
5687 
5688                 // prepare for next iteration
5689                 n1 = n2;
5690                 n2 = n3;
5691                 d0 = d1;
5692                 d1 = n1 - n2;
5693                 G1 = G2;
5694                 G2 = G3;
5695                 if (i > 1)
5696                     h0 = h1;
5697                 i = i + 1;
5698             }
5699         }
5700 
5701         // Optimized calculation of S_e using "Dichotomous Lazard"
Se_Lazardpolynomial::manager::imp5702         void Se_Lazard(unsigned d, polynomial const * lc_S_d, polynomial const * S_d_1, var x, polynomial_ref & S_e) {
5703             unsigned n = d - degree(S_d_1, x) - 1;
5704             TRACE("Lazard", tout << "lc_S_d: "; lc_S_d->display(tout, m_manager); tout << "\nS_d_1: "; S_d_1->display(tout, m_manager);
5705                   tout << "\nn: " << n << "\n";);
5706             if (n == 0) {
5707                 S_e = const_cast<polynomial*>(S_d_1);
5708                 return;
5709             }
5710             polynomial_ref X(pm());
5711             X = lc(S_d_1, x);
5712             polynomial const * Y = lc_S_d;
5713             unsigned a = 1 << log2(n);
5714             TRACE("Lazard", tout << "a: " << a << "\n";);
5715             SASSERT(a <= n);
5716             SASSERT(n < 2*a);
5717             polynomial_ref C(pm());
5718             C = X;
5719             n = n - a;
5720             while (a != 1) {
5721                 a = a / 2;
5722                 // C <- C^2/Y
5723                 C = mul(C, C);
5724                 C = exact_div(C, Y);
5725                 TRACE("Lazard", tout << "loop a: " << a << "\nC : " << C << "\n";);
5726                 if (n >= a) {
5727                     // C <- C*X/Y
5728                     C = mul(C, X);
5729                     C = exact_div(C, Y);
5730                     n = n - a;
5731                     TRACE("Lazard", tout << "if, C: " << C << "\n";);
5732                 }
5733             }
5734             TRACE("Lazard", tout << "C: " << C << "\nY: " << Y << "\n";);
5735             S_e = mul(C, S_d_1);
5736             S_e = exact_div(S_e, Y);
5737         }
5738 
5739         // Optimized calculation of S_{e-1} for optimized psc_chain
optimized_S_e_1polynomial::manager::imp5740         void optimized_S_e_1(unsigned d, unsigned e, polynomial const * A, polynomial const * S_d_1, polynomial const * S_e, polynomial const * s,
5741                              var x, polynomial_ref & S_e_1) {
5742             SASSERT(d == degree(A, x));
5743             SASSERT(e == degree(S_d_1, x));
5744             polynomial_ref c_d_1(pm()), s_e(pm()), x_j(pm()), tmp(pm());
5745             c_d_1 = lc(S_d_1, x);
5746             s_e = lc(S_e, x);
5747             polynomial_ref_buffer H(pm());
5748             x_j = mk_one();
5749             for (unsigned j = 0; j <= e - 1; j++) {
5750                 // H_j <- s_e * x^j
5751                 x_j = mk_polynomial(x, j);
5752                 H.push_back(mul(s_e, x_j));
5753             }
5754             SASSERT(H.size() == e);
5755             // H_e <- s_e * x^e - S_e
5756             x_j = mk_polynomial(x, e);
5757             x_j = mul(s_e, x_j);
5758             H.push_back(sub(x_j, S_e));
5759             SASSERT(H.size() == e+1);
5760             polynomial_ref x_pol(pm()), xH(pm()), xHe(pm());
5761             x_pol = mk_polynomial(x, 1);
5762             for (unsigned j = e + 1; j <= d - 1; j++) {
5763                 // H_j <- x H_{j-1} - (coeff(x H_{j-1}, e) * S_{d-1})/c_{d-1}
5764                 xH = mul(x_pol, H[j-1]);
5765                 xHe = coeff(xH, x, e);
5766                 tmp = mul(xHe, S_d_1);
5767                 tmp = exact_div(tmp, c_d_1);
5768                 H.push_back(sub(xH, tmp));
5769             }
5770             SASSERT(H.size() == d);
5771             // D <- (Sum coeff(A,j) * H[j])/lc(A)
5772             polynomial_ref D(pm());
5773             D = mk_zero();
5774             for (unsigned j = 0; j < d; j++) {
5775                 tmp = coeff(A, x, j);
5776                 tmp = mul(tmp, H[j]);
5777                 D = add(D, tmp);
5778             }
5779             polynomial_ref lc_A(pm());
5780             lc_A = lc(A, x);
5781             D = exact_div(D, lc_A);
5782             // S_e_1 = (-1)^(d-e+1) [c_{d-1} (x H[j-1] + D) - coeff(x H[j-1], e)*S_d-1]/s
5783             xH    = mul(x_pol, H[d-1]);
5784             xHe   = coeff(xH, x, e);
5785             xHe   = mul(xHe, S_d_1);
5786             S_e_1 = add(xH, D);
5787             S_e_1 = mul(c_d_1, S_e_1);
5788             S_e_1 = sub(S_e_1, xHe);
5789             S_e_1 = exact_div(S_e_1, s);
5790             if ((d-e+1) % 2 == 1)
5791                 S_e_1 = neg(S_e_1);
5792         }
5793 
psc_chain_optimized_corepolynomial::manager::imp5794         void psc_chain_optimized_core(polynomial const * P, polynomial const * Q, var x, polynomial_ref_vector & S) {
5795             TRACE("psc_chain_classic", tout << "P: "; P->display(tout, m_manager); tout << "\nQ: "; Q->display(tout, m_manager); tout << "\n";);
5796             unsigned degP = degree(P, x);
5797             unsigned degQ = degree(Q, x);
5798             SASSERT(degP >= degQ);
5799             polynomial_ref A(pm()), B(pm()), C(pm()), minus_Q(pm()), lc_Q(pm()), ps(pm());
5800 
5801             lc_Q = lc(Q, x);
5802             polynomial_ref s(pm());
5803             // s <- lc(Q)^(deg(P)-deg(Q))
5804             pw(lc_Q, degP - degQ, s);
5805             minus_Q = neg(Q);
5806             // A <- Q
5807             A = const_cast<polynomial*>(Q);
5808             // B <- prem(P, -Q)
5809             exact_pseudo_remainder(P, minus_Q, x, B);
5810             while (true) {
5811                 unsigned d = degree(A, x);
5812                 unsigned e = degree(B, x);
5813                 if (is_zero(B))
5814                     return;
5815                 TRACE("psc_chain_classic", tout << "A: " << A << "\nB: " << B << "\ns: " << s << "\nd: " << d << ", e: " << e << "\n";);
5816                 // B is S_{d-1}
5817                 ps = coeff(B, x, d-1);
5818                 if (!is_zero(ps))
5819                     S.push_back(ps);
5820                 SASSERT(d >= e);
5821                 unsigned delta = d - e;
5822                 if (delta > 1) {
5823                     // C <- S_e
5824                     // Optimized S_e calculation
5825                     // s = lc(S_d) at this point
5826                     Se_Lazard(d, s, B, x, C);
5827 
5828                     // C is S_e
5829                     ps = coeff(C, x, e);
5830                     if (!is_zero(ps))
5831                         S.push_back(ps);
5832                 }
5833                 else {
5834                     SASSERT(delta == 0 || delta == 1);
5835                     C = B;
5836                 }
5837                 if (e == 0)
5838                     return;
5839                 // B <- optimized S_e_1
5840                 optimized_S_e_1(d, e, A, B, C, s, x, B);
5841                 // A <- C
5842                 A = C;
5843                 // s <- lc(A)
5844                 s = lc(A, x);
5845             }
5846         }
5847 
psc_chain_optimizedpolynomial::manager::imp5848         void psc_chain_optimized(polynomial const * P, polynomial const * Q, var x, polynomial_ref_vector & S) {
5849             SASSERT(degree(P, x) > 0);
5850             SASSERT(degree(Q, x) > 0);
5851             S.reset();
5852             if (degree(P, x) >= degree(Q, x))
5853                 psc_chain_optimized_core(P, Q, x, S);
5854             else
5855                 psc_chain_optimized_core(Q, P, x, S);
5856             if (S.empty())
5857                 S.push_back(mk_zero());
5858             std::reverse(S.c_ptr(), S.c_ptr() + S.size());
5859         }
5860 
psc_chain_classic_corepolynomial::manager::imp5861         void psc_chain_classic_core(polynomial const * P, polynomial const * Q, var x, polynomial_ref_vector & S) {
5862             TRACE("psc_chain_classic", tout << "P: "; P->display(tout, m_manager); tout << "\nQ: "; Q->display(tout, m_manager); tout << "\n";);
5863             unsigned degP = degree(P, x);
5864             unsigned degQ = degree(Q, x);
5865             SASSERT(degP >= degQ);
5866             polynomial_ref A(pm()), B(pm()), C(pm()), minus_Q(pm()), lc_Q(pm()), lc_B(pm()), lc_A(pm());
5867             polynomial_ref tmp1(pm()), tmp2(pm()), s_delta(pm()), minus_B(pm()), ps(pm());
5868 
5869             lc_Q = lc(Q, x);
5870             polynomial_ref s(pm());
5871             // s <- lc(Q)^(deg(P)-deg(Q))
5872             pw(lc_Q, degP - degQ, s);
5873             minus_Q = neg(Q);
5874             // A <- Q
5875             A = const_cast<polynomial*>(Q);
5876             // B <- prem(P, -Q)
5877             exact_pseudo_remainder(P, minus_Q, x, B);
5878             while (true) {
5879                 unsigned d = degree(A, x);
5880                 unsigned e = degree(B, x);
5881                 if (is_zero(B))
5882                     return;
5883                 TRACE("psc_chain_classic", tout << "A: " << A << "\nB: " << B << "\ns: " << s << "\nd: " << d << ", e: " << e << "\n";);
5884                 // B is S_{d-1}
5885                 ps = coeff(B, x, d-1);
5886                 if (!is_zero(ps))
5887                     S.push_back(ps);
5888                 unsigned delta = d - e;
5889                 if (delta > 1) {
5890                     // C <- S_e
5891                     // Standard S_e calculation
5892                     // C <- (lc(B)^(delta-1) B) / s^(delta-1)
5893                     lc_B = lc(B, x);
5894                     pw(lc_B, delta-1, lc_B);
5895                     lc_B = mul(lc_B, B);
5896                     pw(s, delta - 1, s_delta); // s_delta <- s^(delta-1)
5897                     C = exact_div(lc_B, s_delta);
5898 
5899                     // s_delta <- s^delta
5900                     s_delta = mul(s_delta, s);
5901                     // C is S_e
5902                     ps = coeff(C, x, e);
5903                     if (!is_zero(ps))
5904                         S.push_back(ps);
5905 
5906                 }
5907                 else {
5908                     SASSERT(delta == 0 || delta == 1);
5909                     C = B;
5910                     // s_delta <- s^delta
5911                     pw(s, delta, s_delta);
5912                 }
5913                 if (e == 0)
5914                     return;
5915                 // B <- prem(A, -B)/(s^delta * lc(A)
5916                 lc_A = lc(A, x);
5917                 minus_B = neg(B);
5918                 exact_pseudo_remainder(A, minus_B, x, tmp1);
5919                 tmp2 = mul(lc_A, s_delta);
5920                 B = exact_div(tmp1, tmp2);
5921                 // A <- C
5922                 A = C;
5923                 // s <- lc(A)
5924                 s = lc(A, x);
5925             }
5926         }
5927 
psc_chain_classicpolynomial::manager::imp5928         void psc_chain_classic(polynomial const * P, polynomial const * Q, var x, polynomial_ref_vector & S) {
5929             SASSERT(degree(P, x) > 0);
5930             SASSERT(degree(Q, x) > 0);
5931             S.reset();
5932             if (degree(P, x) >= degree(Q, x))
5933                 psc_chain_classic_core(P, Q, x, S);
5934             else
5935                 psc_chain_classic_core(Q, P, x, S);
5936             if (S.empty())
5937                 S.push_back(mk_zero());
5938             std::reverse(S.c_ptr(), S.c_ptr() + S.size());
5939         }
5940 
psc_chainpolynomial::manager::imp5941         void psc_chain(polynomial const * A, polynomial const * B, var x, polynomial_ref_vector & S) {
5942             // psc_chain1(A, B, x, S);
5943             //psc_chain2(A, B, x, S);
5944             //psc_chain_classic(A, B, x, S);
5945             psc_chain_optimized(A, B, x, S);
5946         }
5947 
normalizepolynomial::manager::imp5948         polynomial * normalize(polynomial const * p) {
5949             if (is_zero(p))
5950                 return const_cast<polynomial*>(p);
5951             unsigned sz = p->size();
5952             if (m().modular()) {
5953                 unsigned i = 0;
5954                 for (; i < sz; i++) {
5955                     if (!m().is_p_normalized(p->a(i)))
5956                         break;
5957                 }
5958                 if (i < sz) {
5959                     m_cheap_som_buffer.reset();
5960                     scoped_numeral a(m_manager);
5961                     for (unsigned i = 0; i < sz; i++) {
5962                         monomial * m = p->m(i);
5963                         m_manager.set(a, p->a(i));
5964                         m_cheap_som_buffer.add_reset(a, m);
5965                     }
5966                     m_cheap_som_buffer.normalize();
5967                     return m_cheap_som_buffer.mk();
5968                 }
5969             }
5970             scoped_numeral g(m_manager);
5971             m_manager.gcd(sz, p->as(), g);
5972             if (m_manager.is_one(g))
5973                 return const_cast<polynomial*>(p);
5974             m_cheap_som_buffer.reset();
5975             scoped_numeral a(m_manager);
5976             for (unsigned i = 0; i < sz; i++) {
5977                 monomial * m = p->m(i);
5978                 m_manager.div(p->a(i), g, a);
5979                 m_cheap_som_buffer.add_reset(a, m);
5980             }
5981             return m_cheap_som_buffer.mk();
5982         }
5983 
negpolynomial::manager::imp5984         polynomial * neg(polynomial const * p) {
5985             SASSERT(m_cheap_som_buffer.empty());
5986             scoped_numeral minus_a(m_manager);
5987             unsigned sz = p->size();
5988             for (unsigned i = 0; i < sz; i++) {
5989                 m_manager.set(minus_a, p->a(i));
5990                 m_manager.neg(minus_a);
5991                 m_cheap_som_buffer.add(minus_a, p->m(i));
5992             }
5993             return m_cheap_som_buffer.mk();
5994         }
5995 
5996         // Return true if is a(i)*m(i) is a perfect square.
5997         // Store sqrt of a(i) in sqrt_a
is_perfect_squarepolynomial::manager::imp5998         bool is_perfect_square(polynomial const * p, unsigned i, numeral & sqrt_a) {
5999             monomial * m = p->m(i);
6000             if (!m->is_square())
6001                 return false;
6002             numeral const & a = p->a(i);
6003             if (!m_manager.is_perfect_square(a, sqrt_a))
6004                 return false;
6005             return true;
6006         }
6007 
sqrtpolynomial::manager::imp6008         bool sqrt(polynomial const * p, polynomial_ref & r) {
6009             SASSERT(p != 0);
6010             if (is_zero(p)) {
6011                 r = const_cast<polynomial*>(p);
6012                 return true;
6013             }
6014             scoped_numeral a(m_manager);
6015             TRACE("sqrt_bug",
6016                   tout << "sqrt:    "; p->display(tout, m_manager); tout << "\n";
6017                   tout << "min pos: " <<  p->graded_lex_min_pos() << "\n";
6018                   tout << "max pos: " <<  p->graded_lex_max_pos() << "\n";);
6019             // Quick Check: the minimal monomial must be a perfect square
6020             unsigned min_pos = p->graded_lex_min_pos();
6021             if (!is_perfect_square(p, min_pos, a))
6022                 return false;
6023             // Quick Check: the maximal monomial must be a perfect square
6024             unsigned max_pos = p->graded_lex_max_pos();
6025             if (!is_perfect_square(p, max_pos, a))
6026                 return false;
6027             // Compute square root using
6028             //    (m_1 + ... + m_k)^2 ==
6029             //         (m_1)m_1
6030             //         (2m_1 + m_2)m_2
6031             //         (2m_1 + 2m_2 + m_3)m_3
6032             //         ...
6033             //
6034             // R <- m1
6035             // C <- p - m1*m1
6036             // while (true) {
6037             //    if (is_zero(C))
6038             //       return true;
6039             //    m <- biggest monomial in C
6040             //    if (m is not divisible by 2*m1)
6041             //       return false;
6042             //    m' <- m/2m1
6043             //    C  <- C - 2*R*m' - m'*m'
6044             //    R  <- R + m'
6045             // }
6046             //
6047             // The loop above terminates because total degree of the
6048             // maximal monomial in C decreases in each iteration.
6049             monomial * m1 = sqrt(p->m(max_pos));
6050             SASSERT(m1 != 0);
6051             som_buffer & R = m_som_buffer;
6052             som_buffer & C = m_som_buffer2;
6053             struct scoped_reset { som_buffer& b; scoped_reset(som_buffer& b) :b(b) {} ~scoped_reset() { b.reset(); } };
6054             scoped_reset _rs1(R);
6055             scoped_reset _rs2(C);
6056             R.reset();
6057             C.reset();
6058             numeral two;
6059             m_manager.set(two, 2);
6060             scoped_numeral two_a(m_manager);
6061             m_manager.mul(a, two, two_a);
6062             // R <- a * m1
6063             R.add(a, m1);
6064             // C <- p - m1*m1
6065             unsigned sz = p->size();
6066             for (unsigned i = 0; i < sz; i++) {
6067                 if (i == max_pos)
6068                     continue;
6069                 C.add(p->a(i), p->m(i));
6070             }
6071             scoped_numeral a_i(m_manager);
6072             scoped_numeral aux(m_manager);
6073             monomial_ref m_aux(pm());
6074             while (true) {
6075                 checkpoint();
6076                 TRACE("sqrt_bug", tout << "R: "; R.display(tout); tout << "C: "; C.display(tout););
6077                 unsigned curr_max = C.graded_lex_max_pos();
6078                 if (curr_max == UINT_MAX) {
6079                     // C is empty
6080                     r = R.mk();
6081                     return true;
6082                 }
6083                 monomial * m = C.m(curr_max);
6084                 monomial_ref m_i(pm());
6085                 // m1 does not divide maximal monomial of C.
6086                 if (!div(m, m1, m_i))
6087                     return false;
6088 
6089                 // 2*a does not divide maximal coefficient of C
6090                 if (!m_manager.divides(two_a, C.a(curr_max)))
6091                     return false;
6092 
6093                 m_manager.div(C.a(curr_max), two_a, a_i);
6094 
6095                 // C  <- C - 2*R*a_i*m_i - a_i*a_i*m_i*m_i
6096                 unsigned R_sz = R.size();
6097                 for (unsigned j = 0; j < R_sz; j++) {
6098                     if (m_manager.is_zero(R.a(j)))
6099                         continue;
6100                     m_manager.mul(R.a(j), a_i, aux);
6101                     m_manager.mul(aux, two, aux);
6102                     m_manager.neg(aux);
6103                     m_aux = mul(R.m(j), m_i);
6104                     C.add(aux, m_aux);
6105                 }
6106                 m_manager.mul(a_i, a_i, aux);
6107                 m_manager.neg(aux);
6108                 m_aux = mul(m_i, m_i);
6109                 C.add(aux, m_aux);
6110                 // R <- R + a_i*m_i
6111                 R.add(a_i, m_i);
6112             }
6113         }
6114 
renamepolynomial::manager::imp6115         void rename(unsigned sz, var const * xs) {
6116             TRACE("rename", for (unsigned i = 0; i < sz; i++) tout << xs[i] << " "; tout << "\n";
6117                   tout << "polynomials before rename\n";
6118                   for (unsigned i = 0; i < m_polynomials.size(); i++) {
6119                       if (m_polynomials[i] == 0)
6120                           continue;
6121                       m_polynomials[i]->display(tout, m_manager);
6122                       tout << "\n";
6123                   });
6124             mm().rename(sz, xs);
6125             // we must traverse the polynomial vector, and update the first monomial,
6126             // since it may not contain anymore the maximal variable with maximal degree.
6127             for (polynomial* p : m_polynomials) {
6128                 if (p != nullptr)
6129                     p->make_first_maximal();
6130                 SASSERT(!p || p->size() <= 1 || !p->lex_sorted());
6131             }
6132             TRACE("rename",
6133                   tout << "polynomials after rename\n";
6134                   for (unsigned i = 0; i < m_polynomials.size(); i++) {
6135                       if (m_polynomials[i] == 0)
6136                           continue;
6137                       m_polynomials[i]->display(tout, m_manager);
6138                       tout << "\n";
6139                   });
6140         }
6141 
signpolynomial::manager::imp6142         lbool sign(monomial* m, numeral const& c, svector<lbool> const& sign_of_vars) {
6143             unsigned sz = size(m);
6144             lbool sign1 = m_manager.is_pos(c) ? l_true : l_false;
6145             for (unsigned i = 0; i < sz; ++i) {
6146                 var v = get_var(m, i);
6147                 unsigned d = degree(m, i);
6148                 lbool sign2 = sign_of_vars.get(v, l_undef);
6149                 if (sign2 == l_undef)
6150                     return l_undef;
6151                 else if (1 == (d % 2) && sign2 == l_false) {
6152                     sign1 = sign1 == l_true ? l_false : l_true;
6153                 }
6154             }
6155             return sign1;
6156         }
6157 
signpolynomial::manager::imp6158         lbool sign(polynomial const * p, svector<lbool> const& sign_of_vars) {
6159             unsigned sz = size(p);
6160             if (sz == 0) return l_undef;
6161             lbool sign1 = sign(p->m(0), p->a(0), sign_of_vars);
6162             for (unsigned i = 1; sign1 != l_undef && i < sz; ++i) {
6163                 if (sign(p->m(i), p->a(i), sign_of_vars) != sign1)
6164                     return l_undef;
6165             }
6166             return sign1;
6167         }
6168 
is_pospolynomial::manager::imp6169         bool is_pos(polynomial const * p) {
6170             bool found_unit = false;
6171             unsigned sz = p->size();
6172             for (unsigned i = 0; i < sz; i++) {
6173                 if (!p->m(i)->is_power_of_two())
6174                     return false;
6175                 if (p->m(i) == mk_unit())
6176                     found_unit = true;
6177                 if (!m_manager.is_pos(p->a(i)))
6178                     return false;
6179             }
6180             return found_unit;
6181         }
6182 
is_negpolynomial::manager::imp6183         bool is_neg(polynomial const * p) {
6184             bool found_unit = false;
6185             unsigned sz = p->size();
6186             for (unsigned i = 0; i < sz; i++) {
6187                 if (!p->m(i)->is_power_of_two())
6188                     return false;
6189                 if (p->m(i) == mk_unit())
6190                     found_unit = true;
6191                 if (!m_manager.is_neg(p->a(i)))
6192                     return false;
6193             }
6194             return found_unit;
6195         }
6196 
is_nonpospolynomial::manager::imp6197         bool is_nonpos(polynomial const * p) {
6198             unsigned sz = p->size();
6199             for (unsigned i = 0; i < sz; i++) {
6200                 if (!p->m(i)->is_power_of_two())
6201                     return false;
6202                 if (!m_manager.is_neg(p->a(i)))
6203                     return false;
6204             }
6205             return true;
6206         }
6207 
is_nonnegpolynomial::manager::imp6208         bool is_nonneg(polynomial const * p) {
6209             unsigned sz = p->size();
6210             for (unsigned i = 0; i < sz; i++) {
6211                 if (!p->m(i)->is_power_of_two())
6212                     return false;
6213                 if (!m_manager.is_pos(p->a(i)))
6214                     return false;
6215             }
6216             return true;
6217         }
6218 
6219         // Functor used to compute the maximal degree of each variable in a polynomial p.
6220         class var_max_degree {
6221             unsigned_vector    m_max_degree;
6222             var_vector         m_xs;
6223         public:
init(polynomial const * p)6224             void init(polynomial const * p) {
6225                 unsigned sz = p->size();
6226                 for (unsigned i = 0; i < sz; i++) {
6227                     monomial * m = p->m(i);
6228                     unsigned msz = m->size();
6229                     for (unsigned j = 0; j < msz; j++) {
6230                         var x = m->get_var(j);
6231                         unsigned k = m->degree(j);
6232                         unsigned max_k = m_max_degree.get(x, 0);
6233                         if (k > max_k) {
6234                             if (max_k == 0)
6235                                 m_xs.push_back(x);
6236                             m_max_degree.setx(x, m->degree(j), 0);
6237                         }
6238                     }
6239                 }
6240             }
6241 
reset()6242             void reset() {
6243                 unsigned sz = m_xs.size();
6244                 for (unsigned i = 0; i < sz; i++) {
6245                     m_max_degree[m_xs[i]] = 0;
6246                 }
6247                 m_xs.reset();
6248             }
6249 
operator ()(var x) const6250             unsigned operator()(var x) const {
6251                 return m_max_degree.get(x, 0);
6252             }
6253 
num_vars() const6254             unsigned num_vars() const { return m_xs.size(); }
6255 
vars() const6256             var const * vars() const { return m_xs.c_ptr(); }
6257         };
6258 
6259         struct scoped_var_max_degree {
6260             var_max_degree & m;
scoped_var_max_degreepolynomial::manager::imp::scoped_var_max_degree6261             scoped_var_max_degree(var_max_degree & _m, polynomial const * p):
6262                 m(_m) {
6263                 m.init(p);
6264             }
~scoped_var_max_degreepolynomial::manager::imp::scoped_var_max_degree6265             ~scoped_var_max_degree() {
6266                 m.reset();
6267             }
operator ()polynomial::manager::imp::scoped_var_max_degree6268             unsigned operator()(var x) const {
6269                 return m(x);
6270             }
num_varspolynomial::manager::imp::scoped_var_max_degree6271             unsigned num_vars() const { return m.num_vars(); }
varspolynomial::manager::imp::scoped_var_max_degree6272             var const * vars() const { return m.vars(); }
6273         };
6274 
6275         var_max_degree  m_var_max_degree;
6276 
6277         // This method uses the tmp fields: m_found_vars, m_var_max_degree.
substitutepolynomial::manager::imp6278         polynomial * substitute(polynomial const * p, var2mpq const & x2v) {
6279             scoped_var_max_degree var2max_degree(m_var_max_degree, p);
6280             unsigned xs_sz = var2max_degree.num_vars();
6281             var const * xs = var2max_degree.vars();
6282             bool found = false;
6283             for (unsigned i = 0; i < xs_sz; i++) {
6284                 var x = xs[i];
6285                 if (x2v.contains(x) && var2max_degree(x) > 0) {
6286                     found = true;
6287                     break;
6288                 }
6289             }
6290             if (!found)
6291                 return const_cast<polynomial*>(p);
6292             scoped_numeral new_a(m_manager);
6293             scoped_numeral tmp(m_manager);
6294             m_found_vars.reserve(num_vars(), false);
6295             m_som_buffer.reset();
6296             som_buffer & R       = m_som_buffer;
6297             tmp_monomial & new_m = m_tmp1;
6298             unsigned sz    = p->size();
6299             for (unsigned i = 0; i < sz; i++) {
6300                 monomial * m = p->m(i);
6301                 unsigned msz = m->size();
6302                 unsigned new_msz = 0;
6303                 m_manager.set(new_a, p->a(i));
6304                 new_m.reserve(msz);
6305                 for (unsigned j = 0; j < msz; j++) {
6306                     var x = m->get_var(j);
6307                     unsigned k = m->degree(j);
6308                     if (x2v.contains(x)) {
6309                         unsigned max_k = var2max_degree(x);
6310                         m_found_vars[x] = true;
6311                         mpq const & x_value = x2v(x);
6312                         m_manager.power(x_value.numerator(), k, tmp);
6313                         m_manager.mul(tmp, new_a, new_a);
6314                         if (k < max_k) {
6315                             m_manager.power(x_value.denominator(), max_k - k, tmp);
6316                             m_manager.mul(tmp, new_a, new_a);
6317                         }
6318                     }
6319                     else {
6320                         new_m.set_power(new_msz, m->get_power(j));
6321                         new_msz++;
6322                     }
6323                 }
6324                 // For each variable x in xs that does not occur in m, I
6325                 // should include (x2v(x).denominator())^{var2max_degree(x)} to new_a
6326                 for (unsigned j = 0; j < xs_sz; j++) {
6327                     var x = xs[j];
6328                     if (m_found_vars[x])
6329                         continue;
6330                     if (x2v.contains(x)) {
6331                         m_manager.power(x2v(x).denominator(), var2max_degree(x), tmp);
6332                         m_manager.mul(tmp, new_a, new_a);
6333                     }
6334                 }
6335                 // Reset m_found_vars
6336                 for (unsigned j = 0; j < msz; j++) {
6337                     var x = m->get_var(j);
6338                     m_found_vars[x] = false;
6339                 }
6340                 // Add new_a*new_m to R
6341                 if (!m_manager.is_zero(new_a)) {
6342                     new_m.set_size(new_msz);
6343                     R.add(new_a, mk_monomial(new_m));
6344                 }
6345             }
6346             return R.mk(true);
6347         }
6348 
6349         struct var_pos {
6350             unsigned_vector m_pos;
6351 
initpolynomial::manager::imp::var_pos6352             void init(unsigned sz, var const * xs) {
6353                 for (unsigned i = 0; i < sz; i++) {
6354                     SASSERT(m_pos.get(xs[i], UINT_MAX) == UINT_MAX);
6355                     m_pos.setx(xs[i], i, UINT_MAX);
6356                 }
6357             }
6358 
resetpolynomial::manager::imp::var_pos6359             void reset(unsigned sz, var const * xs) {
6360                 for (unsigned i = 0; i < sz; i++) {
6361                     SASSERT(m_pos.get(xs[i], UINT_MAX) != UINT_MAX);
6362                     m_pos[xs[i]] = UINT_MAX;
6363                 }
6364             }
6365 
operator ()polynomial::manager::imp::var_pos6366             unsigned operator()(var x) const { return m_pos.get(x, UINT_MAX); }
6367         };
6368 
6369         struct scoped_var_pos {
6370             var_pos &          m;
6371             unsigned           m_xs_sz;
6372             var const *        m_xs;
scoped_var_pospolynomial::manager::imp::scoped_var_pos6373             scoped_var_pos(var_pos & p, unsigned xs_sz, var const * xs):
6374                 m(p),
6375                 m_xs_sz(xs_sz),
6376                 m_xs(xs) {
6377                 m.init(m_xs_sz, m_xs);
6378             }
~scoped_var_pospolynomial::manager::imp::scoped_var_pos6379             ~scoped_var_pos() {
6380                 m.reset(m_xs_sz, m_xs);
6381             }
operator ()polynomial::manager::imp::scoped_var_pos6382             unsigned operator()(var x) const { return m(x); }
6383         };
6384 
6385         var_pos         m_var_pos;
6386 
6387         struct var2mpq_wrapper : public var2mpq {
6388             scoped_var_pos  m_var_pos;
6389             mpq const * m_vs;
var2mpq_wrapperpolynomial::manager::imp::var2mpq_wrapper6390             var2mpq_wrapper(unsigned xs_sz, var const * xs, mpq const * vs, var_pos & buffer):
6391                 m_var_pos(buffer, xs_sz, xs),
6392                 m_vs(vs) {
6393             }
mpolynomial::manager::imp::var2mpq_wrapper6394             unsynch_mpq_manager & m() const override { UNREACHABLE(); static unsynch_mpq_manager m; return m; }
containspolynomial::manager::imp::var2mpq_wrapper6395             bool contains(var x) const override { return m_var_pos(x) != UINT_MAX; }
operator ()polynomial::manager::imp::var2mpq_wrapper6396             mpq const & operator()(var x) const override { return m_vs[m_var_pos(x)]; }
6397         };
6398 
substitutepolynomial::manager::imp6399         polynomial * substitute(polynomial const * p, unsigned xs_sz, var const * xs, mpq const * vs) {
6400             var2mpq_wrapper x2v(xs_sz, xs, vs, m_var_pos);
6401             return substitute(p, x2v);
6402         }
6403 
substitutepolynomial::manager::imp6404         polynomial * substitute(polynomial const * p, unsigned xs_sz, var const * xs, numeral const * vs) {
6405             TRACE("polynomial", tout << "substitute num_vars: " << xs_sz << "\n";
6406                   for (unsigned i = 0; i < xs_sz; i++) { tout << "x" << xs[i] << " -> " << m_manager.to_string(vs[i]) << "\n"; });
6407             scoped_var_pos var2pos(m_var_pos, xs_sz, xs);
6408             scoped_numeral new_a(m_manager);
6409             scoped_numeral tmp(m_manager);
6410             m_som_buffer.reset();
6411             som_buffer & R       = m_som_buffer;
6412             tmp_monomial & new_m = m_tmp1;
6413             unsigned sz    = p->size();
6414             for (unsigned i = 0; i < sz; i++) {
6415                 monomial * m = p->m(i);
6416                 unsigned msz = m->size();
6417                 unsigned new_msz = 0;
6418                 m_manager.set(new_a, p->a(i));
6419                 new_m.reserve(msz);
6420                 for (unsigned j = 0; j < msz; j++) {
6421                     var x = m->get_var(j);
6422                     unsigned k = m->degree(j);
6423                     unsigned pos = var2pos(x);
6424                     if (pos != UINT_MAX) {
6425                         m_manager.power(vs[pos], k, tmp);
6426                         m_manager.mul(tmp, new_a, new_a);
6427                     }
6428                     else {
6429                         SASSERT(var2pos(x) == UINT_MAX); // x is not in xs
6430                         new_m.set_power(new_msz, m->get_power(j));
6431                         new_msz++;
6432                     }
6433                 }
6434                 new_m.set_size(new_msz);
6435                 TRACE("polynomial", tout << "processing " << m_manager.to_string(p->a(i)) << " "; m->display(tout); tout << "\n";
6436                       tout << "new_a: " << m_manager.to_string(new_a) << " "; mk_monomial(new_m)->display(tout); tout << "\n";);
6437                 R.add(new_a, mk_monomial(new_m));
6438             }
6439             return R.mk();
6440         }
6441 
substitutepolynomial::manager::imp6442         void substitute(polynomial const* r, var x, polynomial const* p, polynomial const* q, polynomial_ref& result) {
6443             unsigned md = degree(r, x);
6444             if (md == 0) {
6445                 result = const_cast<polynomial*>(r);
6446                 return;
6447             }
6448             result = nullptr;
6449             polynomial_ref p1(pm()), q1(pm());
6450             polynomial_ref_buffer ps(pm());
6451             unsigned sz = r->size();
6452             for (unsigned i = 0; i < sz; i++) {
6453                 monomial * m0 = r->m(i);
6454                 unsigned dm = m0->degree_of(x);
6455                 SASSERT(md >= dm);
6456                 monomial_ref m1(div_x(m0, x), pm());
6457                 pw(p, dm, p1);
6458                 pw(q, md - dm, q1);
6459                 p1 = mul(r->a(i), m1, p1 * q1);
6460                 if (result)
6461                     result = add(result, p1);
6462                 else
6463                     result = p1;
6464             }
6465         }
6466 
6467 
6468         /**
6469            Auxiliary method used to implement t_eval.
6470            If evaluates the sub-polynomial p composed of the monomials at positions [start, end)
6471            where all variables > x are ignored.
6472 
6473            var2pos is a mapping from variables to the positions.
6474            vs[var2pos(x)] contains the value of x.
6475         */
6476         template<typename ValManager>
t_eval_corepolynomial::manager::imp6477         void t_eval_core(polynomial * p, ValManager & vm, var2value<ValManager> const & x2v,
6478                          unsigned start, unsigned end, var x, typename ValManager::numeral & r) {
6479             TRACE("eval_bug", tout << "p: "; p->display(tout, m()); tout << "\n";
6480                   tout << "start: " << start << ", end: " << end << ", x: " << x << "\n";);
6481             SASSERT(start < end);
6482             SASSERT(end <= p->size());
6483             SASSERT(is_valid(x));
6484             _scoped_numeral<ValManager> aux(vm);
6485             if (end == start + 1) {
6486                 vm.set(r, p->a(start));
6487                 monomial * m = p->m(start);
6488                 SASSERT(m->degree_of(x) > 0);
6489                 unsigned sz = m->size();
6490                 for (unsigned i = 0; i < sz; i++) {
6491                     var y = m->get_var(i);
6492                     if (y > x)
6493                         break;
6494                     SASSERT(x2v.contains(y));
6495                     unsigned d    = m->degree(i);
6496                     vm.power(x2v(y), d, aux);
6497                     vm.mul(r, aux, r);
6498                 }
6499             }
6500             else {
6501                 SASSERT(x2v.contains(x));
6502                 typename ValManager::numeral const & x_value = x2v(x);
6503                 vm.reset(r);
6504                 unsigned i = start;
6505                 while (i < end) {
6506                     checkpoint();
6507                     unsigned d = p->m(i)->degree_of(x);
6508                     if (d == 0) {
6509                         var y = p->max_smaller_than(i, end, x);
6510                         if (y == null_var) {
6511                             SASSERT(end == i+1);
6512                             vm.add(r, p->a(i), r);
6513                         }
6514                         else {
6515                             t_eval_core<ValManager>(p, vm, x2v, i, end, y, aux.get());
6516                             vm.add(r, aux, r);
6517                         }
6518                         break;
6519                     }
6520                     unsigned j = i+1;
6521                     unsigned next_d = 0;
6522                     for (; j < end; j++) {
6523                         unsigned d_j = p->m(j)->degree_of(x);
6524                         SASSERT(d_j <= d);
6525                         if (d_j < d) {
6526                             next_d = d_j;
6527                             break;
6528                         }
6529                     }
6530                     SASSERT(j == end || p->m(j)->degree_of(x) < d);
6531                     var y = p->max_smaller_than(i, j, x);
6532                     if (y == null_var) {
6533                         SASSERT(j == i+1);
6534                         vm.set(aux, p->a(i));
6535                     }
6536                     else {
6537                         t_eval_core<ValManager>(p, vm, x2v, i, j, y, aux.get());
6538                     }
6539                     vm.add(r, aux, r);
6540                     vm.power(x_value, d - next_d, aux);
6541                     vm.mul(r, aux, r);
6542                     i = j;
6543                 }
6544             }
6545             TRACE("eval_bug", tout << "result for start: " << start << ", end: " << end << ", x: " << x << "\n";
6546                   tout << "r: "; vm.display(tout, r); tout << "\n";);
6547         }
6548 
6549         template<typename ValManager>
t_evalpolynomial::manager::imp6550         void t_eval(polynomial * p, var2value<ValManager> const & x2v, typename ValManager::numeral & r) {
6551             ValManager & vm = x2v.m();
6552             if (is_zero(p)) {
6553                 vm.reset(r);
6554                 return;
6555             }
6556             if (is_const(p)) {
6557                 SASSERT(size(p)==1);
6558                 vm.set(r, p->a(0));
6559                 return;
6560             }
6561             lex_sort(p); // lex_sort just reorders the monomials of p. That is, p still represents the same polynomial
6562             t_eval_core(p, vm, x2v, 0, p->size(), max_var(p), r);
6563         }
6564 
6565         class single_var2value : public var2value<numeral_manager> {
6566             numeral_manager & m_manager;
6567             var             m_x;
6568             numeral const & m_val;
6569         public:
single_var2value(numeral_manager & m,var x,numeral const & val)6570             single_var2value(numeral_manager & m, var x, numeral const & val):m_manager(m), m_x(x), m_val(val) {}
m() const6571             numeral_manager & m() const override { return m_manager; }
contains(var x) const6572             bool contains(var x) const override { return m_x == x; }
operator ()(var x) const6573             numeral const & operator()(var x) const override { SASSERT(m_x == x); return m_val; }
6574         };
6575 
univ_evalpolynomial::manager::imp6576         void univ_eval(polynomial const * p, var x, numeral const & val, numeral & r) {
6577             SASSERT(is_univariate(p));
6578             if (is_zero(p))
6579                 m().set(r, 0);
6580             else if (is_const(p))
6581                 m().set(r, p->a(0));
6582             else
6583                 t_eval<numeral_manager>(const_cast<polynomial*>(p), single_var2value(m(),x, val), r);
6584         }
6585 
evalpolynomial::manager::imp6586         void eval(polynomial const * p, var2mpbqi const & x2v, mpbqi & r) {
6587             t_eval<mpbqi_manager>(const_cast<polynomial*>(p), x2v, r);
6588         }
6589 
evalpolynomial::manager::imp6590         void eval(polynomial const * p, var2mpq const & x2v, mpq & r) {
6591             t_eval<unsynch_mpq_manager>(const_cast<polynomial*>(p), x2v, r);
6592         }
6593 
evalpolynomial::manager::imp6594         void eval(polynomial const * p, var2anum const & x2v, anum & r) {
6595             t_eval<anum_manager>(const_cast<polynomial*>(p), x2v, r);
6596         }
6597 
6598         // Return the variable with minimal degree in p
6599         // That is min_x s.t. forall x in p degree(p, min_x) <= degree(p, x)
get_min_degree_varpolynomial::manager::imp6600         var get_min_degree_var(polynomial const * p) {
6601             SASSERT(!is_const(p));
6602             scoped_var_max_degree var2max_degree(m_var_max_degree, p);
6603             unsigned num_vars = var2max_degree.num_vars();
6604             var const * xs = var2max_degree.vars();
6605             var min_x = null_var;
6606             unsigned deg_min = UINT_MAX;
6607             for (unsigned i = 0; i < num_vars; i++) {
6608                 var x_i = xs[i];
6609                 unsigned deg_x_i = var2max_degree(x_i);
6610                 if (deg_x_i < deg_min) {
6611                     min_x   = x_i;
6612                     deg_min = deg_x_i;
6613                 }
6614             }
6615             return min_x;
6616         }
6617 
acc_constantpolynomial::manager::imp6618         void acc_constant(factors & r, numeral const & c) {
6619             TRACE("factor_bug", tout << "acc_constant, c: "; m_manager.display(tout, c); tout << "\n";);
6620             scoped_numeral new_c(m_manager);
6621             m_manager.mul(r.get_constant(), c, new_c);
6622             r.set_constant(new_c);
6623         }
6624 
flip_signpolynomial::manager::imp6625         void flip_sign(factors & r) {
6626             scoped_numeral new_c(m_manager);
6627             m_manager.set(new_c, r.get_constant());
6628             m_manager.neg(new_c);
6629             r.set_constant(new_c);
6630         }
6631 
factor_1_sqf_pppolynomial::manager::imp6632         void factor_1_sqf_pp(polynomial const * p, factors & r, var x, unsigned k) {
6633             SASSERT(degree(p, x) == 1);
6634             SASSERT(is_primitive(p, x));
6635             SASSERT(is_square_free(p, x));
6636             TRACE("factor", tout << "factor square free (degree == 1):\n"; p->display(tout, m_manager); tout << "\n";);
6637             // easy case
6638             r.push_back(const_cast<polynomial*>(p), k);
6639         }
6640 
factor_2_sqf_pppolynomial::manager::imp6641         void factor_2_sqf_pp(polynomial const * p, factors & r, var x, unsigned k) {
6642             SASSERT(degree(p, x) == 2);
6643             SASSERT(is_primitive(p, x));
6644             SASSERT(is_square_free(p, x));
6645             TRACE("factor", tout << "factor square free (degree == 2):\n"; p->display(tout, m_manager); tout << "\n";);
6646 
6647             polynomial_ref a(pm());
6648             polynomial_ref b(pm());
6649             polynomial_ref c(pm());
6650             a = coeff(p, x, 2);
6651             b = coeff(p, x, 1);
6652             c = coeff(p, x, 0);
6653             TRACE("factor", tout << "a: " << a << "\nb: " << b << "\nc: " << c << "\n";);
6654             // make sure the leading monomoal of a is positive
6655             bool flipped_coeffs = false;
6656             SASSERT(!is_zero(a));
6657             unsigned a_glex_max_pos = a->graded_lex_max_pos();
6658             SASSERT(a_glex_max_pos != UINT_MAX);
6659             if (m_manager.is_neg(a->a(a_glex_max_pos))) {
6660                 a = neg(a);
6661                 b = neg(b);
6662                 c = neg(c);
6663                 flipped_coeffs = true;
6664             }
6665             // Create the discriminant: b^2 - 4*a*c
6666             polynomial_ref b2(pm());
6667             b2  = mul(b, b);
6668             polynomial_ref ac(pm());
6669             ac = mul(a, c);
6670             polynomial_ref disc(pm());
6671             numeral m_four;
6672             m_manager.set(m_four, -4);
6673             disc = addmul(b2, m_four, mk_unit(), ac);
6674             // discriminant must be different from 0, since p is square free
6675             SASSERT(!is_zero(disc));
6676             polynomial_ref disc_sqrt(pm());
6677             TRACE("factor", tout << "disc: " << disc << "\n";);
6678             if (!sqrt(disc, disc_sqrt)) {
6679                 // p is irreducible
6680                 r.push_back(const_cast<polynomial*>(p), k);
6681                 return;
6682             }
6683             if (flipped_coeffs && k % 2 == 1) {
6684                 // if k is ODD, and we flipped the coefficients,
6685                 // we must also flip the sign of r.
6686                 flip_sign(r);
6687             }
6688             DEBUG_CODE({
6689                 polynomial_ref tmp(pm());
6690                 tmp = mul(disc_sqrt, disc_sqrt);
6691                 SASSERT(eq(disc, tmp));
6692             });
6693             TRACE("factor", tout << "disc_sqrt: " << disc_sqrt << "\n";);
6694             // p = cont*(2*a*x + b - disc_sqrt)*(2*a*x + b + disc_sqrt)
6695             numeral two;
6696             m_manager.set(two, 2);
6697             polynomial_ref f1(pm());
6698             polynomial_ref f2(pm());
6699             monomial_ref mx(pm());
6700             mx = mk_monomial(x);
6701             polynomial_ref two_ax(pm());
6702             two_ax = mul(two, mx, a);
6703             f1 = add(two_ax, b);
6704             f2 = f1;
6705             f1 = sub(f1, disc_sqrt);
6706             f2 = add(f2, disc_sqrt);
6707             TRACE("factor", tout << "before pp\nf1: " << f1 << "\nf2: " << f2 << "\n";
6708                   polynomial_ref cf1(pm()); m_wrapper.content(f1, x, cf1);
6709                   polynomial_ref cf2(pm()); m_wrapper.content(f2, x, cf2);
6710                   tout << "content(f1): " << cf1 << "\ncontent(f2): " << cf2 << "\n";);
6711             f1 = pp(f1, x);
6712             f2 = pp(f2, x);
6713             TRACE("factor", tout << "f1: " << f1 << "\nf2: " << f2 << "\n";);
6714             DEBUG_CODE({
6715                 polynomial_ref f1f2(pm());
6716                 f1f2 = mul(f1, f2);
6717                 if (flipped_coeffs)
6718                     f1f2 = neg(f1f2);
6719                 SASSERT(eq(f1f2, p));
6720             });
6721             r.push_back(f1, k);
6722             r.push_back(f2, k);
6723         }
6724 
factor_sqf_pp_univpolynomial::manager::imp6725         void factor_sqf_pp_univ(polynomial const * p, factors & r, unsigned k, factor_params const & params) {
6726             SASSERT(is_univariate(p));
6727             SASSERT(is_square_free(p, max_var(p)));
6728             SASSERT(is_primitive(p, max_var(p)));
6729             SASSERT(!is_zero(p));
6730             TRACE("factor", tout << "factor square free univariate:\n"; p->display(tout, m_manager); tout << "\n";);
6731 
6732             // Convert polynomial into a upolynomial, and execute univariate factorization.
6733             var x = max_var(p);
6734             up_manager::scoped_numeral_vector p1(upm().m());
6735             polynomial_ref p_ref(pm());
6736             p_ref = const_cast<polynomial*>(p);
6737             upm().to_numeral_vector(p_ref, p1);
6738             up_manager::factors fs(upm());
6739             upolynomial::factor_square_free(upm(), p1, fs, params);
6740             SASSERT(m().is_one(fs.get_constant()) || m().is_minus_one(fs.get_constant()));
6741 
6742             if (fs.distinct_factors() == 1 && fs.get_degree(0) == 1) {
6743                 // p is irreducible
6744                 r.push_back(const_cast<polynomial*>(p), k);
6745             }
6746             else {
6747                 // Convert factors back into polynomial objects
6748                 TRACE("factor_bug", tout << "factoring fs constant: " << m().to_string(fs.get_constant()) << "\np:\n";
6749                       p->display(tout, m()); tout << "\n";);
6750                 polynomial_ref f(pm());
6751                 unsigned num_factors = fs.distinct_factors();
6752                 for (unsigned i = 0; i < num_factors; i++) {
6753                     numeral_vector const & f1 = fs[i];
6754                     unsigned k1 = fs.get_degree(i);
6755                     f = to_polynomial(f1.size(), f1.c_ptr(), x);
6756                     TRACE("factor_bug",
6757                           tout << "uni-factor:\n"; upm().display(tout, f1); tout << "\n";
6758                           tout << "factor:\n" << f << "\n";);
6759                     r.push_back(f, k*k1);
6760                 }
6761                 TRACE("factor_bug", tout << "end-factors...\n";);
6762                 SASSERT(m().is_one(fs.get_constant()) || m().is_minus_one(fs.get_constant()));
6763                 if (m().is_minus_one(fs.get_constant()) && k % 2 == 1)
6764                     flip_sign(r);
6765             }
6766         }
6767 
factor_n_sqf_pppolynomial::manager::imp6768         void factor_n_sqf_pp(polynomial const * p, factors & r, var x, unsigned k) {
6769             SASSERT(degree(p, x) > 2);
6770             SASSERT(is_primitive(p, x));
6771             SASSERT(is_square_free(p, x));
6772             TRACE("factor", tout << "factor square free (degree > 2):\n"; p->display(tout, m_manager); tout << "\n";);
6773 
6774             // TODO: invoke Dejan's procedure
6775             r.push_back(const_cast<polynomial*>(p), k);
6776         }
6777 
factor_sqf_pppolynomial::manager::imp6778         void factor_sqf_pp(polynomial const * p, factors & r, var x, unsigned k, factor_params const & params) {
6779             SASSERT(degree(p, x) > 0);
6780             SASSERT(is_primitive(p, x));
6781             SASSERT(is_square_free(p, x));
6782             SASSERT(!is_zero(p));
6783 
6784             unsigned deg_x = degree(p, x);
6785             if (deg_x == 1)
6786                 factor_1_sqf_pp(p, r, x, k);
6787             else if (is_univariate(p))
6788                 factor_sqf_pp_univ(p, r, k, params);
6789             else if (deg_x == 2)
6790                 factor_2_sqf_pp(p, r, x, k);
6791             else
6792                 factor_n_sqf_pp(p, r, x, k);
6793         }
6794 
factor_corepolynomial::manager::imp6795         void factor_core(polynomial const * p, factors & r, factor_params const & params) {
6796             TRACE("factor", tout << "factor_core\np: "; p->display(tout, m_manager); tout << "\n";);
6797             TRACE("factor_bug", tout << "factors r.get_constant(): " << m_manager.to_string(r.get_constant()) << "\n";);
6798             SASSERT(!is_zero(p));
6799             if (is_const(p)) {
6800                 SASSERT(!is_zero(p));
6801                 SASSERT(p->size() == 1);
6802                 acc_constant(r, p->a(0));
6803                 return;
6804             }
6805             var x = get_min_degree_var(p);
6806             SASSERT(degree(p, x) > 0);
6807             scoped_numeral i(m_manager);
6808             polynomial_ref c(pm()), pp(pm());
6809             iccp(p, x, i, c, pp);
6810             TRACE("factor", tout << "i: " << i << "\n";);
6811             acc_constant(r, i);
6812             factor_core(c, r, params);
6813 
6814             polynomial_ref C(pm());
6815             C = pp;
6816             // Let C be a primitive polynomial of the form: P_1^1 * P_2^2 * ... * P_k^k, where each P_i is square free
6817             polynomial_ref C_prime(pm());
6818             C_prime = derivative(C, x);
6819             polynomial_ref B(pm()), A(pm()), D(pm());
6820             gcd(C, C_prime, B);
6821             if (is_const(B)) {
6822                 // C must be of the form P_1 (square free)
6823                 SASSERT(degree(C, x) > 0);
6824                 factor_sqf_pp(C, r, x, 1, params);
6825             }
6826             else {
6827                 // B is of the form P_2 * P_3^2 * ... * P_k^{k-1}
6828                 A = exact_div(C, B);
6829                 // A is of the form P_1 * P_2 * ... * P_k
6830                 unsigned j = 1;
6831                 while (!is_const(A)) {
6832                     SASSERT(is_primitive(A, x));
6833                     SASSERT(is_square_free(A, x));
6834                     SASSERT(degree(A, x) > 0);
6835                     checkpoint();
6836                     TRACE("factor", tout << "factor_core main loop j: " << j << "\nA: " << A << "\nB: " << B << "\n";);
6837                     // A is of the form       P_j * P_{j+1} * P_{j+2}   * ... * P_k
6838                     // B is of the form             P_{j+1} * P_{j+2}^2 * ... * P_k^{k - j - 2}
6839                     gcd(A, B, D);
6840                     // D is of the form             P_{j+1} * P_{j+2}   * ... * P_k
6841                     C = exact_div(A, D);
6842                     // C is of the form P_j
6843                     if (!is_const(C)) {
6844                         SASSERT(degree(C, x) > 0);
6845                         factor_sqf_pp(C, r, x, j, params);
6846                     }
6847                     else {
6848                         TRACE("factor", tout << "const C: " << C << "\n";);
6849                         SASSERT(C->size() == 1);
6850                         SASSERT(m_manager.is_one(C->a(0)) || m_manager.is_minus_one(C->a(0)));
6851                         if (m_manager.is_minus_one(C->a(0)) && j % 2 == 1)
6852                             flip_sign(r);
6853                     }
6854                     B = exact_div(B, D);
6855                     // B is of the form                       P_{j+2}   * ... * P_k^{k - j - 3}
6856                     A = D;
6857                     // D is of the form             P_{j+1} * P_{j+2}   * ... * P_k
6858                     j++;
6859                 }
6860                 SASSERT(eq(mk_one(), A));
6861             }
6862         }
6863 
factorpolynomial::manager::imp6864         void factor(polynomial const * p, factors & r, factor_params const & params) {
6865             if (is_zero(p)) {
6866                 r.set_constant(mpz(0));
6867                 return;
6868             }
6869             factor_core(p, r, params);
6870             TRACE("factor_bug", tout << "[factor] end, r.get_constant(): " << m_manager.to_string(r.get_constant()) << "\n";);
6871         }
6872 
to_polynomialpolynomial::manager::imp6873         polynomial * to_polynomial(unsigned sz, numeral const * p, var x) {
6874             if (sz == 0)
6875                 return mk_zero();
6876             _scoped_numeral_buffer<numeral_manager, 128> coeffs(m_manager);
6877             for (unsigned i = 0; i < sz; i++) {
6878                 coeffs.push_back(numeral());
6879                 m_manager.set(coeffs.back(), p[i]);
6880             }
6881             return mk_univariate(x, sz-1, coeffs.c_ptr());
6882         }
6883 
mk_glex_monicpolynomial::manager::imp6884         polynomial * mk_glex_monic(polynomial const * p) {
6885             SASSERT(m_manager.field());
6886             if (is_zero(p))
6887                 return const_cast<polynomial*>(p);
6888             unsigned pos = p->graded_lex_max_pos();
6889             if (m_manager.is_one(p->a(pos)))
6890                 return const_cast<polynomial*>(p);
6891             scoped_numeral inv_c(m());
6892             scoped_numeral new_a(m());
6893             m().set(inv_c, p->a(pos));
6894             m().inv(inv_c);
6895             m_cheap_som_buffer.reset();
6896             cheap_som_buffer & R = m_cheap_som_buffer;
6897             unsigned sz = p->size();
6898             for (unsigned i = 0; i < sz; i++) {
6899                 m().set(new_a, p->a(i));
6900                 m().mul(new_a, inv_c, new_a);
6901                 R.add(new_a, p->m(i));
6902             }
6903             return R.mk();
6904         }
6905 
6906         som_buffer_vector m_translate_buffers;
translatepolynomial::manager::imp6907         polynomial * translate(polynomial const * p, var x, numeral const & v) {
6908             unsigned deg_x = degree(p, x);
6909             if (deg_x == 0 || m().is_zero(v))
6910                 return const_cast<polynomial*>(p);
6911             som_buffer_vector & as = m_translate_buffers;
6912             m_translate_buffers.reset(deg_x+1);
6913             coeffs(p, x, as);
6914             for (unsigned i = 1; i <= deg_x; i++) {
6915                 checkpoint();
6916                 for (unsigned k = deg_x-i; k <= deg_x-1; k++) {
6917                     as[k]->addmul(v, as[k+1]);
6918                 }
6919             }
6920             monomial_ref xk(pm());
6921             som_buffer & R = m_som_buffer;
6922             R.reset();
6923             for (unsigned k = 0; k <= deg_x; k++) {
6924                 xk = mk_monomial(x, k);
6925                 R.addmul(xk, as[k]);
6926             }
6927             m_translate_buffers.reset(deg_x+1);
6928             return R.mk();
6929         }
6930 
translatepolynomial::manager::imp6931         void translate(polynomial const * p, unsigned xs_sz, var const * xs, numeral const * vs, polynomial_ref & r) {
6932             r = const_cast<polynomial*>(p);
6933             if (xs_sz == 0 || is_const(p))
6934                 return;
6935             for (unsigned i = 0; i < xs_sz; i++)
6936                 r = translate(r, xs[i], vs[i]);
6937         }
6938 
mod_dpolynomial::manager::imp6939         polynomial * mod_d(polynomial const * p, var2degree const & x2d) {
6940             if (is_const(p))
6941                 return const_cast<polynomial*>(p);
6942 
6943             cheap_som_buffer & R = m_cheap_som_buffer;
6944             R.reset();
6945             unsigned sz = p->size();
6946             for (unsigned i = 0; i < sz; i++) {
6947                 monomial * m = p->m(i);
6948                 unsigned msz = m->size();
6949                 unsigned j;
6950                 for (j = 0; j < msz; j++) {
6951                     var x = m->get_var(j);
6952                     unsigned dx = x2d.degree(x);
6953                     if (dx == 0)
6954                         continue;
6955                     if (m->degree(j) >= dx)
6956                         break;
6957                 }
6958                 if (j == msz) {
6959                     R.add(p->a(i), p->m(i));
6960                 }
6961             }
6962             return R.mk();
6963         }
6964 
exact_pseudo_division_mod_dpolynomial::manager::imp6965         void exact_pseudo_division_mod_d(polynomial const * p, polynomial const * q, var x, var2degree const & x2d, polynomial_ref & Q, polynomial_ref & R) {
6966             unsigned d;
6967             pseudo_division_core<true, true, true>(p, q, x, d, Q, R, &x2d);
6968         }
6969     };
6970 
manager(reslimit & lim,numeral_manager & m,monomial_manager * mm)6971     manager::manager(reslimit& lim, numeral_manager & m, monomial_manager * mm) {
6972         m_imp = alloc(imp, lim, *this, m, mm);
6973     }
6974 
manager(reslimit & lim,numeral_manager & m,small_object_allocator * a)6975     manager::manager(reslimit& lim, numeral_manager & m, small_object_allocator * a) {
6976         m_imp = alloc(imp, lim, *this, m, a);
6977     }
6978 
~manager()6979     manager::~manager() {
6980         dealloc(m_imp);
6981     }
6982 
m() const6983     numeral_manager & manager::m() const {
6984         return m_imp->m_manager.m();
6985     }
6986 
mm() const6987     monomial_manager & manager::mm() const {
6988         return m_imp->mm();
6989     }
6990 
modular() const6991     bool manager::modular() const {
6992         return m_imp->m().modular();
6993     }
6994 
p() const6995     numeral const & manager::p() const {
6996         return m_imp->m().p();
6997     }
6998 
set_z()6999     void manager::set_z() {
7000         return m_imp->m().set_z();
7001     }
7002 
set_zp(numeral const & p)7003     void manager::set_zp(numeral const & p) {
7004         return m_imp->m().set_zp(p);
7005     }
7006 
set_zp(uint64_t p)7007     void manager::set_zp(uint64_t p) {
7008         return m_imp->m().set_zp(p);
7009     }
7010 
is_var(polynomial const * p,var & v)7011     bool manager::is_var(polynomial const* p, var& v) {
7012         return p->size() == 1 && is_var(p->m(0), v) && m_imp->m().is_one(p->a(0));
7013     }
7014 
is_var(monomial const * m,var & v)7015     bool manager::is_var(monomial const* m, var& v) {
7016         return m->size() == 1 && m->degree(0) == 1 && (v = m->get_var(0), true);
7017     }
7018 
is_var_num(polynomial const * p,var & v,scoped_numeral & n)7019     bool manager::is_var_num(polynomial const* p, var& v, scoped_numeral& n) {
7020         return p->size() == 2 && m_imp->m().is_one(p->a(0)) && is_var(p->m(0), v) && is_unit(p->m(1)) && (n = p->a(1), true);
7021     }
7022 
allocator() const7023     small_object_allocator & manager::allocator() const {
7024         return m_imp->mm().allocator();
7025     }
7026 
add_del_eh(del_eh * eh)7027     void manager::add_del_eh(del_eh * eh) {
7028         m_imp->add_del_eh(eh);
7029     }
7030 
remove_del_eh(del_eh * eh)7031     void manager::remove_del_eh(del_eh * eh) {
7032         m_imp->remove_del_eh(eh);
7033     }
7034 
mk_var()7035     var manager::mk_var() {
7036         return m_imp->mk_var();
7037     }
7038 
num_vars() const7039     unsigned manager::num_vars() const {
7040         return m_imp->num_vars();
7041     }
7042 
inc_ref(monomial * m)7043     void manager::inc_ref(monomial * m) {
7044         if (m)
7045             m->inc_ref();
7046     }
7047 
dec_ref(monomial * m)7048     void manager::dec_ref(monomial * m) {
7049         if (m)
7050             m_imp->dec_ref(m);
7051     }
7052 
inc_ref(polynomial * p)7053     void manager::inc_ref(polynomial * p) {
7054         if (p)
7055             p->inc_ref();
7056     }
7057 
dec_ref(polynomial * p)7058     void manager::dec_ref(polynomial * p) {
7059         if (p)
7060             m_imp->dec_ref(p);
7061     }
7062 
lex_sort(polynomial * p)7063     void manager::lex_sort(polynomial * p) {
7064         m_imp->lex_sort(p);
7065     }
7066 
hash(monomial const * m)7067     unsigned manager::hash(monomial const * m) {
7068         return m->hash();
7069     }
7070 
hash(polynomial const * p)7071     unsigned manager::hash(polynomial const * p) {
7072         return m_imp->hash(p);
7073     }
7074 
gcd_simplify(polynomial * p)7075     void manager::gcd_simplify(polynomial * p) {
7076         m_imp->gcd_simplify(p);
7077     }
7078 
coeff(polynomial const * p,var x,unsigned k)7079     polynomial * manager::coeff(polynomial const * p, var x, unsigned k) {
7080         return m_imp->coeff(p, x, k);
7081     }
7082 
coeff(polynomial const * p,var x,unsigned k,polynomial_ref & reduct)7083     polynomial * manager::coeff(polynomial const * p, var x, unsigned k, polynomial_ref & reduct) {
7084         return m_imp->coeff(p, x, k, reduct);
7085     }
7086 
nonzero_const_coeff(polynomial const * p,var x,unsigned k)7087     bool manager::nonzero_const_coeff(polynomial const * p, var x, unsigned k) {
7088         return m_imp->nonzero_const_coeff(p, x, k);
7089     }
7090 
const_coeff(polynomial const * p,var x,unsigned k,numeral & c)7091     bool manager::const_coeff(polynomial const * p, var x, unsigned k, numeral & c) {
7092         return m_imp->const_coeff(p, x, k, c);
7093     }
7094 
mk_unit()7095     monomial * manager::mk_unit() {
7096         return m_imp->mk_unit();
7097     }
7098 
mk_monomial(var x)7099     monomial * manager::mk_monomial(var x) {
7100         return m_imp->mk_monomial(x);
7101     }
7102 
mk_monomial(var x,unsigned k)7103     monomial * manager::mk_monomial(var x, unsigned k) {
7104         return m_imp->mk_monomial(x, k);
7105     }
7106 
mk_monomial(unsigned sz,var * xs)7107     monomial * manager::mk_monomial(unsigned sz, var * xs) {
7108         return m_imp->mk_monomial(sz, xs);
7109     }
7110 
convert(monomial const * src)7111     monomial * manager::convert(monomial const * src) {
7112         return m_imp->convert(src);
7113     }
7114 
mul(monomial const * m1,monomial const * m2)7115     monomial * manager::mul(monomial const * m1, monomial const * m2) {
7116         return m_imp->mul(m1, m2);
7117     }
7118 
div(monomial const * m1,monomial const * m2)7119     bool manager::div(monomial const * m1, monomial const * m2) {
7120         return m_imp->div(m1, m2);
7121     }
7122 
div(monomial const * m1,monomial const * m2,monomial_ref & r)7123     bool manager::div(monomial const * m1, monomial const * m2, monomial_ref & r) {
7124         return m_imp->div(m1, m2, r);
7125     }
7126 
newton_interpolation(var x,unsigned d,numeral const * inputs,polynomial * const * outputs,polynomial_ref & r)7127     void manager::newton_interpolation(var x, unsigned d, numeral const * inputs, polynomial * const * outputs, polynomial_ref & r) {
7128         return m_imp->newton_interpolation(x, d, inputs, outputs, r);
7129     }
7130 
gcd(monomial const * m1,monomial const * m2,monomial * & q1,monomial * & q2)7131     monomial * manager::gcd(monomial const * m1, monomial const * m2, monomial * & q1, monomial * & q2) {
7132         return m_imp->gcd(m1, m2, q1, q2);
7133     }
7134 
unify(monomial const * m1,monomial const * m2,monomial * & q1,monomial * & q2)7135     bool manager::unify(monomial const * m1, monomial const * m2, monomial * & q1, monomial * & q2) {
7136         return m_imp->unify(m1, m2, q1, q2);
7137     }
7138 
pw(monomial const * m,unsigned k)7139     monomial * manager::pw(monomial const * m, unsigned k) {
7140         return m_imp->pw(m, k);
7141     }
7142 
mk_zero()7143     polynomial * manager::mk_zero() {
7144         return m_imp->mk_zero();
7145     }
7146 
mk_const(numeral & a)7147     polynomial * manager::mk_const(numeral & a) {
7148         return m_imp->mk_const(a);
7149     }
7150 
mk_const(rational const & a)7151     polynomial * manager::mk_const(rational const & a) {
7152         return m_imp->mk_const(a);
7153     }
7154 
mk_polynomial(var x,unsigned k)7155     polynomial * manager::mk_polynomial(var x, unsigned k) {
7156         return m_imp->mk_polynomial(x, k);
7157     }
7158 
mk_polynomial(unsigned sz,numeral * as,monomial * const * ms)7159     polynomial * manager::mk_polynomial(unsigned sz, numeral * as, monomial * const * ms) {
7160         return m_imp->mk_polynomial(sz, as, ms);
7161     }
7162 
mk_polynomial(unsigned sz,rational const * as,monomial * const * ms)7163     polynomial * manager::mk_polynomial(unsigned sz, rational const * as, monomial * const * ms) {
7164         return m_imp->mk_polynomial(sz, as, ms);
7165     }
7166 
mk_linear(unsigned sz,rational const * as,var const * xs,rational const & c)7167     polynomial * manager::mk_linear(unsigned sz, rational const * as, var const * xs, rational const & c) {
7168         return m_imp->mk_linear(sz, as, xs, c);
7169     }
7170 
mk_linear(unsigned sz,numeral * as,var const * xs,numeral & c)7171     polynomial * manager::mk_linear(unsigned sz, numeral * as, var const * xs, numeral & c) {
7172         return m_imp->mk_linear(sz, as, xs, c);
7173     }
7174 
mk_univariate(var x,unsigned n,numeral * as)7175     polynomial * manager::mk_univariate(var x, unsigned n, numeral * as) {
7176         return m_imp->mk_univariate(x, n, as);
7177     }
7178 
neg(polynomial const * p)7179     polynomial * manager::neg(polynomial const * p) {
7180         return m_imp->neg(p);
7181     }
7182 
add(polynomial const * p1,polynomial const * p2)7183     polynomial * manager::add(polynomial const * p1, polynomial const * p2) {
7184         return m_imp->add(p1, p2);
7185     }
7186 
sub(polynomial const * p1,polynomial const * p2)7187     polynomial * manager::sub(polynomial const * p1, polynomial const * p2) {
7188         return m_imp->sub(p1, p2);
7189     }
7190 
addmul(numeral const & a1,monomial const * m1,polynomial const * p1,numeral const & a2,monomial const * m2,polynomial const * p2)7191     polynomial * manager::addmul(numeral const & a1, monomial const * m1, polynomial const * p1,
7192                                  numeral const & a2, monomial const * m2, polynomial const * p2) {
7193         return m_imp->addmul(a1, m1, p1, a2, m2, p2);
7194     }
7195 
addmul(polynomial const * p1,numeral const & a2,monomial const * m2,polynomial const * p2)7196     polynomial * manager::addmul(polynomial const * p1, numeral const & a2, monomial const * m2, polynomial const * p2) {
7197         return m_imp->addmul(p1, a2, m2, p2);
7198     }
7199 
addmul(polynomial const * p1,numeral const & a2,polynomial const * p2)7200     polynomial * manager::addmul(polynomial const * p1, numeral const & a2, polynomial const * p2) {
7201         return m_imp->addmul(p1, a2, p2);
7202     }
7203 
mul(numeral const & a,polynomial const * p)7204     polynomial * manager::mul(numeral const & a, polynomial const * p) {
7205         return m_imp->mul(a, p);
7206     }
7207 
mul(rational const & a,polynomial const * p)7208     polynomial * manager::mul(rational const & a, polynomial const * p) {
7209         return m_imp->mul(a, p);
7210     }
7211 
mul(polynomial const * p1,polynomial const * p2)7212     polynomial * manager::mul(polynomial const * p1, polynomial const * p2) {
7213         return m_imp->mul(p1, p2);
7214     }
7215 
mul(numeral const & a,monomial const * m,polynomial const * p)7216     polynomial * manager::mul(numeral const & a, monomial const * m, polynomial const * p) {
7217         return m_imp->mul(a, m, p);
7218     }
7219 
mul(monomial const * m,polynomial const * p)7220     polynomial * manager::mul(monomial const * m, polynomial const * p) {
7221         return m_imp->mul(m, p);
7222     }
7223 
pw(polynomial const * p,unsigned k,polynomial_ref & r)7224     void manager::pw(polynomial const * p, unsigned k, polynomial_ref & r) {
7225         m_imp->pw(p, k, r);
7226     }
7227 
int_content(polynomial const * p,numeral & c)7228     void manager::int_content(polynomial const * p, numeral & c) {
7229         m_imp->ic(p, c);
7230     }
7231 
abs_norm(polynomial const * p,numeral & norm)7232     void manager::abs_norm(polynomial const * p, numeral & norm) {
7233         m_imp->abs_norm(p, norm);
7234     }
7235 
numeral_lc(polynomial const * p,var x)7236     polynomial::numeral const & manager::numeral_lc(polynomial const * p, var x) {
7237         return m_imp->numeral_lc(p, x);
7238     }
7239 
numeral_tc(polynomial const * p)7240     polynomial::numeral const & manager::numeral_tc(polynomial const * p) {
7241         return m_imp->numeral_tc(p);
7242     }
7243 
content(polynomial const * p,var x,numeral & i,polynomial_ref & c)7244     void manager::content(polynomial const * p, var x, numeral & i, polynomial_ref & c) {
7245         polynomial_ref pp(*this);
7246         m_imp->iccp(p, x, i, c, pp);
7247     }
7248 
content(polynomial const * p,var x,polynomial_ref & c)7249     void manager::content(polynomial const * p, var x, polynomial_ref & c) {
7250         scoped_numeral i(m_imp->m_manager.m());
7251         content(p, x, i, c);
7252         if (!m_imp->m_manager.is_one(i)) {
7253             c = mul(i, c);
7254         }
7255     }
7256 
primitive(polynomial const * p,var x,polynomial_ref & pp)7257     void manager::primitive(polynomial const * p, var x, polynomial_ref & pp) {
7258         pp = m_imp->pp(p, x);
7259     }
7260 
icpp(polynomial const * p,var x,numeral & i,polynomial_ref & c,polynomial_ref & pp)7261     void manager::icpp(polynomial const * p, var x, numeral & i, polynomial_ref & c, polynomial_ref & pp) {
7262         m_imp->iccp(p, x, i, c, pp);
7263     }
7264 
flip_sign_if_lm_neg(polynomial const * p)7265     polynomial * manager::flip_sign_if_lm_neg(polynomial const * p) {
7266         return m_imp->flip_sign_if_lm_neg_core(p);
7267     }
7268 
gcd(polynomial const * p,polynomial const * q,polynomial_ref & g)7269     void manager::gcd(polynomial const * p, polynomial const * q, polynomial_ref & g) {
7270         m_imp->gcd(p, q, g);
7271     }
7272 
derivative(polynomial const * p,var x)7273     polynomial * manager::derivative(polynomial const * p, var x) {
7274         return m_imp->derivative(p, x);
7275     }
7276 
square_free(polynomial const * p,var x,polynomial_ref & r)7277     void manager::square_free(polynomial const * p, var x, polynomial_ref & r) {
7278         m_imp->square_free(p, x, r);
7279     }
7280 
is_square_free(polynomial const * p,var x)7281     bool manager::is_square_free(polynomial const * p, var x) {
7282         return m_imp->is_square_free(p, x);
7283     }
7284 
square_free(polynomial const * p,polynomial_ref & r)7285     void manager::square_free(polynomial const * p, polynomial_ref & r) {
7286         m_imp->square_free(p, r);
7287     }
7288 
is_square_free(polynomial const * p)7289     bool manager::is_square_free(polynomial const * p) {
7290         return m_imp->is_square_free(p);
7291     }
7292 
eq(polynomial const * p1,polynomial const * p2)7293     bool manager::eq(polynomial const * p1, polynomial const * p2) {
7294         return m_imp->eq(p1, p2);
7295     }
7296 
compose_y(polynomial const * p,var y)7297     polynomial * manager::compose_y(polynomial const * p, var y) {
7298         return m_imp->compose_y(p, y);
7299     }
7300 
compose_minus_x(polynomial const * p)7301     polynomial * manager::compose_minus_x(polynomial const * p) {
7302         return m_imp->compose_minus_x(p);
7303     }
7304 
compose_1_div_x(polynomial const * p)7305     polynomial * manager::compose_1_div_x(polynomial const * p) {
7306         return m_imp->compose_1_div_x(p);
7307     }
7308 
compose_x_div_y(polynomial const * p,var y)7309     polynomial * manager::compose_x_div_y(polynomial const * p, var y) {
7310         return m_imp->compose_x_div_y(p, y);
7311     }
7312 
compose(polynomial const * p,polynomial const * q,polynomial_ref & r)7313     void manager::compose(polynomial const * p, polynomial const * q, polynomial_ref & r) {
7314         m_imp->compose(p, q, r);
7315     }
7316 
compose_x_minus_y(polynomial const * p,var y,polynomial_ref & r)7317     void manager::compose_x_minus_y(polynomial const * p, var y, polynomial_ref & r) {
7318         m_imp->compose_x_minus_y(p, y, r);
7319     }
7320 
compose_x_plus_y(polynomial const * p,var y,polynomial_ref & r)7321     void manager::compose_x_plus_y(polynomial const * p, var y, polynomial_ref & r) {
7322         m_imp->compose_x_plus_y(p, y, r);
7323     }
7324 
compose_x_minus_c(polynomial const * p,numeral const & c,polynomial_ref & r)7325     void manager::compose_x_minus_c(polynomial const * p, numeral const & c, polynomial_ref & r) {
7326         m_imp->compose_x_minus_c(p, c, r);
7327     }
7328 
sqrt(polynomial const * p,polynomial_ref & r)7329     bool manager::sqrt(polynomial const * p, polynomial_ref & r) {
7330         return m_imp->sqrt(p, r);
7331     }
7332 
normalize(polynomial const * p)7333     polynomial * manager::normalize(polynomial const * p) {
7334         return m_imp->normalize(p);
7335     }
7336 
exact_pseudo_remainder(polynomial const * p,polynomial const * q,var x,polynomial_ref & R)7337     void manager::exact_pseudo_remainder(polynomial const * p, polynomial const * q, var x, polynomial_ref & R) {
7338         m_imp->exact_pseudo_remainder(p, q, x, R);
7339     }
7340 
pseudo_remainder(polynomial const * p,polynomial const * q,var x,unsigned & d,polynomial_ref & R)7341     void manager::pseudo_remainder(polynomial const * p, polynomial const * q, var x, unsigned & d, polynomial_ref & R) {
7342         m_imp->pseudo_remainder(p, q, x, d, R);
7343     }
7344 
exact_pseudo_division(polynomial const * p,polynomial const * q,var x,polynomial_ref & Q,polynomial_ref & R)7345     void manager::exact_pseudo_division(polynomial const * p, polynomial const * q, var x, polynomial_ref & Q, polynomial_ref & R) {
7346         m_imp->exact_pseudo_division(p, q, x, Q, R);
7347     }
7348 
pseudo_division(polynomial const * p,polynomial const * q,var x,unsigned & d,polynomial_ref & Q,polynomial_ref & R)7349     void manager::pseudo_division(polynomial const * p, polynomial const * q, var x, unsigned & d, polynomial_ref & Q, polynomial_ref & R) {
7350         m_imp->pseudo_division(p, q, x, d, Q, R);
7351     }
7352 
exact_div(polynomial const * p,polynomial const * q)7353     polynomial * manager::exact_div(polynomial const * p, polynomial const * q) {
7354         return m_imp->exact_div(p, q);
7355     }
7356 
exact_div(polynomial const * p,numeral const & c)7357     polynomial * manager::exact_div(polynomial const * p, numeral const & c) {
7358         return m_imp->exact_div(p, c);
7359     }
7360 
divides(polynomial const * q,polynomial const * p)7361     bool manager::divides(polynomial const * q, polynomial const * p) {
7362         return m_imp->divides(q, p);
7363     }
7364 
quasi_resultant(polynomial const * p,polynomial const * q,var x,polynomial_ref & r)7365     void manager::quasi_resultant(polynomial const * p, polynomial const * q, var x, polynomial_ref & r) {
7366         m_imp->quasi_resultant(p, q, x, r);
7367     }
7368 
resultant(polynomial const * p,polynomial const * q,var x,polynomial_ref & r)7369     void manager::resultant(polynomial const * p, polynomial const * q, var x, polynomial_ref & r) {
7370         m_imp->resultant(p, q, x, r);
7371     }
7372 
discriminant(polynomial const * p,var x,polynomial_ref & r)7373     void manager::discriminant(polynomial const * p, var x, polynomial_ref & r) {
7374         m_imp->discriminant(p, x, r);
7375     }
7376 
psc_chain(polynomial const * p,polynomial const * q,var x,polynomial_ref_vector & S)7377     void manager::psc_chain(polynomial const * p, polynomial const * q, var x, polynomial_ref_vector & S) {
7378         m_imp->psc_chain(p, q, x, S);
7379     }
7380 
sign(polynomial const * p,svector<lbool> const & sign_of_vars)7381     lbool manager::sign(polynomial const * p, svector<lbool> const& sign_of_vars) {
7382         return m_imp->sign(p, sign_of_vars);
7383     }
7384 
is_pos(polynomial const * p)7385     bool manager::is_pos(polynomial const * p) {
7386         return m_imp->is_pos(p);
7387     }
7388 
is_neg(polynomial const * p)7389     bool manager::is_neg(polynomial const * p) {
7390         return m_imp->is_neg(p);
7391     }
7392 
is_nonpos(polynomial const * p)7393     bool manager::is_nonpos(polynomial const * p) {
7394         return m_imp->is_nonpos(p);
7395     }
7396 
is_nonneg(polynomial const * p)7397     bool manager::is_nonneg(polynomial const * p) {
7398         return m_imp->is_nonneg(p);
7399     }
7400 
rename(unsigned sz,var const * xs)7401     void manager::rename(unsigned sz, var const * xs) {
7402         return m_imp->rename(sz, xs);
7403     }
7404 
vars(polynomial const * p,var_vector & xs)7405     void manager::vars(polynomial const * p, var_vector & xs) {
7406         m_imp->vars(p, xs);
7407     }
7408 
substitute(polynomial const * p,var2mpq const & x2v)7409     polynomial * manager::substitute(polynomial const * p, var2mpq const & x2v) {
7410         return m_imp->substitute(p, x2v);
7411     }
7412 
substitute(polynomial const * p,unsigned xs_sz,var const * xs,mpq const * vs)7413     polynomial * manager::substitute(polynomial const * p, unsigned xs_sz, var const * xs, mpq const * vs) {
7414         return m_imp->substitute(p, xs_sz, xs, vs);
7415     }
7416 
substitute(polynomial const * p,unsigned xs_sz,var const * xs,numeral const * vs)7417     polynomial * manager::substitute(polynomial const * p, unsigned xs_sz, var const * xs, numeral const * vs) {
7418         return m_imp->substitute(p, xs_sz, xs, vs);
7419     }
7420 
substitute(polynomial const * r,var x,polynomial const * p,polynomial const * q,polynomial_ref & result)7421     void manager::substitute(polynomial const* r, var x, polynomial const* p, polynomial const* q, polynomial_ref& result) {
7422         m_imp->substitute(r, x, p, q, result);
7423     }
7424 
factor(polynomial const * p,factors & r,factor_params const & params)7425     void manager::factor(polynomial const * p, factors & r, factor_params const & params) {
7426         m_imp->factor(p, r, params);
7427     }
7428 
to_polynomial(unsigned sz,numeral const * p,var x)7429     polynomial * manager::to_polynomial(unsigned sz, numeral const * p, var x) {
7430         return m_imp->to_polynomial(sz, p, x);
7431     }
7432 
mk_glex_monic(polynomial const * p)7433     polynomial * manager::mk_glex_monic(polynomial const * p) {
7434         return m_imp->mk_glex_monic(p);
7435     }
7436 
translate(polynomial const * p,var x,numeral const & v)7437     polynomial * manager::translate(polynomial const * p, var x, numeral const & v) {
7438         return m_imp->translate(p, x, v);
7439     }
7440 
translate(polynomial const * p,unsigned xs_sz,var const * xs,numeral const * vs,polynomial_ref & r)7441     void manager::translate(polynomial const * p, unsigned xs_sz, var const * xs, numeral const * vs, polynomial_ref & r) {
7442         return m_imp->translate(p, xs_sz, xs, vs, r);
7443     }
7444 
mod_d(polynomial const * p,var2degree const & x2d)7445     polynomial * manager::mod_d(polynomial const * p, var2degree const & x2d) {
7446         return m_imp->mod_d(p, x2d);
7447     }
7448 
exact_pseudo_division_mod_d(polynomial const * p,polynomial const * q,var x,var2degree const & x2d,polynomial_ref & Q,polynomial_ref & R)7449     void manager::exact_pseudo_division_mod_d(polynomial const * p, polynomial const * q, var x, var2degree const & x2d,
7450                                                                     polynomial_ref & Q, polynomial_ref & R) {
7451         m_imp->exact_pseudo_division_mod_d(p, q, x, x2d, Q, R);
7452     }
7453 
eval(polynomial const * p,var2mpbqi const & x2v,mpbqi & r)7454     void manager::eval(polynomial const * p, var2mpbqi const & x2v, mpbqi & r) {
7455         return m_imp->eval(p, x2v, r);
7456     }
7457 
eval(polynomial const * p,var2mpq const & x2v,mpq & r)7458     void manager::eval(polynomial const * p, var2mpq const & x2v, mpq & r) {
7459         return m_imp->eval(p, x2v, r);
7460     }
7461 
eval(polynomial const * p,var2anum const & x2v,algebraic_numbers::anum & r)7462     void manager::eval(polynomial const * p, var2anum const & x2v, algebraic_numbers::anum & r) {
7463         return m_imp->eval(p, x2v, r);
7464     }
7465 
display(std::ostream & out,monomial const * m,display_var_proc const & proc,bool user_star) const7466     void manager::display(std::ostream & out, monomial const * m, display_var_proc const & proc, bool user_star) const {
7467         m->display(out, proc, user_star);
7468     }
7469 
display(std::ostream & out,polynomial const * p,display_var_proc const & proc,bool use_star) const7470     void manager::display(std::ostream & out, polynomial const * p, display_var_proc const & proc, bool use_star) const {
7471         SASSERT(m_imp->consistent_coeffs(p));
7472         p->display(out, m_imp->m_manager, proc, use_star);
7473     }
7474 
display_smt2(std::ostream & out,polynomial const * p,display_var_proc const & proc) const7475     void manager::display_smt2(std::ostream & out, polynomial const * p, display_var_proc const & proc) const {
7476         p->display_smt2(out, m_imp->m_manager, proc);
7477     }
7478 };
7479 
convert(polynomial::manager & sm,polynomial::polynomial * p,polynomial::manager & tm,polynomial::var x,unsigned max_d)7480 polynomial::polynomial * convert(polynomial::manager & sm, polynomial::polynomial * p, polynomial::manager & tm,
7481                                  polynomial::var x, unsigned max_d) {
7482     ptr_buffer<polynomial::monomial, 128> ms;
7483     polynomial::numeral_manager & nm = tm.m();
7484     _scoped_numeral_buffer<polynomial::numeral_manager, 128> as(nm);
7485     unsigned sz = sm.size(p);
7486     if (&sm == &tm) {
7487         // same source and target manager.
7488         // So, we just return p
7489         return p;
7490     }
7491     else if (&(sm.mm()) == &(tm.mm())) {
7492         // polynomial managers share the same monomial manager.
7493         // So, we don't need to convert monomials.
7494         for (unsigned i = 0; i < sz; i++) {
7495             polynomial::monomial * m = sm.get_monomial(p, i);
7496             if (x == polynomial::null_var || sm.degree_of(m, x) <= max_d) {
7497                 ms.push_back(m);
7498                 as.push_back(polynomial::numeral());
7499                 nm.set(as.back(), sm.coeff(p, i));
7500             }
7501         }
7502     }
7503     else {
7504         for (unsigned i = 0; i < sz; i++) {
7505             polynomial::monomial * m = sm.get_monomial(p, i);
7506             if (x == polynomial::null_var || sm.degree_of(m, x) <= max_d) {
7507                 ms.push_back(tm.convert(m));
7508                 as.push_back(polynomial::numeral());
7509                 nm.set(as.back(), sm.coeff(p, i));
7510             }
7511         }
7512     }
7513     return tm.mk_polynomial(as.size(), as.c_ptr(), ms.c_ptr());
7514 }
7515 
operator <<(std::ostream & out,polynomial_ref_vector const & seq)7516 std::ostream & operator<<(std::ostream & out, polynomial_ref_vector const & seq) {
7517     unsigned sz = seq.size();
7518     for (unsigned i = 0; i < sz; i++) {
7519         seq.m().display(out, seq.get(i));
7520         out << "\n";
7521     }
7522     return out;
7523 }
7524