1 /* -*- mode:C++ ; compile-command: "g++ -I.. -I../include -I.. -g -c -fno-strict-aliasing -DGIAC_GENERIC_CONSTANTS -DHAVE_CONFIG_H -DIN_GIAC -Wall cocoa.cc" -*- */
2 // Thanks to Zoltan Kovacs for motivating this work, in order to improve geogebra theorem proving
3 // Special thanks to Anna M. Bigatti from CoCoA team for insightfull discussions on how to choose an order for elimination
4 #include "giacPCH.h"
5 
6 #ifndef WIN32
7 #define COCOA9950
8 #endif
9 
10 #ifdef HAVE_LIBPTHREAD
11 #endif
12 
13 #if defined(USE_GMP_REPLACEMENTS) || defined(GIAC_VECTOR)
14 #undef HAVE_LIBCOCOA
15 #endif
16 #ifdef HAVE_LIBCOCOA
17 #ifdef COCOA9950
18 #include <CoCoA/RingZZ.H>
19 #include <CoCoA/RingQQ.H>
20 #else
21 #include <CoCoA/ZZ.H>
22 #include <CoCoA/RingQ.H>
23 #endif
24 #include <CoCoA/FractionField.H>
25 #include <CoCoA/GlobalManager.H>
26 #include <CoCoA/SparsePolyRing.H>
27 #include <CoCoA/TmpF5.H>
28 //#include <CoCoA/io.H>
29 #include <CoCoA/VectorOps.H>
30 #include <CoCoA/obsolescent.H>
31 #include <CoCoA/SparsePolyOps-RingElem.H>
32 #include <CoCoA/SparsePolyIter.H>
33 #include <CoCoA/BigInt.H>
34 //
35 #include <CoCoA/symbol.H>
36 #include "TmpFGLM.H"
37 #endif
38 /*
39  *  Copyright (C) 2007,2014 B. Parisse, Institut Fourier, 38402 St Martin d'Heres
40  *
41  *  This program is free software; you can redistribute it and/or modify
42  *  it under the terms of the GNU General Public License as published by
43  *  the Free Software Foundation; either version 3 of the License, or
44  *  (at your option) any later version.
45  *
46  *  This program is distributed in the hope that it will be useful,
47  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
48  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
49  *  GNU General Public License for more details.
50  *
51  *  You should have received a copy of the GNU General Public License
52  *  along with this program. If not, see <http://www.gnu.org/licenses/>.
53  */
54 using namespace std;
55 
56 #include <iostream>
57 #if !defined FXCG && !defined KHICAS
58 #include <iomanip>
59 #endif
60 #include "cocoa.h"
61 #include "gausspol.h"
62 #include "identificateur.h"
63 #include "giacintl.h"
64 #include "index.h"
65 #include "modpoly.h"
66 #ifdef HAVE_SYS_RESOURCE_H
67 #include <sys/resource.h>
68 #endif
69 
70 #if defined(USE_GMP_REPLACEMENTS) || defined(GIAC_VECTOR)
71 #undef HAVE_LIBCOCOA
72 #endif
73 
74 #if defined VISUALC && defined x86_64
75 #undef x86_64
76 #endif
77 
78 #ifndef NO_NAMESPACE_GIAC
79 namespace giac {
80 #endif // ndef NO_NAMESPACE_GIAC
81 
82   //  vecteur trim(const vecteur & p,environment * env);
83 
84 #ifdef HAVE_LIBCOCOA
85   struct order_vectpoly {
86     int order;
87     vectpoly v;
88   };
89 
90   struct Qx_I {
91     CoCoA::SparsePolyRing * Qxptr;
92     CoCoA::ideal * idealptr;
93     CoCoA::PPOrdering * cocoa_order;
Qx_Igiac::Qx_I94     Qx_I(): Qxptr(0), idealptr(0),cocoa_order(0){}
95   };
96 
operator <(const order_vectpoly & ov1,const order_vectpoly & ov2)97   static bool operator < (const order_vectpoly & ov1,const order_vectpoly & ov2){
98     if (ov1.order!=ov2.order)
99       return ov1.order<ov2.order;
100     unsigned ov1s=ov1.v.size(),ov2s=ov2.v.size();
101     if (ov1s!=ov2s)
102       return ov1s<ov2s;
103     for (unsigned i=0;i<ov1s;++i){
104       if (ov1.v[i].dim!=ov2.v[i].dim)
105 	return ov1.v[i].dim<ov2.v[i].dim;
106       polynome p = ov1.v[i]-ov2.v[i];
107       if (p.coord.empty())
108 	continue;
109       return p.coord.front().value.islesscomplexthan(0);
110     }
111     return false;
112   }
113 
114   static CoCoA::GlobalManager CoCoAFoundations;
115 
116   // cache here a list of already known ideals
117   static std::map<order_vectpoly,Qx_I> cocoa_idealptr_map;
118 
119 #ifdef COCOA9950
gen2ZZ(const gen & g)120   static CoCoA::BigInt gen2ZZ(const gen & g){
121     switch (g.type){
122     case _INT_:
123       return CoCoA::BigInt(g.val);
124     case _ZINT:
125 #ifdef COCOA9950
126       return CoCoA::BigIntFromMPZ(*g._ZINTptr);
127       //return CoCoA::BigInt(*g._ZINTptr);
128 #else
129       return CoCoA::BigInt(CoCoA::CopyFromMPZ,*g._ZINTptr);
130 #endif
131     default:
132       setsizeerr(gettext("Invalid giac gen -> CoCoA ZZ conversion")+g.print());
133       return CoCoA::BigInt(0);
134     }
135   }
136 
ZZ2gen(const CoCoA::RingElem & z)137   static gen ZZ2gen(const CoCoA::RingElem & z){
138     CoCoA::BigInt n,d;
139     if (CoCoA::IsInteger(n, z))
140       return gen(CoCoA::mpzref(n));
141     CoCoA::RingElem znum=CoCoA::num(z),zden=CoCoA::den(z);
142     if (CoCoA::IsInteger(n, znum) && CoCoA::IsInteger(d, zden))
143       return gen(CoCoA::mpzref(n))/gen(CoCoA::mpzref(d));
144     setsizeerr(gettext("Unable to convert CoCoA data"));
145     return undef;
146   }
147 #else
gen2ZZ(const gen & g)148   static CoCoA::ZZ gen2ZZ(const gen & g){
149     switch (g.type){
150     case _INT_:
151       return CoCoA::ZZ(g.val);
152     case _ZINT:
153       return CoCoA::ZZ(CoCoA::CopyFromMPZ,*g._ZINTptr);
154     default:
155       setsizeerr(gettext("Invalid giac gen -> CoCoA ZZ conversion")+g.print());
156       return CoCoA::ZZ(0);
157     }
158   }
159 
ZZ2gen(const CoCoA::RingElem & z)160   static gen ZZ2gen(const CoCoA::RingElem & z){
161     CoCoA::ZZ n,d;
162     if (CoCoA::IsInteger(n, z))
163       return gen(CoCoA::mpzref(n));
164     CoCoA::RingElem znum=CoCoA::num(z),zden=CoCoA::den(z);
165     if (CoCoA::IsInteger(n, znum) && CoCoA::IsInteger(d, zden))
166       return gen(CoCoA::mpzref(n))/gen(CoCoA::mpzref(d));
167     setsizeerr(gettext("Unable to convert CoCoA data"));
168     return undef;
169   }
170 #endif
171 
polynome2ringelem(const polynome & p,const std::vector<CoCoA::RingElem> & x)172   static CoCoA::RingElem polynome2ringelem(const polynome & p,const std::vector<CoCoA::RingElem> & x){
173     if (unsigned(p.dim)>x.size())
174       setdimerr();
175     CoCoA::RingElem res(x[0]-x[0]); // how do you construct 0 in CoCoA?
176     vector<monomial<gen> >::const_iterator it=p.coord.begin(),itend=p.coord.end();
177     for (;it!=itend;++it){
178       CoCoA::RingElem tmp(gen2ZZ(it->value)*power(x[0],0));
179       index_t::const_iterator jt=it->index.begin(),jtend=it->index.end();
180       for (int i=0;jt!=jtend;++jt,++i)
181 	tmp *= power(x[i],*jt);
182       res += tmp;
183     }
184     return res;
185   }
186 
ringelem2polynome(const CoCoA::RingElem & f,const gen & order)187   static polynome ringelem2polynome(const CoCoA::RingElem & f,const gen & order){
188     CoCoA::SparsePolyIter it=CoCoA::BeginIter(f);
189     unsigned dim=CoCoA::IsEnded(it)?0:CoCoA::NumIndets(CoCoA::owner(CoCoA::PP(it)));
190     polynome res(dim);
191     vector<long> expv;
192     index_t index(dim);
193     for (;!CoCoA::IsEnded(it);++it){
194       const CoCoA::RingElem & z=CoCoA::coeff(it);
195       gen coeff=ZZ2gen(z);
196       const CoCoA::PPMonoidElem & pp=CoCoA::PP(it);
197       CoCoA::exponents(expv,pp);
198       for (unsigned i=0;i<dim;++i)
199 	index[i]=expv[i];
200       res.coord.push_back(monomial<gen>(coeff,index));
201     }
202     change_monomial_order(res,order); // res.tsort();
203     return res;
204   }
205 
vector_polynome2vector_ringelem(const vectpoly & v,const CoCoA::SparsePolyRing & Qx,vector<CoCoA::RingElem> & g)206   static void vector_polynome2vector_ringelem(const vectpoly & v,const CoCoA::SparsePolyRing & Qx,vector<CoCoA::RingElem> & g){
207     const vector<CoCoA::RingElem> & x = CoCoA::indets(Qx);
208     g.reserve(v.size());
209     vectpoly::const_iterator it=v.begin(),itend=v.end();
210     for (;it!=itend;++it){
211       g.push_back(polynome2ringelem(*it,x));
212     }
213   }
214 #if 0
215   static vector<CoCoA::RingElem> vector_polynome2vector_ringelem(const vectpoly & v,const CoCoA::SparsePolyRing & Qx){
216     vector<CoCoA::RingElem> g;
217     vector_polynome2vector_ringelem(v,Qx,g);
218     return g;
219   }
220   static vectpoly vector_ringelem2vector_polynome(const vector<CoCoA::RingElem> & g,const gen & order){
221     vectpoly res;
222     vector_ringelem2vector_polynome(g,res,order);
223     return res;
224   }
225 #endif
vector_ringelem2vector_polynome(const vector<CoCoA::RingElem> & g,vectpoly & res,const gen & order)226   static void vector_ringelem2vector_polynome(const vector<CoCoA::RingElem> & g, vectpoly & res,const gen & order){
227     vector<CoCoA::RingElem>::const_iterator it=g.begin(),itend=g.end();
228     res.reserve(itend-it);
229     for (;it!=itend;++it)
230       res.push_back(ringelem2polynome(*it,order));
231     sort(res.begin(),res.end(),tensor_is_strictly_greater<gen>);
232     reverse(res.begin(),res.end());
233   }
234 
get_or_make_idealptr(const vectpoly & v,const gen & order)235   static Qx_I get_or_make_idealptr(const vectpoly & v,const gen & order){
236     if (order.type!=_INT_ || v.empty())
237       settypeerr();
238     order_vectpoly ov;
239     ov.v=v;
240     ov.order=order.val;
241     std::map<order_vectpoly,Qx_I>::const_iterator it=cocoa_idealptr_map.find(ov),itend=cocoa_idealptr_map.end();
242     if (it!=itend)
243       return it->second;
244     int d=v[0].dim;
245     Qx_I qx_i;
246     if (order.type==_INT_ && order.val!=0){
247       switch (order.val){
248       case _PLEX_ORDER:
249 	qx_i.cocoa_order = new CoCoA::PPOrdering(CoCoA::NewLexOrdering(d));
250 	break;
251       case _TDEG_ORDER:
252 	qx_i.cocoa_order = new CoCoA::PPOrdering(CoCoA::NewStdDegLexOrdering(d));
253 	break;
254       default:
255 	qx_i.cocoa_order = new CoCoA::PPOrdering(CoCoA::NewStdDegRevLexOrdering(d));
256       }
257       qx_i.Qxptr = new CoCoA::SparsePolyRing(CoCoA::NewPolyRing(
258 #ifdef COCOA9950
259 								CoCoA::RingQQ(),
260 #else
261 								CoCoA::RingQ(),
262 #endif
263 								CoCoA::SymbolRange("x",0,d-1),*qx_i.cocoa_order));
264     }
265     else
266       qx_i.Qxptr = new CoCoA::SparsePolyRing(CoCoA::NewPolyRing(
267 #ifdef COCOA9950
268 								CoCoA::RingQQ(),
269 #else
270 								CoCoA::RingQ(),
271 #endif
272 								CoCoA::SymbolRange("x",0,d-1)));
273     vector<CoCoA::RingElem> g;
274     vector_polynome2vector_ringelem(v,*qx_i.Qxptr,g);
275     qx_i.idealptr=new CoCoA::ideal(*qx_i.Qxptr,g);
276     cocoa_idealptr_map[ov]=qx_i;
277     // if (cocoa_order)
278     //  delete cocoa_order;
279     return qx_i;
280   }
281 
282   // add a dimension so that p is homogeneous of degree d
homogeneize(polynome & p,int deg)283   static void homogeneize(polynome & p,int deg){
284     vector<monomial<gen> >::iterator it=p.coord.begin(),itend=p.coord.end();
285     int n;
286     for (;it!=itend;++it){
287       index_t i=it->index.iref();
288       n=total_degree(i);
289       i.push_back(deg-n);
290       it->index=i;
291     }
292     ++p.dim;
293   }
294 
homogeneize(vectpoly & v)295   static void homogeneize(vectpoly & v){
296     vectpoly::iterator it=v.begin(),itend=v.end();
297     int d=0;
298     for (;it!=itend;++it){
299       d=giacmax(d,total_degree(*it));
300     }
301     for (it=v.begin();it!=itend;++it){
302       homogeneize(*it,d);
303     }
304   }
305 
unhomogeneize(polynome & p)306   static void unhomogeneize(polynome & p){
307     vector<monomial<gen> >::iterator it=p.coord.begin(),itend=p.coord.end();
308     for (;it!=itend;++it){
309       index_t i=it->index.iref();
310       i.pop_back();
311       it->index=i;
312     }
313     --p.dim;
314   }
315 
unhomogeneize(vectpoly & v)316   static void unhomogeneize(vectpoly & v){
317     vectpoly::iterator it=v.begin(),itend=v.end();
318     for (;it!=itend;++it){
319       unhomogeneize(*it);
320     }
321   }
322 
f5(vectpoly & v,const gen & order)323   bool f5(vectpoly & v,const gen & order){
324     homogeneize(v);
325     CoCoA::SparsePolyRing Qx = CoCoA::NewPolyRing(
326 #ifdef COCOA9950
327 								CoCoA::RingQQ(),
328 #else
329 								CoCoA::RingQ(),
330 #endif
331 						  CoCoA::SymbolRange("x",0,v[0].dim-1));
332     vector<CoCoA::RingElem> g;
333     vector_polynome2vector_ringelem(v,Qx,g);
334     CoCoA::ideal I(Qx,g);
335     vector<CoCoA::RingElem> gb;
336     CoCoA::F5(gb,I);
337     CoCoA::operator<<(cout,gb);
338     cout << '\n';
339     v.clear();
340     vector_ringelem2vector_polynome(gb,v,order);
341     unhomogeneize(v);
342     return true;
343   }
344 
345   // order may be 0 (use cocoa default and convert to lex for 0-dim ideals)
346   // or _PLEX_ORDER (lexicographic) or _TDEG_ORDER (total degree)
347   // or _REVLEX_ORDER (total degree then reverse of lexicographic)
cocoa_gbasis(vectpoly & v,const gen & order)348   bool cocoa_gbasis(vectpoly & v,const gen & order){
349     Qx_I qx_i = get_or_make_idealptr(v,order);
350     int d=v[0].dim;
351     vector<CoCoA::RingElem> gb=TidyGens(*qx_i.idealptr);
352     // CoCoA::operator<<(cout,gb);
353     // cout << '\n';
354     // 0-dim ideals convert to lexicographic order using CoCoA FGLM routine
355     // otherwise leaves revlex order
356     vector<CoCoA::RingElem> NewGBasis;
357     if (order.type==_INT_ && order.val!=0)
358       NewGBasis=gb;
359     else {
360       CoCoA::PPOrdering NewOrdering = CoCoA::NewLexOrdering(d);
361       try {
362 	CoCoADortmund::FGLMBasisConversion(NewGBasis, gb, NewOrdering);
363       } catch (...){
364 	v.clear();
365 	vector_ringelem2vector_polynome(gb,v,order);
366 	return false;
367       }
368       // CoCoA::operator<<(cout,NewGBasis);
369       // cout << '\n';
370     }
371     v.clear();
372     vector_ringelem2vector_polynome(NewGBasis,v,order);
373     // reverse(v.begin(),v.end());
374     // unhomogeneize(v);
375     return true;
376   }
377 
cocoa_in_ideal(const vectpoly & r,const vectpoly & v,const gen & order)378   vecteur cocoa_in_ideal(const vectpoly & r,const vectpoly & v,const gen & order){
379     Qx_I qx_i = get_or_make_idealptr(v,order);
380     vector<CoCoA::RingElem> cocoa_r;
381     vector_polynome2vector_ringelem(r,*qx_i.Qxptr,cocoa_r);
382     int s=cocoa_r.size();
383     gen tmp(-1);
384     tmp.subtype=_INT_BOOLEAN;
385     vecteur res(s,tmp);
386     for (int i=0;i<s;++i)
387       res[i].val=CoCoA::IsElem(cocoa_r[i],*qx_i.idealptr);
388     return res;
389   }
390 
cocoa_greduce(const vectpoly & r,const vectpoly & v,const gen & order,vectpoly & res)391   bool cocoa_greduce(const vectpoly & r,const vectpoly & v,const gen & order,vectpoly & res){
392     Qx_I qx_i = get_or_make_idealptr(v,order);
393     vector<CoCoA::RingElem> cocoa_r;
394     vector_polynome2vector_ringelem(r,*qx_i.Qxptr,cocoa_r);
395     int s=cocoa_r.size();
396     polynome tmp;
397     for (int i=0;i<s;++i){
398       CoCoA::RingElem tmpc=CoCoA::NF(cocoa_r[i],*qx_i.idealptr);
399       tmp=ringelem2polynome(tmpc,order);
400       res.push_back(tmp);
401     }
402     return true;
403   }
404 
405 #else // HAVE_LIBCOCOA
406 
407   bool f5(vectpoly & v,const gen & ordre){
408     return false;
409   }
410 
411   bool cocoa_gbasis(vectpoly & v,const gen & ordre){
412     return false;
413   }
414 
415   vecteur cocoa_in_ideal(const vectpoly & r,const vectpoly & v,const gen & ordre){
416     return vecteur(r.size(),-1);
417   }
418 
419   bool cocoa_greduce(const vectpoly & r,const vectpoly & v,const gen & order,vectpoly & res){
420     return false;
421   }
422 
423 #endif  // HAVE_LIBCOCOA
424 
425   struct paire {
426     unsigned first;
427     unsigned second;
428     bool live; // set to false to defer the pair for reduction at end
pairegiac::paire429     paire(unsigned f,unsigned s):first(f),second(s),live(true){}
pairegiac::paire430     paire(const paire & p):first(p.first),second(p.second),live(p.live) {}
pairegiac::paire431     paire():first(-1),second(-1) {}
432   };
433 
operator <<(ostream & os,const paire & p)434   ostream & operator << (ostream & os,const paire & p){
435     return os << "<" << p.first << "," << p.second << ">";
436   }
437 
operator ==(const paire & a,const paire & b)438   inline bool operator == (const paire & a,const paire &b){
439     return a.first==b.first && a.second==b.second;
440   }
441 
442 #ifdef WORDS_BIGENDIAN // autoconf macro defines this (thanks to Julien Puydt for pointing this and checking for s390x architecture)
443 #define BIGENDIAN
444 #endif
445 
446 #if !defined CAS38_DISABLED && !defined FXCG
447   //#define GBASIS_SELECT_TOTAL_DEGREE
448 #if GROEBNER_VARS!=15 && !defined BIGENDIAN // double revlex ordering is not compatible with indices swapping
449 #define GBASIS_SWAP
450 #endif
451   // minimal numbers of pair to reduce simultaneously with f4buchberger
452 #ifdef __APPLE__
453   #define GBASISF4_BUCHBERGER 0 // temp. disabled on mac
454 #else
455   #define GBASISF4_BUCHBERGER 4
456 #endif
457 
458 #define GBASIS_POSTF4BUCHBERGER 0 // 0 means final simplification at the end, 1 at each loop
459 
460   // #define GIAC_GBASIS_REDUCTOR_MAXSIZE 10 // max size for keeping a reductor even if it should be removed from gbasis
461 
462   // if GIAC_SHORTSHIFTTYPE is defined, sparse matrix is using shift index
463   // coded on 2 bytes -> FIXME segfault for cyclic9
464 
465 #define GIAC_SHORTSHIFTTYPE 16
466   //#define GIAC_GBASIS_DELAYPAIRS
467 
swap_indices(short * tab)468   void swap_indices(short * tab){
469     swap(tab[1],tab[3]);
470     swap(tab[4],tab[7]);
471     swap(tab[5],tab[6]);
472     swap(tab[8],tab[11]);
473     swap(tab[9],tab[10]);
474 #if GROEBNER_VARS>11
475     swap(tab[12],tab[15]);
476     swap(tab[13],tab[14]);
477 #endif
478   }
479 
480   template<class T>
swap_indices14(T * tab)481   void swap_indices14(T * tab){
482     swap(tab[2],tab[7]);
483     swap(tab[3],tab[6]);
484     swap(tab[4],tab[5]);
485     swap(tab[8],tab[15]);
486     swap(tab[9],tab[14]);
487     swap(tab[10],tab[13]);
488     swap(tab[11],tab[12]);
489   }
490 
swap_indices11(short * tab)491   void swap_indices11(short * tab){
492     swap(tab[1],tab[3]);
493     swap(tab[4],tab[7]);
494     swap(tab[5],tab[6]);
495     swap(tab[8],tab[11]);
496     swap(tab[9],tab[10]);
497   }
498 
swap_indices15_revlex(short * tab)499   void swap_indices15_revlex(short * tab){
500     swap(tab[1],tab[3]);
501     swap(tab[4],tab[7]);
502     swap(tab[5],tab[6]);
503     swap(tab[8],tab[11]);
504     swap(tab[9],tab[10]);
505     swap(tab[12],tab[15]);
506     swap(tab[13],tab[14]);
507   }
508 
swap_indices15_3(short * tab)509   void swap_indices15_3(short * tab){
510     swap(tab[1],tab[3]);
511     swap(tab[5],tab[7]);
512     swap(tab[8],tab[11]);
513     swap(tab[9],tab[10]);
514     swap(tab[12],tab[15]);
515     swap(tab[13],tab[14]);
516   }
517 
swap_indices15_7(short * tab)518   void swap_indices15_7(short * tab){
519     swap(tab[1],tab[3]);
520     swap(tab[4],tab[7]);
521     swap(tab[5],tab[6]);
522     swap(tab[9],tab[11]);
523     swap(tab[12],tab[15]);
524     swap(tab[13],tab[14]);
525   }
526 
swap_indices15_11(short * tab)527   void swap_indices15_11(short * tab){
528     swap(tab[1],tab[3]);
529     swap(tab[4],tab[7]);
530     swap(tab[5],tab[6]);
531     swap(tab[8],tab[11]);
532     swap(tab[9],tab[10]);
533     swap(tab[13],tab[15]);
534   }
535 
swap_indices15(short * tab,int o)536   void swap_indices15(short * tab,int o){
537     if (o==_REVLEX_ORDER){
538       swap_indices15_revlex(tab);
539       return;
540     }
541     if (o==_3VAR_ORDER){
542       swap_indices15_3(tab);
543       return;
544     }
545     if (o==_7VAR_ORDER){
546       swap_indices15_7(tab);
547       return;
548     }
549     if (o==_11VAR_ORDER){
550       swap_indices15_11(tab);
551       return;
552     }
553   }
554 
555   // #define GIAC_CHARDEGTYPE should be in solve.h
556 #if defined BIGENDIAN && defined GIAC_CHARDEGTYPE
557 #undef GIAC_CHARDEGTYPE
558 #endif
559 
560 #ifdef GIAC_CHARDEGTYPE
561   typedef unsigned char degtype; // type for degree for large number of variables
562   #define degratio 8
563   #define degratiom1 7
564 #else
565   typedef short degtype; // type for degree for large number of variables
566   #define degratio 4
567   #define degratiom1 3
568 #endif
569 
570 #ifndef GIAC_64VARS
571 #define GBASIS_NO_OUTPUT
572 #endif
573 
574 #define GIAC_RDEG
575   // #define GIAC_HASH
576 #if defined GIAC_HASH && defined HASH_MAP_NAMESPACE
577 #define GIAC_RHASH
578 #endif
579 
580 #ifdef GIAC_RHASH
581   class tdeg_t64;
582   class tdeg_t64_hash_function_object {
583   public:
584     size_t operator () (const tdeg_t64 & ) const; // defined at the end of this file
tdeg_t64_hash_function_object()585     tdeg_t64_hash_function_object() {};
586   };
587 
588   typedef HASH_MAP_NAMESPACE::hash_map< tdeg_t64,int,tdeg_t64_hash_function_object > tdeg_t64_hash_t ;
589 #endif
590 
591 #ifndef VISUALC
592   #define GIAC_ELIM
593 #endif
594   short hash64tab[]={1933,1949,1951,1973,1979,1987,1993,1997,1999,2003,2011,2017,2027,2029,2039,2053,2063,2069,2081,2083,2087,2089,2099,2111,2113,2129,2131,2137,2141,2143,2153,2161,2179,2203,2207,2213,2221,2237,2239,2243,2251,2267,2269,2273,2281,2287,2293,2297,2309,2311,2333,2339,2341,2347,2351,2357,2371,2377,2381,2383,2389,2393,2399,2411};
595 
596   // storing indices in reverse order to have tdeg_t_greater access them
597   // in increasing order seems slower (cocoa.cc.64)
598   struct tdeg_t64 {
vars64giac::tdeg_t64599     bool vars64() const {return true;}
600 #ifdef GIAC_RHASH
hash_indexgiac::tdeg_t64601     int hash_index(void * ptr_) const {
602       if (!ptr_) return -1;
603       tdeg_t64_hash_t & h=*(tdeg_t64_hash_t *) ptr_;
604       tdeg_t64_hash_t::const_iterator it=h.find(*this),itend=h.end();
605       if (it==itend)
606 	return -1;
607       return it->second;
608     }
add_to_hashgiac::tdeg_t64609     bool add_to_hash(void *ptr_,int no) const {
610       if (!ptr_) return false;
611       tdeg_t64_hash_t & h=*(tdeg_t64_hash_t *) ptr_;
612       h[*this]=no;
613       return true;
614     }
615 #else
hash_indexgiac::tdeg_t64616   int hash_index(void * ptr_) const { return -1; }
add_to_hashgiac::tdeg_t64617   bool add_to_hash(void *ptr_,int no) const { return false; }
618 #endif
619     void dbgprint() const;
620     // data
621 #ifdef GIAC_64VARS
622     union {
623       short tab[GROEBNER_VARS+1];
624       struct {
625 	short tdeg; // actually it's twice the total degree+1
626 	short tdeg2;
627 	order_t order_;
628 	longlong * ui;
629 #ifdef GIAC_HASH
630 	longlong hash;
631 #endif
632 #ifdef GIAC_ELIM
633 	ulonglong elim; // used for elimination order (modifies revlex/revlex)
634 #endif
635       };
636     };
637     //int front() const { if (tdeg % 2) return (*(ui+1)) & 0xffff; else return order_.o==_PLEX_ORDER?tab[0]:tab[1];}
tdeg_t64giac::tdeg_t64638     tdeg_t64(const tdeg_t64 & a){
639       if (a.tab[0]%2){
640 	tdeg=a.tdeg;
641 	tdeg2=a.tdeg2;
642 	order_=a.order_;
643 	ui=a.ui;
644 #ifdef GIAC_HASH
645 	hash=a.hash;
646 #endif
647 #ifdef GIAC_ELIM
648 	elim=a.elim;
649 #endif
650 	++(*ui);
651       }
652       else {
653 	longlong * ptr = (longlong *) tab;
654 	longlong * aptr = (longlong *) a.tab;
655 	ptr[0]=aptr[0];
656 	ptr[1]=aptr[1];
657 	ptr[2]=aptr[2];
658 	ptr[3]=aptr[3];
659       }
660     }
661 #ifdef GIAC_ELIM
compute_elimgiac::tdeg_t64662     void compute_elim(longlong * ptr,longlong * ptrend){
663       elim=0;
664       if (order_.o==_PLEX_ORDER) // don't use elim for plex
665 	return;
666       if (tdeg>31){
667 	elim=0x1fffffffffffffffULL;
668 	return;
669       }
670       bool tdegcare=false;
671       if (ptr<ptrend-3)
672 	ptr=ptrend-3;
673       for (--ptrend;ptr<=ptrend;--ptrend){
674 	longlong x=*ptrend;
675 	elim <<= 20;
676 	elim += (x&0xffff)+(((x>>16)&0xffff)<<5)+(((x>>32)&0xffff)<<10)+(((x>>48)&0xffff)<<15);
677       }
678     }
679 #endif
compute_degsgiac::tdeg_t64680     void compute_degs(){
681       if (tab[0]%2){
682 	longlong * ptr=ui+1;
683 	tdeg=0;
684 	int firstblock=order_.o;
685 	if (firstblock!=_3VAR_ORDER && firstblock<_7VAR_ORDER)
686 	  firstblock=order_.dim;
687 	longlong * ptrend=ui+1+(firstblock+degratiom1)/degratio;
688 #ifdef GIAC_HASH
689 	hash=0;
690 #endif
691 #ifdef GIAC_ELIM
692 	compute_elim(ptr,ptrend);
693 #endif
694 	int i=0;
695 	for (;ptr!=ptrend;i+=4,++ptr){
696 	  longlong x=*ptr;
697 #ifdef GIAC_CHARDEGTYPE
698 	  tdeg += ((x+(x>>8)+(x>>16)+(x>>24)+(x>>32)+(x>>40)+(x>>48)+(x>>56))&0xff);
699 #else
700 	  tdeg += ((x+(x>>16)+(x>>32)+(x>>48))&0xffff);
701 #endif
702 #ifdef GIAC_HASH
703 	  hash += (x&0xffff)*hash64tab[i]+((x>>16)&0xffff)*hash64tab[i+1]+((x>>32)&0xffff)*hash64tab[i+2]+(x>>48)*hash64tab[i+3];
704 #endif
705 	}
706 #ifdef GIAC_ELIM
707 	if (tdeg>=16)
708 	  elim=0x1fffffffffffffffULL;
709 #endif
710 	tdeg=2*tdeg+1;
711 	tdeg2=0;
712 	ptrend=ui+1+(order_.dim+degratiom1)/degratio;
713 	for (;ptr!=ptrend;i+=4,++ptr){
714 	  longlong x=*ptr;
715 #ifdef GIAC_CHARDEGTYPE
716 	  tdeg2 += ((x+(x>>8)+(x>>16)+(x>>24)+(x>>32)+(x>>40)+(x>>48)+(x>>56))&0xff);
717 #else
718 	  tdeg2 += ((x+(x>>16)+(x>>32)+(x>>48))&0xffff);
719 #endif
720 #ifdef GIAC_HASH
721 	  hash += (x&0xffff)*hash64tab[i]+((x>>16)&0xffff)*hash64tab[i+1]+((x>>32)&0xfff)*hash64tab[i+2]+(x>>48)*hash64tab[i+3];
722 #endif
723 	}
724       }
725     }
~tdeg_t64giac::tdeg_t64726     ~tdeg_t64(){
727       if (tab[0]%2){
728 	--(*ui);
729 	if (*ui==0)
730 	  free(ui);
731       }
732     }
operator =giac::tdeg_t64733     tdeg_t64 & operator = (const tdeg_t64 & a){
734       if (tab[0] % 2){
735 	--(*ui);
736 	if (*ui==0)
737 	  free(ui);
738 	if (a.tab[0] % 2){
739 	  tdeg=a.tdeg;
740 	  tdeg2=a.tdeg2;
741 	  order_=a.order_;
742 	  ui=a.ui;
743 #ifdef GIAC_HASH
744 	  hash=a.hash;
745 #endif
746 #ifdef GIAC_ELIM
747 	  elim=a.elim;
748 #endif
749 	  ++(*ui);
750 	  return *this;
751 	}
752       }
753       else {
754 	if (a.tab[0]%2){
755 	  ++(*a.ui);
756 	}
757       }
758       longlong * ptr = (longlong *) tab;
759       longlong * aptr = (longlong *) a.tab;
760       ptr[0]=aptr[0];
761       ptr[1]=aptr[1];
762       ptr[2]=aptr[2];
763       ptr[3]=aptr[3];
764       return *this;
765     }
766 #else
767     short tab[GROEBNER_VARS+1];
frontgiac::tdeg_t64768     int front(){ return tab[1];}
769 #endif
770     // methods
selection_degreegiac::tdeg_t64771     inline unsigned selection_degree(order_t order) const {
772 #ifdef GBASIS_SELECT_TOTAL_DEGREE
773       return total_degree(order);
774 #endif
775 #ifdef GIAC_64VARS
776       if (tab[0]%2)
777 	return tdeg/2;
778 #endif
779       return tdeg;
780     }
total_degreegiac::tdeg_t64781     inline unsigned total_degree(order_t order) const {
782 #ifdef GIAC_64VARS
783       if (tab[0]%2)
784 	return tdeg/2+tdeg2;
785 #endif
786       // works only for revlex and tdeg
787 #if 0
788       if (order==_REVLEX_ORDER || order==_TDEG_ORDER)
789 	return tab[0];
790       if (order==_3VAR_ORDER)
791 	return (tab[0] << 16)+tab[4];
792       if (order==_7VAR_ORDER)
793 	return (tab[0] << 16) +tab[8];
794       if (order==_11VAR_ORDER)
795 	return (tab[0] << 16) +tab[12];
796 #endif
797       return tab[0];
798     }
799     // void set_total_degree(unsigned d) { tab[0]=d;}
tdeg_t64giac::tdeg_t64800     tdeg_t64() {
801       longlong * ptr = (longlong *) tab;
802       ptr[2]=ptr[1]=ptr[0]=0;
803 #if GROEBNER_VARS>11
804       ptr[3]=0;
805 #endif
806     }
tdeg_t64giac::tdeg_t64807     tdeg_t64(int i){
808       longlong * ptr = (longlong *) tab;
809       ptr[2]=ptr[1]=ptr[0]=0;
810 #if GROEBNER_VARS>11
811       ptr[3]=0;
812 #endif
813     }
get_tabgiac::tdeg_t64814     void get_tab(short * ptr,order_t order) const {
815 #ifdef GIAC_64VARS
816       if (tab[0]%2){ // copy only 16 first
817 	degtype * ptr_=(degtype *)(ui+1);
818 	for (unsigned i=0;i<=GROEBNER_VARS;++i)
819 	  ptr[i]=ptr_[i];
820 	return;
821       }
822 #endif
823       for (unsigned i=0;i<=GROEBNER_VARS;++i)
824 	ptr[i]=tab[i];
825 #ifdef GIAC_64VARS
826       ptr[0]/=2;
827 #endif
828 #ifdef GBASIS_SWAP
829       swap_indices(ptr);
830 #endif
831     }
tdeg_t64giac::tdeg_t64832     tdeg_t64(const index_m & lm,order_t order){
833 #ifdef GIAC_64VARS
834       if (lm.size()>GROEBNER_VARS){
835 	ui=(longlong *)malloc((1+(lm.size()+degratiom1)/degratio)*sizeof(longlong));
836 	longlong* ptr=ui;
837 	*ptr=1; ++ ptr;
838 #ifdef GIAC_CHARDEGTYPE
839 	for (int i=0;i<lm.size();){
840 	  unsigned char tableau[8]={0,0,0,0,0,0,0,0};
841 	  tableau[0]=lm[i];
842 	  ++i;
843 	  if (i<lm.size())
844 	    tableau[1] = lm[i];
845 	  ++i;
846 	  if (i<lm.size())
847 	    tableau[2]= lm[i];
848 	  ++i;
849 	  if (i<lm.size())
850 	    tableau[3]= lm[i];
851 	  ++i;
852 	  if (i<lm.size())
853 	    tableau[4]= lm[i];
854 	  ++i;
855 	  if (i<lm.size())
856 	    tableau[5]= lm[i];
857 	  ++i;
858 	  if (i<lm.size())
859 	    tableau[6]= lm[i];
860 	  ++i;
861 	  if (i<lm.size())
862 	    tableau[7]= lm[i];
863 	  ++i;
864 	  *ptr = * (longlong *)tableau ;
865 	  ++ptr;
866 	}
867 #else
868 	for (int i=0;i<lm.size();){
869 	  longlong x=lm[i];
870 	  ++i;
871 	  x <<= 16;
872 	  if (i<lm.size())
873 	    x += lm[i];
874 	  ++i;
875 	  x <<= 16;
876 	  if (i<lm.size())
877 	    x += lm[i];
878 	  ++i;
879 	  x <<= 16;
880 	  if (i<lm.size())
881 	    x += lm[i];
882 #ifndef BIGENDIAN
883 	  x = (x>>48) | (((x>>32)&0xffff)<<16) | (((x>>16)&0xffff)<<32) | ((x&0xffff)<<48);
884 #endif
885 	  *ptr = x;
886 	  ++ptr;
887 	  ++i;
888 	}
889 #endif // GIAC_CHARDEGTYPE
890 	if (order.o==_3VAR_ORDER || order.o>=_7VAR_ORDER){
891 	  tdeg=2*nvar_total_degree(lm,order.o)+1;
892 	  tdeg2=sum_degree_from(lm,order.o);
893 	}
894 	else {
895 	  tdeg=short(2*lm.total_degree()+1);
896 	  tdeg2=0;
897 	}
898 	order_=order;
899 #if 1 // def GIAC_HASH
900 	compute_degs(); // for hash
901 #else
902 #ifdef GIAC_ELIM
903 	ptr=ui+1;
904 	int firstblock=order_.o;
905 	if (firstblock!=_3VAR_ORDER && firstblock<_7VAR_ORDER)
906 	  firstblock=order_.dim;
907 	compute_elim(ptr,ptr+(firstblock+degratiom1)/degratio);
908 #endif
909 #endif
910 	return;
911       }
912 #endif // GIAC_64VARS
913       longlong * ptr_ = (longlong *) tab;
914       ptr_[2]=ptr_[1]=ptr_[0]=0;
915       short * ptr=tab;
916 #if GROEBNER_VARS>11
917       ptr_[3]=0;
918 #endif
919       // tab[GROEBNER_VARS]=order;
920 #if GROEBNER_VARS==15
921       if (order.o==_3VAR_ORDER){
922 #ifdef GIAC_64VARS
923 	ptr[0]=2*(lm[0]+lm[1]+lm[2]);
924 #else
925 	ptr[0]=lm[0]+lm[1]+lm[2];
926 #endif
927 	ptr[1]=lm[2];
928 	ptr[2]=lm[1];
929 	ptr[3]=lm[0];
930 	ptr +=5;
931 	short t=0;
932 	vector<deg_t>::const_iterator it=lm.begin()+3,itend=lm.end();
933 	for (--itend,--it;it!=itend;++ptr,--itend){
934 	  t += *itend;
935 	  *ptr=*itend;
936 	}
937 	tab[4]=t;
938 	return;
939       }
940       if (order.o==_7VAR_ORDER){
941 #ifdef GIAC_64VARS
942 	ptr[0]=2*(lm[0]+lm[1]+lm[2]+lm[3]+lm[4]+lm[5]+lm[6]);
943 #else
944 	ptr[0]=lm[0]+lm[1]+lm[2]+lm[3]+lm[4]+lm[5]+lm[6];
945 #endif
946 	ptr[1]=lm[6];
947 	ptr[2]=lm[5];
948 	ptr[3]=lm[4];
949 	ptr[4]=lm[3];
950 	ptr[5]=lm[2];
951 	ptr[6]=lm[1];
952 	ptr[7]=lm[0];
953 	ptr +=9;
954 	short t=0;
955 	vector<deg_t>::const_iterator it=lm.begin()+7,itend=lm.end();
956 	for (--itend,--it;it!=itend;++ptr,--itend){
957 	  t += *itend;
958 	  *ptr=*itend;
959 	}
960 	tab[8]=t;
961 	return;
962       }
963       if (order.o==_11VAR_ORDER){
964 #ifdef GIAC_64VARS
965 	ptr[0]=2*(lm[0]+lm[1]+lm[2]+lm[3]+lm[4]+lm[5]+lm[6]+lm[7]+lm[8]+lm[9]+lm[10]);
966 #else
967 	ptr[0]=lm[0]+lm[1]+lm[2]+lm[3]+lm[4]+lm[5]+lm[6]+lm[7]+lm[8]+lm[9]+lm[10];
968 #endif
969 	ptr[1]=lm[10];
970 	ptr[2]=lm[9];
971 	ptr[3]=lm[8];
972 	ptr[4]=lm[7];
973 	ptr[5]=lm[6];
974 	ptr[6]=lm[5];
975 	ptr[7]=lm[4];
976 	ptr[8]=lm[3];
977 	ptr[9]=lm[2];
978 	ptr[10]=lm[1];
979 	ptr[11]=lm[0];
980 	ptr += 13;
981 	short t=0;
982 	vector<deg_t>::const_iterator it=lm.begin()+11,itend=lm.end();
983 	for (--itend,--it;it!=itend;++ptr,--itend){
984 	  t += *itend;
985 	  *ptr=*itend;
986 	}
987 	tab[12]=t;
988 	return;
989       }
990 #endif
991       vector<deg_t>::const_iterator it=lm.begin(),itend=lm.end();
992       if (order.o==_REVLEX_ORDER || order.o==_TDEG_ORDER){
993 	*ptr=sum_degree(lm);
994 	++ptr;
995       }
996       if (order.o==_REVLEX_ORDER){
997 	for (--itend,--it;it!=itend;++ptr,--itend)
998 	  *ptr=*itend;
999       }
1000       else {
1001 	for (;it!=itend;++ptr,++it)
1002 	  *ptr=*it;
1003       }
1004 #ifdef GBASIS_SWAP
1005       swap_indices(tab);
1006 #endif
1007 #ifdef GIAC_64VARS
1008       *tab *=2;
1009 #endif
1010     }
1011   };
1012 
1013   typedef map<tdeg_t64,unsigned> annuaire;
1014 
1015 #ifdef NSPIRE
1016   template<class T>
operator <<(nio::ios_base<T> & os,const tdeg_t64 & x)1017   nio::ios_base<T> & operator << (nio::ios_base<T> & os,const tdeg_t64 & x){
1018 #ifdef GIAC_64VARS
1019     if (x.tab[0]%2){
1020       os << "[";
1021       const longlong * ptr=x.ui+1,*ptrend=ptr+(x.order_.dim+degratiom1)/degratio;
1022       for (;ptr!=ptrend;++ptr){
1023 	longlong x=*ptr;
1024 #ifdef BIGENDIAN
1025 	os << ((x>>48) &0xffff)<< "," << ((x>>32) & 0xffff) << "," << ((x>>16) & 0xffff) << "," << ((x) & 0xffff) << ",";
1026 #else
1027 	os << ((x) &0xffff)<< "," << ((x>>16) & 0xffff) << "," << ((x>>32) & 0xffff) << "," << ((x>>48) & 0xffff) << ",";
1028 #endif
1029       }
1030       return os << "]";
1031     }
1032 #endif
1033     os << "[";
1034     for (unsigned i=0; i<=GROEBNER_VARS;++i){
1035       os << x.tab[i] << ",";
1036     }
1037     return os << "]";
1038   }
1039 #else
operator <<(ostream & os,const tdeg_t64 & x)1040   ostream & operator << (ostream & os,const tdeg_t64 & x){
1041 #ifdef GIAC_64VARS
1042     if (x.tab[0]%2){
1043       // debugging
1044       tdeg_t64 xsave(x); xsave.compute_degs();
1045       if (xsave.tdeg!=x.tdeg || xsave.tdeg2!=x.tdeg2)
1046 	os << "degree error " ;
1047       os << "[";
1048       const longlong * ptr=x.ui+1,*ptrend=ptr+(x.order_.dim+degratiom1)/degratio;
1049       for (;ptr!=ptrend;++ptr){
1050 	longlong x=*ptr;
1051 #ifdef BIGENDIAN
1052 	os << ((x>>48) &0xffff)<< "," << ((x>>32) & 0xffff) << "," << ((x>>16) & 0xffff) << "," << ((x) & 0xffff) << ",";
1053 #else
1054 	os << ((x) &0xffff)<< "," << ((x>>16) & 0xffff) << "," << ((x>>32) & 0xffff) << "," << ((x>>48) & 0xffff) << ",";
1055 #endif
1056       }
1057       return os << "]";
1058     }
1059 #endif
1060     os << "[";
1061     for (unsigned i=0; i<=GROEBNER_VARS;++i){
1062       os << x.tab[i] << ",";
1063     }
1064     return os << "]";
1065   }
1066 #endif
dbgprint() const1067   void tdeg_t64::dbgprint() const { COUT << * this << '\n'; }
1068   tdeg_t64 operator + (const tdeg_t64 & x,const tdeg_t64 & y);
operator +=(tdeg_t64 & x,const tdeg_t64 & y)1069   tdeg_t64 & operator += (tdeg_t64 & x,const tdeg_t64 & y){
1070 #ifdef GIAC_64VARS
1071     if (x.tab[0]%2){
1072 #ifdef GIAC_DEBUG_TDEG_T64
1073       if (!(y.tab[0]%2)){
1074 	y.dbgprint();
1075 	COUT << "erreur" << '\n';
1076       }
1077 #endif
1078       return x=x+y;
1079     }
1080 #endif
1081 #if 1
1082     ulonglong *xtab=(ulonglong *)&x,*ytab=(ulonglong *)&y;
1083     xtab[0]+=ytab[0];
1084     xtab[1]+=ytab[1];
1085     xtab[2]+=ytab[2];
1086 #if GROEBNER_VARS>11
1087     xtab[3]+=ytab[3];
1088 #endif
1089 #else
1090     for (unsigned i=0;i<=GROEBNER_VARS;++i)
1091       x.tab[i]+=y.tab[i];
1092 #endif
1093     return x;
1094   }
1095 
dynamic_plus(const tdeg_t64 & x,const tdeg_t64 & y)1096   inline tdeg_t64 dynamic_plus(const tdeg_t64 & x,const tdeg_t64 & y){
1097     tdeg_t64 res;
1098     res.order_=x.order_;
1099     res.ui=(longlong *)malloc((1+(x.order_.dim+degratiom1)/degratio)*sizeof(longlong));
1100     res.ui[0]=1;
1101     const longlong * xptr=x.ui+1,*xend=xptr+(x.order_.dim+degratiom1)/degratio,*yptr=y.ui+1;
1102     longlong * resptr=res.ui+1;
1103     for (;xptr!=xend;++resptr,++yptr,++xptr)
1104       *resptr=*xptr+*yptr;
1105 #if 1
1106     res.tdeg=1+2*(x.tdeg/2+y.tdeg/2);
1107     res.tdeg2=x.tdeg2+y.tdeg2;
1108 #ifdef GIAC_HASH
1109     res.hash=x.hash+y.hash;
1110 #endif
1111 #ifdef GIAC_ELIM
1112     if (res.tdeg>=33)
1113       res.elim=0x1fffffffffffffffULL;
1114     else
1115       res.elim=x.elim+y.elim;
1116 #endif
1117 #else
1118     res.tdeg=1;
1119     res.compute_degs();
1120 #endif
1121     return res;
1122   }
1123 
operator +(const tdeg_t64 & x,const tdeg_t64 & y)1124   tdeg_t64 operator + (const tdeg_t64 & x,const tdeg_t64 & y){
1125 #ifdef GIAC_64VARS
1126     if (x.tab[0]%2){
1127 #ifdef GIAC_DEBUG_TDEG_T64
1128       if (!(y.tab[0]%2))
1129 	COUT << "erreur" << '\n';
1130 #endif
1131       return dynamic_plus(x,y);
1132     }
1133 #endif
1134     tdeg_t64 res(x);
1135     return res += y;
1136 #if 1
1137     ulonglong *xtab=(ulonglong *)&x,*ytab=(ulonglong *)&y,*ztab=(ulonglong *)&res;
1138     ztab[0]=xtab[0]+ytab[0];
1139     ztab[1]=xtab[1]+ytab[1];
1140     ztab[2]=xtab[2]+ytab[2];
1141 #if GROEBNER_VARS>11
1142     ztab[3]=xtab[3]+ytab[3];
1143 #endif
1144 #else
1145     for (unsigned i=0;i<=GROEBNER_VARS;++i)
1146       res.tab[i]=x.tab[i]+y.tab[i];
1147 #endif
1148     return res;
1149   }
add(const tdeg_t64 & x,const tdeg_t64 & y,tdeg_t64 & res,int dim)1150   inline void add(const tdeg_t64 & x,const tdeg_t64 & y,tdeg_t64 & res,int dim){
1151 #ifdef GIAC_64VARS
1152     if (x.tab[0]%2){
1153 #ifdef GIAC_DEBUG_TDEG_T64
1154       if (!(y.tab[0]%2))
1155 	COUT << "erreur" << '\n';
1156 #endif
1157       if (res.tab[0]%2 && res.ui[0]==1){
1158 	const longlong * xptr=x.ui+1,*xend=xptr+(x.order_.dim+degratiom1)/degratio,*yptr=y.ui+1;
1159 	longlong * resptr=res.ui+1;
1160 #ifndef GIAC_CHARDEGTYPE
1161 	*resptr=*xptr+*yptr;++resptr,++yptr,++xptr;
1162 	*resptr=*xptr+*yptr;++resptr,++yptr,++xptr;
1163 	*resptr=*xptr+*yptr;++resptr,++yptr,++xptr;
1164 	*resptr=*xptr+*yptr;++resptr,++yptr,++xptr;
1165 #endif
1166 	for (;xptr!=xend;++resptr,++yptr,++xptr)
1167 	  *resptr=*xptr+*yptr;
1168 #if 1
1169 	res.tdeg=1+2*(x.tdeg/2+y.tdeg/2);
1170 	res.tdeg2=x.tdeg2+y.tdeg2;
1171 #ifdef GIAC_HASH
1172 	res.hash=x.hash+y.hash;
1173 #endif
1174 #ifdef GIAC_ELIM
1175 	if (res.tdeg>=33)
1176 	  res.elim=0x1fffffffffffffffULL;
1177 	else
1178 	  res.elim=x.elim+y.elim;
1179 #endif
1180 #else
1181 	res.tdeg=1;
1182 	res.compute_degs();
1183 #endif
1184       }
1185       else
1186 	res=dynamic_plus(x,y);
1187       return;
1188     }
1189 #endif
1190 #if 0 // def GIAC_64VARS
1191     if (x.tab[0]%2){
1192       res = x;
1193       res += y;
1194       return;
1195     }
1196 #endif
1197 #if 1
1198     ulonglong *xtab=(ulonglong *)&x,*ytab=(ulonglong *)&y,*ztab=(ulonglong *)&res;
1199     ztab[0]=xtab[0]+ytab[0];
1200     ztab[1]=xtab[1]+ytab[1];
1201     ztab[2]=xtab[2]+ytab[2];
1202 #if GROEBNER_VARS>11
1203     ztab[3]=xtab[3]+ytab[3];
1204 #endif
1205 #else
1206     for (unsigned i=0;i<=dim;++i)
1207       res.tab[i]=x.tab[i]+y.tab[i];
1208 #endif
1209   }
1210 
operator -(const tdeg_t64 & x,const tdeg_t64 & y)1211   tdeg_t64 operator - (const tdeg_t64 & x,const tdeg_t64 & y){
1212 #ifdef GIAC_64VARS
1213     if (x.tab[0]%2){
1214 #ifdef GIAC_DEBUG_TDEG_T64
1215       if (!(y.tab[0]%2))
1216 	COUT << "erreur" << '\n';
1217 #endif
1218       tdeg_t64 res;
1219       res.order_=x.order_;
1220       res.ui=(longlong *)malloc((1+(x.order_.dim+degratiom1)/degratio)*sizeof(longlong));
1221       res.ui[0]=1;
1222       const longlong * xptr=x.ui+1,*xend=xptr+(x.order_.dim+degratiom1)/degratio,*yptr=y.ui+1;
1223       longlong * resptr=res.ui+1;
1224       for (;xptr!=xend;++resptr,++yptr,++xptr)
1225 	*resptr=*xptr-*yptr;
1226       res.tdeg=1;
1227       res.compute_degs();
1228       return res;
1229     }
1230 #endif
1231     tdeg_t64 res;
1232 #if 1
1233     ulonglong *xtab=(ulonglong *)&x,*ytab=(ulonglong *)&y,*ztab=(ulonglong *)&res;
1234     ztab[0]=xtab[0]-ytab[0];
1235     ztab[1]=xtab[1]-ytab[1];
1236     ztab[2]=xtab[2]-ytab[2];
1237 #if GROEBNER_VARS>11
1238     ztab[3]=xtab[3]-ytab[3];
1239 #endif
1240 #else
1241     for (unsigned i=0;i<=GROEBNER_VARS;++i)
1242       res.tab[i]=x.tab[i]-y.tab[i];
1243 #endif
1244     return res;
1245   }
operator ==(const tdeg_t64 & x,const tdeg_t64 & y)1246   inline bool operator == (const tdeg_t64 & x,const tdeg_t64 & y){
1247     longlong X=((longlong *) x.tab)[0];
1248     if (X!= ((longlong *) y.tab)[0])
1249       return false;
1250 #ifdef GIAC_HASH
1251     if (x.hash!=y.hash)
1252       return false;
1253 #endif
1254 #ifdef GIAC_ELIM
1255     if (x.elim!=y.elim) return false;
1256 #endif
1257 #ifdef GIAC_64VARS
1258     if (
1259 #ifdef BIGENDIAN
1260 	x.tab[0]%2
1261 #else
1262 	X%2
1263 #endif
1264 	){
1265       //if (x.ui==y.ui) return true;
1266       const longlong * xptr=x.ui+1,*xend=xptr+(x.order_.dim+degratiom1)/degratio,*yptr=y.ui+1;
1267 #ifndef GIAC_CHARTABDEG
1268       // dimension+3 is at least 16 otherwise the alternative code would be called
1269       if (*xptr!=*yptr)
1270 	return false;
1271       ++yptr,++xptr;
1272       if (*xptr!=*yptr)
1273 	return false;
1274       ++yptr,++xptr;
1275       if (*xptr!=*yptr)
1276 	return false;
1277       ++yptr,++xptr;
1278       if (*xptr!=*yptr)
1279 	return false;
1280       ++yptr,++xptr;
1281 #endif
1282       for (;xptr!=xend;++yptr,++xptr){
1283 	if (*xptr!=*yptr)
1284 	  return false;
1285       }
1286       return true;
1287     }
1288 #endif
1289     return ((longlong *) x.tab)[1] == ((longlong *) y.tab)[1] &&
1290       ((longlong *) x.tab)[2] == ((longlong *) y.tab)[2]
1291 #if GROEBNER_VARS>11
1292       &&  ((longlong *) x.tab)[3] == ((longlong *) y.tab)[3]
1293 #endif
1294     ;
1295   }
operator !=(const tdeg_t64 & x,const tdeg_t64 & y)1296   inline bool operator != (const tdeg_t64 & x,const tdeg_t64 & y){
1297     return !(x==y);
1298   }
1299 
tdeg_t64_revlex_greater(const tdeg_t64 & x,const tdeg_t64 & y)1300   static inline int tdeg_t64_revlex_greater (const tdeg_t64 & x,const tdeg_t64 & y){
1301 #ifdef GBASIS_SWAP
1302     ulonglong *xtab=(ulonglong *)&x,*ytab=(ulonglong *)&y;
1303     if (xtab[0]!=ytab[0]) // tdeg test already donne by caller
1304       return xtab[0]<=ytab[0]?1:0;
1305     if (xtab[1]!=ytab[1])
1306       return xtab[1]<=ytab[1]?1:0;
1307     if (xtab[2]!=ytab[2])
1308       return xtab[2]<=ytab[2]?1:0;
1309 #if GROEBNER_VARS>11
1310     return xtab[3]<=ytab[3]?1:0;
1311 #endif
1312     return 2;
1313 #else // GBASIS_SWAP
1314     if (((longlong *) x.tab)[0] != ((longlong *) y.tab)[0]){
1315       if (x.tab[0]!=y.tab[0])
1316 	return x.tab[0]>=y.tab[0]?1:0;
1317       if (x.tab[1]!=y.tab[1])
1318 	return x.tab[1]<=y.tab[1]?1:0;
1319       if (x.tab[2]!=y.tab[2])
1320 	return x.tab[2]<=y.tab[2]?1:0;
1321       return x.tab[3]<=y.tab[3]?1:0;
1322     }
1323     if (((longlong *) x.tab)[1] != ((longlong *) y.tab)[1]){
1324       if (x.tab[4]!=y.tab[4])
1325 	return x.tab[4]<=y.tab[4]?1:0;
1326       if (x.tab[5]!=y.tab[5])
1327 	return x.tab[5]<=y.tab[5]?1:0;
1328       if (x.tab[6]!=y.tab[6])
1329 	return x.tab[6]<=y.tab[6]?1:0;
1330       return x.tab[7]<=y.tab[7]?1:0;
1331     }
1332     if (((longlong *) x.tab)[2] != ((longlong *) y.tab)[2]){
1333       if (x.tab[8]!=y.tab[8])
1334 	return x.tab[8]<=y.tab[8]?1:0;
1335       if (x.tab[9]!=y.tab[9])
1336 	return x.tab[9]<=y.tab[9]?1:0;
1337       if (x.tab[10]!=y.tab[10])
1338 	return x.tab[10]<=y.tab[10]?1:0;
1339       return x.tab[11]<=y.tab[11]?1:0;
1340     }
1341 #if GROEBNER_VARS>11
1342     if (((longlong *) x.tab)[3] != ((longlong *) y.tab)[3]){
1343       if (x.tab[12]!=y.tab[12])
1344 	return x.tab[12]<=y.tab[12]?1:0;
1345       if (x.tab[13]!=y.tab[13])
1346 	return x.tab[13]<=y.tab[13]?1:0;
1347       if (x.tab[14]!=y.tab[14])
1348 	return x.tab[14]<=y.tab[14]?1:0;
1349       return x.tab[15]<=y.tab[15]?1:0;
1350     }
1351 #endif
1352     return 2;
1353 #endif // GBASIS_SWAP
1354   }
1355 
1356   // inline bool operator <  (const tdeg_t64 & x,const tdeg_t64 & y){ return !tdeg_t64_revlex_greater(x,y); }
1357   // inline bool operator >  (const tdeg_t64 & x,const tdeg_t64 & y){ return !tdeg_t64_revlex_greater(y,x); }
1358   // inline bool operator <= (const tdeg_t64 & x,const tdeg_t64 & y){ return tdeg_t64_revlex_greater(y,x); }
1359   // inline bool operator >=  (const tdeg_t64 & x,const tdeg_t64 & y){ return tdeg_t64_revlex_greater(x,y); }
1360 
1361 #if GROEBNER_VARS==15
1362 
tdeg_t64_3var_greater(const tdeg_t64 & x,const tdeg_t64 & y)1363   int tdeg_t64_3var_greater (const tdeg_t64 & x,const tdeg_t64 & y){
1364     if (x.tab[0]!=y.tab[0])
1365       return x.tab[0]>=y.tab[0]?1:0;
1366     if (x.tab[4]!=y.tab[4])
1367       return x.tab[4]>=y.tab[4]?1:0;
1368     if (((longlong *) x.tab)[0] != ((longlong *) y.tab)[0]){
1369       if (x.tab[1]!=y.tab[1])
1370 	return x.tab[1]<=y.tab[1]?1:0;
1371       if (x.tab[2]!=y.tab[2])
1372 	return x.tab[2]<=y.tab[2]?1:0;
1373       return x.tab[3]<=y.tab[3]?1:0;
1374     }
1375     if (((longlong *) x.tab)[1] != ((longlong *) y.tab)[1]){
1376       if (x.tab[5]!=y.tab[5])
1377 	return x.tab[5]<=y.tab[5]?1:0;
1378       if (x.tab[6]!=y.tab[6])
1379 	return x.tab[6]<=y.tab[6]?1:0;
1380       return x.tab[7]<=y.tab[7]?1:0;
1381     }
1382     if (((longlong *) x.tab)[2] != ((longlong *) y.tab)[2]){
1383       if (x.tab[8]!=y.tab[8])
1384 	return x.tab[8]<=y.tab[8]?1:0;
1385       if (x.tab[9]!=y.tab[9])
1386 	return x.tab[9]<=y.tab[9]?1:0;
1387       if (x.tab[10]!=y.tab[10])
1388 	return x.tab[10]<=y.tab[10]?1:0;
1389       return x.tab[11]<=y.tab[11]?1:0;
1390     }
1391     if (((longlong *) x.tab)[3] != ((longlong *) y.tab)[3]){
1392       if (x.tab[12]!=y.tab[12])
1393 	return x.tab[12]<=y.tab[12]?1:0;
1394       if (x.tab[13]!=y.tab[13])
1395 	return x.tab[13]<=y.tab[13]?1:0;
1396       if (x.tab[14]!=y.tab[14])
1397 	return x.tab[14]<=y.tab[14]?1:0;
1398       return x.tab[15]<=y.tab[15]?1:0;
1399     }
1400     return 2;
1401   }
1402 
tdeg_t64_7var_greater(const tdeg_t64 & x,const tdeg_t64 & y)1403   int tdeg_t64_7var_greater (const tdeg_t64 & x,const tdeg_t64 & y){
1404     if (x.tab[0]!=y.tab[0])
1405       return x.tab[0]>=y.tab[0]?1:0;
1406     if (x.tab[8]!=y.tab[8])
1407       return x.tab[8]>=y.tab[8]?1:0;
1408     if (((longlong *) x.tab)[0] != ((longlong *) y.tab)[0]){
1409       if (x.tab[1]!=y.tab[1])
1410 	return x.tab[1]<=y.tab[1]?1:0;
1411       if (x.tab[2]!=y.tab[2])
1412 	return x.tab[2]<=y.tab[2]?1:0;
1413       return x.tab[3]<=y.tab[3]?1:0;
1414     }
1415     if (((longlong *) x.tab)[1] != ((longlong *) y.tab)[1]){
1416       if (x.tab[4]!=y.tab[4])
1417 	return x.tab[4]<=y.tab[4]?1:0;
1418       if (x.tab[5]!=y.tab[5])
1419 	return x.tab[5]<=y.tab[5]?1:0;
1420       if (x.tab[6]!=y.tab[6])
1421 	return x.tab[6]<=y.tab[6]?1:0;
1422       return x.tab[7]<=y.tab[7]?1:0;
1423     }
1424     if (((longlong *) x.tab)[2] != ((longlong *) y.tab)[2]){
1425       if (x.tab[9]!=y.tab[9])
1426 	return x.tab[9]<=y.tab[9]?1:0;
1427       if (x.tab[10]!=y.tab[10])
1428 	return x.tab[10]<=y.tab[10]?1:0;
1429       return x.tab[11]<=y.tab[11]?1:0;
1430     }
1431     if (((longlong *) x.tab)[3] != ((longlong *) y.tab)[3]){
1432       if (x.tab[12]!=y.tab[12])
1433 	return x.tab[12]<=y.tab[12]?1:0;
1434       if (x.tab[13]!=y.tab[13])
1435 	return x.tab[13]<=y.tab[13]?1:0;
1436       if (x.tab[14]!=y.tab[14])
1437 	return x.tab[14]<=y.tab[14]?1:0;
1438       return x.tab[15]<=y.tab[15]?1:0;
1439     }
1440     return 2;
1441   }
1442 
tdeg_t64_11var_greater(const tdeg_t64 & x,const tdeg_t64 & y)1443   int tdeg_t64_11var_greater (const tdeg_t64 & x,const tdeg_t64 & y){
1444     if (x.tab[0]!=y.tab[0])
1445       return x.tab[0]>=y.tab[0]?1:0;
1446     if (x.tab[12]!=y.tab[12])
1447       return x.tab[12]>=y.tab[12]?1:0;
1448     if (((longlong *) x.tab)[0] != ((longlong *) y.tab)[0]){
1449       if (x.tab[1]!=y.tab[1])
1450 	return x.tab[1]<=y.tab[1]?1:0;
1451       if (x.tab[2]!=y.tab[2])
1452 	return x.tab[2]<=y.tab[2]?1:0;
1453       return x.tab[3]<=y.tab[3]?1:0;
1454     }
1455     if (((longlong *) x.tab)[1] != ((longlong *) y.tab)[1]){
1456       if (x.tab[4]!=y.tab[4])
1457 	return x.tab[4]<=y.tab[4]?1:0;
1458       if (x.tab[5]!=y.tab[5])
1459 	return x.tab[5]<=y.tab[5]?1:0;
1460       if (x.tab[6]!=y.tab[6])
1461 	return x.tab[6]<=y.tab[6]?1:0;
1462       return x.tab[7]<=y.tab[7]?1:0;
1463     }
1464     if (((longlong *) x.tab)[2] != ((longlong *) y.tab)[2]){
1465       if (x.tab[8]!=y.tab[8])
1466 	return x.tab[8]<=y.tab[8]?1:0;
1467       if (x.tab[9]!=y.tab[9])
1468 	return x.tab[9]<=y.tab[9]?1:0;
1469       if (x.tab[10]!=y.tab[10])
1470 	return x.tab[10]<=y.tab[10]?1:0;
1471       return x.tab[11]<=y.tab[11]?1:0;
1472     }
1473     if (((longlong *) x.tab)[3] != ((longlong *) y.tab)[3]){
1474       if (x.tab[13]!=y.tab[13])
1475 	return x.tab[13]<=y.tab[13]?1:0;
1476       if (x.tab[14]!=y.tab[14])
1477 	return x.tab[14]<=y.tab[14]?1:0;
1478       return x.tab[15]<=y.tab[15]?1:0;
1479     }
1480     return 2;
1481   }
1482 #endif // GROEBNER_VARS==15
1483 
tdeg_t64_lex_greater(const tdeg_t64 & x,const tdeg_t64 & y)1484   int tdeg_t64_lex_greater (const tdeg_t64 & x,const tdeg_t64 & y){
1485 #ifdef GBASIS_SWAP
1486     ulonglong *xtab=(ulonglong *)&x,*ytab=(ulonglong *)&y;
1487     ulonglong X=*xtab, Y=*ytab;
1488     if (X!=Y){
1489       if ( (X & 0xffff) != (Y &0xffff))
1490 	return (X&0xffff)>=(Y&0xffff)?1:0;
1491       return X>=Y?1:0;
1492     }
1493     if (xtab[1]!=ytab[1])
1494       return xtab[1]>=ytab[1]?1:0;
1495     if (xtab[2]!=ytab[2])
1496       return xtab[2]>=ytab[2]?1:0;
1497 #if GROEBNER_VARS>11
1498     return xtab[3]>=ytab[3]?1:0;
1499 #endif
1500     return 2;
1501 #else
1502     if (((longlong *) x.tab)[0] != ((longlong *) y.tab)[0]){
1503       if (x.tab[0]!=y.tab[0])
1504 	return x.tab[0]>y.tab[0]?1:0;
1505       if (x.tab[1]!=y.tab[1])
1506 	return x.tab[1]>y.tab[1]?1:0;
1507       if (x.tab[2]!=y.tab[2])
1508 	return x.tab[2]>y.tab[2]?1:0;
1509       return x.tab[3]>y.tab[3]?1:0;
1510     }
1511     if (((longlong *) x.tab)[1] != ((longlong *) y.tab)[1]){
1512       if (x.tab[4]!=y.tab[4])
1513 	return x.tab[4]>y.tab[4]?1:0;
1514       if (x.tab[5]!=y.tab[5])
1515 	return x.tab[5]>y.tab[5]?1:0;
1516       if (x.tab[6]!=y.tab[6])
1517 	return x.tab[6]>y.tab[6]?1:0;
1518       return x.tab[7]>y.tab[7]?1:0;
1519     }
1520     if (((longlong *) x.tab)[2] != ((longlong *) y.tab)[2]){
1521       if (x.tab[8]!=y.tab[8])
1522 	return x.tab[8]>y.tab[8]?1:0;
1523       if (x.tab[9]!=y.tab[9])
1524 	return x.tab[9]>y.tab[9]?1:0;
1525       if (x.tab[10]!=y.tab[10])
1526 	return x.tab[10]>y.tab[10]?1:0;
1527       return x.tab[11]>=y.tab[11]?1:0;
1528     }
1529 #if GROEBNER_VARS>11
1530     if (((longlong *) x.tab)[3] != ((longlong *) y.tab)[3]){
1531       if (x.tab[12]!=y.tab[12])
1532 	return x.tab[12]>y.tab[12]?1:0;
1533       if (x.tab[13]!=y.tab[13])
1534 	return x.tab[13]>y.tab[13]?1:0;
1535       if (x.tab[14]!=y.tab[14])
1536 	return x.tab[14]>y.tab[14]?1:0;
1537       return x.tab[15]>=y.tab[15]?1:0;
1538     }
1539 #endif
1540     return 2;
1541 #endif
1542   }
1543 
tdeg_t_greater_dyn(const tdeg_t64 & x,const tdeg_t64 & y,order_t order)1544   inline int tdeg_t_greater_dyn(const tdeg_t64 & x,const tdeg_t64 & y,order_t order){
1545     const longlong * it1=x.ui,* it2=y.ui,*it1beg;
1546     longlong a=0;
1547     switch (order.o){
1548     case _REVLEX_ORDER:
1549       it1beg=x.ui;
1550       it1=x.ui+(x.order_.dim+degratiom1)/degratio;
1551       it2=y.ui+(y.order_.dim+degratiom1)/degratio;
1552 #if 0 // def GIAC_ELIM
1553       --it1; --it2; // first test already done with elim field
1554 #endif
1555       for (;it1!=it1beg;--it2,--it1){
1556 	a=*it1-*it2;
1557 	if (a)
1558 	  return a<=0?1:0;
1559       }
1560       return 2;
1561     case _64VAR_ORDER:
1562       a=it1[16]-it2[16];
1563       if (a)
1564 	return a<=0?1:0;
1565       a=it1[15]-it2[15];
1566       if (a)
1567 	return a<=0?1:0;
1568       a=it1[14]-it2[14];
1569       if (a)
1570 	return a<=0?1:0;
1571       a=it1[13]-it2[13];
1572       if (a)
1573 	return a<=0?1:0;
1574     case _48VAR_ORDER:
1575       a=it1[12]-it2[12];
1576       if (a)
1577 	return a<=0?1:0;
1578       a=it1[11]-it2[11];
1579       if (a)
1580 	return a<=0?1:0;
1581       a=it1[10]-it2[10];
1582       if (a)
1583 	return a<=0?1:0;
1584       a=it1[9]-it2[9];
1585       if (a)
1586 	return a<=0?1:0;
1587     case _32VAR_ORDER:
1588       a=it1[8]-it2[8];
1589       if (a)
1590 	return a<=0?1:0;
1591       a=it1[7]-it2[7];
1592       if (a)
1593 	return a<=0?1:0;
1594       a=it1[6]-it2[6];
1595       if (a)
1596 	return a<=0?1:0;
1597       a=it1[5]-it2[5];
1598       if (a)
1599 	return a<=0?1:0;
1600     case _16VAR_ORDER:
1601       a=it1[4]-it2[4];
1602       if (a)
1603 	return a<=0?1:0;
1604     case _11VAR_ORDER:
1605       a=it1[3]-it2[3];
1606       if (a)
1607 	return a<=0?1:0;
1608     case _7VAR_ORDER:
1609       a=it1[2]-it2[2];
1610       if (a)
1611 	return a<=0?1:0;
1612     case _3VAR_ORDER:
1613       a=it1[1]-it2[1];
1614       if (a)
1615 	return a<=0?1:0;
1616       if (x.tdeg2!=y.tdeg2)
1617 	return x.tdeg2>y.tdeg2?1:0;
1618       it1beg=it1+(x.order_.o+degratiom1)/degratio;
1619       it1 += (x.order_.dim+degratiom1)/degratio;;
1620       it2 += (x.order_.dim+degratiom1)/degratio;;
1621       for (;;){
1622 	a=*it1-*it2;
1623 	if (a)
1624 	  return a<=0?1:0;
1625 	--it2;--it1;
1626 	if (it1<=it1beg)
1627 	  return 2;
1628       }
1629     case _TDEG_ORDER: case _PLEX_ORDER: {
1630       const degtype * it1=(degtype *)(x.ui+1),*it1end=it1+x.order_.dim,*it2=(degtype *)(y.ui+1);
1631       for (;it1!=it1end;++it2,++it1){
1632 	if (*it1!=*it2)
1633 	  return *it1>=*it2?1:0;
1634       }
1635       return 2;
1636     }
1637     } // end swicth
1638     return -1;
1639   }
1640 
tdeg_t_greater(const tdeg_t64 & x,const tdeg_t64 & y,order_t order)1641   inline int tdeg_t_greater(const tdeg_t64 & x,const tdeg_t64 & y,order_t order){
1642     short X=x.tab[0];
1643     if (X!=y.tab[0]) return X>y.tab[0]?1:0; // since tdeg is tab[0] for plex
1644 #ifdef GIAC_64VARS
1645     if (X%2){
1646       if (x.tdeg2!=y.tdeg2) return x.tdeg2>y.tdeg2?1:0;
1647 #ifdef GIAC_ELIM
1648       if ( x.elim!=y.elim) return x.elim<y.elim?1:0;
1649 #endif
1650       //if (x.ui==y.ui) return 2;
1651 #if 1 && !defined BIGENDIAN && !defined GIAC_CHARDEGTYPE
1652       return tdeg_t_greater_dyn(x,y,order);
1653 #else // BIGENDIAN, GIAC_CHARDEGTYPE
1654       if (order.o>=_7VAR_ORDER || order.o==_3VAR_ORDER){
1655 	int n=(order.o+degratiom1)/degratio;
1656 	const longlong * it1beg=x.ui,*it1=x.ui+n,*it2=y.ui+n;
1657 	longlong a=0,b=0;
1658 #ifdef BIGENDIAN
1659 	for (;it1!=it1beg;--it2,--it1){
1660 	  a=*it1;
1661 	  b=*it2;
1662 	  if (a!=b)
1663 	    break;
1664 	}
1665 	if (a!=b){
1666 	  if ( ((a)&0xffff) != ((b)&0xffff) )
1667 	    return ((a)&0xffff) <= ((b)&0xffff)?1:0;
1668 	  if ( ((a>>16)&0xffff) != ((b>>16)&0xffff) )
1669 	    return ((a>>16)&0xffff) <= ((b>>16)&0xffff)?1:0;
1670 	  if ( ((a>>32)&0xffff) != ((b>>32)&0xffff) )
1671 	    return ((a>>32)&0xffff) <= ((b>>32)&0xffff)?1:0;
1672 	  return a <= b?1:0;
1673 	}
1674 #else
1675 	for (;it1!=it1beg;--it2,--it1){
1676 	  a=*it1-*it2;
1677 	  if (a)
1678 	    return a<=0?1:0;
1679 	}
1680 #endif
1681 	// if (x.tdeg2!=y.tdeg2) return x.tdeg2>=y.tdeg2;
1682 	it1beg=x.ui+n;
1683 	n=(x.order_.dim+degratiom1)/degratio;
1684 	it1=x.ui+n;
1685 	it2=y.ui+n;
1686 #ifdef BIGENDIAN
1687 	for (a=0,b=0;it1!=it1beg;--it2,--it1){
1688 	  a=*it1; b=*it2;
1689 	  if (a!=b)
1690 	    break;
1691 	}
1692 	if (a!=b){
1693 	  if ( ((a)&0xffff) != ((b)&0xffff) )
1694 	    return ((a)&0xffff) <= ((b)&0xffff)?1:0;
1695 	  if ( ((a>>16)&0xffff) != ((b>>16)&0xffff) )
1696 	    return ((a>>16)&0xffff) <= ((b>>16)&0xffff) ?1:0;
1697 	  if ( ((a>>32)&0xffff) != ((b>>32)&0xffff) )
1698 	    return ((a>>32)&0xffff) <= ((b>>32)&0xffff) ?1:0;
1699 	  return a <= b?1:0;
1700 	}
1701 #else
1702 	for (;it1!=it1beg;--it2,--it1){
1703 	  a=*it1-*it2;
1704 	  if (a)
1705 	    return a<=0?1:0;
1706 	}
1707 #endif
1708 	return 2;
1709       }
1710       if (order.o==_REVLEX_ORDER){
1711 	//if (x.tdeg!=y.tdeg) return x.tdeg>y.tdeg?1:0;
1712 	const longlong * it1beg=x.ui,*it1=x.ui+(x.order_.dim+degratiom1)/degratio,*it2=y.ui+(y.order_.dim+degratiom1)/degratio;
1713 	longlong a=0,b=0;
1714 #ifdef BIGENDIAN
1715 	for (;it1!=it1beg;--it2,--it1){
1716 	  a=*it1; b=*it2;
1717 	  if (a!=b)
1718 	    break;
1719 	}
1720 	if (a!=b){
1721 	  if ( ((a)&0xffff) != ((b)&0xffff) )
1722 	    return ((a)&0xffff) <= ((b)&0xffff)?1:0;
1723 	  if ( ((a>>16)&0xffff) != ((b>>16)&0xffff) )
1724 	    return ((a>>16)&0xffff) <= ((b>>16)&0xffff)?1:0;
1725 	  if ( ((a>>32)&0xffff) != ((b>>32)&0xffff) )
1726 	    return ((a>>32)&0xffff) <= ((b>>32)&0xffff)?1:0;
1727 	  return a <= b?1:0;
1728 	}
1729 #else
1730 	for (;it1!=it1beg;--it2,--it1){
1731 	  a=*it1-*it2;
1732 	  if (a)
1733 	    return a<=0?1:0;
1734 	}
1735 #endif
1736 	return 2;
1737       }
1738       // plex and tdeg share the same code since total degree already checked
1739       const degtype * it1=(degtype *)(x.ui+1),*it1end=it1+x.order_.dim,*it2=(degtype *)(y.ui+1);
1740       for (;it1!=it1end;++it2,++it1){
1741 	if (*it1!=*it2)
1742 	  return *it1>=*it2?1:0;
1743       }
1744       return 2;
1745 #endif // BIGENDIAN, GIAC_CHARDEGTYPE
1746     } // end if X%2
1747 #endif // GIAC_64VARS
1748     if (order.o==_REVLEX_ORDER)
1749       return tdeg_t64_revlex_greater(x,y);
1750 #if GROEBNER_VARS==15
1751     if (order.o==_3VAR_ORDER)
1752       return tdeg_t64_3var_greater(x,y);
1753     if (order.o==_7VAR_ORDER)
1754       return tdeg_t64_7var_greater(x,y);
1755     if (order.o==_11VAR_ORDER)
1756       return tdeg_t64_11var_greater(x,y);
1757 #endif
1758     return tdeg_t64_lex_greater(x,y);
1759   }
tdeg_t_strictly_greater(const tdeg_t64 & x,const tdeg_t64 & y,order_t order)1760   inline bool tdeg_t_strictly_greater (const tdeg_t64 & x,const tdeg_t64 & y,order_t order){
1761     return !tdeg_t_greater(y,x,order); // total order
1762   }
1763 
tdeg_t_all_greater(const tdeg_t64 & x,const tdeg_t64 & y,order_t order)1764   inline bool tdeg_t_all_greater(const tdeg_t64 & x,const tdeg_t64 & y,order_t order){
1765     if ((*((ulonglong*)&x)-*((ulonglong*)&y)) & 0x8000800080008000ULL)
1766       return false;
1767 #ifdef GIAC_64VARS
1768     if (x.tab[0]%2){
1769 #ifdef GIAC_ELIM
1770       //bool debug=false;
1771       if ( !( (x.elim | y.elim) & 0x1000000000000000ULL) &&
1772 #if 0 // ndef BESTA_OS // Keil compiler, for some reason does not like the 0b syntax!
1773 	   ( (x.elim-y.elim) & 0b1111100001000010000100001000010000100001000010000100001000010000ULL) )
1774 #else
1775 	( (x.elim-y.elim) & 0xf842108421084210ULL) )
1776 #endif
1777       {
1778 	//debug=true;
1779 	return false;
1780       }
1781 #endif
1782 #ifdef GIAC_DEBUG_TDEG_T64
1783       if (!(y.tab[0]%2))
1784 	COUT << "erreur" << '\n';
1785 #endif
1786 #ifdef GIAC_HASH
1787       if (x.hash<y.hash)
1788 	return false;
1789 #endif
1790 #if 0
1791       const degtype * it1=(degtype *)(x.ui+1),*it1end=it1+x.order_.dim,*it2=(degtype *)(y.ui+1);
1792       for (;it1!=it1end;++it2,++it1){
1793 	if (*it1<*it2)
1794 	  return false;
1795       }
1796 #else
1797       const longlong * it1=x.ui+1,*it1end=it1+(x.order_.dim+degratiom1)/degratio,*it2=y.ui+1;
1798 #ifndef GIAC_CHARDEGTYPE
1799       if ((*it1-*it2) & 0x8000800080008000ULL)
1800 	return false;
1801       ++it2; ++it1;
1802       if ((*it1-*it2) & 0x8000800080008000ULL)
1803 	return false;
1804       ++it2; ++it1;
1805       if ((*it1-*it2) & 0x8000800080008000ULL)
1806 	return false;
1807       ++it2; ++it1;
1808       if ((*it1-*it2) & 0x8000800080008000ULL)
1809 	return false;
1810       ++it2; ++it1;
1811 #endif
1812       for (;it1!=it1end;++it2,++it1){
1813 #ifdef GIAC_CHARDEGTYPE
1814 	if ((*it1-*it2) & 0x8080808080808080ULL)
1815 	  return false;
1816 #else
1817 	if ((*it1-*it2) & 0x8000800080008000ULL)
1818 	  return false;
1819 #endif
1820       }
1821 #endif
1822       // if (debug) CERR << x << " " << y << '\n' << x.elim << " " << y.elim << " " << x.tdeg << " " << y.tdeg << '\n';
1823       return true;
1824     }
1825 #endif
1826     ulonglong *xtab=(ulonglong *)&x,*ytab=(ulonglong *)&y;
1827   // if ((xtab[0]-ytab[0]) & 0x8000800080008000ULL) return false;
1828     if ((xtab[1]-ytab[1]) & 0x8000800080008000ULL)
1829       return false;
1830     if ((xtab[2]-ytab[2]) & 0x8000800080008000ULL)
1831       return false;
1832 #if GROEBNER_VARS>11
1833     if ((xtab[3]-ytab[3]) & 0x8000800080008000ULL)
1834       return false;
1835 #endif
1836     return true;
1837   }
1838 
1839   const longlong mask2=0x8080808080808080ULL;
1840 #ifdef GIAC_CHARDEGTYPE
1841     const longlong mask=0x8080808080808080ULL;
1842 #else
1843     const longlong mask=0x8000800080008000ULL;
1844 #endif
1845 
1846   // 1 (all greater), 0 (unknown), -1 (all smaller)
tdeg_t_compare_all(const tdeg_t64 & x,const tdeg_t64 & y,order_t order)1847   int tdeg_t_compare_all(const tdeg_t64 & x,const tdeg_t64 & y,order_t order){
1848 #ifdef GIAC_64VARS
1849     if (x.tab[0]%2){
1850 #ifdef GIAC_DEBUG_TDEG_T64
1851       if (!(y.tab[0]%2))
1852 	COUT << "erreur" << '\n';
1853 #endif
1854       if ( (x.tdeg<y.tdeg) ^ (x.tdeg2<y.tdeg2))
1855 	return 0;
1856       const longlong * it1=x.ui+1,*it1end=it1+(x.order_.dim+degratiom1)/degratio,*it2=y.ui+1;
1857       int res=0;
1858       for (;it1!=it1end;++it2,++it1){
1859 	longlong tmp=*it1-*it2;
1860 	if (tmp & mask){
1861 	  if (res==1 || ((-tmp) & mask)) return 0;
1862 	  res=-1;
1863 	}
1864 	else {
1865 	  if (res==-1) return 0; else res=1;
1866 	}
1867       }
1868       return res;
1869     }
1870 #endif // GIAC_64VARS
1871     int res=0;
1872     ulonglong *xtab=(ulonglong *)&x,*ytab=(ulonglong *)&y;
1873     longlong tmp=xtab[0]-ytab[0];
1874     if (tmp & mask){
1875       if (res==1 || ((-tmp) & mask)) return 0;
1876       res=-1;
1877     }
1878     else {
1879       if (res==-1) return 0; else res=1;
1880     }
1881     tmp=xtab[1]-ytab[1];
1882     if (tmp & mask){
1883       if (res==1 || ((-tmp) & mask)) return 0;
1884       res=-1;
1885     }
1886     else {
1887       if (res==-1) return 0; else res=1;
1888     }
1889     tmp=xtab[2]-ytab[2];
1890     if (tmp & mask){
1891       if (res==1 || ((-tmp) & mask)) return 0;
1892       res=-1;
1893     }
1894     else {
1895       if (res==-1) return 0; else res=1;
1896     }
1897 #if GROEBNER_VARS>11
1898     tmp=xtab[3]-ytab[3];
1899     if (tmp & mask){
1900       if (res==1 || ((-tmp) & mask)) return 0;
1901       res=-1;
1902     }
1903     else {
1904       if (res==-1) return 0; else res=1;
1905     }
1906 #endif
1907     return res;
1908   }
1909 
index_lcm(const tdeg_t64 & x,const tdeg_t64 & y,tdeg_t64 & z,order_t order)1910   void index_lcm(const tdeg_t64 & x,const tdeg_t64 & y,tdeg_t64 & z,order_t order){
1911 #ifdef GIAC_64VARS
1912     if (x.tdeg%2){
1913 #ifdef GIAC_DEBUG_TDEG_T64
1914       if (!(y.tab[0]%2))
1915 	COUT << "erreur" << '\n';
1916 #endif
1917       z=tdeg_t64();
1918       z.tdeg=1;
1919       z.order_=x.order_;
1920       z.ui=(longlong *)malloc((1+(x.order_.dim+degratiom1)/degratio)*sizeof(longlong));
1921       z.ui[0]=1;
1922       const degtype * xptr=(degtype *)(x.ui+1),*xend=xptr+degratio*((x.order_.dim+degratiom1)/degratio),*yptr=(degtype *)(y.ui+1);
1923       degtype * resptr=(degtype *)(z.ui+1);
1924       for (;xptr!=xend;++resptr,++yptr,++xptr)
1925 	*resptr=*xptr>*yptr?*xptr:*yptr;
1926       z.tdeg=1;
1927       z.compute_degs();
1928       return ;
1929     }
1930 #endif
1931     int t=0;
1932     const short * xtab=&x.tab[1],*ytab=&y.tab[1];
1933     short *ztab=&z.tab[1];
1934     t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 1
1935     ++xtab; ++ytab; ++ztab;
1936     t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 2
1937     ++xtab; ++ytab; ++ztab;
1938     t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 3
1939     ++xtab; ++ytab; ++ztab;
1940 #if GROEBNER_VARS==15
1941     if (order.o==_3VAR_ORDER){
1942 #ifdef GIAC_64VARS
1943       z.tab[0]=2*t;
1944 #else
1945       z.tab[0]=t;
1946 #endif
1947       t=0;
1948       ++xtab;++ytab;++ztab;
1949       t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 5
1950       ++xtab; ++ytab; ++ztab;
1951       t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 6
1952       ++xtab; ++ytab; ++ztab;
1953       t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 7
1954       ++xtab; ++ytab; ++ztab;
1955       t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 8
1956       ++xtab; ++ytab; ++ztab;
1957       t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 9
1958       ++xtab; ++ytab; ++ztab;
1959       t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 10
1960       ++xtab; ++ytab; ++ztab;
1961       t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 11
1962       ++xtab; ++ytab; ++ztab;
1963       t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 12
1964       ++xtab; ++ytab; ++ztab;
1965       t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 13
1966       ++xtab; ++ytab; ++ztab;
1967       t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 14
1968       ++xtab; ++ytab; ++ztab;
1969       t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 15
1970       z.tab[4]=t; // 4
1971       return;
1972     }
1973 #endif
1974     t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 4
1975     ++xtab; ++ytab; ++ztab;
1976     t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 5
1977     ++xtab; ++ytab; ++ztab;
1978     t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 6
1979     ++xtab; ++ytab; ++ztab;
1980     t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 7
1981     ++xtab; ++ytab; ++ztab;
1982 #if GROEBNER_VARS==15
1983     if (order.o==_7VAR_ORDER){
1984 #ifdef GIAC_64VARS
1985       z.tab[0]=2*t;
1986 #else
1987       z.tab[0]=t;
1988 #endif
1989       t=0;
1990       ++xtab;++ytab;++ztab;
1991       t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 9
1992       ++xtab; ++ytab; ++ztab;
1993       t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 10
1994       ++xtab; ++ytab; ++ztab;
1995       t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 11
1996       ++xtab; ++ytab; ++ztab;
1997       t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 12
1998       ++xtab; ++ytab; ++ztab;
1999       t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 13
2000       ++xtab; ++ytab; ++ztab;
2001       t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 14
2002       ++xtab; ++ytab; ++ztab;
2003       t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 15
2004       z.tab[8]=t; // 8
2005       return;
2006     }
2007 #endif
2008     t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 8
2009     ++xtab; ++ytab; ++ztab;
2010     t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 9
2011     ++xtab; ++ytab; ++ztab;
2012     t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 10
2013     ++xtab; ++ytab; ++ztab;
2014     t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 11
2015 #if GROEBNER_VARS>11
2016     ++xtab; ++ytab; ++ztab;
2017 #if GROEBNER_VARS==15
2018     if (order.o==_11VAR_ORDER){
2019 #ifdef GIAC_64VARS
2020       z.tab[0]=2*t;
2021 #else
2022       z.tab[0]=t;
2023 #endif
2024       t=0;
2025       ++xtab; ++ytab; ++ztab;
2026       t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 13
2027       ++xtab; ++ytab; ++ztab;
2028       t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 14
2029       ++xtab; ++ytab; ++ztab;
2030       t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 15
2031       z.tab[12]=t; // 12
2032       return;
2033     }
2034 #endif
2035     t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 12
2036     ++xtab; ++ytab; ++ztab;
2037     t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 13
2038     ++xtab; ++ytab; ++ztab;
2039     t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 14
2040     ++xtab; ++ytab; ++ztab;
2041     t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 15
2042 #endif
2043     if (order.o==_REVLEX_ORDER || order.o==_TDEG_ORDER){
2044 #ifdef GIAC_64VARS
2045       z.tab[0]=2*t;
2046 #else
2047       z.tab[0]=t;
2048 #endif
2049     }
2050     else {
2051 #ifdef GIAC_64VARS
2052       z.tab[0]=2*((x.tab[0]>y.tab[0])?x.tab[0]:y.tab[0]);
2053 #else
2054       z.tab[0]=(x.tab[0]>y.tab[0])?x.tab[0]:y.tab[0];
2055 #endif
2056     }
2057   }
2058 
index_lcm_overwrite(const tdeg_t64 & x,const tdeg_t64 & y,tdeg_t64 & z,order_t order)2059   void index_lcm_overwrite(const tdeg_t64 & x,const tdeg_t64 & y,tdeg_t64 & z,order_t order){
2060     if (z.tdeg%2==0){
2061       index_lcm(x,y,z,order);
2062       return;
2063     }
2064     const degtype * xptr=(degtype *)(x.ui+1),*xend=xptr+degratio*((x.order_.dim+degratiom1)/degratio),*yptr=(degtype *)(y.ui+1);
2065     degtype * resptr=(degtype *)(z.ui+1);
2066     for (;xptr!=xend;++resptr,++yptr,++xptr)
2067       *resptr=*xptr>*yptr?*xptr:*yptr;
2068     z.tdeg=1;
2069     z.compute_degs();
2070   }
2071 
get_index(const tdeg_t64 & x_,index_t & idx,order_t order,int dim)2072   void get_index(const tdeg_t64 & x_,index_t & idx,order_t order,int dim){
2073 #ifdef GIAC_64VARS
2074     if (x_.tab[0]%2){
2075       idx.resize(dim);
2076       const degtype * ptr=(degtype *)(x_.ui+1),*ptrend=ptr+x_.order_.dim;
2077       index_t::iterator target=idx.begin();
2078       for (;ptr!=ptrend;++target,++ptr)
2079 	*target=*ptr;
2080       return;
2081     }
2082 #endif
2083     idx.resize(dim);
2084 #ifdef GBASIS_SWAP
2085     tdeg_t64 x(x_);
2086     swap_indices(x.tab);
2087 #else
2088     const tdeg_t64 & x= x_;
2089 #endif
2090     const short * ptr=x.tab;
2091 #if GROEBNER_VARS==15
2092     if (order.o==_3VAR_ORDER){
2093       ++ptr;
2094       for (int i=1;i<=3;++ptr,++i)
2095 	idx[3-i]=*ptr;
2096       ++ptr;
2097       for (int i=1;i<=dim-3;++ptr,++i)
2098 	idx[dim-i]=*ptr;
2099       return;
2100     }
2101     if (order.o==_7VAR_ORDER){
2102       ++ptr;
2103       for (int i=1;i<=7;++ptr,++i)
2104 	idx[7-i]=*ptr;
2105       ++ptr;
2106       for (int i=1;i<=dim-7;++ptr,++i)
2107 	idx[dim-i]=*ptr;
2108       return;
2109     }
2110     if (order.o==_11VAR_ORDER){
2111       ++ptr;
2112       for (int i=1;i<=11;++ptr,++i)
2113 	idx[11-i]=*ptr;
2114       ++ptr;
2115       for (int i=1;i<=dim-11;++ptr,++i)
2116 	idx[dim-i]=*ptr;
2117       return;
2118     }
2119 #endif
2120     if (order.o==_REVLEX_ORDER || order.o==_TDEG_ORDER)
2121       ++ptr;
2122     if (order.o==_REVLEX_ORDER){
2123       for (int i=1;i<=dim;++ptr,++i)
2124 	idx[dim-i]=*ptr;
2125     }
2126     else {
2127       for (int i=0;i<dim;++ptr,++i)
2128 	idx[i]=*ptr;
2129 #ifdef GIAC_64VARS
2130       idx[0]/=2;
2131 #endif
2132     }
2133   }
2134 
disjoint(const tdeg_t64 & a,const tdeg_t64 & b,order_t order,short dim)2135   bool disjoint(const tdeg_t64 & a,const tdeg_t64 & b,order_t order,short dim){
2136 #ifdef GIAC_64VARS
2137     if (a.tab[0]%2){
2138 #ifdef GIAC_DEBUG_TDEG_T64
2139       if (!(b.tab[0]%2))
2140 	COUT << "erreur" << '\n';
2141 #endif
2142       const degtype * xptr=(degtype *)(a.ui+1),*xend=xptr+dim,*yptr=(degtype *)(b.ui+1);
2143       for (;xptr!=xend;++yptr,++xptr){
2144 	if (*xptr && *yptr)
2145 	  return false;
2146       }
2147       return true;
2148     }
2149 #endif
2150 #if GROEBNER_VARS==15
2151     if (order.o==_3VAR_ORDER){
2152       if ( (a.tab[1] && b.tab[1]) ||
2153 	   (a.tab[2] && b.tab[2]) ||
2154 	   (a.tab[3] && b.tab[3]) ||
2155 	   (a.tab[5] && b.tab[5]) ||
2156 	   (a.tab[6] && b.tab[6]) ||
2157 	   (a.tab[7] && b.tab[7]) ||
2158 	   (a.tab[8] && b.tab[8]) ||
2159 	   (a.tab[9] && b.tab[9]) ||
2160 	   (a.tab[10] && b.tab[10]) ||
2161 	   (a.tab[11] && b.tab[11]) ||
2162 	   (a.tab[12] && b.tab[12]) ||
2163 	   (a.tab[13] && b.tab[13]) ||
2164 	   (a.tab[14] && b.tab[14]) ||
2165 	   (a.tab[15] && b.tab[15]) )
2166 	return false;
2167       return true;
2168     }
2169     if (order.o==_7VAR_ORDER){
2170       if ( (a.tab[1] && b.tab[1]) ||
2171 	   (a.tab[2] && b.tab[2]) ||
2172 	   (a.tab[3] && b.tab[3]) ||
2173 	   (a.tab[4] && b.tab[4]) ||
2174 	   (a.tab[5] && b.tab[5]) ||
2175 	   (a.tab[6] && b.tab[6]) ||
2176 	   (a.tab[7] && b.tab[7]) ||
2177 	   (a.tab[9] && b.tab[9]) ||
2178 	   (a.tab[10] && b.tab[10]) ||
2179 	   (a.tab[11] && b.tab[11]) ||
2180 	   (a.tab[12] && b.tab[12]) ||
2181 	   (a.tab[13] && b.tab[13]) ||
2182 	   (a.tab[14] && b.tab[14]) ||
2183 	   (a.tab[15] && b.tab[15]) )
2184 	return false;
2185       return true;
2186     }
2187     if (order.o==_11VAR_ORDER){
2188       if ( (a.tab[1] && b.tab[1]) ||
2189 	   (a.tab[2] && b.tab[2]) ||
2190 	   (a.tab[3] && b.tab[3]) ||
2191 	   (a.tab[4] && b.tab[4]) ||
2192 	   (a.tab[5] && b.tab[5]) ||
2193 	   (a.tab[6] && b.tab[6]) ||
2194 	   (a.tab[7] && b.tab[7]) ||
2195 	   (a.tab[8] && b.tab[8]) ||
2196 	   (a.tab[9] && b.tab[9]) ||
2197 	   (a.tab[10] && b.tab[10]) ||
2198 	   (a.tab[11] && b.tab[11]) ||
2199 	   (a.tab[13] && b.tab[13]) ||
2200 	   (a.tab[14] && b.tab[14]) ||
2201 	   (a.tab[15] && b.tab[15]))
2202 	return false;
2203       return true;
2204     }
2205 #endif
2206     const short * it=a.tab, * jt=b.tab;
2207 #ifdef GBASIS_SWAP
2208     const short * itend=it+GROEBNER_VARS+1;
2209 #endif
2210     if (order.o==_REVLEX_ORDER || order.o==_TDEG_ORDER){
2211       ++it; ++jt;
2212     }
2213 #ifndef GBASIS_SWAP
2214     const short * itend=it+dim;
2215 #endif
2216     for (;it<itend;++jt,++it){
2217       if (*it && *jt)
2218 	return false;
2219     }
2220     return true;
2221   }
2222 
2223   // polynomial are vector< T_unsigned<gen,tdeg_t> >
2224   template<class tdeg_t>
2225   struct poly8 {
2226     std::vector< T_unsigned<gen,tdeg_t> > coord;
2227     // lex order is implemented using tdeg_t as a list of degrees
2228     // tdeg uses total degree 1st then partial degree in lex order, max 7 vars
2229     // revlex uses total degree 1st then opposite of partial degree in reverse ordre, max 7 vars
2230     order_t order; // _PLEX_ORDER, _REVLEX_ORDER or _TDEG_ORDER or _7VAR_ORDER or _11VAR_ORDER
2231     short int dim;
2232     unsigned sugar;
2233     double logz; // unused, it's here for tripolymod_tri
2234     int age; // unused, it's here for tripolymod_tri
2235     void dbgprint() const;
poly8giac::poly82236     poly8():dim(0),sugar(0),logz(0),age(-1) {order.o=_PLEX_ORDER; order.lex=0; order.dim=0;}
poly8giac::poly82237     poly8(order_t o_,int dim_): order(o_),dim(dim_),sugar(0),logz(0),age(-1) {order.dim=dim_;}
poly8giac::poly82238     poly8(const polynome & p,order_t o_){
2239       order=o_;
2240       dim=p.dim;
2241       order.dim=p.dim;
2242       logz=0;
2243       age=-1;
2244       if (order.o%4!=3){
2245 	if (p.is_strictly_greater==i_lex_is_strictly_greater)
2246 	  order.o=_PLEX_ORDER;
2247 	if (p.is_strictly_greater==i_total_revlex_is_strictly_greater)
2248 	  order.o=_REVLEX_ORDER;
2249 	if (p.is_strictly_greater==i_total_lex_is_strictly_greater)
2250 	  order.o=_TDEG_ORDER;
2251       }
2252       if (
2253 #ifdef GIAC_64VARS
2254 	  0 &&
2255 #endif
2256 	  p.dim>GROEBNER_VARS)
2257 	CERR << "Number of variables is too large to be handled by giac";
2258       else {
2259 	coord.reserve(p.coord.size());
2260 	for (unsigned i=0;i<p.coord.size();++i){
2261 	  coord.push_back(T_unsigned<gen,tdeg_t>(p.coord[i].value,tdeg_t(p.coord[i].index,order)));
2262 	}
2263       }
2264       if (coord.empty())
2265 	sugar=0;
2266       else
2267 	sugar=coord.front().u.total_degree(order);
2268     }
get_polynomegiac::poly82269     void get_polynome(polynome & p) const {
2270       p.dim=dim;
2271       switch (order.o){
2272       case _REVLEX_ORDER:
2273 	p.is_strictly_greater=i_total_revlex_is_strictly_greater;
2274 	break;
2275       case _3VAR_ORDER:
2276 	p.is_strictly_greater=i_3var_is_strictly_greater;
2277 	break;
2278       case _7VAR_ORDER:
2279 	p.is_strictly_greater=i_7var_is_strictly_greater;
2280 	break;
2281       case _11VAR_ORDER:
2282 	p.is_strictly_greater=i_11var_is_strictly_greater;
2283 	break;
2284       case _TDEG_ORDER:
2285 	p.is_strictly_greater=i_total_lex_is_strictly_greater;
2286 	break;
2287       default:
2288       case _PLEX_ORDER:
2289 	p.is_strictly_greater=i_lex_is_strictly_greater;
2290 	break;
2291       }
2292       p.coord.clear();
2293       p.coord.reserve(coord.size());
2294       index_t idx(dim);
2295       for (unsigned i=0;i<coord.size();++i){
2296 	get_index(coord[i].u,idx,order,dim);
2297 	p.coord.push_back(monomial<gen>(coord[i].g,idx));
2298       }
2299       // if (order==_3VAR_ORDER || order==_7VAR_ORDER || order==_11VAR_ORDER) p.tsort();
2300     }
2301   };
2302   template<class tdeg_t>
operator ==(const poly8<tdeg_t> & p,const poly8<tdeg_t> & q)2303   bool operator == (const poly8<tdeg_t> & p,const poly8<tdeg_t> &q){
2304     if (p.coord.size()!=q.coord.size())
2305       return false;
2306     for (unsigned i=0;i<p.coord.size();++i){
2307       if (p.coord[i].u!=q.coord[i].u || p.coord[i].g!=q.coord[i].g)
2308 	return false;
2309     }
2310     return true;
2311   }
2312 
2313 #ifdef NSPIRE
operator <<(nio::ios_base<T> & os,const poly8<tdeg_t> & p)2314   template<class tdeg_t,class T> nio::ios_base<T> & operator << (nio::ios_base<T> & os, const poly8<tdeg_t> & p)
2315 #else
2316   template<class tdeg_t>
2317     ostream & operator << (ostream & os, const poly8<tdeg_t> & p)
2318 #endif
2319   {
2320     typename std::vector< T_unsigned<gen,tdeg_t> >::const_iterator it=p.coord.begin(),itend=p.coord.end();
2321     int t2;
2322     if (it==itend)
2323       return os << 0 ;
2324     for (;it!=itend;){
2325       os << it->g  ;
2326 #ifndef GBASIS_NO_OUTPUT
2327       if (it->u.vars64()){
2328 	if (it->u.tdeg%2){
2329 	  degtype * i=(degtype *)(it->u.ui+1);
2330 	  int s=it->u.order_.dim;
2331 	  for (int j=0;j<s;++j){
2332 	    t2=i[j];
2333 	    if (t2)
2334 	      os << "*x"<< j << "^" << t2  ;
2335 	  }
2336 	  ++it;
2337 	  if (it==itend)
2338 	    break;
2339 	  os << " + ";
2340 	  continue;
2341 	}
2342       }
2343 #endif
2344       short tab[GROEBNER_VARS+1];
2345       it->u.get_tab(tab,p.order);
2346       switch (p.order.o){
2347       case _PLEX_ORDER:
2348 	for (int i=0;i<=GROEBNER_VARS;++i){
2349 	  t2 = tab[i];
2350 	  if (t2)
2351 	    os << "*x"<< i << "^" << t2  ;
2352 	}
2353 	break;
2354       case _REVLEX_ORDER:
2355 	for (int i=1;i<=GROEBNER_VARS;++i){
2356 	  t2 = tab[i];
2357 	  if (t2==0)
2358 	    continue;
2359 	  os << "*x"<< p.dim-i;
2360 	  if (t2!=1)
2361 	    os << "^" << t2;
2362 	}
2363 	break;
2364 #if GROEBNER_VARS==15
2365       case _3VAR_ORDER:
2366 	for (int i=1;i<=3;++i){
2367 	  t2 = tab[i];
2368 	  if (t2==0)
2369 	    continue;
2370 	  os << "*x"<< 3-i;
2371 	  if (t2!=1)
2372 	    os << "^" << t2;
2373 	}
2374 	for (int i=5;i<=15;++i){
2375 	  t2 = tab[i];
2376 	  if (t2==0)
2377 	    continue;
2378 	  os << "*x"<< 7+p.dim-i;
2379 	  if (t2!=1)
2380 	    os << "^" << t2;
2381 	}
2382 	break;
2383       case _7VAR_ORDER:
2384 	for (int i=1;i<=7;++i){
2385 	  t2 = tab[i];
2386 	  if (t2==0)
2387 	    continue;
2388 	  os << "*x"<< 7-i;
2389 	  if (t2!=1)
2390 	    os << "^" << t2;
2391 	}
2392 	for (int i=9;i<=15;++i){
2393 	  t2 = tab[i];
2394 	  if (t2==0)
2395 	    continue;
2396 	  os << "*x"<< 11+p.dim-i;
2397 	  if (t2!=1)
2398 	    os << "^" << t2;
2399 	}
2400 	break;
2401       case _11VAR_ORDER:
2402 	for (int i=1;i<=11;++i){
2403 	  t2 = tab[i];
2404 	  if (t2==0)
2405 	    continue;
2406 	  os << "*x"<< 11-i;
2407 	  if (t2!=1)
2408 	    os << "^" << t2;
2409 	}
2410 	for (int i=13;i<=15;++i){
2411 	  t2 = tab[i];
2412 	  if (t2==0)
2413 	    continue;
2414 	  os << "*x"<< 15+p.dim-i;
2415 	  if (t2!=1)
2416 	    os << "^" << t2;
2417 	}
2418 	break;
2419 #endif
2420       case _TDEG_ORDER:
2421 	for (int i=1;i<=GROEBNER_VARS;++i){
2422 	  t2 = tab[i];
2423 	  if (t2==0)
2424 	    continue;
2425 	  if (t2)
2426 	    os << "*x"<< i-1 << "^" << t2  ;
2427 	}
2428 	break;
2429       }
2430       ++it;
2431       if (it==itend)
2432 	break;
2433       os << " + ";
2434     }
2435     return os;
2436   }
2437 
2438 
2439   template<class tdeg_t>
dbgprint() const2440   void poly8<tdeg_t>::dbgprint() const {
2441     CERR << *this << '\n';
2442   }
2443 
2444   template<class tdeg_t>
2445   class vectpoly8:public vector<poly8<tdeg_t> >{
2446   public:
dbgprint() const2447     void dbgprint() const { CERR << *this << '\n'; }
2448   };
2449 
2450   template<class tdeg_t>
vectpoly_2_vectpoly8(const vectpoly & v,order_t order,vectpoly8<tdeg_t> & v8)2451   void vectpoly_2_vectpoly8(const vectpoly & v,order_t order,vectpoly8<tdeg_t> & v8){
2452     v8.clear();
2453     v8.reserve(v.size()); if (debug_infolevel>1000){ v8.dbgprint(); v8[0].dbgprint();}
2454     for (unsigned i=0;i<v.size();++i){
2455       v8.push_back(poly8<tdeg_t>(v[i],order));
2456     }
2457   }
2458 
2459   template<class tdeg_t>
vectpoly8_2_vectpoly(const vectpoly8<tdeg_t> & v8,vectpoly & v)2460   void vectpoly8_2_vectpoly(const vectpoly8<tdeg_t> & v8,vectpoly & v){
2461     v.clear();
2462     v.reserve(v8.size());
2463     for (unsigned i=0;i<v8.size();++i){
2464       v.push_back(polynome(v8[i].dim));
2465       v8[i].get_polynome(v[i]);
2466     }
2467   }
2468 
2469   // Groebner basis code begins here
2470 
2471   template<class tdeg_t>
inplace_ppz(poly8<tdeg_t> & p,bool divide=true,bool quick=false)2472   gen inplace_ppz(poly8<tdeg_t> & p,bool divide=true,bool quick=false){
2473     typename vector< T_unsigned<gen,tdeg_t> >::iterator it=p.coord.begin(),itend=p.coord.end();
2474     if (it==itend)
2475       return 1;
2476     gen res=(itend-1)->g;
2477     for (;it!=itend;++it){
2478       if (it->g.type==_INT_){
2479 	res=it->g;
2480 	if (quick)
2481 	  return 1;
2482 	break;
2483       }
2484     }
2485     if (res.type==_ZINT)
2486       res=*res._ZINTptr; // realloc for inplace gcd
2487     for (it=p.coord.begin();it!=itend;++it){
2488       if (res.type==_ZINT && it->g.type==_ZINT){
2489 	mpz_gcd(*res._ZINTptr,*res._ZINTptr,*it->g._ZINTptr);
2490       }
2491       else
2492 	res=gcd(res,it->g);
2493       if (is_one(res))
2494 	return 1;
2495     }
2496     if (!divide)
2497       return res;
2498 #ifndef USE_GMP_REPLACEMENTS
2499     if (res.type==_INT_ && res.val>0){
2500       for (it=p.coord.begin();it!=itend;++it){
2501 	if (it->g.type!=_ZINT || it->g.ref_count()>1)
2502 	  it->g=it->g/res;
2503 	else
2504 	  mpz_divexact_ui(*it->g._ZINTptr,*it->g._ZINTptr,res.val);
2505       }
2506       return res;
2507     }
2508     if (res.type==_ZINT){
2509       for (it=p.coord.begin();it!=itend;++it){
2510 	if (it->g.type!=_ZINT || it->g.ref_count()>1)
2511 	  it->g=it->g/res;
2512 	else
2513 	  mpz_divexact(*it->g._ZINTptr,*it->g._ZINTptr,*res._ZINTptr);
2514       }
2515       return res;
2516     }
2517 #endif
2518     for (it=p.coord.begin();it!=itend;++it){
2519       it->g=it->g/res;
2520     }
2521     return res;
2522   }
2523 
2524   template<class tdeg_t>
inplace_mult(const gen & g,vector<T_unsigned<gen,tdeg_t>> & v)2525   void inplace_mult(const gen & g,vector< T_unsigned<gen,tdeg_t> > & v){
2526     typename std::vector< T_unsigned<gen,tdeg_t> >::iterator it1=v.begin(),it1end=v.end();
2527     for (;it1!=it1end;++it1){
2528 #if 0
2529       it1->g=g*(it1->g);
2530 #else
2531       type_operator_times(g,it1->g,it1->g);
2532 #endif
2533     }
2534   }
2535 
2536 #define GBASIS_HEAP
2537 #ifdef GBASIS_HEAP
2538   // heap: remove bitfields if that's not enough
2539   template<class tdeg_t>
2540   struct heap_t {
2541     unsigned i:16; // index in pairs of quotients/divisors
2542     unsigned qi:24;
2543     unsigned gj:24; // monomial index for quotient and divisor
2544     tdeg_t u; // product
2545   };
2546 
2547   // inline bool operator > (const heap_t & a,const heap_t & b){ return a.u>b.u; }
2548 
2549   // inline bool operator < (const heap_t & a,const heap_t & b){ return b>a; }
2550   template<class tdeg_t>
2551   struct heap_t_compare {
2552     order_t order;
2553     const heap_t<tdeg_t> * ptr;
operator ()giac::heap_t_compare2554     inline bool operator () (unsigned a,unsigned b){
2555       return !tdeg_t_greater((ptr+a)->u,(ptr+b)->u,order);
2556       // return (ptr+a)->u<(ptr+b)->u;
2557     }
heap_t_comparegiac::heap_t_compare2558     heap_t_compare(const vector<heap_t<tdeg_t> > & v,order_t o):order(o),ptr(v.empty()?0:&v.front()){};
2559   };
2560 
2561   template<class tdeg_t>
2562   struct compare_heap_t {
2563     order_t order;
operator ()giac::compare_heap_t2564     inline bool operator () (const heap_t<tdeg_t> & a,const heap_t<tdeg_t> & b){
2565       return !tdeg_t_greater(a.u,b.u,order);
2566       // return (ptr+a)->u<(ptr+b)->u;
2567     }
compare_heap_tgiac::compare_heap_t2568     compare_heap_t(order_t o):order(o) {}
2569   };
2570 
2571   template<class tdeg_t>
2572   struct heap_t_ptr {
2573     heap_t<tdeg_t> * ptr;
2574   };
2575 
2576   template<class tdeg_t>
heap_reduce(const poly8<tdeg_t> & f,const vectpoly8<tdeg_t> & g,const vector<unsigned> & G,unsigned excluded,vectpoly8<tdeg_t> & q,poly8<tdeg_t> & rem,poly8<tdeg_t> & R,gen & s,environment * env)2577   void heap_reduce(const poly8<tdeg_t> & f,const vectpoly8<tdeg_t> & g,const vector<unsigned> & G,unsigned excluded,vectpoly8<tdeg_t> & q,poly8<tdeg_t> & rem,poly8<tdeg_t>& R,gen & s,environment * env){
2578     // divides f by g[G[0]] to g[G[G.size()-1]] except maybe g[G[excluded]]
2579     // first implementation: use quotxsient heap for all quotient/divisor
2580     // do not use heap chain
2581     // ref Monaghan Pearce if g.size()==1
2582     // R is a temporary polynomial, should be different from f
2583     if (&rem==&f){
2584       R.dim=f.dim; R.order=f.order;
2585       heap_reduce(f,g,G,excluded,q,R,R,s,env);
2586       swap(rem.coord,R.coord);
2587       if (debug_infolevel>1000)
2588 	g.dbgprint(); // instantiate dbgprint()
2589       return;
2590     }
2591     rem.coord.clear();
2592     if (f.coord.empty())
2593       return ;
2594     if (q.size()<G.size())
2595       q.resize(G.size());
2596     unsigned guess=0;
2597     for (unsigned i=0;i<G.size();++i){
2598       q[i].dim=f.dim;
2599       q[i].order=f.order;
2600       q[i].coord.clear();
2601       guess += unsigned(g[G[i]].coord.size());
2602     }
2603     vector<heap_t<tdeg_t> > H;
2604     compare_heap_t<tdeg_t> key(f.order);
2605     H.reserve(guess);
2606     vecteur invlcg(G.size());
2607     if (env && env->moduloon){
2608       for (unsigned i=0;i<G.size();++i){
2609 	invlcg[i]=invmod(g[G[i]].coord.front().g,env->modulo);
2610       }
2611     }
2612     s=1;
2613     gen c,numer,denom;
2614     longlong C;
2615     unsigned k=0,i; // k=position in f
2616     tdeg_t m;
2617     bool finish=false;
2618     bool small0=env && env->moduloon && env->modulo.type==_INT_ && env->modulo.val;
2619     int p=env?env->modulo.val:0;
2620     while (!H.empty() || k<f.coord.size()){
2621       // is highest remaining degree in f or heap?
2622       if (k<f.coord.size() && (H.empty() || tdeg_t_greater(f.coord[k].u,H.front().u,f.order)) ){
2623 	// it's in f or both
2624 	m=f.coord[k].u;
2625 	if (small0)
2626 	  C=smod(f.coord[k].g,p).val;
2627 	else {
2628 	  if (s==1)
2629 	    c=f.coord[k].g;
2630 	  else
2631 	    c=s*f.coord[k].g;
2632 	}
2633 	++k;
2634       }
2635       else {
2636 	m=H.front().u;
2637 	c=0;
2638 	C=0;
2639       }
2640       // extract from heap all terms having m as monomials, substract from c
2641       while (!H.empty() && H.front().u==m){
2642 	std::pop_heap(H.begin(),H.end(),key);
2643 	heap_t<tdeg_t> & current=H.back(); // was root node of the heap
2644 	const poly8<tdeg_t> & gcurrent = g[G[current.i]];
2645 	if (small0)
2646 	  C -= longlong(q[current.i].coord[current.qi].g.val) * smod(gcurrent.coord[current.gj].g,p).val;
2647 	else {
2648 	  if (env && env->moduloon){
2649 	    c -= q[current.i].coord[current.qi].g * gcurrent.coord[current.gj].g;
2650 	  }
2651 	  else {
2652 	    fxnd(q[current.i].coord[current.qi].g,numer,denom);
2653 	    if (denom==s)
2654 	      c -= numer*gcurrent.coord[current.gj].g;
2655 	    else {
2656 	      if (denom==1)
2657 		c -= s*numer*gcurrent.coord[current.gj].g;
2658 	      else
2659 		c -= (s/denom)*numer*gcurrent.coord[current.gj].g;
2660 	    }
2661 	  }
2662 	}
2663 	if (current.gj<gcurrent.coord.size()-1){
2664 	  ++current.gj;
2665 	  current.u=q[current.i].coord[current.qi].u+gcurrent.coord[current.gj].u;
2666 	  push_heap(H.begin(),H.end(),key);
2667 	}
2668 	else
2669 	  H.pop_back();
2670       }
2671       if (small0){
2672 	C %= p;
2673 	if (C==0)
2674 	  continue;
2675 	c=C;
2676       }
2677       else {
2678 	if (env && env->moduloon)
2679 	  c=smod(c,env->modulo);
2680 	if (c==0)
2681 	  continue;
2682       }
2683       // divide (c,m) by one of the g if possible, otherwise push in remainder
2684       if (finish)
2685 	i=unsigned(G.size());
2686       else {
2687 	finish=true;
2688 	for (i=0;i<G.size();++i){
2689 	  if (i==excluded || g[G[i]].coord.empty())
2690 	    continue;
2691 	  if (tdeg_t_greater(m,g[G[i]].coord.front().u,f.order)){
2692 	    finish=false;
2693 	    if (tdeg_t_all_greater(m,g[G[i]].coord.front().u,f.order))
2694 	      break;
2695 	  }
2696 	}
2697       }
2698       if (i==G.size()){
2699 	if (s==1)
2700 	  rem.coord.push_back(T_unsigned<gen,tdeg_t>(c,m)); // add c/s*m to remainder
2701 	else {
2702 	  //rem.coord.push_back(T_unsigned<gen,tdeg_t>(c/s,m)); // add c/s*m to remainder
2703 	  rem.coord.push_back(T_unsigned<gen,tdeg_t>(Tfraction<gen>(c,s),m)); // add c/s*m to remainder
2704 	}
2705 	continue;
2706       }
2707       // add c/s*m/leading monomial of g[G[i]] to q[i]
2708       tdeg_t monom=m-g[G[i]].coord.front().u;
2709       if (env && env->moduloon){
2710 	if (invlcg[i]!=1){
2711 	  if (invlcg[i]==-1)
2712 	    c=-c;
2713 	  else
2714 	    c=smod(c*invlcg[i],env->modulo);
2715 	}
2716 	q[i].coord.push_back(T_unsigned<gen,tdeg_t>(c,monom));
2717       }
2718       else {
2719 	gen lcg=g[G[i]].coord.front().g;
2720 	gen pgcd=simplify3(lcg,c);
2721 	if (is_positive(-lcg,context0)){
2722 	  lcg=-lcg;
2723 	  c=-c;
2724 	}
2725 	s=s*lcg;
2726 	if (s==1)
2727 	  q[i].coord.push_back(T_unsigned<gen,tdeg_t>(c,monom));
2728 	else
2729 	  q[i].coord.push_back(T_unsigned<gen,tdeg_t>(Tfraction<gen>(c,s),monom));
2730       }
2731       // push in heap
2732       if (g[G[i]].coord.size()>1){
2733 	heap_t<tdeg_t> current={i,int(q[i].coord.size())-1,1,g[G[i]].coord[1].u+monom};
2734 	H.push_back(current);
2735 	push_heap(H.begin(),H.end(),key);
2736       }
2737     } // end main heap pseudo-division loop
2738   }
2739 
2740   template<class tdeg_t>
heap_reduce(const poly8<tdeg_t> & f,const vectpoly8<tdeg_t> & g,const vector<unsigned> & G,unsigned excluded,vectpoly8<tdeg_t> & q,poly8<tdeg_t> & rem,poly8<tdeg_t> & TMP1,environment * env)2741   void heap_reduce(const poly8<tdeg_t> & f,const vectpoly8<tdeg_t> & g,const vector<unsigned> & G,unsigned excluded,vectpoly8<tdeg_t> & q,poly8<tdeg_t> & rem,poly8<tdeg_t>& TMP1,environment * env){
2742     gen s;
2743     if (debug_infolevel>2)
2744       CERR << f << " = " << '\n';
2745     heap_reduce(f,g,G,excluded,q,rem,TMP1,s,env);
2746     // end up by multiplying rem by s (so that everything is integer)
2747     if (debug_infolevel>2){
2748       for (unsigned i=0;i<G.size();++i)
2749 	CERR << "(" << g[G[i]]<< ")*(" << q[i] << ")+ ";
2750       CERR << rem << '\n';
2751     }
2752     if (env && env->moduloon){
2753       if (!rem.coord.empty() && rem.coord.front().g!=1)
2754 	smallmult(invmod(rem.coord.front().g,env->modulo),rem.coord,rem.coord,env->modulo.val);
2755       return;
2756     }
2757     if (s!=1)
2758       smallmult(s,rem.coord,rem.coord);
2759     gen tmp=inplace_ppz(rem);
2760     if (debug_infolevel>1)
2761       CERR << "ppz was " << tmp << '\n';
2762   }
2763 
2764 #endif // GBASIS_HEAP
2765 
2766 
2767   template<class tdeg_t>
smallmult(const gen & a,poly8<tdeg_t> & p,gen & m)2768   void smallmult(const gen & a,poly8<tdeg_t> & p,gen & m){
2769     typename std::vector< T_unsigned<gen,tdeg_t> >::iterator pt=p.coord.begin(),ptend=p.coord.end();
2770     if (a.type==_INT_ && m.type==_INT_){
2771       for (;pt!=ptend;++pt){
2772 	if (pt->g.type==_INT_)
2773 	  pt->g=(longlong(pt->g.val)*a.val)%m.val;
2774 	else
2775 	  pt->g=smod(a*pt->g,m);
2776       }
2777     }
2778     else {
2779       for (;pt!=ptend;++pt){
2780 	pt->g=smod(a*pt->g,m);
2781       }
2782     }
2783   }
2784 
2785   // p - a*q shifted mod m -> r
2786   template<class tdeg_t>
smallmultsub(const poly8<tdeg_t> & p,unsigned pos,int a,const poly8<tdeg_t> & q,const tdeg_t & shift,poly8<tdeg_t> & r,int m)2787   void smallmultsub(const poly8<tdeg_t> & p,unsigned pos,int a,const poly8<tdeg_t> & q,const tdeg_t & shift,poly8<tdeg_t> & r,int m){
2788     r.coord.clear();
2789     r.coord.reserve(p.coord.size()+q.coord.size());
2790     typename vector< T_unsigned<gen,tdeg_t> >::const_iterator it=p.coord.begin()+pos,itend=p.coord.end(),jt=q.coord.begin(),jtend=q.coord.end();
2791     for (;jt!=jtend;++jt){
2792       tdeg_t v=jt->u+shift;
2793       for (;it!=itend && tdeg_t_strictly_greater(it->u,v,p.order);++it){
2794 	r.coord.push_back(*it);
2795       }
2796       if (it!=itend && it->u==v){
2797 	if (it->g.type==_INT_ && jt->g.type==_INT_){
2798 	  int tmp=(it->g.val-longlong(a)*jt->g.val)%m;
2799 	  if (tmp)
2800 	    r.coord.push_back(T_unsigned<gen,tdeg_t>(tmp,v));
2801 	}
2802 	else
2803 	  r.coord.push_back(T_unsigned<gen,tdeg_t>(smod(it->g-a*jt->g,m),v));
2804 	++it;
2805       }
2806       else {
2807 	if (jt->g.type==_INT_){
2808 	  int tmp=(-longlong(a)*jt->g.val)%m;
2809 	  r.coord.push_back(T_unsigned<gen,tdeg_t>(tmp,v));
2810 	}
2811 	else
2812 	  r.coord.push_back(T_unsigned<gen,tdeg_t>(smod(-a*jt->g,m),v));
2813       }
2814     }
2815     for (;it!=itend;++it){
2816       r.coord.push_back(*it);
2817     }
2818   }
2819 
2820   // a and b are assumed to be _ZINT
2821   template<class tdeg_t>
linear_combination(const gen & a,const poly8<tdeg_t> & p,tdeg_t * ashift,const gen & b,const poly8<tdeg_t> & q,tdeg_t * bshift,poly8<tdeg_t> & r,environment * env)2822   void linear_combination(const gen & a,const poly8<tdeg_t> &p,tdeg_t * ashift,const gen &b,const poly8<tdeg_t> & q,tdeg_t * bshift,poly8<tdeg_t> & r,environment * env){
2823     r.coord.clear();
2824     typename std::vector< T_unsigned<gen,tdeg_t> >::const_iterator it=p.coord.begin(),itend=p.coord.end(),jt=q.coord.begin(),jtend=q.coord.end();
2825     r.coord.reserve((itend-it)+(jtend-jt));
2826     mpz_t tmpz;
2827     mpz_init(tmpz);
2828     if (jt!=jtend){
2829       tdeg_t v=jt->u;
2830       if (bshift)
2831 	v=v+*bshift;
2832       for (;it!=itend;){
2833 	tdeg_t u=it->u;
2834 	if (ashift)
2835 	  u=u+*ashift;
2836 	if (u==v){
2837 	  gen g;
2838 #ifndef USE_GMP_REPLACEMENTS
2839 	  if ( (it->g.type==_INT_ || it->g.type==_ZINT) &&
2840 	       (jt->g.type==_INT_ || jt->g.type==_ZINT) ){
2841 	    if (it->g.type==_INT_)
2842 	      mpz_mul_si(tmpz,*a._ZINTptr,it->g.val);
2843 	    else
2844 	      mpz_mul(tmpz,*a._ZINTptr,*it->g._ZINTptr);
2845 	    if (jt->g.type==_INT_){
2846 	      if (jt->g.val>=0)
2847 		mpz_addmul_ui(tmpz,*b._ZINTptr,jt->g.val);
2848 	      else
2849 		mpz_submul_ui(tmpz,*b._ZINTptr,-jt->g.val);
2850 	    }
2851 	    else
2852 	      mpz_addmul(tmpz,*b._ZINTptr,*jt->g._ZINTptr);
2853 	    if (mpz_sizeinbase(tmpz,2)<31)
2854 	      g=int(mpz_get_si(tmpz));
2855 	    else {
2856 	      ref_mpz_t * ptr =new ref_mpz_t;
2857 	      mpz_swap(ptr->z,tmpz);
2858 	      g=ptr; // g=tmpz;
2859 	    }
2860 	  }
2861 	  else
2862 #endif
2863 	    g=a*it->g+b*jt->g;
2864 	  if (env && env->moduloon)
2865 	    g=smod(g,env->modulo);
2866 	  if (!is_zero(g))
2867 	    r.coord.push_back(T_unsigned<gen,tdeg_t>(g,u));
2868 	  ++it; ++jt;
2869 	  if (jt==jtend)
2870 	    break;
2871 	  v=jt->u;
2872 	  if (bshift)
2873 	    v=v+*bshift;
2874 	  continue;
2875 	}
2876 	if (tdeg_t_strictly_greater(u,v,p.order)){
2877 	  gen g=a*it->g;
2878 	  if (env && env->moduloon)
2879 	    g=smod(g,env->modulo);
2880 	  r.coord.push_back(T_unsigned<gen,tdeg_t>(g,u));
2881 	  ++it;
2882 	}
2883 	else {
2884 	  gen g=b*jt->g;
2885 	  if (env && env->moduloon)
2886 	    g=smod(g,env->modulo);
2887 	  r.coord.push_back(T_unsigned<gen,tdeg_t>(g,v));
2888 	  ++jt;
2889 	  if (jt==jtend)
2890 	    break;
2891 	  v=jt->u;
2892 	  if (bshift)
2893 	    v=v+*bshift;
2894 	}
2895       }
2896     }
2897     for (;it!=itend;++it){
2898       tdeg_t u=it->u;
2899       if (ashift)
2900 	u=u+*ashift;
2901       gen g=a*it->g;
2902       if (env && env->moduloon)
2903 	g=smod(g,env->modulo);
2904       r.coord.push_back(T_unsigned<gen,tdeg_t>(g,u));
2905     }
2906     for (;jt!=jtend;++jt){
2907       tdeg_t v=jt->u;
2908       if (bshift)
2909 	v=v+*bshift;
2910       gen g=b*jt->g;
2911       if (env && env->moduloon)
2912 	g=smod(g,env->modulo);
2913       r.coord.push_back(T_unsigned<gen,tdeg_t>(g,v));
2914     }
2915     mpz_clear(tmpz);
2916   }
2917 
2918   // check that &v1!=&v and &v2!=&v
2919   template<class tdeg_t>
sub(const poly8<tdeg_t> & v1,const poly8<tdeg_t> & v2,poly8<tdeg_t> & v,environment * env)2920   void sub(const poly8<tdeg_t> & v1,const poly8<tdeg_t> & v2,poly8<tdeg_t> & v,environment * env){
2921     typename std::vector< T_unsigned<gen,tdeg_t> >::const_iterator it1=v1.coord.begin(),it1end=v1.coord.end(),it2=v2.coord.begin(),it2end=v2.coord.end();
2922     gen g;
2923     v.coord.clear();
2924     v.coord.reserve((it1end-it1)+(it2end-it2)); // worst case
2925     for (;it1!=it1end && it2!=it2end;){
2926       if (it1->u==it2->u){
2927 	g=it1->g-it2->g;
2928 	if (env && env->moduloon)
2929 	  g=smod(g,env->modulo);
2930 	if (!is_zero(g))
2931 	  v.coord.push_back(T_unsigned<gen,tdeg_t>(g,it1->u));
2932 	++it1;
2933 	++it2;
2934       }
2935       else {
2936 	if (tdeg_t_strictly_greater(it1->u,it2->u,v1.order)){
2937 	  v.coord.push_back(*it1);
2938 	  ++it1;
2939 	}
2940 	else {
2941 	  v.coord.push_back(T_unsigned<gen,tdeg_t>(-it2->g,it2->u));
2942 	  ++it2;
2943 	}
2944       }
2945     }
2946     for (;it1!=it1end;++it1)
2947       v.coord.push_back(*it1);
2948     for (;it2!=it2end;++it2)
2949       v.coord.push_back(T_unsigned<gen,tdeg_t>(-it2->g,it2->u));
2950   }
2951 
2952   template<class tdeg_t>
reduce(const poly8<tdeg_t> & p,const vectpoly8<tdeg_t> & res,const vector<unsigned> & G,unsigned excluded,vectpoly8<tdeg_t> & quo,poly8<tdeg_t> & rem,poly8<tdeg_t> & TMP1,poly8<tdeg_t> & TMP2,gen & lambda,environment * env,vector<bool> * Gusedptr=0)2953   void reduce(const poly8<tdeg_t> & p,const vectpoly8<tdeg_t> & res,const vector<unsigned> & G,unsigned excluded,vectpoly8<tdeg_t> & quo,poly8<tdeg_t> & rem,poly8<tdeg_t> & TMP1, poly8<tdeg_t> & TMP2,gen & lambda,environment * env,vector<bool> * Gusedptr=0){
2954     lambda=1;
2955     // last chance of improving = modular method for reduce or modular algo
2956     if (&p!=&rem)
2957       rem=p;
2958     if (p.coord.empty())
2959       return ;
2960     typename std::vector< T_unsigned<gen,tdeg_t> >::const_iterator pt,ptend;
2961     unsigned i,rempos=0;
2962     bool small0=env && env->moduloon && env->modulo.type==_INT_ && env->modulo.val;
2963     TMP1.order=p.order; TMP1.dim=p.dim; TMP2.order=p.order; TMP2.dim=p.dim; TMP1.coord.clear();
2964     for (unsigned count=0;;++count){
2965       ptend=rem.coord.end();
2966       // this branch search first in all leading coeff of G for a monomial
2967       // <= to the current rem monomial
2968       pt=rem.coord.begin()+rempos;
2969       if (pt>=ptend)
2970 	break;
2971       for (i=0;i<G.size();++i){
2972 	if (i==excluded || res[G[i]].coord.empty())
2973 	  continue;
2974 	if (tdeg_t_all_greater(pt->u,res[G[i]].coord.front().u,p.order))
2975 	  break;
2976       }
2977       if (i==G.size()){ // no leading coeff of G is smaller than the current coeff of rem
2978 	++rempos;
2979 	// if (small0) TMP1.coord.push_back(*pt);
2980 	continue;
2981       }
2982       if (Gusedptr)
2983 	(*Gusedptr)[i]=true;
2984       gen a(pt->g),b(res[G[i]].coord.front().g);
2985       if (small0){
2986 	smallmultsub(rem,0,smod(a*invmod(b,env->modulo),env->modulo).val,res[G[i]],pt->u-res[G[i]].coord.front().u,TMP2,env->modulo.val);
2987 	// smallmultsub(rem,rempos,smod(a*invmod(b,env->modulo),env->modulo).val,res[G[i]],pt->u-res[G[i]].coord.front().u,TMP2,env->modulo.val);
2988 	// rempos=0; // since we have removed the beginning of rem (copied in TMP1)
2989 	swap(rem.coord,TMP2.coord);
2990 	continue;
2991       }
2992       TMP1.coord.clear();
2993       TMP2.coord.clear();
2994       tdeg_t resshift=pt->u-res[G[i]].coord.front().u;
2995       if (env && env->moduloon){
2996 	gen ab=a;
2997 	if (b!=1)
2998 	  ab=a*invmod(b,env->modulo);
2999 	ab=smod(ab,env->modulo);
3000 	smallshift(res[G[i]].coord,resshift,TMP1.coord);
3001 	if (ab!=1)
3002 	  smallmult(ab,TMP1,env->modulo);
3003 	sub(rem,TMP1,TMP2,env);
3004       }
3005       else {
3006 	// -b*rem+a*shift(res[G[i]])
3007 	simplify(a,b);
3008 	if (b==-1){
3009 	  b=-b;
3010 	  a=-a;
3011 	}
3012 	gen c=-b;
3013 	if (a.type==_ZINT && c.type==_ZINT && !is_one(a) && !is_one(b)){
3014 	  linear_combination<tdeg_t>(c,rem,0,a,res[G[i]],&resshift,TMP2,0);
3015 	  lambda=c*lambda;
3016 	}
3017 	else {
3018 	  smallshift(res[G[i]].coord,resshift,TMP1.coord);
3019 	  if (!is_one(a))
3020 	    inplace_mult(a,TMP1.coord);
3021 	  if (!is_one(b)){
3022 	    inplace_mult(b,rem.coord);
3023 	    lambda=b*lambda;
3024 	  }
3025 	  sub(rem,TMP1,TMP2,0);
3026 	}
3027 	//if (count % 6==5) inplace_ppz(TMP2,true,true); // quick gcd check
3028       }
3029       swap(rem.coord,TMP2.coord);
3030     }
3031     if (env && env->moduloon){
3032       // if (small0) swap(rem.coord,TMP1.coord);
3033       if (!rem.coord.empty() && rem.coord.front().g!=1)
3034 	smallmult(invmod(rem.coord.front().g,env->modulo),rem.coord,rem.coord,env->modulo.val);
3035       return;
3036     }
3037     gen g=inplace_ppz(rem);
3038     lambda=lambda/g;
3039     if (debug_infolevel>2){
3040       if (rem.coord.empty())
3041 	CERR << "0 reduction" << '\n';
3042       if (g.type==_ZINT && mpz_sizeinbase(*g._ZINTptr,2)>16)
3043 	CERR << "ppz size was " << mpz_sizeinbase(*g._ZINTptr,2) << '\n';
3044     }
3045   }
3046 
3047   template<class tdeg_t>
reduce(const poly8<tdeg_t> & p,const vectpoly8<tdeg_t> & res,const vector<unsigned> & G,unsigned excluded,vectpoly8<tdeg_t> & quo,poly8<tdeg_t> & rem,poly8<tdeg_t> & TMP1,poly8<tdeg_t> & TMP2,environment * env,vector<bool> * Gusedptr=0)3048   void reduce(const poly8<tdeg_t> & p,const vectpoly8<tdeg_t> & res,const vector<unsigned> & G,unsigned excluded,vectpoly8<tdeg_t> & quo,poly8<tdeg_t> & rem,poly8<tdeg_t> & TMP1, poly8<tdeg_t> & TMP2,environment * env,vector<bool> * Gusedptr=0){
3049     gen lambda;
3050     reduce(p,res,G,excluded,quo,rem,TMP1,TMP2,lambda,env,Gusedptr);
3051   }
3052 
3053   template<class tdeg_t>
reduce1small(poly8<tdeg_t> & p,const poly8<tdeg_t> & q,poly8<tdeg_t> & TMP1,poly8<tdeg_t> & TMP2,environment * env)3054   void reduce1small(poly8<tdeg_t> & p,const poly8<tdeg_t> & q,poly8<tdeg_t> & TMP1, poly8<tdeg_t> & TMP2,environment * env){
3055     if (p.coord.empty())
3056       return ;
3057     typename std::vector< T_unsigned<gen,tdeg_t> >::const_iterator pt,ptend;
3058     unsigned rempos=0;
3059     TMP1.coord.clear();
3060     const tdeg_t & u = q.coord.front().u;
3061     const gen g=q.coord.front().g;
3062     for (unsigned count=0;;++count){
3063       ptend=p.coord.end();
3064       // this branch search first in all leading coeff of G for a monomial
3065       // <= to the current rem monomial
3066       pt=p.coord.begin()+rempos;
3067       if (pt>=ptend)
3068 	break;
3069       if (!tdeg_t_all_greater(pt->u,u,p.order)){
3070 	++rempos;
3071 	// TMP1.coord.push_back(*pt);
3072 	continue;
3073       }
3074       smallmultsub(p,0,smod(pt->g*invmod(g,env->modulo),env->modulo).val,q,pt->u-u,TMP2,env->modulo.val);
3075       // smallmultsub(p,rempos,smod(a*invmod(b,env->modulo),env->modulo).val,q,pt->u-u,TMP2,env->modulo.val);
3076       // rempos=0; // since we have removed the beginning of rem (copied in TMP1)
3077       swap(p.coord,TMP2.coord);
3078     }
3079     // if (small0) swap(p.coord,TMP1.coord);
3080     if (env && env->moduloon && !p.coord.empty() && p.coord.front().g!=1)
3081       smallmult(invmod(p.coord.front().g,env->modulo),p.coord,p.coord,env->modulo.val);
3082   }
3083 
3084   // reduce with respect to itself the elements of res with index in G
3085   template<class tdeg_t>
reduce(vectpoly8<tdeg_t> & res,vector<unsigned> G,environment * env)3086   void reduce(vectpoly8<tdeg_t> & res,vector<unsigned> G,environment * env){
3087     if (res.empty() || G.empty())
3088       return;
3089     poly8<tdeg_t> pred(res.front().order,res.front().dim),
3090       TMP1(res.front().order,res.front().dim),
3091       TMP2(res.front().order,res.front().dim);
3092     vectpoly8<tdeg_t> q;
3093     // reduce res
3094     for (unsigned i=0;i<G.size();++i){
3095 #ifdef TIMEOUT
3096       control_c();
3097 #endif
3098       if (interrupted || ctrl_c)
3099 	return;
3100       poly8<tdeg_t> & p=res[i];
3101       reduce(p,res,G,i,q,pred,TMP1,TMP2,env);
3102       swap(res[i].coord,pred.coord);
3103       pred.sugar=res[i].sugar;
3104     }
3105   }
3106 
3107   template<class tdeg_t>
spoly(const poly8<tdeg_t> & p,const poly8<tdeg_t> & q,poly8<tdeg_t> & res,poly8<tdeg_t> & TMP1,environment * env)3108   void spoly(const poly8<tdeg_t> & p,const poly8<tdeg_t> & q,poly8<tdeg_t> & res,poly8<tdeg_t> & TMP1, environment * env){
3109     if (p.coord.empty()){
3110       res=q;
3111       return ;
3112     }
3113     if (q.coord.empty()){
3114       res= p;
3115       return;
3116     }
3117     const tdeg_t & pi = p.coord.front().u;
3118     const tdeg_t & qi = q.coord.front().u;
3119     tdeg_t lcm;
3120     index_lcm(pi,qi,lcm,p.order);
3121     tdeg_t pshift=lcm-pi;
3122     unsigned sugarshift=pshift.total_degree(p.order);
3123     // adjust sugar for res
3124     res.sugar=p.sugar+sugarshift;
3125     // CERR << "spoly " << res.sugar << " " << pi << qi << '\n';
3126     gen a=p.coord.front().g,b=q.coord.front().g;
3127     simplify3(a,b);
3128     if (debug_infolevel>2)
3129       CERR << "spoly " << a << " " << b << '\n';
3130     if (a.type==_ZINT && b.type==_ZINT){
3131       tdeg_t u=lcm-pi,v=lcm-qi;
3132       linear_combination(b,p,&u,a,q,&v,res,env);
3133     }
3134     else {
3135       poly8<tdeg_t> tmp1(p),tmp2(q);
3136       smallshift(tmp1.coord,lcm-pi,tmp1.coord);
3137       smallmult(b,tmp1.coord,tmp1.coord);
3138       smallshift(tmp2.coord,lcm-qi,tmp2.coord);
3139       smallmult(a,tmp2.coord,tmp2.coord);
3140       sub(tmp1,tmp2,res,env);
3141     }
3142     a=inplace_ppz(res);
3143     if (debug_infolevel>2)
3144       CERR << "spoly ppz " << a << '\n';
3145   }
3146 
3147   template<class tdeg_t>
gbasis_update(vector<unsigned> & G,vector<paire> & B,vectpoly8<tdeg_t> & res,unsigned pos,poly8<tdeg_t> & TMP1,poly8<tdeg_t> & TMP2,vectpoly8<tdeg_t> & vtmp,environment * env)3148   void gbasis_update(vector<unsigned> & G,vector< paire > & B,vectpoly8<tdeg_t> & res,unsigned pos,poly8<tdeg_t> & TMP1,poly8<tdeg_t> & TMP2,vectpoly8<tdeg_t> & vtmp,environment * env){
3149     if (debug_infolevel>1)
3150       CERR << CLOCK()*1e-6 << " begin gbasis update " << '\n';
3151     const poly8<tdeg_t> & h = res[pos];
3152     order_t order=h.order;
3153     vector<unsigned> C;
3154     C.reserve(G.size());
3155     const tdeg_t & h0=h.coord.front().u;
3156     tdeg_t tmp1,tmp2;
3157     // C is used to construct new pairs
3158     // create pairs with h and elements g of G, then remove
3159     // -> if g leading monomial is prime with h, remove the pair
3160     // -> if g leading monomial is not disjoint from h leading monomial
3161     //    keep it only if lcm of leading monomial is not divisible by another one
3162     for (unsigned i=0;i<G.size();++i){
3163 #ifdef TIMEOUT
3164       control_c();
3165 #endif
3166       if (interrupted || ctrl_c)
3167 	return;
3168       if (res[G[i]].coord.empty() || disjoint(h0,res[G[i]].coord.front().u,res.front().order,res.front().dim))
3169 	continue;
3170       index_lcm(h0,res[G[i]].coord.front().u,tmp1,order); // h0 and G[i] leading monomial not prime together
3171       unsigned j;
3172       for (j=0;j<G.size();++j){
3173 #ifdef TIMEOUT
3174 	control_c();
3175 #endif
3176 	if (interrupted || ctrl_c)
3177 	  return;
3178 	if (i==j || res[G[j]].coord.empty())
3179 	  continue;
3180 	index_lcm(h0,res[G[j]].coord.front().u,tmp2,order);
3181 	if (tdeg_t_all_greater(tmp1,tmp2,order)){
3182 	  // found another pair, keep the smallest, or the first if equal
3183 	  if (tmp1!=tmp2)
3184 	    break;
3185 	  if (i>j)
3186 	    break;
3187 	}
3188       } // end for j
3189       if (j==G.size())
3190 	C.push_back(G[i]);
3191     }
3192     vector< paire > B1;
3193     B1.reserve(B.size()+C.size());
3194     for (unsigned i=0;i<B.size();++i){
3195 #ifdef TIMEOUT
3196       control_c();
3197 #endif
3198       if (interrupted || ctrl_c)
3199 	return;
3200       if (res[B[i].first].coord.empty() || res[B[i].second].coord.empty())
3201 	continue;
3202       index_lcm(res[B[i].first].coord.front().u,res[B[i].second].coord.front().u,tmp1,order);
3203       if (!tdeg_t_all_greater(tmp1,h0,order)){
3204 	B1.push_back(B[i]);
3205 	continue;
3206       }
3207       index_lcm(res[B[i].first].coord.front().u,h0,tmp2,order);
3208       if (tmp2==tmp1){
3209 	B1.push_back(B[i]);
3210 	continue;
3211       }
3212       index_lcm(res[B[i].second].coord.front().u,h0,tmp2,order);
3213       if (tmp2==tmp1){
3214 	B1.push_back(B[i]);
3215 	continue;
3216       }
3217     }
3218     // B <- B union pairs(h,g) with g in C
3219     for (unsigned i=0;i<C.size();++i)
3220       B1.push_back(paire(pos,C[i]));
3221     swap(B1,B);
3222     // Update G by removing elements with leading monomial >= leading monomial of h
3223     if (debug_infolevel>1)
3224       CERR << CLOCK()*1e-6 << " begin Groebner interreduce " << '\n';
3225     C.clear();
3226     C.reserve(G.size());
3227     vector<unsigned> hG(1,pos);
3228     bool small0=env && env->moduloon && env->modulo.type==_INT_ && env->modulo.val;
3229     for (unsigned i=0;i<G.size();++i){
3230 #ifdef TIMEOUT
3231       control_c();
3232 #endif
3233       if (interrupted || ctrl_c)
3234 	return;
3235       if (!res[G[i]].coord.empty() && !tdeg_t_all_greater(res[G[i]].coord.front().u,h0,order)){
3236 	// reduce res[G[i]] with respect to h
3237 	if (small0)
3238 	  reduce1small(res[G[i]],h,TMP1,TMP2,env);
3239 	else
3240 	  reduce(res[G[i]],res,hG,-1,vtmp,res[G[i]],TMP1,TMP2,env);
3241 	C.push_back(G[i]);
3242       }
3243       // NB: removing all pairs containing i in it does not work
3244     }
3245     if (debug_infolevel>1)
3246       CERR << CLOCK()*1e-6 << " end Groebner interreduce " << '\n';
3247     C.push_back(pos);
3248     swap(C,G);
3249   }
3250 
3251   template<class tdeg_t>
in_gbasis(vectpoly8<tdeg_t> & res,vector<unsigned> & G,environment * env,bool sugar)3252   bool in_gbasis(vectpoly8<tdeg_t> & res,vector<unsigned> & G,environment * env,bool sugar){
3253     poly8<tdeg_t> TMP1(res.front().order,res.front().dim),TMP2(res.front().order,res.front().dim);
3254     vectpoly8<tdeg_t> vtmp;
3255     vector< paire > B;
3256     order_t order=res.front().order;
3257     //if (order==_PLEX_ORDER)
3258       sugar=false; // otherwise cyclic6 fails (bus error), don't know why
3259     for (unsigned l=0;l<res.size();++l){
3260       gbasis_update(G,B,res,l,TMP1,TMP2,vtmp,env);
3261     }
3262     for (int age=1;!B.empty() && !interrupted && !ctrl_c;++age){
3263       if (debug_infolevel>1)
3264 	CERR << CLOCK()*1e-6 << " number of pairs: " << B.size() << ", base size: " << G.size() << '\n';
3265       // find smallest lcm pair in B
3266       tdeg_t small0,cur;
3267       unsigned smallpos,smallsugar=0,cursugar=0;
3268       for (smallpos=0;smallpos<B.size();++smallpos){
3269 	if (!res[B[smallpos].first].coord.empty() && !res[B[smallpos].second].coord.empty())
3270 	  break;
3271 #ifdef TIMEOUT
3272 	control_c();
3273 #endif
3274 	if (interrupted || ctrl_c)
3275 	  return false;
3276       }
3277       index_lcm(res[B[smallpos].first].coord.front().u,res[B[smallpos].second].coord.front().u,small0,order);
3278       if (sugar)
3279 	smallsugar=res[B[smallpos].first].sugar+(small0-res[B[smallpos].first].coord.front().u).total_degree(order);
3280       for (unsigned i=smallpos+1;i<B.size();++i){
3281 #ifdef TIMEOUT
3282 	control_c();
3283 #endif
3284 	if (interrupted || ctrl_c)
3285 	  return false;
3286 	if (res[B[i].first].coord.empty() || res[B[i].second].coord.empty())
3287 	  continue;
3288 	index_lcm(res[B[i].first].coord.front().u,res[B[i].second].coord.front().u,cur,order);
3289 	if (sugar)
3290 	  cursugar=res[B[smallpos].first].sugar+(cur-res[B[smallpos].first].coord.front().u).total_degree(order);
3291 	bool doswap;
3292 	if (order.o==_PLEX_ORDER)
3293 	  doswap=tdeg_t_strictly_greater(small0,cur,order);
3294 	else {
3295 	  if (cursugar!=smallsugar)
3296 	    doswap = smallsugar > cursugar;
3297 	  else
3298 	    doswap=tdeg_t_strictly_greater(small0,cur,order);
3299 	}
3300 	if (doswap){
3301 	  // CERR << "swap " << cursugar << " " << res[B[i].first].coord.front().u << " " << res[B[i].second].coord.front().u << '\n';
3302 	  swap(small0,cur); // small0=cur;
3303 	  swap(smallsugar,cursugar);
3304 	  smallpos=i;
3305 	}
3306       }
3307       paire bk=B[smallpos];
3308       if (debug_infolevel>1 && (equalposcomp(G,bk.first)==0 || equalposcomp(G,bk.second)==0))
3309 	CERR << CLOCK()*1e-6 << " reducing pair with 1 element not in basis " << bk << '\n';
3310       B.erase(B.begin()+smallpos);
3311       poly8<tdeg_t> h(res.front().order,res.front().dim);
3312       spoly(res[bk.first],res[bk.second],h,TMP1,env);
3313       if (debug_infolevel>1)
3314 	CERR << CLOCK()*1e-6 << " reduce begin, pair " << bk << " remainder size " << h.coord.size() << '\n';
3315       reduce(h,res,G,-1,vtmp,h,TMP1,TMP2,env);
3316       if (debug_infolevel>1){
3317 	if (debug_infolevel>3){ CERR << h << '\n'; }
3318 	CERR << CLOCK()*1e-6 << " reduce end, remainder size " << h.coord.size() << '\n';
3319       }
3320       if (!h.coord.empty()){
3321 	res.push_back(h);
3322 	gbasis_update(G,B,res,unsigned(res.size()-1),TMP1,TMP2,vtmp,env);
3323 	if (debug_infolevel>2)
3324 	  CERR << CLOCK()*1e-6 << " basis indexes " << G << " pairs indexes " << B << '\n';
3325       }
3326     }
3327     return true;
3328   }
3329 
invmod(longlong a,longlong b)3330   longlong invmod(longlong a,longlong b){
3331     if (a==1 || a==-1 || a==1-b)
3332       return a;
3333     longlong aa(1),ab(0),ar(0);
3334 #ifdef VISUALC
3335     longlong q,r;
3336     while (b){
3337       q=a/b;
3338       r=a-q*b;
3339       ar=aa-q*ab;
3340       a=b;
3341       b=r;
3342       aa=ab;
3343       ab=ar;
3344     }
3345 #else
3346     lldiv_t qr;
3347     while (b){
3348       qr=lldiv(a,b);
3349       ar=aa-qr.quot*ab;
3350       a=b;
3351       b=qr.rem;
3352       aa=ab;
3353       ab=ar;
3354     }
3355 #endif
3356     if (a==1)
3357       return aa;
3358     if (a!=-1){
3359 #ifndef NO_STDEXCEPT
3360       setsizeerr(gettext("Not invertible"));
3361 #endif
3362       return 0;
3363     }
3364     return -aa;
3365   }
3366 
smod(longlong a,longlong b)3367   longlong smod(longlong a,longlong b){
3368     longlong r=a%b;
3369     if (r>b/2)
3370       r -= b;
3371     else {
3372       if (r<=-b/2)
3373 	r += b;
3374     }
3375     return r;
3376   }
3377 
3378 #if 0 // def x86_64
3379   typedef longlong modint;
3380   typedef int128_t modint2;
3381   longlong smod(int128_t a,longlong b){
3382     longlong r=a%b;
3383     if (r>b/2)
3384       r -= b;
3385     else {
3386       if (r<=-b/2)
3387 	r += b;
3388     }
3389   }
3390 
3391 #else
3392   typedef int modint;
3393   typedef longlong modint2;
3394 #endif
3395 
3396   template<class tdeg_t>
3397   struct polymod {
3398     std::vector< T_unsigned<modint,tdeg_t> > coord;
3399     // lex order is implemented using tdeg_t as a list of degrees
3400     // tdeg uses total degree 1st then partial degree in lex order, max 7 vars
3401     // revlex uses total degree 1st then opposite of partial degree in reverse ordre, max 7 vars
3402     order_t order; // _PLEX_ORDER, _REVLEX_ORDER or _TDEG_ORDER or _7VAR_ORDER or _11VAR_ORDER
3403     short int dim;
3404     unsigned sugar;
3405     int fromleft,fromright,age;
3406     double logz; // trace origin as a s-polynomial
3407     void dbgprint() const;
swapgiac::polymod3408     void swap(polymod & q){
3409       order_t tmp;
3410       tmp=order; order=q.order; q.order=tmp;
3411       int tmp2=dim; dim=q.dim; q.dim=tmp2;
3412       tmp2=sugar; sugar=q.sugar; q.sugar=tmp2;
3413       coord.swap(q.coord);
3414       tmp2=fromleft; fromleft=q.fromleft; q.fromleft=tmp2;
3415       tmp2=fromright; fromright=q.fromright; q.fromright=tmp2;
3416       tmp2=age; age=q.age; q.age=tmp2;
3417       double tmp3=logz; logz=q.logz; q.logz=tmp3;
3418    }
polymodgiac::polymod3419     polymod():dim(0),fromleft(-1),fromright(-1),logz(1) {order_t tmp={_PLEX_ORDER,0}; order=tmp;}
polymodgiac::polymod3420     polymod(order_t o_,int dim_): dim(dim_),fromleft(-1),fromright(-1),logz(1) {order=o_; order.dim=dim_;}
polymodgiac::polymod3421     polymod(const polynome & p,order_t o_,modint m):fromleft(-1),fromright(-1),logz(1){
3422       order=o_;
3423       dim=p.dim;
3424       order.dim=dim;
3425       if (order.o%4!=3){
3426 	if (p.is_strictly_greater==i_lex_is_strictly_greater)
3427 	  order.o=_PLEX_ORDER;
3428 	if (p.is_strictly_greater==i_total_revlex_is_strictly_greater)
3429 	  order.o=_REVLEX_ORDER;
3430 	if (p.is_strictly_greater==i_total_lex_is_strictly_greater)
3431 	  order.o=_TDEG_ORDER;
3432       }
3433       if (p.dim>GROEBNER_VARS-(order.o==_REVLEX_ORDER || order.o==_TDEG_ORDER))
3434 	CERR << "Number of variables is too large to be handled by giac";
3435       else {
3436 	if (!p.coord.empty()){
3437 	  coord.reserve(p.coord.size());
3438 	  for (unsigned i=0;i<p.coord.size();++i){
3439 	    modint n;
3440 	    if (p.coord[i].value.type==_ZINT)
3441 	      n=modulo(*p.coord[i].value._ZINTptr,m);
3442 	    else
3443 	      n=p.coord[i].value.val % m;
3444 	    coord.push_back(T_unsigned<modint,tdeg_t>(n,tdeg_t(p.coord[i].index,order)));
3445 	  }
3446 	  sugar=coord.front().u.total_degree(order);
3447 	}
3448       }
3449     }
get_polynomegiac::polymod3450     void get_polynome(polynome & p) const {
3451       p.dim=dim;
3452       switch (order.o){
3453       case _PLEX_ORDER:
3454 	p.is_strictly_greater=i_lex_is_strictly_greater;
3455 	break;
3456       case _REVLEX_ORDER:
3457 	p.is_strictly_greater=i_total_revlex_is_strictly_greater;
3458 	break;
3459       case _3VAR_ORDER:
3460 	p.is_strictly_greater=i_3var_is_strictly_greater;
3461 	break;
3462       case _7VAR_ORDER:
3463 	p.is_strictly_greater=i_7var_is_strictly_greater;
3464 	break;
3465       case _11VAR_ORDER:
3466 	p.is_strictly_greater=i_11var_is_strictly_greater;
3467 	break;
3468       case _TDEG_ORDER:
3469 	p.is_strictly_greater=i_total_lex_is_strictly_greater;
3470 	break;
3471       }
3472       p.coord.clear();
3473       p.coord.reserve(coord.size());
3474       index_t idx(dim);
3475       for (unsigned i=0;i<coord.size();++i){
3476 	get_index(coord[i].u,idx,order,dim);
3477 	p.coord.push_back(monomial<gen>(coord[i].g,idx));
3478       }
3479       // if (order==_3VAR_ORDER || order==_7VAR_ORDER || order==_11VAR_ORDER) p.tsort();
3480     }
3481   }; // end polymod
3482 
3483   template<class T>
increase(vector<T> & v)3484   void increase(vector<T> &v){
3485     if (v.size()!=v.capacity())
3486       return;
3487     vector<T> w;
3488     w.reserve(v.size()*2);
3489     for (unsigned i=0;i<v.size();++i){
3490       w.push_back(T(v[i].order,v[i].dim));
3491       w[i].coord.swap(v[i].coord);
3492     }
3493     v.swap(w);
3494   }
3495 
3496   template<class tdeg_t>
3497   struct polymod_sort_t {
polymod_sort_tgiac::polymod_sort_t3498     polymod_sort_t() {}
operator ()giac::polymod_sort_t3499     bool operator () (const polymod<tdeg_t> & p,const polymod<tdeg_t> & q) const {
3500       if (q.coord.empty())
3501 	return false;
3502       if (p.coord.empty())
3503 	return true;
3504       if (p.coord.front().u==q.coord.front().u)
3505 	return false;
3506       return tdeg_t_greater(q.coord.front().u,p.coord.front().u,p.order); // p.coord.front().u<q.coord.front().u;
3507       // this should be enough to sort groebner basis
3508     }
3509   };
3510 
3511   template<class tdeg_t>
smallmultmod(modint a,polymod<tdeg_t> & p,modint m,bool makepositive=true)3512   void smallmultmod(modint a,polymod<tdeg_t> & p,modint m,bool makepositive=true){
3513     if (a==1 || a==1-m)
3514       return;
3515     typename std::vector< T_unsigned<modint,tdeg_t> >::iterator pt=p.coord.begin(),ptend=p.coord.end();
3516     if (makepositive){
3517       for (;pt!=ptend;++pt){
3518 	modint tmp=(longlong(pt->g)*a)%m;
3519 	if (tmp<0) tmp += m;
3520 	pt->g=tmp;
3521       }
3522     }
3523     else {
3524       for (;pt!=ptend;++pt){
3525 	modint tmp=(longlong(pt->g)*a)%m;
3526 	pt->g=tmp;
3527       }
3528     }
3529   }
3530 
3531   template<class tdeg_t>
3532   struct tdeg_t_sort_t {
3533     order_t order;
tdeg_t_sort_tgiac::tdeg_t_sort_t3534     tdeg_t_sort_t() {order_t tmp={_REVLEX_ORDER,0}; order=tmp;}
tdeg_t_sort_tgiac::tdeg_t_sort_t3535     tdeg_t_sort_t(order_t o):order(o) {}
operator ()giac::tdeg_t_sort_t3536     bool operator ()(const T_unsigned<modint,tdeg_t> & a,const T_unsigned<modint,tdeg_t> & b) const {return !tdeg_t_greater(b.u,a.u,order);}
operator ()giac::tdeg_t_sort_t3537     bool operator ()(const T_unsigned<gen,tdeg_t> & a,const T_unsigned<gen,tdeg_t> & b) const {return !tdeg_t_greater(b.u,a.u,order);}
3538   };
3539   template<class tdeg_t>
convert(const poly8<tdeg_t> & p,polymod<tdeg_t> & q,modint env)3540   void convert(const poly8<tdeg_t> & p,polymod<tdeg_t> &q,modint env){
3541 #if 0
3542     q.coord.reserve(p.coord.size());
3543     q.dim=p.dim;
3544     q.order=p.order;
3545     q.sugar=0;
3546     for (unsigned i=0;i<p.coord.size();++i){
3547       int g=1;
3548       if (env){
3549 	if (p.coord[i].g.type==_ZINT)
3550 	  g=modulo(*p.coord[i].g._ZINTptr,env);
3551 	else
3552 	  g=(p.coord[i].g.val)%env;
3553       }
3554       if (g!=0)
3555 	q.coord.push_back(T_unsigned<int,tdeg_t>(g,p.coord[i].u));
3556     }
3557 #else
3558     q.coord.resize(p.coord.size());
3559     q.dim=p.dim;
3560     q.order=p.order;
3561     q.sugar=0;
3562     for (unsigned i=0;i<p.coord.size();++i){
3563       if (!env)
3564 	q.coord[i].g=1;
3565       else {
3566 	if (p.coord[i].g.type==_ZINT)
3567 	  q.coord[i].g=modulo(*p.coord[i].g._ZINTptr,env);
3568 	else
3569 	  q.coord[i].g=(p.coord[i].g.val)%env;
3570       }
3571       q.coord[i].u=p.coord[i].u;
3572     }
3573 #endif
3574     if (env && !q.coord.empty()){
3575       q.sugar=q.coord.front().u.total_degree(p.order);
3576       if (q.coord.front().g!=1)
3577 	smallmultmod(invmod(q.coord.front().g,env),q,env);
3578       q.coord.front().g=1;
3579     }
3580     sort(q.coord.begin(),q.coord.end(),tdeg_t_sort_t<tdeg_t>(p.order));
3581   }
3582   template<class tdeg_t>
convert(const polymod<tdeg_t> & p,poly8<tdeg_t> & q,modint env)3583   void convert(const polymod<tdeg_t> & p,poly8<tdeg_t> &q,modint env){
3584     q.coord.resize(p.coord.size());
3585     q.dim=p.dim;
3586     q.order=p.order;
3587     for (unsigned i=0;i<p.coord.size();++i){
3588       modint n=p.coord[i].g % env;
3589       if (n>env/2)
3590 	n-=env;
3591       else {
3592 	if (n<=-env/2)
3593 	  n += env;
3594       }
3595       q.coord[i].g=n;
3596       q.coord[i].u=p.coord[i].u;
3597     }
3598     if (!q.coord.empty())
3599       q.sugar=q.coord.front().u.total_degree(p.order);
3600     else
3601       q.sugar=0;
3602   }
3603 
3604   template<class tdeg_t>
operator ==(const polymod<tdeg_t> & p,const polymod<tdeg_t> & q)3605   bool operator == (const polymod<tdeg_t> & p,const polymod<tdeg_t> &q){
3606     if (p.coord.size()!=q.coord.size())
3607       return false;
3608     for (unsigned i=0;i<p.coord.size();++i){
3609       if (p.coord[i].u!=q.coord[i].u || p.coord[i].g!=q.coord[i].g)
3610 	return false;
3611     }
3612     return true;
3613   }
3614 
3615 #ifdef NSPIRE
3616   template<class T,class tdeg_t>
operator <<(nio::ios_base<T> & os,const polymod<tdeg_t> & p)3617   nio::ios_base<T> & operator << (nio::ios_base<T> & os, const polymod<tdeg_t> & p)
3618 #else
3619   template<class tdeg_t>
3620   ostream & operator << (ostream & os, const polymod<tdeg_t> & p)
3621 #endif
3622   {
3623     typename std::vector< T_unsigned<modint,tdeg_t> >::const_iterator it=p.coord.begin(),itend=p.coord.end();
3624     int t2;
3625     if (it==itend)
3626       return os << 0 ;
3627     for (;it!=itend;){
3628       os << it->g  ;
3629 #ifndef GBASIS_NO_OUTPUT
3630       if (it->u.vars64()){
3631 	if (it->u.tdeg%2){
3632 	  degtype * i=(degtype *)(it->u.ui+1);
3633 	  for (int j=0;j<it->u.order_.dim;++j){
3634 	    t2=i[j];
3635 	    if (t2)
3636 	      os << "*x"<< j << "^" << t2  ;
3637 	  }
3638 	  ++it;
3639 	  if (it==itend)
3640 	    break;
3641 	  os << " + ";
3642 	  continue;
3643 	}
3644       }
3645 #endif
3646       short tab[GROEBNER_VARS+1];
3647       tab[GROEBNER_VARS]=0;
3648       it->u.get_tab(tab,p.order);
3649       switch (p.order.o){
3650       case _PLEX_ORDER:
3651 	for (int i=0;i<=GROEBNER_VARS;++i){
3652 	  t2 = tab[i];
3653 	  if (t2)
3654 	    os << "*x"<< i << "^" << t2  ;
3655 	}
3656 	break;
3657       case _TDEG_ORDER:
3658 	for (int i=1;i<=GROEBNER_VARS;++i){
3659 	  t2 = tab[i];
3660 	  if (t2==0)
3661 	    continue;
3662 	  if (t2)
3663 	    os << "*x"<< i-1 << "^" << t2  ;
3664 	}
3665 	break;
3666       case _REVLEX_ORDER:
3667 	for (int i=1;i<=GROEBNER_VARS;++i){
3668 	  t2 = tab[i];
3669 	  if (t2==0)
3670 	    continue;
3671 	  os << "*x"<< p.dim-i;
3672 	  if (t2!=1)
3673 	    os << "^" << t2;
3674 	}
3675 	break;
3676 #if GROEBNER_VARS==15
3677       case _3VAR_ORDER:
3678 	for (int i=1;i<=3;++i){
3679 	  t2 = tab[i];
3680 	  if (t2==0)
3681 	    continue;
3682 	  os << "*x"<< 3-i;
3683 	  if (t2!=1)
3684 	    os << "^" << t2;
3685 	}
3686 	for (int i=5;i<=15;++i){
3687 	  t2 = tab[i];
3688 	  if (t2==0)
3689 	    continue;
3690 	  os << "*x"<< 7+p.dim-i;
3691 	  if (t2!=1)
3692 	    os << "^" << t2;
3693 	}
3694 	break;
3695       case _7VAR_ORDER:
3696 	for (int i=1;i<=7;++i){
3697 	  t2 = tab[i];
3698 	  if (t2==0)
3699 	    continue;
3700 	  os << "*x"<< 7-i;
3701 	  if (t2!=1)
3702 	    os << "^" << t2;
3703 	}
3704 	for (int i=9;i<=15;++i){
3705 	  t2 = tab[i];
3706 	  if (t2==0)
3707 	    continue;
3708 	  os << "*x"<< 11+p.dim-i;
3709 	  if (t2!=1)
3710 	    os << "^" << t2;
3711 	}
3712 	break;
3713       case _11VAR_ORDER:
3714 	for (int i=1;i<=11;++i){
3715 	  t2 = tab[i];
3716 	  if (t2==0)
3717 	    continue;
3718 	  os << "*x"<< 11-i;
3719 	  if (t2!=1)
3720 	    os << "^" << t2;
3721 	}
3722 	for (int i=13;i<=15;++i){
3723 	  t2 = tab[i];
3724 	  if (t2==0)
3725 	    continue;
3726 	  os << "*x"<< 15+p.dim-i;
3727 	  if (t2!=1)
3728 	    os << "^" << t2;
3729 	}
3730 	break;
3731 #endif
3732       }
3733       ++it;
3734       if (it==itend)
3735 	break;
3736       os << " + ";
3737     }
3738     return os;
3739   }
3740 
3741   template<class tdeg_t>
dbgprint() const3742   void polymod<tdeg_t>::dbgprint() const {
3743     CERR << *this << '\n';
3744   }
3745 
3746   template<class tdeg_t>
3747   class vectpolymod:public vector<polymod<tdeg_t> >{
3748   public:
dbgprint() const3749     void dbgprint() const { CERR << *this << '\n'; }
3750   };
3751 
3752   template<class tdeg_t>
vectpoly_2_vectpolymod(const vectpoly & v,order_t order,vectpolymod<tdeg_t> & v8,modint m)3753   void vectpoly_2_vectpolymod(const vectpoly & v,order_t order,vectpolymod<tdeg_t> & v8,modint m){
3754     v8.clear();
3755     v8.reserve(v.size());
3756     for (unsigned i=0;i<v.size();++i){
3757       v8.push_back(polymod<tdeg_t>(v[i],order,m));
3758       v8.back().order=order;
3759     }
3760   }
3761 
3762   template<class tdeg_t>
vectpolymod_2_vectpoly(const vectpoly8<tdeg_t> & v8,vectpoly & v)3763   void vectpolymod_2_vectpoly(const vectpoly8<tdeg_t> & v8,vectpoly & v){
3764     v.clear();
3765     v.reserve(v8.size());
3766     for (unsigned i=0;i<v8.size();++i){
3767       v.push_back(polynome(v8[i].dim));
3768       v8[i].get_polynome(v[i]);
3769     }
3770   }
3771 
3772   template<class tdeg_t>
convert(const vectpoly8<tdeg_t> & v,vectpolymod<tdeg_t> & w,modint env)3773   void convert(const vectpoly8<tdeg_t> & v,vectpolymod<tdeg_t> & w,modint env){
3774     if (w.size()<v.size())
3775       w.resize(v.size());
3776     for (unsigned i=0;i<v.size();++i){
3777       convert(v[i],w[i],env);
3778     }
3779   }
3780 
3781   template<class tdeg_t>
convert(const vectpolymod<tdeg_t> & v,vectpoly8<tdeg_t> & w,modint env)3782   void convert(const vectpolymod<tdeg_t> & v,vectpoly8<tdeg_t> & w,modint env){
3783     w.resize(v.size());
3784     for (unsigned i=0;i<v.size();++i){
3785       convert(v[i],w[i],env);
3786     }
3787   }
3788 
3789   template<class tdeg_t>
convert(const vectpolymod<tdeg_t> & v,const vector<unsigned> & G,vectpoly8<tdeg_t> & w,modint env)3790   void convert(const vectpolymod<tdeg_t> & v,const vector<unsigned> & G,vectpoly8<tdeg_t> & w,modint env){
3791     w.resize(v.size());
3792     for (unsigned i=0;i<G.size();++i){
3793       convert(v[G[i]],w[G[i]],env);
3794     }
3795   }
3796 
3797 #ifdef GBASIS_HEAP
3798   template<class tdeg_t>
in_heap_reducemod(const polymod<tdeg_t> & f,const vectpolymod<tdeg_t> & g,const vector<unsigned> & G,unsigned excluded,vectpolymod<tdeg_t> & q,polymod<tdeg_t> & rem,polymod<tdeg_t> * R,modint env)3799   void in_heap_reducemod(const polymod<tdeg_t> & f,const vectpolymod<tdeg_t> & g,const vector<unsigned> & G,unsigned excluded,vectpolymod<tdeg_t> & q,polymod<tdeg_t> & rem,polymod<tdeg_t> * R,modint env){
3800     // divides f by g[G[0]] to g[G[G.size()-1]] except maybe g[G[excluded]]
3801     // first implementation: use quotxsient heap for all quotient/divisor
3802     // do not use heap chain
3803     // ref Monaghan Pearce if g.size()==1
3804     // R is the list of all monomials
3805     if (R){
3806       R->dim=f.dim; R->order=f.order;
3807       R->coord.clear();
3808     }
3809     if (&rem==&f){
3810       polymod<tdeg_t> TMP;
3811       in_heap_reducemod(f,g,G,excluded,q,TMP,R,env);
3812       swap(rem.coord,TMP.coord);
3813       if (debug_infolevel>1000)
3814 	g.dbgprint(); // instantiate dbgprint()
3815       return;
3816     }
3817     rem.coord.clear();
3818     if (f.coord.empty())
3819       return ;
3820     if (q.size()<G.size())
3821       q.resize(G.size());
3822     unsigned guess=0;
3823     for (unsigned i=0;i<G.size();++i){
3824       q[i].dim=f.dim;
3825       q[i].order=f.order;
3826       q[i].coord.clear();
3827       guess += unsigned(g[G[i]].coord.size());
3828     }
3829     vector<heap_t<tdeg_t> > H;
3830     compare_heap_t<tdeg_t> key(f.order);
3831     H.reserve(guess);
3832     vector<modint> invlcg(G.size());
3833     for (unsigned i=0;i<G.size();++i){
3834       invlcg[i]=invmod(g[G[i]].coord.front().g,env);
3835     }
3836     modint c=1;
3837 #ifdef x86_64
3838     int128_t C=0; // int128_t to avoid %
3839 #else
3840     modint2 C=0; // int128_t to avoid %
3841 #endif
3842     unsigned k=0,i; // k=position in f
3843     tdeg_t m;
3844     bool finish=false;
3845     while (!H.empty() || k<f.coord.size()){
3846       // is highest remaining degree in f or heap?
3847       if (k<f.coord.size() && (H.empty() || tdeg_t_greater(f.coord[k].u,H.front().u,f.order)) ){
3848 	// it's in f or both
3849 	m=f.coord[k].u;
3850 	C=f.coord[k].g;
3851 	++k;
3852       }
3853       else {
3854 	m=H[0].u;
3855 	C=0;
3856       }
3857       if (R)
3858 	R->coord.push_back(T_unsigned<modint,tdeg_t>(1,m));
3859       // extract from heap all terms having m as monomials, substract from c
3860       while (!H.empty() && H.front().u==m){
3861 	std::pop_heap(H.begin(),H.end(),key);
3862 	heap_t<tdeg_t> & current=H.back(); // was root node of the heap
3863 	const polymod<tdeg_t> & gcurrent = g[G[current.i]];
3864 	if (!R){
3865 #ifdef x86_64
3866 	  C -= modint2(q[current.i].coord[current.qi].g) * gcurrent.coord[current.gj].g;
3867 #else
3868 	  C = (C-modint2(q[current.i].coord[current.qi].g) * gcurrent.coord[current.gj].g) % env;
3869 #endif
3870 	}
3871 	if (current.gj<gcurrent.coord.size()-1){
3872 	  ++current.gj;
3873 	  current.u=q[current.i].coord[current.qi].u+gcurrent.coord[current.gj].u;
3874 	  push_heap(H.begin(),H.end(),key);
3875 	}
3876 	else
3877 	  H.pop_back();
3878       }
3879       if (!R){
3880 #ifdef x86_64
3881 	c = C % env;
3882 #else
3883 	c=modint(C);
3884 #endif
3885 	if (c==0)
3886 	  continue;
3887       }
3888       // divide (c,m) by one of the g if possible, otherwise push in remainder
3889       if (finish){
3890 	rem.coord.push_back(T_unsigned<modint,tdeg_t>(c,m)); // add c*m to remainder
3891 	continue;
3892       }
3893       finish=true;
3894 #if 0
3895       for (i=G.size()-1;i!=-1;--i){
3896 	if (i==excluded || g[G[i]].coord.empty())
3897 	  continue;
3898 	if (tdeg_t_greater(m,g[G[i]].coord.front().u,f.order)){
3899 	  finish=false;
3900 	  if (tdeg_t_all_greater(m,g[G[i]].coord.front().u,f.order))
3901 	    break;
3902 	}
3903       }
3904       if (i==-1){
3905 	rem.coord.push_back(T_unsigned<modint,tdeg_t>(c,m)); // add c*m to remainder
3906 	continue;
3907       }
3908 #else
3909       for (i=0;i<G.size();++i){
3910 	if (i==excluded || g[G[i]].coord.empty())
3911 	  continue;
3912 	if (tdeg_t_greater(m,g[G[i]].coord.front().u,f.order)){
3913 	  finish=false;
3914 	  if (tdeg_t_all_greater(m,g[G[i]].coord.front().u,f.order))
3915 	    break;
3916 	}
3917       }
3918       if (i==G.size()){
3919 	rem.coord.push_back(T_unsigned<modint,tdeg_t>(c,m)); // add c*m to remainder
3920 	continue;
3921       }
3922 #endif
3923       // add c*m/leading monomial of g[G[i]] to q[i]
3924       tdeg_t monom=m-g[G[i]].coord.front().u;
3925       if (!R){
3926 	if (invlcg[i]!=1){
3927 	  if (invlcg[i]==-1)
3928 	    c=-c;
3929 	  else
3930 	    c=(modint2(c)*invlcg[i]) % env;
3931 	}
3932       }
3933       q[i].coord.push_back(T_unsigned<modint,tdeg_t>(c,monom));
3934       // push in heap
3935       if (g[G[i]].coord.size()>1){
3936 	heap_t<tdeg_t> current={i,unsigned(q[i].coord.size())-1,1,g[G[i]].coord[1].u+monom};
3937 	H.push_back(current);
3938 	push_heap(H.begin(),H.end(),key);
3939       }
3940     } // end main heap pseudo-division loop
3941   }
3942 
3943   template<class tdeg_t>
heap_reducemod(const polymod<tdeg_t> & f,const vectpolymod<tdeg_t> & g,const vector<unsigned> & G,unsigned excluded,vectpolymod<tdeg_t> & q,polymod<tdeg_t> & rem,modint env)3944   void heap_reducemod(const polymod<tdeg_t> & f,const vectpolymod<tdeg_t> & g,const vector<unsigned> & G,unsigned excluded,vectpolymod<tdeg_t> & q,polymod<tdeg_t> & rem,modint env){
3945     in_heap_reducemod(f,g,G,excluded,q,rem,0,env);
3946     // end up by multiplying rem by s (so that everything is integer)
3947     if (debug_infolevel>2){
3948       for (unsigned i=0;i<G.size();++i)
3949 	CERR << "(" << g[G[i]]<< ")*(" << q[i] << ")+ ";
3950       CERR << rem << '\n';
3951     }
3952     if (!rem.coord.empty() && rem.coord.front().g!=1){
3953       smallmult(invmod(rem.coord.front().g,env),rem.coord,rem.coord,env);
3954       rem.coord.front().g=1;
3955     }
3956   }
3957 
3958 #endif
3959 
3960   template<class tdeg_t>
symbolic_preprocess(const polymod<tdeg_t> & f,const vectpolymod<tdeg_t> & g,const vector<unsigned> & G,unsigned excluded,vectpolymod<tdeg_t> & q,polymod<tdeg_t> & rem,polymod<tdeg_t> * R)3961   void symbolic_preprocess(const polymod<tdeg_t> & f,const vectpolymod<tdeg_t> & g,const vector<unsigned> & G,unsigned excluded,vectpolymod<tdeg_t> & q,polymod<tdeg_t> & rem,polymod<tdeg_t> * R){
3962     // divides f by g[G[0]] to g[G[G.size()-1]] except maybe g[G[excluded]]
3963     // first implementation: use quotient heap for all quotient/divisor
3964     // do not use heap chain
3965     // ref Monaghan Pearce if g.size()==1
3966     // R is the list of all monomials
3967     if (R){
3968       R->dim=f.dim; R->order=f.order;
3969       R->coord.clear();
3970     }
3971     rem.coord.clear();
3972     if (f.coord.empty())
3973       return ;
3974     if (q.size()<G.size())
3975       q.resize(G.size());
3976     unsigned guess=0;
3977     for (unsigned i=0;i<G.size();++i){
3978       q[i].dim=f.dim;
3979       q[i].order=f.order;
3980       q[i].coord.clear();
3981       guess += unsigned(g[G[i]].coord.size());
3982     }
3983     vector<heap_t<tdeg_t> > H_;
3984     vector<unsigned> H;
3985     H_.reserve(guess);
3986     H.reserve(guess);
3987     heap_t_compare<tdeg_t> keyheap(H_,f.order);
3988     unsigned k=0,i; // k=position in f
3989     tdeg_t m;
3990     bool finish=false;
3991     while (!H.empty() || k<f.coord.size()){
3992       // is highest remaining degree in f or heap?
3993       if (k<f.coord.size() && (H.empty() || tdeg_t_greater(f.coord[k].u,H_[H.front()].u,f.order)) ){
3994 	// it's in f or both
3995 	m=f.coord[k].u;
3996 	++k;
3997       }
3998       else {
3999 	m=H_[H.front()].u;
4000       }
4001       if (R)
4002 	R->coord.push_back(T_unsigned<modint,tdeg_t>(1,m));
4003       // extract from heap all terms having m as monomials, substract from c
4004       while (!H.empty() && H_[H.front()].u==m){
4005 	std::pop_heap(H.begin(),H.end(),keyheap);
4006 	heap_t<tdeg_t> & current=H_[H.back()]; // was root node of the heap
4007 	const polymod<tdeg_t> & gcurrent = g[G[current.i]];
4008 	if (current.gj<gcurrent.coord.size()-1){
4009 	  ++current.gj;
4010 	  current.u=q[current.i].coord[current.qi].u+gcurrent.coord[current.gj].u;
4011 	  std::push_heap(H.begin(),H.end(),keyheap);
4012 	}
4013 	else
4014 	  H.pop_back();
4015       }
4016       // divide (c,m) by one of the g if possible, otherwise push in remainder
4017       if (finish){
4018 	rem.coord.push_back(T_unsigned<modint,tdeg_t>(1,m)); // add to remainder
4019 	continue;
4020       }
4021       finish=true;
4022       for (i=0;i<G.size();++i){
4023 	const vector< T_unsigned<modint,tdeg_t> > & gGicoord=g[G[i]].coord;
4024 	if (i==excluded || gGicoord.empty())
4025 	  continue;
4026 	if (tdeg_t_greater(m,gGicoord.front().u,f.order)){
4027 	  finish=false;
4028 	  if (tdeg_t_all_greater(m,gGicoord.front().u,f.order))
4029 	    break;
4030 	}
4031       }
4032       if (i==G.size()){
4033 	rem.coord.push_back(T_unsigned<modint,tdeg_t>(1,m)); // add to remainder
4034 	continue;
4035       }
4036       // add m/leading monomial of g[G[i]] to q[i]
4037       tdeg_t monom=m-g[G[i]].coord.front().u;
4038       q[i].coord.push_back(T_unsigned<modint,tdeg_t>(1,monom));
4039       // push in heap
4040       if (g[G[i]].coord.size()>1){
4041 	heap_t<tdeg_t> current={i,unsigned(q[i].coord.size())-1,1,g[G[i]].coord[1].u+monom};
4042 	H.push_back(unsigned(H_.size()));
4043 	H_.push_back(current);
4044 	keyheap.ptr=&H_.front();
4045 	std::push_heap(H.begin(),H.end(),keyheap);
4046       }
4047     } // end main heap pseudo-division loop
4048     // CERR << H_.size() << '\n';
4049   }
4050 
4051   // p - a*q shifted mod m -> r
4052   template<class tdeg_t>
smallmultsubmodshift(const polymod<tdeg_t> & p,unsigned pos,modint a,const polymod<tdeg_t> & q,const tdeg_t & shift,polymod<tdeg_t> & r,modint m)4053   void smallmultsubmodshift(const polymod<tdeg_t> & p,unsigned pos,modint a,const polymod<tdeg_t> & q,const tdeg_t & shift,polymod<tdeg_t> & r,modint m){
4054     r.coord.clear();
4055     r.coord.reserve(p.coord.size()+q.coord.size());
4056     typename vector< T_unsigned<modint,tdeg_t> >::const_iterator it0=p.coord.begin(),it=it0+pos,itend=p.coord.end(),jt=q.coord.begin(),jtend=q.coord.end();
4057     // for (;it0!=it;++it0){ r.coord.push_back(*it0); }
4058     tdeg_t v=shift+shift; // new memory slot
4059     int dim=p.dim;
4060     for (;jt!=jtend;++jt){
4061       add(jt->u,shift,v,dim);
4062       for (;it!=itend && tdeg_t_strictly_greater(it->u,v,p.order);++it){
4063 	r.coord.push_back(*it);
4064       }
4065       if (it!=itend && it->u==v){
4066 	modint tmp=(it->g-modint2(a)*jt->g)%m;
4067 	if (tmp)
4068 	  r.coord.push_back(T_unsigned<modint,tdeg_t>(tmp,v));
4069 	++it;
4070       }
4071       else {
4072 	modint tmp=(-modint2(a)*jt->g)%m;
4073 	r.coord.push_back(T_unsigned<modint,tdeg_t>(tmp,v));
4074       }
4075     }
4076     for (;it!=itend;++it){
4077       r.coord.push_back(*it);
4078     }
4079   }
4080 
4081   // p - a*q mod m -> r
4082   template<class tdeg_t>
smallmultsubmod(const polymod<tdeg_t> & p,modint a,const polymod<tdeg_t> & q,polymod<tdeg_t> & r,modint m)4083   void smallmultsubmod(const polymod<tdeg_t> & p,modint a,const polymod<tdeg_t> & q,polymod<tdeg_t> & r,modint m){
4084     r.coord.clear();
4085     r.coord.reserve(p.coord.size()+q.coord.size());
4086     typename vector< T_unsigned<modint,tdeg_t> >::const_iterator it=p.coord.begin(),itend=p.coord.end(),jt=q.coord.begin(),jtend=q.coord.end();
4087     for (;jt!=jtend;++jt){
4088       const tdeg_t & v=jt->u;
4089       for (;it!=itend && tdeg_t_strictly_greater(it->u,v,p.order);++it){
4090 	r.coord.push_back(*it);
4091       }
4092       if (it!=itend && it->u==v){
4093 	modint tmp=(it->g-modint2(a)*jt->g)%m;
4094 	if (tmp)
4095 	  r.coord.push_back(T_unsigned<modint,tdeg_t>(tmp,v));
4096 	++it;
4097       }
4098       else {
4099 	int tmp=(-modint2(a)*jt->g)%m;
4100 	r.coord.push_back(T_unsigned<modint,tdeg_t>(tmp,v));
4101       }
4102     }
4103     for (;it!=itend;++it){
4104       r.coord.push_back(*it);
4105     }
4106   }
4107 
4108   // p + q  -> r
4109   template<class tdeg_t>
smallmerge(polymod<tdeg_t> & p,polymod<tdeg_t> & q,polymod<tdeg_t> & r)4110   void smallmerge(polymod<tdeg_t> & p,polymod<tdeg_t> & q,polymod<tdeg_t> & r){
4111     if (p.coord.empty()){
4112       swap(q.coord,r.coord);
4113       return;
4114     }
4115     if (q.coord.empty()){
4116       swap(p.coord,r.coord);
4117       return;
4118     }
4119     r.coord.clear();
4120     r.coord.reserve(p.coord.size()+q.coord.size());
4121     typename vector< T_unsigned<modint,tdeg_t> >::const_iterator it=p.coord.begin(),itend=p.coord.end(),jt=q.coord.begin(),jtend=q.coord.end();
4122     for (;jt!=jtend;++jt){
4123       const tdeg_t & v=jt->u;
4124       for (;it!=itend && tdeg_t_strictly_greater(it->u,v,p.order);++it){
4125 	r.coord.push_back(*it);
4126       }
4127       r.coord.push_back(*jt);
4128     }
4129     for (;it!=itend;++it){
4130       r.coord.push_back(*it);
4131     }
4132   }
4133 
4134   template<class tdeg_t>
reducemod(const polymod<tdeg_t> & p,const vectpolymod<tdeg_t> & res,const vector<unsigned> & G,unsigned excluded,polymod<tdeg_t> & rem,modint env,bool topreduceonly=false)4135   void reducemod(const polymod<tdeg_t> & p,const vectpolymod<tdeg_t> & res,const vector<unsigned> & G,unsigned excluded,polymod<tdeg_t> & rem,modint env,bool topreduceonly=false){
4136     if (&p!=&rem)
4137       rem=p;
4138     if (p.coord.empty())
4139       return ;
4140     polymod<tdeg_t> TMP2(p.order,p.dim);
4141     unsigned i,rempos=0;
4142     for (unsigned count=0;;++count){
4143       // this branch search first in all leading coeff of G for a monomial
4144       // <= to the current rem monomial
4145       typename std::vector< T_unsigned<modint,tdeg_t> >::const_iterator pt=rem.coord.begin()+rempos;
4146       if (pt>=rem.coord.end())
4147 	break;
4148       for (i=0;i<G.size();++i){
4149 	if (i==excluded || res[G[i]].coord.empty())
4150 	  continue;
4151 	if (tdeg_t_all_greater(pt->u,res[G[i]].coord.front().u,p.order))
4152 	  break;
4153       }
4154       if (i==G.size()){ // no leading coeff of G is smaller than the current coeff of rem
4155 	++rempos;
4156 	if (topreduceonly)
4157 	  break;
4158 	// if (small0) TMP1.coord.push_back(*pt);
4159 	continue;
4160       }
4161       modint a(pt->g),b(res[G[i]].coord.front().g);
4162       if (pt->u==res[G[i]].coord.front().u){
4163 	smallmultsubmod(rem,smod(modint2(a)*invmod(b,env),env),res[G[i]],TMP2,env);
4164 	// Gpos=i; // assumes basis element in G are sorted wrt >
4165       }
4166       else
4167 	smallmultsubmodshift(rem,0,smod(modint2(a)*invmod(b,env),env),res[G[i]],pt->u-res[G[i]].coord.front().u,TMP2,env);
4168       swap(rem.coord,TMP2.coord);
4169     }
4170     if (!rem.coord.empty() && rem.coord.front().g!=1){
4171       smallmultmod(invmod(rem.coord.front().g,env),rem,env);
4172       rem.coord.front().g=1;
4173     }
4174   }
4175 
4176 #if 0
4177   // reduce with respect to itself the elements of res with index in G
4178   template<class tdeg_t>
4179   void reducemod(vectpolymod<tdeg_t> & res,vector<unsigned> G,modint env){
4180     if (res.empty() || G.empty())
4181       return;
4182     polymod<tdeg_t> pred(res.front().order,res.front().dim),
4183       TMP2(res.front().order,res.front().dim);
4184     vectpolymod<tdeg_t> q;
4185     // reduce res
4186     for (unsigned i=0;i<G.size();++i){
4187 #ifdef TIMEOUT
4188       control_c();
4189 #endif
4190       if (interrupted || ctrl_c)
4191 	return;
4192       polymod<tdeg_t> & p=res[i];
4193       reducemod(p,res,G,i,q,pred,TMP2,env);
4194       swap(res[i].coord,pred.coord);
4195       pred.sugar=res[i].sugar;
4196     }
4197   }
4198 #endif
4199 
4200   template<class tdeg_t>
spolymod(const polymod<tdeg_t> & p,const polymod<tdeg_t> & q,polymod<tdeg_t> & res,polymod<tdeg_t> & TMP1,modint env)4201   void spolymod(const polymod<tdeg_t> & p,const polymod<tdeg_t> & q,polymod<tdeg_t> & res,polymod<tdeg_t> & TMP1,modint env){
4202     if (p.coord.empty()){
4203       res=q;
4204       return ;
4205     }
4206     if (q.coord.empty()){
4207       res= p;
4208       return;
4209     }
4210     const tdeg_t & pi = p.coord.front().u;
4211     const tdeg_t & qi = q.coord.front().u;
4212     tdeg_t lcm;
4213     index_lcm(pi,qi,lcm,p.order);
4214     //polymod<tdeg_t> TMP1(p);
4215     TMP1=p;
4216     // polymod<tdeg_t> TMP2(q);
4217     const polymod<tdeg_t> &TMP2=q;
4218     modint a=p.coord.front().g,b=q.coord.front().g;
4219     tdeg_t pshift=lcm-pi;
4220     unsigned sugarshift=pshift.total_degree(p.order);
4221     // adjust sugar for res
4222     res.sugar=p.sugar+sugarshift;
4223     // CERR << "spoly mod " << res.sugar << " " << pi << qi << '\n';
4224     if (p.order.o==_PLEX_ORDER || sugarshift!=0)
4225       smallshift(TMP1.coord,pshift,TMP1.coord);
4226     // smallmultmod(b,TMP1,env);
4227     if (lcm==qi)
4228       smallmultsubmod(TMP1,smod(modint2(a)*invmod(b,env),env),TMP2,res,env);
4229     else
4230       smallmultsubmodshift(TMP1,0,smod(modint2(a)*invmod(b,env),env),TMP2,lcm-qi,res,env);
4231     if (!res.coord.empty() && res.coord.front().g!=1){
4232       smallmultmod(invmod(res.coord.front().g,env),res,env);
4233       res.coord.front().g=1;
4234     }
4235     if (debug_infolevel>2)
4236       CERR << "spolymod " << res << '\n';
4237   }
4238 
4239   template<class tdeg_t>
reduce1smallmod(polymod<tdeg_t> & p,const polymod<tdeg_t> & q,polymod<tdeg_t> & TMP2,modint env)4240   void reduce1smallmod(polymod<tdeg_t> & p,const polymod<tdeg_t> & q,polymod<tdeg_t> & TMP2,modint env){
4241     if (p.coord.empty())
4242       return ;
4243     unsigned rempos=0;
4244     const tdeg_t & u = q.coord.front().u;
4245     const modint invg=invmod(q.coord.front().g,env);
4246     for (unsigned count=0;;++count){
4247       // this branch search first in all leading coeff of G for a monomial
4248       // <= to the current rem monomial
4249       typename std::vector< T_unsigned<modint,tdeg_t> >::const_iterator pt=p.coord.begin()+rempos;
4250       if (pt>=p.coord.end())
4251 	break;
4252       if (pt->u==u){
4253 	smallmultsubmodshift(p,0,smod(modint2(pt->g)*invg,env),q,pt->u-u,TMP2,env);
4254 	swap(p.coord,TMP2.coord);
4255 	break;
4256       }
4257       if (!tdeg_t_all_greater(pt->u,u,p.order)){
4258 	++rempos;
4259 	// TMP1.coord.push_back(*pt);
4260 	continue;
4261       }
4262       smallmultsubmodshift(p,0,smod(modint2(pt->g)*invg,env),q,pt->u-u,TMP2,env);
4263       // smallmultsubmodshift(p,rempos,smod(modint2(pt->g)*invmod(g,env),env),q,pt->u-u,TMP2,env);
4264       rempos=0;
4265       swap(p.coord,TMP2.coord);
4266     }
4267     // if (small0) swap(p.coord,TMP1.coord);
4268     if (!p.coord.empty() && p.coord.front().g!=1){
4269       smallmultmod(invmod(p.coord.front().g,env),p,env);
4270       p.coord.front().g=1;
4271     }
4272   }
4273 
4274 #define GIAC_GBASIS_PERMUTATION
4275   //#define GIAC_GBASIS_PERMUTATION2
4276   template<class tdeg_t>
4277   struct zsymb_data {
4278     unsigned pos;
4279     tdeg_t deg;
4280     order_t o;
4281     unsigned terms;
4282     int age;
4283   };
4284 
4285 #ifdef GIAC_GBASIS_PERMUTATION2
4286   template<class tdeg_t>
tri(const zsymb_data<tdeg_t> & z1,const zsymb_data<tdeg_t> & z2)4287   bool tri (const zsymb_data<tdeg_t> & z1,const zsymb_data<tdeg_t> & z2){
4288     if (z1.terms!=z2.terms)
4289       return z1.terms<z2.terms;
4290     int d1=z1.deg.total_degree(z1.o),d2=z2.deg.total_degree(z2.o);
4291     if (d1!=d2) return d1<d2;
4292     if (z1.pos!=z2.pos)
4293       return z2.pos>z1.pos;
4294     return false;
4295   }
4296 #endif
4297 
4298   // #define GIAC_DEG_FIRST
4299 
4300   template <class tdeg_t>
operator <(const zsymb_data<tdeg_t> & z1,const zsymb_data<tdeg_t> & z2)4301   bool operator < (const zsymb_data<tdeg_t> & z1,const zsymb_data<tdeg_t> & z2){
4302     // reductor choice: less terms is better
4303     // but small degree gives a reductor sooner
4304     // e.g. less terms is faster for botana* but slower for cyclic*
4305     // if (z1.terms!=z2.terms){ return z2.terms>z1.terms; }
4306     int d1=z1.deg.total_degree(z1.o),d2=z2.deg.total_degree(z2.o);
4307 #ifdef GIAC_DEG_FIRST
4308     if (d1!=d2)
4309       return d1<d2;
4310 #endif
4311     // double Z1=d1*double(z1.terms)*(z1.age+1); double Z2=d2*double(z2.terms)*(z2.age+1); if (Z1!=Z2) return Z2>Z1;
4312     double Z1=z1.terms*double(z1.terms)*d1; double Z2=z2.terms*double(z2.terms)*d2; if (Z1!=Z2) return Z2>Z1;
4313     //double Z1=double(z1.terms)*d1; double Z2=double(z2.terms)*d2; if (Z1!=Z2) return Z2>Z1;
4314     if (z1.terms!=z2.terms) return z2.terms>z1.terms;
4315     if (z1.deg!=z2.deg)
4316       return tdeg_t_greater(z1.deg,z2.deg,z1.o)!=0;
4317     if (z1.pos!=z2.pos)
4318       return z2.pos>z1.pos;
4319     return false;
4320   }
4321 
4322   template<class tdeg_t>
reducesmallmod(polymod<tdeg_t> & rem,const vectpolymod<tdeg_t> & res,const vector<unsigned> & G,unsigned excluded,modint env,polymod<tdeg_t> & TMP1,bool normalize,int start_index=0,bool topreduceonly=false)4323   void reducesmallmod(polymod<tdeg_t> & rem,const vectpolymod<tdeg_t> & res,const vector<unsigned> & G,unsigned excluded,modint env,polymod<tdeg_t> & TMP1,bool normalize,int start_index=0,bool topreduceonly=false){
4324     if (debug_infolevel>1000){
4325       rem.dbgprint();
4326       if (!rem.coord.empty()) rem.coord.front().u.dbgprint();
4327     }
4328     typename std::vector< T_unsigned<modint,tdeg_t> >::const_iterator pt,ptend;
4329     unsigned i,rempos=0;
4330     TMP1.coord.clear();
4331     unsigned Gs=unsigned(G.size());
4332     const order_t o=rem.order;
4333     int Gstart_index=0;
4334     // starting at excluded may fail because the batch of new basis element created
4335     // by f4mod is reduced with respect to the previous batches but not necessarily
4336     // with respect to itself
4337     if (start_index && excluded<Gs){
4338       for (int i=excluded;i>=0;--i){
4339 	int Gi=G[i];
4340 	if (Gi<=start_index){
4341 	  Gstart_index=i;
4342 	  break;
4343 	}
4344       }
4345     }
4346 #ifdef GIAC_GBASIS_PERMUTATION2
4347     if (excluded<Gs)
4348       excluded=G[excluded];
4349     else
4350       excluded=-1;
4351     vector<zsymb_data> zsGi(Gs);
4352     for (unsigned i=0;i<Gs;++i){
4353       int Gi=G[i];
4354       const polymod<tdeg_t> & cur=res[Gi];
4355       zsymb_data tmp={Gi,cur.coord.empty()?0:cur.coord.front().u,o,cur.coord.size(),0};
4356       zsGi[i]=tmp;
4357     }
4358     sort(zsGi.begin(),zsGi.end(),tri);
4359 #else
4360     const tdeg_t ** resGi=(const tdeg_t **) malloc(Gs*sizeof(tdeg_t *));
4361     for (unsigned i=0;i<Gs;++i){
4362       resGi[i]=res[G[i]].coord.empty()?0:&res[G[i]].coord.front().u;
4363     }
4364 #endif
4365     for (unsigned count=0;;++count){
4366       ptend=rem.coord.end();
4367       // this branch search first in all leading coeff of G for a monomial
4368       // <= to the current rem monomial
4369       pt=rem.coord.begin()+rempos;
4370       if (pt>=ptend)
4371 	break;
4372       const tdeg_t &ptu=pt->u;
4373 #ifdef GIAC_GBASIS_PERMUTATION2
4374       for (i=0;i<Gs;++i){
4375 	zsymb_data & zs=zsGi[i];
4376 	if (zs.terms && zs.pos!=excluded && tdeg_t_all_greater(ptu,zs.deg,o))
4377 	  break;
4378       }
4379 #else // GIAC_GBASIS_PERMUTATION2
4380       if (excluded<Gs){
4381 	i=Gs;
4382 	const tdeg_t ** resGi_=resGi+excluded+1,**resGiend=resGi+Gs;
4383 	for (;resGi_<resGiend;++resGi_){
4384 	  if (!*resGi_)
4385 	    continue;
4386 	  if (tdeg_t_all_greater(ptu,**resGi_,o)){
4387 	    i=unsigned(resGi_-resGi);
4388 	    break;
4389 	  }
4390 	}
4391 	if (i==Gs){
4392 	  resGi_=resGi+Gstart_index;
4393 	  resGiend=resGi+excluded;
4394 	  for (;resGi_<resGiend;++resGi_){
4395 	    if (!*resGi_)
4396 	      continue;
4397 	    if (tdeg_t_all_greater(ptu,**resGi_,o)){
4398 	      i=unsigned(resGi_-resGi);
4399 	      break;
4400 	    }
4401 	  }
4402 	}
4403       }
4404       else {
4405 	const tdeg_t ** resGi_=resGi,**resGiend=resGi+Gs;
4406 	for (;resGi_<resGiend;++resGi_){
4407 	  if (!*resGi_)
4408 	    continue;
4409 #if 0
4410 	  int res=tdeg_t_compare_all(ptu,**resGi_,o);
4411 	  if (res==1) break;
4412 	  if (res==-1)
4413 	    *resGi_=0;
4414 #else
4415 	  if (tdeg_t_all_greater(ptu,**resGi_,o))
4416 	    break;
4417 #endif
4418 	}
4419 	i=unsigned(resGi_-resGi);
4420       }
4421 #endif // GIAC_GBASIS_PERMUTATION2
4422       if (i==G.size()){ // no leading coeff of G is smaller than the current coeff of rem
4423 	++rempos;
4424 	if (topreduceonly)
4425 	  break;
4426 	// if (small0) TMP1.coord.push_back(*pt);
4427 	continue;
4428       }
4429 #ifdef GIAC_GBASIS_PERMUTATION2
4430       int Gi=zsGi[i].pos;
4431 #else
4432       int Gi=G[i];
4433 #endif
4434       modint a(pt->g),b(res[Gi].coord.front().g);
4435       smallmultsubmodshift(rem,0,smod(a*modint2(invmod(b,env)),env),res[Gi],pt->u-res[Gi].coord.front().u,TMP1,env);
4436       // smallmultsub(rem,rempos,smod(a*invmod(b,env->modulo),env->modulo).val,res[G[i]],pt->u-res[G[i]].coord.front().u,TMP2,env->modulo.val);
4437       // rempos=0; // since we have removed the beginning of rem (copied in TMP1)
4438       swap(rem.coord,TMP1.coord);
4439       continue;
4440     }
4441     if (normalize && !rem.coord.empty() && rem.coord.front().g!=1){
4442       // smallmult does %, smallmultmod also make the result positive
4443       // smallmult(invmod(rem.coord.front().g,env),rem.coord,rem.coord,env);
4444       smallmultmod(invmod(rem.coord.front().g,env),rem,env,false);
4445       rem.coord.front().g=1;
4446     }
4447 #ifndef GIAC_GBASIS_PERMUTATION2
4448     free(resGi);
4449 #endif
4450   }
4451 
4452   template<class tdeg_t>
reducemod(vectpolymod<tdeg_t> & resmod,modint env)4453   static void reducemod(vectpolymod<tdeg_t> &resmod,modint env){
4454     if (resmod.empty())
4455       return;
4456     // Initial interreduce step
4457     polymod<tdeg_t> TMP1(resmod.front().order,resmod.front().dim);
4458     vector<unsigned> G(resmod.size());
4459     for (unsigned j=0;j<G.size();++j)
4460       G[j]=j;
4461     for (unsigned j=0; j<resmod.size();++j){
4462 #ifdef TIMEOUT
4463       control_c();
4464 #endif
4465       if (interrupted || ctrl_c)
4466 	return;
4467       reducesmallmod(resmod[j],resmod,G,j,env,TMP1,true);
4468     }
4469   }
4470 
4471   template<class tdeg_t>
gbasis_updatemod(vector<unsigned> & G,vector<paire> & B,vectpolymod<tdeg_t> & res,unsigned pos,polymod<tdeg_t> & TMP2,modint env,bool reduce,const vector<unsigned> & oldG)4472   void gbasis_updatemod(vector<unsigned> & G,vector< paire > & B,vectpolymod<tdeg_t> & res,unsigned pos,polymod<tdeg_t> & TMP2,modint env,bool reduce,const vector<unsigned> & oldG){
4473     if (debug_infolevel>2)
4474       CERR << CLOCK()*1e-6 << " mod begin gbasis update " << G.size() << '\n';
4475     if (debug_infolevel>3)
4476       CERR << G << '\n';
4477     const polymod<tdeg_t> & h = res[pos];
4478     if (h.coord.empty())
4479       return;
4480     order_t order=h.order;
4481     vector<unsigned> C;
4482     C.reserve(G.size()+1);
4483     const tdeg_t & h0=h.coord.front().u;
4484     // FIXME: should use oldG instead of G here
4485     for (unsigned i=0;i<oldG.size();++i){
4486       if (tdeg_t_all_greater(h0,res[oldG[i]].coord.front().u,order))
4487 	return;
4488     }
4489     tdeg_t tmp1,tmp2;
4490     // C is used to construct new pairs
4491     // create pairs with h and elements g of G, then remove
4492     // -> if g leading monomial is prime with h, remove the pair
4493     // -> if g leading monomial is not disjoint from h leading monomial
4494     //    keep it only if lcm of leading monomial is not divisible by another one
4495 #if 1
4496     size_t tmpsize=G.size();
4497     vector<tdeg_t> tmp(tmpsize);
4498     for (unsigned i=0;i<tmpsize;++i){
4499       if (res[G[i]].coord.empty()){
4500 	tmp[i].tab[0]=-2;
4501       }
4502       else
4503 	index_lcm(h0,res[G[i]].coord.front().u,tmp[i],order);
4504     }
4505 #else
4506     // this would be faster but it does not work for
4507     // gbasis([25*y^2*x^6-10*y^2*x^5+59*y^2*x^4-20*y^2*x^3+43*y^2*x^2-10*y^2*x+9*y^2-80*y*x^6+136*y*x^5+56*y*x^4-240*y*x^3+104*y*x^2+64*x^6-192*x^5+192*x^4-64*x^3,25*y^2*6*x^5-10*y^2*5*x^4+59*y^2*4*x^3-20*y^2*3*x^2+43*y^2*2*x-10*y^2-80*y*6*x^5+136*y*5*x^4+56*y*4*x^3-240*y*3*x^2+104*y*2*x+64*6*x^5-192*5*x^4+192*4*x^3-64*3*x^2,25*2*y*x^6-10*2*y*x^5+59*2*y*x^4-20*2*y*x^3+43*2*y*x^2-10*2*y*x+9*2*y-80*x^6+136*x^5+56*x^4-240*x^3+104*x^2],[x,y],revlex);
4508     // pair <4,3> is not generated
4509     unsigned tmpsize=G.empty()?0:G.back()+1;
4510     vector<tdeg_t> tmp(tmpsize);
4511     for (unsigned i=0;i<tmpsize;++i){
4512       if (res[i].coord.empty()){
4513 	tmp[i].tab[0]=-2;
4514       }
4515       else
4516 	index_lcm(h0,res[i].coord.front().u,tmp[i],order);
4517     }
4518 #endif
4519     for (unsigned i=0;i<G.size();++i){
4520 #ifdef TIMEOUT
4521       control_c();
4522 #endif
4523       if (interrupted || ctrl_c)
4524 	return;
4525       if (res[G[i]].coord.empty() || disjoint(h0,res[G[i]].coord.front().u,res.front().order,res.front().dim))
4526 	continue;
4527       // h0 and G[i] leading monomial not prime together
4528 #if 1
4529       tdeg_t * tmp1=&tmp[i];
4530 #else
4531       tdeg_t * tmp1=&tmp[G[i]];
4532 #endif
4533       tdeg_t * tmp2=&tmp[0],*tmpend=tmp2+tmpsize;
4534       for (;tmp2!=tmp1;++tmp2){
4535 	if (tmp2->tab[0]<0)
4536 	  continue;
4537 	if (tdeg_t_all_greater(*tmp1,*tmp2,order))
4538 	  break; // found another pair, keep the smallest, or the first if equal
4539       }
4540       if (tmp2!=tmp1)
4541 	continue;
4542       for (++tmp2;tmp2<tmpend;++tmp2){
4543 	if (tmp2->tab[0]<0)
4544 	  continue;
4545 	if (tdeg_t_all_greater(*tmp1,*tmp2,order) && *tmp1!=*tmp2){
4546 	  break;
4547 	}
4548       }
4549       if (tmp2==tmpend)
4550 	C.push_back(G[i]);
4551     }
4552     vector< paire > B1;
4553     B1.reserve(B.size()+C.size());
4554     for (unsigned i=0;i<B.size();++i){
4555 #ifdef TIMEOUT
4556       control_c();
4557 #endif
4558       if (interrupted || ctrl_c)
4559 	return;
4560       if (res[B[i].first].coord.empty() || res[B[i].second].coord.empty())
4561 	continue;
4562       index_lcm(res[B[i].first].coord.front().u,res[B[i].second].coord.front().u,tmp1,order);
4563       if (!tdeg_t_all_greater(tmp1,h0,order)){
4564 	B1.push_back(B[i]);
4565 	continue;
4566       }
4567       index_lcm(res[B[i].first].coord.front().u,h0,tmp2,order);
4568       if (tmp2==tmp1){
4569 	B1.push_back(B[i]);
4570 	continue;
4571       }
4572       index_lcm(res[B[i].second].coord.front().u,h0,tmp2,order);
4573       if (tmp2==tmp1){
4574 	B1.push_back(B[i]);
4575 	continue;
4576       }
4577     }
4578     // B <- B union pairs(h,g) with g in C
4579     for (unsigned i=0;i<C.size();++i){
4580       B1.push_back(paire(pos,C[i]));
4581     }
4582     swap(B1,B);
4583     // Update G by removing elements with leading monomial >= leading monomial of h
4584     if (debug_infolevel>2){
4585       CERR << CLOCK()*1e-6 << " end, pairs:"<< '\n';
4586       if (debug_infolevel>3)
4587 	CERR << B << '\n';
4588       CERR << "mod begin Groebner interreduce " << '\n';
4589     }
4590     C.clear();
4591     C.reserve(G.size()+1);
4592     // bool pos_pushed=false;
4593     for (unsigned i=0;i<G.size();++i){
4594 #ifdef TIMEOUT
4595       control_c();
4596 #endif
4597       if (interrupted || ctrl_c)
4598 	return;
4599       if (!res[G[i]].coord.empty() && !tdeg_t_all_greater(res[G[i]].coord.front().u,h0,order)){
4600 	if (reduce){
4601 	  // reduce res[G[i]] with respect to h
4602 	  reduce1smallmod(res[G[i]],h,TMP2,env);
4603 	}
4604 	C.push_back(G[i]);
4605       }
4606       // NB: removing all pairs containing i in it does not work
4607     }
4608     if (debug_infolevel>2)
4609       CERR << CLOCK()*1e-6 << " mod end Groebner interreduce " << '\n';
4610     C.push_back(pos);
4611     swap(C,G);
4612 #if 0
4613     // clear in res polymod<tdeg_t> that are no more referenced
4614     vector<bool> used(res.size(),false);
4615     for (unsigned i=0;i<G.size();++i){
4616       used[G[i]]=true;
4617     }
4618     for (unsigned i=0;i<B.size();++i){
4619       used[B[i].first]=true;
4620       used[B[i].first]=false;
4621     }
4622     for (unsigned i=0;i<res.size();++i){
4623       if (!used[i] && !res[i].coord.capacity()){
4624 	polymod<tdeg_t> clearer;
4625 	swap(res[i].coord,clearer.coord);
4626       }
4627     }
4628 #endif
4629   }
4630 
4631 #if 0
4632   // update G, G is a list of index of the previous gbasis + new spolys
4633   // new spolys index are starting at debut
4634   template<class tdeg_t>
4635   void gbasis_multiupdatemod(vector<unsigned> & G,vector< paire > & B,vectpolymod<tdeg_t> & res,unsigned debut,polymod<tdeg_t> & TMP2,modint env){
4636     if (debug_infolevel>2)
4637       CERR << CLOCK()*1e-6 << " mod begin gbasis update " << G.size() << "+" << add.size() << '\n';
4638     if (debug_infolevel>3)
4639       CERR << G << '\n';
4640     vector<unsigned> C;
4641     // C is used to construct new pairs
4642     tdeg_t tmp1,tmp2;
4643     order_t order;
4644     for (unsigned pos=debut;pos<G.size();++pos){
4645       const polymod<tdeg_t> & h = res[pos];
4646       const tdeg_t & h0=h.coord.front().u;
4647       // create pairs with h and elements g of G, then remove
4648       // -> if g leading monomial is prime with h, remove the pair
4649       // -> if g leading monomial is not disjoint from h leading monomial
4650       //    keep it only if lcm of leading monomial is not divisible by another one
4651       for (unsigned i=0;i<pos;++i){
4652 #ifdef TIMEOUT
4653 	control_c();
4654 #endif
4655 	if (interrupted || ctrl_c)
4656 	  return;
4657 	if (res[G[i]].coord.empty() || disjoint(h0,res[G[i]].coord.front().u,res.front().order,res.front().dim))
4658 	  continue;
4659 	index_lcm(h0,res[G[i]].coord.front().u,tmp1,order); // h0 and G[i] leading monomial not prime together
4660 	unsigned j;
4661 	for (j=0;j<G.size();++j){
4662 	  if (i==j || res[G[j]].coord.empty())
4663 	    continue;
4664 	  index_lcm(h0,res[G[j]].coord.front().u,tmp2,order);
4665 	  if (tdeg_t_all_greater(tmp1,tmp2,order)){
4666 	    // found another pair, keep the smallest, or the first if equal
4667 	    if (tmp1!=tmp2)
4668 	      break;
4669 	    if (i>j)
4670 	      break;
4671 	  }
4672 	} // end for j
4673 	if (j==G.size())
4674 	  C.push_back(G[i]);
4675       }
4676     }
4677     vector< paire > B1;
4678     B1.reserve(B.size()+C.size());
4679     for (unsigned i=0;i<B.size();++i){
4680 #ifdef TIMEOUT
4681       control_c();
4682 #endif
4683       if (interrupted || ctrl_c)
4684 	return;
4685       if (res[B[i].first].coord.empty() || res[B[i].second].coord.empty())
4686 	continue;
4687       index_lcm(res[B[i].first].coord.front().u,res[B[i].second].coord.front().u,tmp1,order);
4688       for (unsigned pos=debut;pos<G.size();++pos){
4689 	const tdeg_t & h0=res[G[pos]].front().u;
4690 	if (!tdeg_t_all_greater(tmp1,h0,order)){
4691 	  B1.push_back(B[i]);
4692 	  break;
4693 	}
4694 	index_lcm(res[B[i].first].coord.front().u,h0,tmp2,order);
4695 	if (tmp2==tmp1){
4696 	  B1.push_back(B[i]);
4697 	  break;
4698 	}
4699 	index_lcm(res[B[i].second].coord.front().u,h0,tmp2,order);
4700 	if (tmp2==tmp1){
4701 	  B1.push_back(B[i]);
4702 	  break;
4703 	}
4704       }
4705     }
4706     // B <- B union B2
4707     for (unsigned i=0;i<B2.size();++i)
4708       B1.push_back(B2[i]);
4709     swap(B1,B);
4710     // Update G by removing elements with leading monomial >= leading monomial of h
4711     if (debug_infolevel>2){
4712       CERR << CLOCK()*1e-6 << " end, pairs:"<< '\n';
4713       if (debug_infolevel>3)
4714 	CERR << B << '\n';
4715       CERR << "mod begin Groebner interreduce " << '\n';
4716     }
4717     vector<unsigned> C;
4718     C.reserve(G.size());
4719     for (unsigned i=0;i<G.size();++i){
4720 #ifdef TIMEOUT
4721       control_c();
4722 #endif
4723       if (interrupted || ctrl_c)
4724 	return;
4725       if (res[G[i]].coord.empty())
4726 	continue;
4727       const tdeg_t & Gi=res[G[i]].coord.front().u;
4728       unsigned j;
4729       for (j=i+1;j<G.size();++j){
4730 	if (tdeg_t_all_greater(Gi,res[G[j]].coord.front().u,order))
4731 	  break;
4732       }
4733       if (i==G.size()-1 || j==G.size())
4734 	C.push_back(G[i]);
4735     }
4736     if (debug_infolevel>2)
4737       CERR << CLOCK()*1e-6 << " mod end Groebner interreduce " << '\n';
4738     swap(C,G);
4739   }
4740 #endif
4741 
4742   template<class tdeg_t>
in_gbasismod(vectpoly8<tdeg_t> & res8,vectpolymod<tdeg_t> & res,vector<unsigned> & G,modint env,bool sugar,vector<paire> * pairs_reducing_to_zero)4743   bool in_gbasismod(vectpoly8<tdeg_t> & res8,vectpolymod<tdeg_t> &res,vector<unsigned> & G,modint env,bool sugar,vector< paire > * pairs_reducing_to_zero){
4744     convert(res8,res,env);
4745     unsigned ressize=unsigned(res8.size());
4746     unsigned learned_position=0;
4747     bool learning=pairs_reducing_to_zero && pairs_reducing_to_zero->empty();
4748     if (debug_infolevel>1000)
4749       res.dbgprint(); // instantiate dbgprint()
4750     polymod<tdeg_t> TMP1(res.front().order,res.front().dim),TMP2(res.front().order,res.front().dim);
4751     vector< paire > B;
4752     order_t order=res.front().order;
4753     if (order.o==_PLEX_ORDER)
4754       sugar=false;
4755     vector<unsigned> oldG(G);
4756     if (debug_infolevel>1)
4757       CERR << CLOCK()*1e-6 << " initial reduction/gbasis_updatemod: " << ressize << '\n';
4758     for (unsigned l=0;l<ressize;++l){
4759 #ifdef GIAC_REDUCEMODULO
4760       reducesmallmod(res[l],res,G,-1,env,TMP2,env!=0);
4761 #endif
4762       gbasis_updatemod(G,B,res,l,TMP2,env,true,oldG);
4763     }
4764     for (;!B.empty() && !interrupted && !ctrl_c;){
4765       oldG=G;
4766       if (debug_infolevel>1)
4767 	CERR << CLOCK()*1e-6 << " mod number of pairs: " << B.size() << ", base size: " << G.size() << '\n';
4768       // find smallest lcm pair in B
4769       tdeg_t small0,cur;
4770       unsigned smallpos,smallsugar=0,cursugar=0;
4771       for (smallpos=0;smallpos<B.size();++smallpos){
4772 	if (!res[B[smallpos].first].coord.empty() && !res[B[smallpos].second].coord.empty())
4773 	  break;
4774 #ifdef TIMEOUT
4775 	control_c();
4776 #endif
4777 	if (interrupted || ctrl_c)
4778 	  return false;
4779       }
4780       index_lcm(res[B[smallpos].first].coord.front().u,res[B[smallpos].second].coord.front().u,small0,order);
4781       if (sugar)
4782 	smallsugar=res[B[smallpos].first].sugar+(small0-res[B[smallpos].first].coord.front().u).total_degree(order);
4783       for (unsigned i=smallpos+1;i<B.size();++i){
4784 #ifdef TIMEOUT
4785 	control_c();
4786 #endif
4787 	if (interrupted || ctrl_c)
4788 	  return false;
4789 	if (res[B[i].first].coord.empty() || res[B[i].second].coord.empty())
4790 	  continue;
4791 	bool doswap=false;
4792 	index_lcm(res[B[i].first].coord.front().u,res[B[i].second].coord.front().u,cur,order);
4793 	if (sugar)
4794 	  cursugar=res[B[smallpos].first].sugar+(cur-res[B[smallpos].first].coord.front().u).total_degree(order);
4795 	if (order.o==_PLEX_ORDER)
4796 	  doswap=tdeg_t_strictly_greater(small0,cur,order);
4797 	else {
4798 	  if (cursugar!=smallsugar)
4799 	    doswap = smallsugar > cursugar;
4800 	  else
4801 	    doswap=tdeg_t_strictly_greater(small0,cur,order);
4802 	}
4803 	if (doswap){
4804 	  // CERR << "swap mod " << cursugar << " " << res[B[i].first].coord.front().u << " " << res[B[i].second].coord.front().u << '\n';
4805 	  swap(small0,cur); // small0=cur;
4806 	  swap(smallsugar,cursugar);
4807 	  smallpos=i;
4808 	}
4809       }
4810       paire bk=B[smallpos];
4811       B.erase(B.begin()+smallpos);
4812       if (pairs_reducing_to_zero && learned_position<pairs_reducing_to_zero->size() && bk==(*pairs_reducing_to_zero)[learned_position]){
4813 	++learned_position;
4814 	continue;
4815       }
4816       if (debug_infolevel>1 && (equalposcomp(G,bk.first)==0 || equalposcomp(G,bk.second)==0))
4817 	CERR << CLOCK()*1e-6 << " mod reducing pair with 1 element not in basis " << bk << '\n';
4818       // polymod<tdeg_t> h(res.front().order,res.front().dim);
4819       spolymod<tdeg_t>(res[bk.first],res[bk.second],TMP1,TMP2,env);
4820       if (debug_infolevel>1){
4821 	CERR << CLOCK()*1e-6 << " mod reduce begin, pair " << bk << " spoly size " << TMP1.coord.size() << " sugar deg " << TMP1.sugar << " degree " << TMP1.coord.front().u << '\n';
4822       }
4823       reducemod(TMP1,res,G,-1,TMP1,env);
4824       if (debug_infolevel>1){
4825 	if (debug_infolevel>2){ CERR << TMP1 << '\n'; }
4826 	CERR << CLOCK()*1e-6 << " mod reduce end, remainder size " << TMP1.coord.size() << '\n';
4827       }
4828       if (!TMP1.coord.empty()){
4829 	if (ressize==res.size())
4830 	  res.push_back(polymod<tdeg_t>(TMP1.order,TMP1.dim));
4831 	swap(res[ressize],TMP1);
4832 	++ressize;
4833 	gbasis_updatemod(G,B,res,ressize-1,TMP2,env,true,oldG);
4834 	if (debug_infolevel>2)
4835 	  CERR << CLOCK()*1e-6 << " mod basis indexes " << G << " pairs indexes " << B << '\n';
4836       }
4837       else {
4838 	if (learning && pairs_reducing_to_zero)
4839 	  pairs_reducing_to_zero->push_back(bk);
4840       }
4841     }
4842     if (ressize<res.size())
4843       res.resize(ressize);
4844     // sort(res.begin(),res.end(),tripolymod<tdeg_t>);
4845     convert(res,G,res8,env);
4846     return true;
4847   }
4848 
4849   // F4BUCHBERGER algorithm
4850   template<class tdeg_t>
4851   struct heap_tt {
4852     bool left;
4853     unsigned f4buchbergervpos:31;
4854     unsigned polymodpos;
4855     tdeg_t u;
heap_ttgiac::heap_tt4856     heap_tt(bool l,unsigned a,unsigned b,tdeg_t t):left(l),f4buchbergervpos(a),polymodpos(b),u(t){};
heap_ttgiac::heap_tt4857     heap_tt(unsigned a,unsigned b,tdeg_t t):left(true),f4buchbergervpos(a),polymodpos(b),u(t){};
heap_ttgiac::heap_tt4858     heap_tt():left(true),f4buchbergervpos(0),polymodpos(0),u(){};
4859   };
4860 
4861   template<class tdeg_t>
4862   struct heap_tt_compare {
4863     order_t order;
4864     const heap_tt<tdeg_t> * ptr;
operator ()giac::heap_tt_compare4865     inline bool operator () (unsigned a,unsigned b){
4866       return !tdeg_t_greater((ptr+a)->u,(ptr+b)->u,order);
4867       // return (ptr+a)->u<(ptr+b)->u;
4868     }
heap_tt_comparegiac::heap_tt_compare4869     heap_tt_compare(const vector<heap_tt<tdeg_t> > & v,order_t o):order(o),ptr(v.empty()?0:&v.front()){};
4870   };
4871 
4872 
4873   template<class tdeg_t>
4874   struct compare_heap_tt {
4875     order_t order;
operator ()giac::compare_heap_tt4876     inline bool operator () (const heap_tt<tdeg_t> & a,const heap_tt<tdeg_t> & b){
4877       return !tdeg_t_greater(a.u,b.u,order);
4878       // return (ptr+a)->u<(ptr+b)->u;
4879     }
compare_heap_ttgiac::compare_heap_tt4880     compare_heap_tt(order_t o):order(o) {}
4881   };
4882 
4883 
4884   // inline bool operator > (const heap_tt & a,const heap_tt & b){ return a.u>b.u; }
4885 
4886   // inline bool operator < (const heap_tt & a,const heap_tt & b){ return b>a;}
4887 
4888   template<class tdeg_t>
4889   struct heap_tt_ptr {
4890     heap_tt<tdeg_t> * ptr;
heap_tt_ptrgiac::heap_tt_ptr4891     heap_tt_ptr(heap_tt<tdeg_t> * ptr_):ptr(ptr_){};
heap_tt_ptrgiac::heap_tt_ptr4892     heap_tt_ptr():ptr(0){};
4893   };
4894 
4895 
4896   // inline bool operator > (const heap_tt_ptr & a,const heap_tt_ptr & b){ return a.ptr->u > b.ptr->u; }
4897 
4898   // inline bool operator < (const heap_tt_ptr & a,const heap_tt_ptr & b){ return b>a; }
4899   template<class tdeg_t>
4900   struct compare_heap_tt_ptr {
4901     order_t order;
operator ()giac::compare_heap_tt_ptr4902     inline bool operator () (const heap_tt_ptr<tdeg_t> & a,const heap_tt_ptr<tdeg_t> & b){
4903       return !tdeg_t_greater(a.ptr->u,b.ptr->u,order);
4904       // return (ptr+a)->u<(ptr+b)->u;
4905     }
compare_heap_tt_ptrgiac::compare_heap_tt_ptr4906     compare_heap_tt_ptr(order_t o):order(o) {}
4907   };
4908 
4909 
4910   template<class tdeg_t>
collect(const vectpolymod<tdeg_t> & f4buchbergerv,polymod<tdeg_t> & allf4buchberger,int start=0)4911   void collect(const vectpolymod<tdeg_t> & f4buchbergerv,polymod<tdeg_t> & allf4buchberger,int start=0){
4912     typename vectpolymod<tdeg_t>::const_iterator it=f4buchbergerv.begin(),itend=f4buchbergerv.end();
4913     vector<heap_tt<tdeg_t> > Ht;
4914     vector<heap_tt_ptr<tdeg_t> > H;
4915     Ht.reserve(itend-it);
4916     H.reserve(itend-it);
4917     unsigned s=0;
4918     order_t keyorder={_REVLEX_ORDER,0};
4919     for (unsigned i=0;it!=itend;++i,++it){
4920       keyorder=it->order;
4921       if (int(it->coord.size())>start){
4922 	s=giacmax(s,unsigned(it->coord.size()));
4923 	Ht.push_back(heap_tt<tdeg_t>(i,start,it->coord[start].u));
4924 	H.push_back(heap_tt_ptr<tdeg_t>(&Ht.back()));
4925       }
4926     }
4927     allf4buchberger.coord.reserve(s); // int(s*std::log(1+H.size())));
4928     compare_heap_tt_ptr<tdeg_t> key(keyorder);
4929     make_heap(H.begin(),H.end(),key);
4930     while (!H.empty()){
4931       std::pop_heap(H.begin(),H.end(),key);
4932       // push root node of the heap in allf4buchberger
4933       heap_tt<tdeg_t> & current = *H.back().ptr;
4934       if (allf4buchberger.coord.empty() || allf4buchberger.coord.back().u!=current.u)
4935 	allf4buchberger.coord.push_back(T_unsigned<modint,tdeg_t>(1,current.u));
4936       ++current.polymodpos;
4937       if (current.polymodpos>=f4buchbergerv[current.f4buchbergervpos].coord.size()){
4938 	H.pop_back();
4939 	continue;
4940       }
4941       current.u=f4buchbergerv[current.f4buchbergervpos].coord[current.polymodpos].u;
4942       std::push_heap(H.begin(),H.end(),key);
4943     }
4944   }
4945 
4946   template<class tdeg_t>
collect(const vectpolymod<tdeg_t> & f4buchbergerv,const vector<unsigned> & G,polymod<tdeg_t> & allf4buchberger,unsigned start=0)4947   void collect(const vectpolymod<tdeg_t> & f4buchbergerv,const vector<unsigned> & G,polymod<tdeg_t> & allf4buchberger,unsigned start=0){
4948     unsigned Gsize=unsigned(G.size());
4949     if (!Gsize) return;
4950     vector<heap_tt<tdeg_t> > H;
4951     compare_heap_tt<tdeg_t> key(f4buchbergerv[G[0]].order);
4952     H.reserve(Gsize);
4953     for (unsigned i=0;i<Gsize;++i){
4954       if (f4buchbergerv[G[i]].coord.size()>start)
4955 	H.push_back(heap_tt<tdeg_t>(i,start,f4buchbergerv[G[i]].coord[start].u));
4956     }
4957     make_heap(H.begin(),H.end(),key);
4958     while (!H.empty()){
4959       std::pop_heap(H.begin(),H.end(),key);
4960       // push root node of the heap in allf4buchberger
4961       heap_tt<tdeg_t> & current =H.back();
4962       if (allf4buchberger.coord.empty() || allf4buchberger.coord.back().u!=current.u)
4963 	allf4buchberger.coord.push_back(T_unsigned<modint,tdeg_t>(1,current.u));
4964       ++current.polymodpos;
4965       if (current.polymodpos>=f4buchbergerv[G[current.f4buchbergervpos]].coord.size()){
4966 	H.pop_back();
4967 	continue;
4968       }
4969       current.u=f4buchbergerv[G[current.f4buchbergervpos]].coord[current.polymodpos].u;
4970       std::push_heap(H.begin(),H.end(),key);
4971     }
4972   }
4973 
4974   template<class tdeg_t>
leftright(const vectpolymod<tdeg_t> & res,vector<paire> & B,vector<tdeg_t> & leftshift,vector<tdeg_t> & rightshift)4975   void leftright(const vectpolymod<tdeg_t> & res,vector< paire > & B,vector<tdeg_t> & leftshift,vector<tdeg_t> & rightshift){
4976     for (unsigned i=0;i<B.size();++i){
4977       const polymod<tdeg_t> & p=res[B[i].first];
4978       const polymod<tdeg_t> & q=res[B[i].second];
4979       if (debug_infolevel>2)
4980 	CERR << "leftright " << p << "," << q << '\n';
4981       tdeg_t l(p.coord.front().u);
4982       index_lcm(p.coord.front().u,q.coord.front().u,l,p.order);
4983       leftshift[i]=l-p.coord.front().u;
4984       rightshift[i]=l-q.coord.front().u;
4985     }
4986   }
4987 
4988   // collect monomials from pairs of res (vector of polymods), shifted by lcm
4989   // does not collect leading monomial (since they cancel)
4990   template<class tdeg_t>
collect(const vectpolymod<tdeg_t> & res,vector<paire> & B,polymod<tdeg_t> & allf4buchberger,vector<tdeg_t> & leftshift,vector<tdeg_t> & rightshift)4991   void collect(const vectpolymod<tdeg_t> & res,vector< paire > & B,polymod<tdeg_t> & allf4buchberger,vector<tdeg_t> & leftshift,vector<tdeg_t> & rightshift){
4992     int start=1;
4993     vector<heap_tt<tdeg_t> > Ht;
4994     vector<heap_tt_ptr<tdeg_t> > H;
4995     Ht.reserve(2*B.size());
4996     H.reserve(2*B.size());
4997     unsigned s=0;
4998     order_t keyorder={_REVLEX_ORDER,0};
4999     for (unsigned i=0;i<B.size();++i){
5000       const polymod<tdeg_t> & p=res[B[i].first];
5001       const polymod<tdeg_t> & q=res[B[i].second];
5002       keyorder=p.order;
5003       if (int(p.coord.size())>start){
5004 	s=giacmax(s,unsigned(p.coord.size()));
5005 	Ht.push_back(heap_tt<tdeg_t>(true,i,start,p.coord[start].u+leftshift[i]));
5006 	H.push_back(heap_tt_ptr<tdeg_t>(&Ht.back()));
5007       }
5008       if (int(q.coord.size())>start){
5009 	s=giacmax(s,unsigned(q.coord.size()));
5010 	Ht.push_back(heap_tt<tdeg_t>(false,i,start,q.coord[start].u+rightshift[i]));
5011 	H.push_back(heap_tt_ptr<tdeg_t>(&Ht.back()));
5012       }
5013     }
5014     allf4buchberger.coord.reserve(s); // int(s*std::log(1+H.size())));
5015     compare_heap_tt_ptr<tdeg_t> key(keyorder);
5016     make_heap(H.begin(),H.end(),key);
5017     while (!H.empty()){
5018       std::pop_heap(H.begin(),H.end(),key);
5019       // push root node of the heap in allf4buchberger
5020       heap_tt<tdeg_t> & current = *H.back().ptr;
5021       if (allf4buchberger.coord.empty() || allf4buchberger.coord.back().u!=current.u)
5022 	allf4buchberger.coord.push_back(T_unsigned<modint,tdeg_t>(1,current.u));
5023       ++current.polymodpos;
5024       unsigned vpos;
5025       if (current.left)
5026 	vpos=B[current.f4buchbergervpos].first;
5027       else
5028 	vpos=B[current.f4buchbergervpos].second;
5029       if (current.polymodpos>=res[vpos].coord.size()){
5030 	H.pop_back();
5031 	continue;
5032       }
5033       if (current.left)
5034 	current.u=res[vpos].coord[current.polymodpos].u+leftshift[current.f4buchbergervpos];
5035       else
5036 	current.u=res[vpos].coord[current.polymodpos].u+rightshift[current.f4buchbergervpos];
5037       std::push_heap(H.begin(),H.end(),key);
5038     }
5039   }
5040 
5041   struct sparse_element {
5042     modint val;
5043     unsigned pos;
sparse_elementgiac::sparse_element5044     sparse_element(modint v,size_t u):val(v),pos(unsigned(u)){};
sparse_elementgiac::sparse_element5045     sparse_element():val(0),pos(-1){};
5046   };
5047 
5048 #ifdef NSPIRE
5049   template<class T>
operator <<(nio::ios_base<T> & os,const sparse_element & s)5050   nio::ios_base<T> & operator << (nio::ios_base<T> & os,const sparse_element & s){
5051     return os << '{' << s.val<<',' << s.pos << '}' ;
5052   }
5053 #else
operator <<(ostream & os,const sparse_element & s)5054   ostream & operator << (ostream & os,const sparse_element & s){
5055     return os << '{' << s.val<<',' << s.pos << '}' ;
5056   }
5057 #endif
5058 
5059 #ifdef GBASISF4_BUCHBERGER
reducef4buchbergerpos(vector<modint> & v,const vector<vector<modint>> & M,vector<int> pivotpos,modint env)5060   bool reducef4buchbergerpos(vector<modint> &v,const vector< vector<modint> > & M,vector<int> pivotpos,modint env){
5061     unsigned pos=0;
5062     bool res=false;
5063     for (unsigned i=0;i<M.size();++i){
5064       const vector<modint> & m=M[i];
5065       pos=pivotpos[i];
5066       if (pos==-1)
5067 	return res;
5068       modint c=v[pos];
5069       if (!c)
5070 	continue;
5071       res=true;
5072       c=(modint2(invmod(m[pos],env))*c)%env;
5073       vector<modint>::const_iterator jt=m.begin()+pos+1;
5074       vector<modint>::iterator it=v.begin()+pos,itend=v.end();
5075       *it=0; ++it;
5076       for (;it!=itend;++jt,++it){
5077 	if (*jt)
5078 	  *it=(*it-modint2(c)*(*jt))%env;
5079       }
5080     }
5081     return res;
5082   }
5083 
5084 #ifdef x86_64
reducef4buchberger_64(vector<modint> & v,const vector<vector<sparse_element>> & M,modint env,vector<int128_t> & w)5085   unsigned reducef4buchberger_64(vector<modint> &v,const vector< vector<sparse_element> > & M,modint env,vector<int128_t> & w){
5086     w.resize(v.size());
5087     vector<modint>::iterator vt=v.begin(),vtend=v.end();
5088     vector<int128_t>::iterator wt=w.begin();
5089     for (;vt!=vtend;++wt,++vt){
5090       *wt=*vt;
5091     }
5092     for (unsigned i=0;i<M.size();++i){
5093       const vector<sparse_element> & m=M[i];
5094       const sparse_element * it=&m.front(),*itend=it+m.size(),*it2;
5095       if (it==itend)
5096 	continue;
5097       int128_t & ww=w[it->pos];
5098       if (ww==0)
5099 	continue;
5100       modint c=(modint2(invmod(it->val,env))*ww)%env;
5101       // CERR << "multiplier ok line " << i << " value " << c << " " << w << '\n';
5102       if (!c)
5103 	continue;
5104       ww=0;
5105       ++it;
5106       it2=itend-8;
5107       for (;it<=it2;){
5108 #if 0
5109 	w[it[0].pos] -= modint2(c)*(it[0].val);
5110 	w[it[1].pos] -= modint2(c)*(it[1].val);
5111 	w[it[2].pos] -= modint2(c)*(it[2].val);
5112 	w[it[3].pos] -= modint2(c)*(it[3].val);
5113 	w[it[4].pos] -= modint2(c)*(it[4].val);
5114 	w[it[5].pos] -= modint2(c)*(it[5].val);
5115 	w[it[6].pos] -= modint2(c)*(it[6].val);
5116 	w[it[7].pos] -= modint2(c)*(it[7].val);
5117 	it+=8;
5118 #else
5119 	w[it->pos] -= modint2(c)*(it->val);
5120 	++it;
5121 	w[it->pos] -= modint2(c)*(it->val);
5122 	++it;
5123 	w[it->pos] -= modint2(c)*(it->val);
5124 	++it;
5125 	w[it->pos] -= modint2(c)*(it->val);
5126 	++it;
5127 	w[it->pos] -= modint2(c)*(it->val);
5128 	++it;
5129 	w[it->pos] -= modint2(c)*(it->val);
5130 	++it;
5131 	w[it->pos] -= modint2(c)*(it->val);
5132 	++it;
5133 	w[it->pos] -= modint2(c)*(it->val);
5134 	++it;
5135 #endif
5136       }
5137       for (;it!=itend;++it){
5138 	w[it->pos] -= modint2(c)*(it->val);
5139       }
5140     }
5141     for (vt=v.begin(),wt=w.begin();vt!=vtend;++wt,++vt){
5142       if (*wt)
5143 	*vt=*wt % env;
5144       else
5145 	*vt=0;
5146     }
5147     for (vt=v.begin();vt!=vtend;++vt){
5148       if (*vt)
5149 	return vt-v.begin();
5150     }
5151     return v.size();
5152   }
5153 
5154 #ifdef NSPIRE
5155   template<class T>
operator <<(nio::ios_base<T> & os,const int128_t & i)5156   nio::ios_base<T> & operator << (nio::ios_base<T> & os,const int128_t & i){
5157     return os << longlong(i) ;
5158     // return os << "(" << longlong(i>>64) <<","<< longlong(i) <<")" ;
5159   }
5160 #else
operator <<(ostream & os,const int128_t & i)5161   ostream & operator << (ostream & os,const int128_t & i){
5162     return os << longlong(i) ;
5163     // return os << "(" << longlong(i>>64) <<","<< longlong(i) <<")" ;
5164   }
5165 #endif
5166 
5167 #endif
5168   // sparse element if prime is < 2^24
5169   // if shift == 0 the position is absolute in the next sparse32 of the vector
5170   struct sparse32 {
5171     modint val:25;
5172     unsigned shift:7;
sparse32giac::sparse325173     sparse32(modint v,unsigned s):val(v),shift(s){};
sparse32giac::sparse325174     sparse32():val(0),shift(0){};
5175   };
5176 
5177 #ifdef NSPIRE
5178   template<class T>
operator <<(nio::ios_base<T> & os,const sparse32 & s)5179   nio::ios_base<T> & operator << (nio::ios_base<T> & os,const sparse32 & s){
5180     return os << "(" << s.val << "," << s.shift << ")" ;
5181   }
5182 #else
operator <<(ostream & os,const sparse32 & s)5183   ostream & operator << (ostream & os,const sparse32 & s){
5184     return os << "(" << s.val << "," << s.shift << ")" ;
5185   }
5186 #endif
5187 
reducef4buchberger_32(vector<modint> & v,const vector<vector<sparse32>> & M,modint env,vector<modint2> & w)5188   unsigned reducef4buchberger_32(vector<modint> &v,const vector< vector<sparse32> > & M,modint env,vector<modint2> & w){
5189     w.resize(v.size());
5190     vector<modint>::iterator vt=v.begin(),vtend=v.end();
5191     vector<modint2>::iterator wt=w.begin();
5192     for (;vt!=vtend;++wt,++vt){
5193       *wt=*vt;
5194     }
5195     for (unsigned i=0;i<M.size();++i){
5196       const vector<sparse32> & m=M[i];
5197       vector<sparse32>::const_iterator it=m.begin(),itend=m.end(),it2=itend-16;
5198       if (it==itend)
5199 	continue;
5200       unsigned p=0;
5201       modint val;
5202       if (it->shift){
5203 	p += it->shift;
5204 	val=it->val;
5205       }
5206       else {
5207 	val=it->val;
5208 	++it;
5209 	p=*(unsigned *)&(*it);
5210       }
5211       modint2 & ww=w[p];
5212       if (ww==0)
5213 	continue;
5214       modint c=(modint2(invmod(val,env))*ww)%env;
5215       if (!c)
5216 	continue;
5217       ww=0;
5218       ++it;
5219       for (;it<=it2;){
5220 	sparse32 se = *it;
5221 	unsigned seshift=se.shift;
5222 	if (seshift){
5223 	  p += seshift;
5224 	  w[p] -= modint2(c)*se.val;
5225 	}
5226 	else {
5227 	  ++it;
5228 	  p = *(unsigned *) &*it;
5229 	  w[p] -= modint2(c)*se.val;
5230 	}
5231 	++it;
5232 	se = *it;
5233 	seshift=se.shift;
5234 	if (seshift){
5235 	  p += seshift;
5236 	  w[p] -= modint2(c)*se.val;
5237 	}
5238 	else {
5239 	  ++it;
5240 	  p = *(unsigned *) &*it;
5241 	  w[p] -= modint2(c)*se.val;
5242 	}
5243 	++it;
5244 	se = *it;
5245 	seshift=se.shift;
5246 	if (seshift){
5247 	  p += seshift;
5248 	  w[p] -= modint2(c)*se.val;
5249 	}
5250 	else {
5251 	  ++it;
5252 	  p = *(unsigned *) &*it;
5253 	  w[p] -= modint2(c)*se.val;
5254 	}
5255 	++it;
5256 	se = *it;
5257 	seshift=se.shift;
5258 	if (seshift){
5259 	  p += seshift;
5260 	  w[p] -= modint2(c)*se.val;
5261 	}
5262 	else {
5263 	  ++it;
5264 	  p = *(unsigned *) &*it;
5265 	  w[p] -= modint2(c)*se.val;
5266 	}
5267 	++it;
5268 	se = *it;
5269 	seshift=se.shift;
5270 	if (seshift){
5271 	  p += seshift;
5272 	  w[p] -= modint2(c)*se.val;
5273 	}
5274 	else {
5275 	  ++it;
5276 	  p = *(unsigned *) &*it;
5277 	  w[p] -= modint2(c)*se.val;
5278 	}
5279 	++it;
5280 	se = *it;
5281 	seshift=se.shift;
5282 	if (seshift){
5283 	  p += seshift;
5284 	  w[p] -= modint2(c)*se.val;
5285 	}
5286 	else {
5287 	  ++it;
5288 	  p = *(unsigned *) &*it;
5289 	  w[p] -= modint2(c)*se.val;
5290 	}
5291 	++it;
5292 	se = *it;
5293 	seshift=se.shift;
5294 	if (seshift){
5295 	  p += seshift;
5296 	  w[p] -= modint2(c)*se.val;
5297 	}
5298 	else {
5299 	  ++it;
5300 	  p = *(unsigned *) &*it;
5301 	  w[p] -= modint2(c)*se.val;
5302 	}
5303 	++it;
5304 	se = *it;
5305 	seshift=se.shift;
5306 	if (seshift){
5307 	  p += seshift;
5308 	  w[p] -= modint2(c)*se.val;
5309 	}
5310 	else {
5311 	  ++it;
5312 	  p = *(unsigned *) &*it;
5313 	  w[p] -= modint2(c)*se.val;
5314 	}
5315 	++it;
5316       }
5317       for (;it!=itend;++it){
5318 	const sparse32 & se = *it;
5319 	unsigned seshift=se.shift;
5320 	if (seshift){
5321 	  p += seshift;
5322 	  w[p] -= modint2(c)*se.val;
5323 	}
5324 	else {
5325 	  ++it;
5326 	  p = *(unsigned *) &*it;
5327 	  w[p] -= modint2(c)*se.val;
5328 	}
5329       }
5330     }
5331     for (vt=v.begin(),wt=w.begin();vt!=vtend;++wt,++vt){
5332       if (*wt)
5333 	*vt = *wt % env;
5334       else
5335 	*vt =0;
5336     }
5337     for (vt=v.begin();vt!=vtend;++vt){
5338       if (*vt)
5339 	return unsigned(vt-v.begin());
5340     }
5341     return unsigned(v.size());
5342   }
5343 
5344 #ifdef PSEUDO_MOD
5345   // find pseudo remainder of x mod p, 2^nbits>=p>2^(nbits-1)
5346   // assumes invp=2^(2*nbits)/p+1 has been precomputed
5347   // and abs(x)<2^(31+nbits)
5348   // |remainder| <= max(2^nbits,|x|*p/2^(2nbits)), <=2*p if |x|<=p^2
pseudo_mod(longlong x,int p,unsigned invp,unsigned nbits)5349   inline int pseudo_mod(longlong x,int p,unsigned invp,unsigned nbits){
5350     return int(x - (((x>>nbits)*invp)>>(nbits))*p);
5351   }
5352   // a <- (a+b*c) mod or smod p
pseudo_mod(int & a,int b,int c,int p,unsigned invp,unsigned nbits)5353   inline void pseudo_mod(int & a,int b,int c,int p,unsigned invp,unsigned nbits){
5354     a=pseudo_mod(a+((longlong)b)*c,p,invp,nbits);
5355   }
5356 #endif
5357 
reducef4buchberger(vector<modint> & v,const vector<vector<sparse_element>> & M,modint env)5358   unsigned reducef4buchberger(vector<modint> &v,const vector< vector<sparse_element> > & M,modint env){
5359 #ifdef PSEUDO_MOD
5360     int nbits=sizeinbase2(env);
5361     unsigned invmodulo=((1ULL<<(2*nbits)))/env+1;
5362 #endif
5363     for (unsigned i=0;i<M.size();++i){
5364       const vector<sparse_element> & m=M[i];
5365       vector<sparse_element>::const_iterator it=m.begin(),itend=m.end();
5366       if (it==itend)
5367 	continue;
5368       modint c=(modint2(invmod(it->val,env))*v[it->pos])%env;
5369       v[it->pos]=0;
5370       if (!c)
5371 	continue;
5372 #ifdef PSEUDO_MOD
5373       if (env<(1<<29)){
5374 	c=-c;
5375 	for (++it;it!=itend;++it){
5376 	  pseudo_mod(v[it->pos],c,it->val,env,invmodulo,nbits);
5377 	}
5378 	continue;
5379       }
5380 #endif
5381       for (++it;it!=itend;++it){
5382 	modint &x=v[it->pos];
5383 	x=(x-modint2(c)*(it->val))%env;
5384       }
5385     }
5386     vector<modint>::iterator vt=v.begin(),vtend=v.end();
5387 #ifdef PSEUDO_MOD
5388     for (vt=v.begin();vt!=vtend;++vt){
5389       if (*vt)
5390 	*vt %= env;
5391     }
5392 #endif
5393     for (vt=v.begin();vt!=vtend;++vt){
5394       if (*vt)
5395 	return unsigned(vt-v.begin());
5396     }
5397     return unsigned(v.size());
5398   }
5399 
5400 
5401 #if GIAC_SHORTSHIFTTYPE==8
5402   typedef unsigned char shifttype;
5403   // assumes that all shifts are less than 2^(3*sizeof()),
5404   // and almost all shifts are less than 2^sizeof()-1
5405   // for unsigned char here matrix density should be significantly above 0.004
5406 
next_index(unsigned & pos,const shifttype * & it)5407   inline void next_index(unsigned & pos,const shifttype * & it){
5408     if (*it)
5409       pos+=(*it);
5410     else { // next 3 will make the shift
5411       ++it;
5412       pos += (*it << 16);
5413       ++it;
5414       pos += (*it << 8);
5415       ++it;
5416       pos += *it;
5417     }
5418     ++it;
5419   }
5420 
next_index(vector<modint>::iterator & pos,const shifttype * & it)5421   inline void next_index(vector<modint>::iterator & pos,const shifttype * & it){
5422     if (*it)
5423       pos+=(*it);
5424     else { // next 3 will make the shift
5425       ++it;
5426       pos += (*it << 16);
5427       ++it;
5428       pos += (*it << 8);
5429       ++it;
5430       pos += *it;
5431     }
5432     ++it;
5433   }
5434 
next_index(vector<modint2>::iterator & pos,const shifttype * & it)5435   inline void next_index(vector<modint2>::iterator & pos,const shifttype * & it){
5436     if (*it)
5437       pos+=(*it);
5438     else { // next 3 will make the shift
5439       ++it;
5440       pos += (*it << 16);
5441       ++it;
5442       pos += (*it << 8);
5443       ++it;
5444       pos += *it;
5445     }
5446     ++it;
5447   }
5448 
next_index(vector<double>::iterator & pos,const shifttype * & it)5449   inline void next_index(vector<double>::iterator & pos,const shifttype * & it){
5450     if (*it)
5451       pos+=(*it);
5452     else { // next 3 will make the shift
5453       ++it;
5454       pos += (*it << 16);
5455       ++it;
5456       pos += (*it << 8);
5457       ++it;
5458       pos += *it;
5459     }
5460     ++it;
5461   }
5462 
5463 #ifdef x86_64
next_index(vector<int128_t>::iterator & pos,const shifttype * & it)5464   inline void next_index(vector<int128_t>::iterator & pos,const shifttype * & it){
5465     if (*it)
5466       pos+=(*it);
5467     else { // next 3 will make the shift
5468       ++it;
5469       pos += (*it << 16);
5470       ++it;
5471       pos += (*it << 8);
5472       ++it;
5473       pos += *it;
5474     }
5475     ++it;
5476   }
5477 #endif
5478 
first_index(const vector<shifttype> & v)5479   unsigned first_index(const vector<shifttype> & v){
5480     if (v.front())
5481       return v.front();
5482     return (v[1]<<16)+(v[2]<<8)+v[3];
5483   }
5484 
pushsplit(vector<shifttype> & v,unsigned & pos,unsigned newpos)5485   inline void pushsplit(vector<shifttype> & v,unsigned & pos,unsigned newpos){
5486     unsigned shift=newpos-pos;
5487     if (shift && (shift <(1<<8)))
5488       v.push_back(shift);
5489     else {
5490       v.push_back(0);
5491       v.push_back(shift >> 16 );
5492       v.push_back(shift >> 8);
5493       v.push_back(shift);
5494     }
5495     pos=newpos;
5496   }
5497 #endif
5498 
5499 #if GIAC_SHORTSHIFTTYPE==16
5500   typedef unsigned short shifttype;
5501 
next_index(unsigned & pos,const shifttype * & it)5502   inline void next_index(unsigned & pos,const shifttype * & it){
5503     if (*it)
5504       pos += (*it);
5505     else { // next will make the shift
5506       ++it;
5507       pos += (*it << 16);
5508       ++it;
5509       pos += *it;
5510     }
5511     ++it;
5512   }
5513 
next_index(vector<modint>::iterator & pos,const shifttype * & it)5514   inline void next_index(vector<modint>::iterator & pos,const shifttype * & it){
5515     if (*it)
5516       pos += (*it);
5517     else { // next will make the shift
5518       ++it;
5519       pos += (*it << 16);
5520       ++it;
5521       pos += *it;
5522     }
5523     ++it;
5524   }
5525 
next_index(vector<modint2>::iterator & pos,const shifttype * & it)5526   inline void next_index(vector<modint2>::iterator & pos,const shifttype * & it){
5527     if (*it)
5528       pos += (*it);
5529     else { // next will make the shift
5530       ++it;
5531       pos += (*it << 16);
5532       ++it;
5533       pos += *it;
5534     }
5535     ++it;
5536   }
5537 
next_index(vector<double>::iterator & pos,const shifttype * & it)5538   inline void next_index(vector<double>::iterator & pos,const shifttype * & it){
5539     if (*it)
5540       pos += (*it);
5541     else { // next will make the shift
5542       ++it;
5543       pos += (*it << 16);
5544       ++it;
5545       pos += *it;
5546     }
5547     ++it;
5548   }
5549 
5550 #ifdef x86_64
next_index(vector<int128_t>::iterator & pos,const shifttype * & it)5551   inline void next_index(vector<int128_t>::iterator & pos,const shifttype * & it){
5552     if (*it)
5553       pos += (*it);
5554     else { // next will make the shift
5555       ++it;
5556       pos += (*it << 16);
5557       ++it;
5558       pos += *it;
5559     }
5560     ++it;
5561   }
5562 #endif
5563 
first_index(const vector<shifttype> & v)5564   unsigned first_index(const vector<shifttype> & v){
5565     if (v.front())
5566       return v.front();
5567     return (v[1]<<16)+v[2];
5568   }
5569 
pushsplit(vector<shifttype> & v,unsigned & pos,unsigned newpos)5570   inline void pushsplit(vector<shifttype> & v,unsigned & pos,unsigned newpos){
5571     unsigned shift=newpos-pos;
5572     if ( shift && (shift < (1<<16)) )
5573       v.push_back(shift);
5574     else {
5575       v.push_back(0);
5576       v.push_back(shift >> 16 );
5577       v.push_back(shift);
5578     }
5579     pos=newpos;
5580   }
5581 #endif
5582 
5583 #ifndef GIAC_SHORTSHIFTTYPE
5584   typedef unsigned shifttype;
next_index(unsigned & pos,const shifttype * & it)5585   inline void next_index(unsigned & pos,const shifttype * & it){
5586     pos=(*it);
5587     ++it;
5588   }
first_index(const vector<shifttype> & v)5589   inline unsigned first_index(const vector<shifttype> & v){
5590     return v.front();
5591   }
pushsplit(vector<shifttype> & v,unsigned & pos,unsigned newpos)5592   inline void pushsplit(vector<shifttype> & v,unsigned & pos,unsigned newpos){
5593     v.push_back(pos=newpos);
5594   }
5595 
5596 #endif
5597 
5598   struct coeffindex_t {
5599     bool b;
5600     unsigned u:24;
coeffindex_tgiac::coeffindex_t5601     coeffindex_t(bool b_,unsigned u_):b(b_),u(u_) {};
coeffindex_tgiac::coeffindex_t5602     coeffindex_t():b(false),u(0) {};
5603   };
5604 
5605 #ifdef x86_64
reducef4buchbergersplit64(vector<modint> & v,const vector<vector<shifttype>> & M,const vector<unsigned> & firstpos,vector<vector<modint>> & coeffs,vector<coeffindex_t> & coeffindex,modint env,vector<int128_t> & v128)5606   unsigned reducef4buchbergersplit64(vector<modint> &v,const vector< vector<shifttype> > & M,const vector<unsigned> & firstpos,vector< vector<modint> > & coeffs,vector<coeffindex_t> & coeffindex,modint env,vector<int128_t> & v128){
5607     vector<modint>::iterator vt=v.begin(),vtend=v.end();
5608     v128.resize(v.size());
5609     vector<int128_t>::iterator wt=v128.begin(),wt0=wt;
5610     for (;vt!=vtend;++wt,++vt)
5611       *wt=*vt;
5612     vector<unsigned>::const_iterator fit=firstpos.begin(),fit0=fit,fitend=firstpos.end();
5613     for (;fit!=fitend;++fit){
5614       if (*(wt0+*fit)==0)
5615 	continue;
5616       unsigned i=fit-fit0;
5617       const vector<modint> & mcoeff=coeffs[coeffindex[i].u];
5618       bool shortshifts=coeffindex[i].b;
5619       vector<modint>::const_iterator jt=mcoeff.begin(),jtend=mcoeff.end(),jt_=jtend-8;
5620       if (jt==jtend)
5621 	continue;
5622       const vector<shifttype> & mindex=M[i];
5623       const shifttype * it=&mindex.front();
5624       unsigned pos=0;
5625       next_index(pos,it);
5626       wt=wt0+pos;
5627       // if (*wt==0) continue;
5628       // if (pos>v.size()) CERR << "error" <<'\n';
5629       modint c=(invmod(*jt,env)*(*wt))%env;
5630       *wt=0;
5631       if (!c)
5632 	continue;
5633       ++jt;
5634 #ifdef GIAC_SHORTSHIFTTYPE
5635       if (shortshifts){
5636 #if 0
5637 	if (jt<jt_){
5638 	  while (ulonglong(it)%4){
5639 	    wt += *it; ++it;;
5640 	    *wt -=modint2(c)*(*jt);
5641 	    ++jt;
5642 	  }
5643 	}
5644 #endif
5645 	for (;jt<jt_;){
5646 	  wt += *it; ++it;;
5647 	  *wt -=modint2(c)*(*jt);
5648 	  ++jt;
5649 	  wt += *it; ++it;;
5650 	  *wt -=modint2(c)*(*jt);
5651 	  ++jt;
5652 	  wt += *it; ++it;;
5653 	  *wt -=modint2(c)*(*jt);
5654 	  ++jt;
5655 	  wt += *it; ++it;;
5656 	  *wt -=modint2(c)*(*jt);
5657 	  ++jt;
5658 	  wt += *it; ++it;;
5659 	  *wt -=modint2(c)*(*jt);
5660 	  ++jt;
5661 	  wt += *it; ++it;;
5662 	  *wt -=modint2(c)*(*jt);
5663 	  ++jt;
5664 	  wt += *it; ++it;;
5665 	  *wt -=modint2(c)*(*jt);
5666 	  ++jt;
5667 	  wt += *it; ++it;;
5668 	  *wt -=modint2(c)*(*jt);
5669 	  ++jt;
5670 	}
5671       } // if (shortshifts)
5672       else {
5673 	for (;jt<jt_;){
5674 	  next_index(wt,it);
5675 	  *wt -=modint2(c)*(*jt);
5676 	  ++jt;
5677 	  next_index(wt,it);
5678 	  *wt -=modint2(c)*(*jt);
5679 	  ++jt;
5680 	  next_index(wt,it);
5681 	  *wt -=modint2(c)*(*jt);
5682 	  ++jt;
5683 	  next_index(wt,it);
5684 	  *wt -=modint2(c)*(*jt);
5685 	  ++jt;
5686 	  next_index(wt,it);
5687 	  *wt -=modint2(c)*(*jt);
5688 	  ++jt;
5689 	  next_index(wt,it);
5690 	  *wt -=modint2(c)*(*jt);
5691 	  ++jt;
5692 	  next_index(wt,it);
5693 	  *wt -=modint2(c)*(*jt);
5694 	  ++jt;
5695 	  next_index(wt,it);
5696 	  *wt -=modint2(c)*(*jt);
5697 	  ++jt;
5698 	}
5699       }
5700 #else // GIAC_SHORTSHIFTTYPE
5701       for (;jt<jt_;){
5702 	v128[*it]-=modint2(c)*(*jt);
5703 	++it; ++jt;
5704 	v128[*it]-=modint2(c)*(*jt);
5705 	++it; ++jt;
5706 	v128[*it]-=modint2(c)*(*jt);
5707 	++it; ++jt;
5708 	v128[*it]-=modint2(c)*(*jt);
5709 	++it; ++jt;
5710 	v128[*it]-=modint2(c)*(*jt);
5711 	++it; ++jt;
5712 	v128[*it]-=modint2(c)*(*jt);
5713 	++it; ++jt;
5714 	v128[*it]-=modint2(c)*(*jt);
5715 	++it; ++jt;
5716 	v128[*it]-=modint2(c)*(*jt);
5717 	++it; ++jt;
5718       }
5719 #endif
5720       for (;jt!=jtend;++jt){
5721 #ifdef GIAC_SHORTSHIFTTYPE
5722 	next_index(wt,it);
5723 	*wt -=modint2(c)*(*jt);
5724 #else
5725 	v128[*it]-=modint2(c)*(*jt);
5726 	++it;
5727 #endif
5728       }
5729     }
5730     unsigned res=v.size();
5731     for (vt=v.begin(),wt=v128.begin();vt!=vtend;++wt,++vt){
5732       int128_t i=*wt;
5733       if (i)
5734 	i %= env;
5735       *vt = i;
5736       if (i){
5737 	res=vt-v.begin();
5738 	break;
5739       }
5740     }
5741     for (;vt!=vtend;++wt,++vt){
5742       if (*wt)
5743 	*vt = *wt % env;
5744       else
5745 	*vt = 0;
5746     }
5747     return res;
5748   }
5749 
reducef4buchbergersplit64u(vector<modint> & v,const vector<vector<unsigned>> & M,vector<vector<modint>> & coeffs,vector<coeffindex_t> & coeffindex,modint env,vector<int128_t> & v128)5750   unsigned reducef4buchbergersplit64u(vector<modint> &v,const vector< vector<unsigned> > & M,vector< vector<modint> > & coeffs,vector<coeffindex_t> & coeffindex,modint env,vector<int128_t> & v128){
5751     vector<modint>::iterator vt=v.begin(),vtend=v.end();
5752     v128.resize(v.size());
5753     vector<int128_t>::iterator wt=v128.begin();
5754     for (;vt!=vtend;++wt,++vt)
5755       *wt=*vt;
5756     for (unsigned i=0;i<M.size();++i){
5757       const vector<modint> & mcoeff=coeffs[coeffindex[i].u];
5758       vector<modint>::const_iterator jt=mcoeff.begin(),jtend=mcoeff.end(),jt_=jtend-8;
5759       if (jt==jtend)
5760 	continue;
5761       const vector<unsigned> & mindex=M[i];
5762       const unsigned * it=&mindex.front();
5763       unsigned pos=*it;
5764       // if (pos>v.size()) CERR << "error" <<'\n';
5765       modint c=(invmod(*jt,env)*v128[pos])%env;
5766       v128[pos]=0;
5767       if (!c)
5768 	continue;
5769       ++it;++jt;
5770       for (;jt<jt_;){
5771 	v128[*it]-=modint2(c)*(*jt);
5772 	++it; ++jt;
5773 	v128[*it]-=modint2(c)*(*jt);
5774 	++it; ++jt;
5775 	v128[*it]-=modint2(c)*(*jt);
5776 	++it; ++jt;
5777 	v128[*it]-=modint2(c)*(*jt);
5778 	++it; ++jt;
5779 	v128[*it]-=modint2(c)*(*jt);
5780 	++it; ++jt;
5781 	v128[*it]-=modint2(c)*(*jt);
5782 	++it; ++jt;
5783 	v128[*it]-=modint2(c)*(*jt);
5784 	++it; ++jt;
5785 	v128[*it]-=modint2(c)*(*jt);
5786 	++it; ++jt;
5787       }
5788       for (;jt!=jtend;++jt){
5789 	v128[*it]-=modint2(c)*(*jt);
5790 	++it;
5791       }
5792     }
5793     for (vt=v.begin(),wt=v128.begin();vt!=vtend;++wt,++vt){
5794       if (*wt)
5795 	*vt = *wt % env;
5796       else
5797 	*vt=0;
5798     }
5799     for (vt=v.begin();vt!=vtend;++vt){
5800       if (*vt)
5801 	return vt-v.begin();
5802     }
5803     return v.size();
5804   }
5805 
reducef4buchbergersplit64s(vector<modint> & v,const vector<vector<short unsigned>> & M,vector<vector<modint>> & coeffs,vector<coeffindex_t> & coeffindex,modint env,vector<int128_t> & v128)5806   unsigned reducef4buchbergersplit64s(vector<modint> &v,const vector< vector<short unsigned> > & M,vector< vector<modint> > & coeffs,vector<coeffindex_t> & coeffindex,modint env,vector<int128_t> & v128){
5807     vector<modint>::iterator vt=v.begin(),vtend=v.end();
5808     v128.resize(v.size());
5809     vector<int128_t>::iterator wt=v128.begin();
5810     for (;vt!=vtend;++wt,++vt)
5811       *wt=*vt;
5812     for (unsigned i=0;i<M.size();++i){
5813       const vector<modint> & mcoeff=coeffs[coeffindex[i].u];
5814       vector<modint>::const_iterator jt=mcoeff.begin(),jtend=mcoeff.end(),jt_=jtend-8;
5815       if (jt==jtend)
5816 	continue;
5817       const vector<short unsigned> & mindex=M[i];
5818       const short unsigned * it=&mindex.front();
5819       unsigned pos=*it;
5820       // if (pos>v.size()) CERR << "error" <<'\n';
5821       modint c=(invmod(*jt,env)*v128[pos])%env;
5822       v128[pos]=0;
5823       if (!c)
5824 	continue;
5825       ++it;++jt;
5826       for (;jt<jt_;){
5827 	v128[*it]-=modint2(c)*(*jt);
5828 	++it; ++jt;
5829 	v128[*it]-=modint2(c)*(*jt);
5830 	++it; ++jt;
5831 	v128[*it]-=modint2(c)*(*jt);
5832 	++it; ++jt;
5833 	v128[*it]-=modint2(c)*(*jt);
5834 	++it; ++jt;
5835 	v128[*it]-=modint2(c)*(*jt);
5836 	++it; ++jt;
5837 	v128[*it]-=modint2(c)*(*jt);
5838 	++it; ++jt;
5839 	v128[*it]-=modint2(c)*(*jt);
5840 	++it; ++jt;
5841 	v128[*it]-=modint2(c)*(*jt);
5842 	++it; ++jt;
5843       }
5844       for (;jt!=jtend;++jt){
5845 	v128[*it]-=modint2(c)*(*jt);
5846 	++it;
5847       }
5848     }
5849     for (vt=v.begin(),wt=v128.begin();vt!=vtend;++wt,++vt){
5850       if (*wt)
5851 	*vt = *wt % env;
5852       else
5853 	*vt=0;
5854     }
5855     for (vt=v.begin();vt!=vtend;++vt){
5856       if (*vt)
5857 	return vt-v.begin();
5858     }
5859     return v.size();
5860   }
5861 
5862 #endif
5863 
5864   // reducef4buchberger matrix M has band structure, to spare memory
5865   // we split coeffs/index in :
5866   // - M each line is a list of shift index,
5867   // - coeffindex, relative to coeffs, M[i][j] corresponds to coeffs[coeffinde[i]][j]
5868   // - coeffs is the list of coefficients
reducef4buchbergersplit(vector<modint> & v,const vector<vector<shifttype>> & M,const vector<unsigned> & firstpos,vector<vector<modint>> & coeffs,vector<coeffindex_t> & coeffindex,modint env,vector<modint2> & v64)5869   unsigned reducef4buchbergersplit(vector<modint> &v,const vector< vector<shifttype> > & M,const vector<unsigned> & firstpos,vector< vector<modint> > & coeffs,vector<coeffindex_t> & coeffindex,modint env,vector<modint2> & v64){
5870     vector<modint>::iterator vt=v.begin(),vt0=vt,vtend=v.end();
5871     vector<unsigned>::const_iterator fit=firstpos.begin(),fit0=fit,fitend=firstpos.end();
5872     if (env<(1<<24)){
5873       v64.resize(v.size());
5874       vector<modint2>::iterator wt=v64.begin(),wt0=wt,wtend=v64.end();
5875       for (;vt!=vtend;++wt,++vt){
5876 	*wt=*vt;
5877 	*vt=0;
5878       }
5879       bool fastcheck = (fitend-fit0)<=0xffff;
5880       for (;fit!=fitend;++fit){
5881 	if (fastcheck && *(wt0+*fit)==0)
5882 	  continue;
5883 	unsigned i=unsigned(fit-fit0);
5884 	if (!fastcheck){
5885 	  if ((i&0xffff)==0xffff){
5886 	    // reduce the line mod env
5887 	    for (wt=v64.begin();wt!=wtend;++wt){
5888 	      if (*wt)
5889 		*wt %= env;
5890 	    }
5891 	  }
5892 	  if (v64[*fit]==0)
5893 	    continue;
5894 	}
5895 	const vector<shifttype> & mindex=M[i];
5896 	const shifttype * it=&mindex.front();
5897 	unsigned pos=0;
5898 	next_index(pos,it);
5899 	wt=wt0+pos;
5900 	// if (*wt==0) continue;
5901 	const vector<modint> & mcoeff=coeffs[coeffindex[i].u];
5902 	bool shortshifts=coeffindex[i].b;
5903 	if (mcoeff.empty())
5904 	  continue;
5905 	const modint * jt=&mcoeff.front(),*jtend=jt+mcoeff.size(),*jt_=jtend-8;
5906 	// if (pos>v.size()) CERR << "error" <<'\n';
5907 	// if (*jt!=1) CERR << "not normalized" << '\n';
5908 	modint c=(modint2(invmod(*jt,env))*(*wt % env))%env;
5909 	*wt=0;
5910 	if (!c)
5911 	  continue;
5912 	++jt;
5913 #ifdef GIAC_SHORTSHIFTTYPE
5914 	if (shortshifts){
5915 	  for (;jt<jt_;){
5916 	    wt += *it; ++it;
5917 	    *wt-=modint2(c)*(*jt);
5918 	    ++jt;
5919 	    wt += *it; ++it;
5920 	    *wt-=modint2(c)*(*jt);
5921 	    ++jt;
5922 	    wt += *it; ++it;
5923 	    *wt-=modint2(c)*(*jt);
5924 	    ++jt;
5925 	    wt += *it; ++it;
5926 	    *wt-=modint2(c)*(*jt);
5927 	    ++jt;
5928 	    wt += *it; ++it;
5929 	    *wt-=modint2(c)*(*jt);
5930 	    ++jt;
5931 	    wt += *it; ++it;
5932 	    *wt-=modint2(c)*(*jt);
5933 	    ++jt;
5934 	    wt += *it; ++it;
5935 	    *wt-=modint2(c)*(*jt);
5936 	    ++jt;
5937 	    wt += *it; ++it;
5938 	    *wt-=modint2(c)*(*jt);
5939 	    ++jt;
5940 	  }
5941 	  for (;jt!=jtend;++jt){
5942 	    wt += *it; ++it;
5943 	    *wt-=modint2(c)*(*jt);
5944 	  }
5945 	}
5946 	else {
5947 	  for (;jt!=jtend;++jt){
5948 	    next_index(wt,it);
5949 	    *wt-=modint2(c)*(*jt);
5950 	  }
5951 	}
5952 #else // def GIAC_SHORTSHIFTTYPE
5953 	for (;jt<jt_;){
5954 	  v64[*it]-=modint2(c)*(*jt);
5955 	  ++it; ++jt;
5956 	  v64[*it]-=modint2(c)*(*jt);
5957 	  ++it; ++jt;
5958 	  v64[*it]-=modint2(c)*(*jt);
5959 	  ++it; ++jt;
5960 	  v64[*it]-=modint2(c)*(*jt);
5961 	  ++it; ++jt;
5962 	  v64[*it]-=modint2(c)*(*jt);
5963 	  ++it; ++jt;
5964 	  v64[*it]-=modint2(c)*(*jt);
5965 	  ++it; ++jt;
5966 	  v64[*it]-=modint2(c)*(*jt);
5967 	  ++it; ++jt;
5968 	  v64[*it]-=modint2(c)*(*jt);
5969 	  ++it; ++jt;
5970 	}
5971 	for (;jt!=jtend;++jt){
5972 	  v64[*it]-=modint2(c)*(*jt);
5973 	  ++it; ++jt;
5974 	}
5975 #endif // def GIAC_SHORTSHIFTTYPE
5976       }
5977       unsigned res=unsigned(v.size());
5978       for (vt=v.begin(),wt=v64.begin();vt!=vtend;++wt,++vt){
5979 	modint2 i=*wt;
5980 	if (i) // if (i>=env || i<=-env)
5981 	  i %= env;
5982 	*vt = modint(i);
5983 	if (i){
5984 	  res=unsigned(vt-v.begin());
5985 	  break;
5986 	}
5987       }
5988       for (;vt!=vtend;++wt,++vt){
5989 	if (modint2 i=*wt) // if (i>=env || i<=-env)
5990 	  *vt = i % env;
5991       }
5992       return res;
5993     }
5994 #ifdef PSEUDO_MOD
5995     int nbits=sizeinbase2(env);
5996     unsigned invmodulo=((1ULL<<(2*nbits)))/env+1;
5997 #endif
5998     for (;fit!=fitend;++fit){
5999       if (*(vt0+*fit)==0)
6000 	continue;
6001       unsigned i=unsigned(fit-fit0);
6002       const vector<modint> & mcoeff=coeffs[coeffindex[i].u];
6003       bool shortshifts=coeffindex[i].b;
6004       vector<modint>::const_iterator jt=mcoeff.begin(),jtend=mcoeff.end(),jt_=jt-8;
6005       if (jt==jtend)
6006 	continue;
6007       const vector<shifttype> & mindex=M[i];
6008       const shifttype * it=&mindex.front();
6009       unsigned pos=0;
6010       next_index(pos,it);
6011       vt=v.begin()+pos;
6012       // if (pos>v.size()) CERR << "error" <<'\n';
6013       modint c=(modint2(invmod(*jt,env))*(*vt))%env;
6014       *vt=0;
6015       if (!c)
6016 	continue;
6017       ++jt;
6018 #ifdef PSEUDO_MOD
6019       if (env<(1<<29)){
6020 	c=-c;
6021 #ifdef GIAC_SHORTSHIFTTYPE
6022 	if (shortshifts){
6023 	  for (;jt<jt_;){
6024 	    vt += *it; ++it;
6025 	    // if (pos>v.size()) CERR << "error" <<'\n';
6026 	    pseudo_mod(*vt,c,*jt,env,invmodulo,nbits);
6027 	    ++jt;
6028 	    vt += *it; ++it;
6029 	    // if (pos>v.size()) CERR << "error" <<'\n';
6030 	    pseudo_mod(*vt,c,*jt,env,invmodulo,nbits);
6031 	    ++jt;
6032 	    vt += *it; ++it;
6033 	    // if (pos>v.size()) CERR << "error" <<'\n';
6034 	    pseudo_mod(*vt,c,*jt,env,invmodulo,nbits);
6035 	    ++jt;
6036 	    vt += *it; ++it;
6037 	    // if (pos>v.size()) CERR << "error" <<'\n';
6038 	    pseudo_mod(*vt,c,*jt,env,invmodulo,nbits);
6039 	    ++jt;
6040 	    vt += *it; ++it;
6041 	    // if (pos>v.size()) CERR << "error" <<'\n';
6042 	    pseudo_mod(*vt,c,*jt,env,invmodulo,nbits);
6043 	    ++jt;
6044 	    vt += *it; ++it;
6045 	    // if (pos>v.size()) CERR << "error" <<'\n';
6046 	    pseudo_mod(*vt,c,*jt,env,invmodulo,nbits);
6047 	    ++jt;
6048 	    vt += *it; ++it;
6049 	    // if (pos>v.size()) CERR << "error" <<'\n';
6050 	    pseudo_mod(*vt,c,*jt,env,invmodulo,nbits);
6051 	    ++jt;
6052 	    vt += *it; ++it;
6053 	    // if (pos>v.size()) CERR << "error" <<'\n';
6054 	    pseudo_mod(*vt,c,*jt,env,invmodulo,nbits);
6055 	    ++jt;
6056 	  }
6057 	  for (;jt!=jtend;++jt){
6058 	    vt += *it; ++it;
6059 	    // if (pos>v.size()) CERR << "error" <<'\n';
6060 	    pseudo_mod(*vt,c,*jt,env,invmodulo,nbits);
6061 	  }
6062 	}
6063 	else {
6064 	  for (;jt<jt_;){
6065 	    next_index(vt,it); pseudo_mod(*vt,c,*jt,env,invmodulo,nbits); ++jt;
6066 	    next_index(vt,it); pseudo_mod(*vt,c,*jt,env,invmodulo,nbits); ++jt;
6067 	    next_index(vt,it); pseudo_mod(*vt,c,*jt,env,invmodulo,nbits); ++jt;
6068 	    next_index(vt,it); pseudo_mod(*vt,c,*jt,env,invmodulo,nbits); ++jt;
6069 	    next_index(vt,it); pseudo_mod(*vt,c,*jt,env,invmodulo,nbits); ++jt;
6070 	    next_index(vt,it); pseudo_mod(*vt,c,*jt,env,invmodulo,nbits); ++jt;
6071 	    next_index(vt,it); pseudo_mod(*vt,c,*jt,env,invmodulo,nbits); ++jt;
6072 	    next_index(vt,it); pseudo_mod(*vt,c,*jt,env,invmodulo,nbits); ++jt;
6073 	  }
6074 	  for (;jt!=jtend;++jt){
6075 	    next_index(vt,it);
6076 	    // if (pos>v.size()) CERR << "error" <<'\n';
6077 	    pseudo_mod(*vt,c,*jt,env,invmodulo,nbits);
6078 	  }
6079 	}
6080 	continue;
6081 #else
6082 	for (;jt!=jtend;++jt){
6083 	  // if (pos>v.size()) CERR << "error" <<'\n';
6084 	  pseudo_mod(v[*it],c,*jt,env,invmodulo,nbits);
6085 	  ++it;
6086 	}
6087 	continue;
6088 #endif // GIAC_SHORTSHIFTTYPES
6089       } // end if env<1<<29
6090 #endif // PSEUDOMOD
6091       for (;jt!=jtend;++jt){
6092 #ifdef GIAC_SHORTSHIFTTYPE
6093 	next_index(vt,it);
6094 	*vt = (*vt-modint2(c)*(*jt))%env;
6095 #else
6096 	modint &x=v[*it];
6097 	++it;
6098 	x=(x-modint2(c)*(*jt))%env;
6099 #endif
6100       }
6101     }
6102     vt=v.begin();vtend=v.end();
6103 #ifdef PSEUDO_MOD
6104     unsigned res=v.size();
6105     for (;vt!=vtend;++vt){ // or if (*vt) *vt %= env;
6106       if (!*vt) continue;
6107       *vt %= env;
6108       if (*vt){
6109 	res=vt-v.begin();
6110 	break;
6111       }
6112     }
6113     for (;vt!=vtend;++vt){ // or if (*vt) *vt %= env;
6114       modint v=*vt;
6115       if (v>-env && v<env)
6116 	continue;
6117       *vt = v % env;
6118     }
6119     return res;
6120 #endif
6121     for (vt=v.begin();vt!=vtend;++vt){
6122       if (*vt)
6123 	return unsigned(vt-v.begin());
6124     }
6125     return unsigned(v.size());
6126   }
6127 
special_mod(modint2 & x,modint2 c,modint d,modint env,modint2 env2)6128   inline void special_mod(modint2 & x,modint2 c,modint d,modint env,modint2 env2){
6129     register modint2 y=x-c*d;
6130     //x=y%env;
6131     //if (y<0) x = y+env2; else x=y;// if y is negative make it positive by adding env^2
6132     x = y - (y>>63)*env2;
6133   }
6134 
special_mod(double & x,double c,modint d,modint env,double env2)6135   inline void special_mod(double & x,double c,modint d,modint env,double env2){
6136     register modint2 y=modint2(x-c*d);
6137     if (y<0) x = double(y+env2); else x=double(y);// if y is negative make it positive by adding env^2
6138   }
6139 
6140   typedef char used_t;
6141   // typedef bool used_t;
6142 
f4_innerloop_(modint2 * wt,const modint * jt,const modint * jtend,modint c,const shifttype * it)6143   void f4_innerloop_(modint2 * wt,const modint * jt,const modint * jtend,modint c,const shifttype* it){
6144     jtend -= 8;
6145     for (;jt<=jtend;){
6146       wt += *it; ++it;
6147       *wt-=modint2(c)*(*jt);
6148       ++jt;
6149       wt += *it; ++it;
6150       *wt-=modint2(c)*(*jt);
6151       ++jt;
6152       wt += *it; ++it;
6153       *wt-=modint2(c)*(*jt);
6154       ++jt;
6155       wt += *it; ++it;
6156       *wt-=modint2(c)*(*jt);
6157       ++jt;
6158       wt += *it; ++it;
6159       *wt-=modint2(c)*(*jt);
6160       ++jt;
6161       wt += *it; ++it;
6162       *wt-=modint2(c)*(*jt);
6163       ++jt;
6164       wt += *it; ++it;
6165       *wt-=modint2(c)*(*jt);
6166       ++jt;
6167       wt += *it; ++it;
6168       *wt-=modint2(c)*(*jt);
6169       ++jt;
6170     }
6171     jtend+=8;
6172     for (;jt!=jtend;++jt){
6173       wt += *it; ++it;
6174       *wt-=modint2(c)*(*jt);
6175     }
6176   }
6177 
f4_innerloop(modint2 * wt,const modint * jt,const modint * jtend,modint C,const shifttype * it)6178   inline void f4_innerloop(modint2 * wt,const modint * jt,const modint * jtend,modint C,const shifttype* it){
6179     jtend -= 16;
6180     for (;jt<=jtend;){
6181 #if 1
6182       wt += it[0]; int b=it[1];
6183       *wt -= modint2(C)*jt[0];
6184       wt[b] -= modint2(C)*jt[1];
6185       wt += b+it[2]; b=it[3];
6186       *wt -= modint2(C)*jt[2];
6187       wt[b] -= modint2(C)*jt[3];
6188       wt += b+it[4]; b=it[5];
6189       *wt -= modint2(C)*jt[4];
6190       wt[b] -= modint2(C)*jt[5];
6191       wt += b+it[6]; b=it[7];
6192       *wt -= modint2(C)*jt[6];
6193       wt[b] -= modint2(C)*jt[7];
6194       wt += b+it[8]; b=it[9];
6195       *wt -= modint2(C)*jt[8];
6196       wt[b] -= modint2(C)*jt[9];
6197       wt += b+it[10]; b=it[11];
6198       *wt -= modint2(C)*jt[10];
6199       wt[b] -= modint2(C)*jt[11];
6200       wt += b+it[12]; b=it[13];
6201       *wt -= modint2(C)*jt[12];
6202       wt[b] -= modint2(C)*jt[13];
6203       wt += b+it[14]; b=it[15];
6204       *wt -= modint2(C)*jt[14];
6205       wt[b] -= modint2(C)*jt[15];
6206       wt += b;
6207       it += 16; jt+=16;
6208 #else
6209       wt += it[0]; *wt -= modint2(C)*jt[0];
6210       wt += it[1]; *wt -= modint2(C)*jt[1];
6211       wt += it[2]; *wt -= modint2(C)*jt[2];
6212       wt += it[3]; *wt -= modint2(C)*jt[3];
6213       wt += it[4]; *wt -= modint2(C)*jt[4];
6214       wt += it[5]; *wt -= modint2(C)*jt[5];
6215       wt += it[6]; *wt -= modint2(C)*jt[6];
6216       wt += it[7]; *wt -= modint2(C)*jt[7];
6217       wt += it[8]; *wt -= modint2(C)*jt[8];
6218       wt += it[9]; *wt -= modint2(C)*jt[9];
6219       wt += it[10]; *wt -= modint2(C)*jt[10];
6220       wt += it[11]; *wt -= modint2(C)*jt[11];
6221       wt += it[12]; *wt -= modint2(C)*jt[12];
6222       wt += it[13]; *wt -= modint2(C)*jt[13];
6223       wt += it[14]; *wt -= modint2(C)*jt[14];
6224       wt += it[15]; *wt -= modint2(C)*jt[15];
6225       it += 16; jt+=16;
6226 #endif
6227     }
6228     jtend += 16;
6229     for (;jt!=jtend;++jt){
6230       wt += *it; ++it;
6231       *wt-=modint2(C)*(*jt);
6232     }
6233   }
6234 
f4_innerloop_special_mod(modint2 * wt,const modint * jt,const modint * jtend,modint C,const shifttype * it,modint env)6235   void f4_innerloop_special_mod(modint2 * wt,const modint * jt,const modint * jtend,modint C,const shifttype* it,modint env){
6236     modint2 env2=modint2(env)*env;
6237     jtend -= 16;
6238     for (;jt<=jtend;){
6239       wt += it[0]; int b=it[1];
6240       special_mod(*wt,C,*jt,env,env2);
6241       special_mod(wt[b],C,jt[1],env,env2);
6242       wt += b+it[2]; b=it[3];
6243       special_mod(*wt,C,jt[2],env,env2);
6244       special_mod(wt[b],C,jt[3],env,env2);
6245       wt += b+it[4]; b=it[5];
6246       special_mod(*wt,C,jt[4],env,env2);
6247       special_mod(wt[b],C,jt[5],env,env2);
6248       wt += b+it[6]; b=it[7];
6249       special_mod(*wt,C,jt[6],env,env2);
6250       special_mod(wt[b],C,jt[7],env,env2);
6251       wt += b+it[8]; b=it[9];
6252       special_mod(*wt,C,jt[8],env,env2);
6253       special_mod(wt[b],C,jt[9],env,env2);
6254       wt += b+it[10]; b=it[11];
6255       special_mod(*wt,C,jt[10],env,env2);
6256       special_mod(wt[b],C,jt[11],env,env2);
6257       wt += b+it[12]; b=it[13];
6258       special_mod(*wt,C,jt[12],env,env2);
6259       special_mod(wt[b],C,jt[13],env,env2);
6260       wt += b+it[14]; b=it[15];
6261       special_mod(*wt,C,jt[14],env,env2);
6262       special_mod(wt[b],C,jt[15],env,env2);
6263       wt += b;
6264       it += 16; jt+=16;
6265     }
6266     jtend += 16;
6267     for (;jt!=jtend;++jt){
6268       wt += *it; ++it;
6269       special_mod(*wt,C,*jt,env,env2);
6270     }
6271   }
6272 
f4_innerloop_special_mod(double * wt,const modint * jt,const modint * jtend,modint C,const shifttype * it,modint env)6273   void f4_innerloop_special_mod(double * wt,const modint * jt,const modint * jtend,modint C,const shifttype* it,modint env){
6274     double env2=double(env)*env;
6275     jtend -= 16;
6276     for (;jt<=jtend;){
6277       wt += it[0]; int b=it[1];
6278       special_mod(*wt,C,*jt,env,env2);
6279       special_mod(wt[b],C,jt[1],env,env2);
6280       wt += b+it[2]; b=it[3];
6281       special_mod(*wt,C,jt[2],env,env2);
6282       special_mod(wt[b],C,jt[3],env,env2);
6283       wt += b+it[4]; b=it[5];
6284       special_mod(*wt,C,jt[4],env,env2);
6285       special_mod(wt[b],C,jt[5],env,env2);
6286       wt += b+it[6]; b=it[7];
6287       special_mod(*wt,C,jt[6],env,env2);
6288       special_mod(wt[b],C,jt[7],env,env2);
6289       wt += b+it[8]; b=it[9];
6290       special_mod(*wt,C,jt[8],env,env2);
6291       special_mod(wt[b],C,jt[9],env,env2);
6292       wt += b+it[10]; b=it[11];
6293       special_mod(*wt,C,jt[10],env,env2);
6294       special_mod(wt[b],C,jt[11],env,env2);
6295       wt += b+it[12]; b=it[13];
6296       special_mod(*wt,C,jt[12],env,env2);
6297       special_mod(wt[b],C,jt[13],env,env2);
6298       wt += b+it[14]; b=it[15];
6299       special_mod(*wt,C,jt[14],env,env2);
6300       special_mod(wt[b],C,jt[15],env,env2);
6301       wt += b;
6302       it += 16; jt+=16;
6303     }
6304     jtend += 16;
6305     for (;jt!=jtend;++jt){
6306       wt += *it; ++it;
6307       special_mod(*wt,C,*jt,env,env2);
6308     }
6309   }
6310 
store_coeffs(vector<modint2> & v64,unsigned firstcol,vector<modint> & lescoeffs,unsigned * bitmap,vector<used_t> & used,modint env)6311   unsigned store_coeffs(vector<modint2> &v64,unsigned firstcol,vector<modint> & lescoeffs,unsigned * bitmap,vector<used_t> & used,modint env){
6312     unsigned res=0;
6313     used_t * uit=&used.front();
6314     vector<modint2>::iterator wt0=v64.begin(),wt=v64.begin()+firstcol,wtend=v64.end();
6315     vector<modint2>::iterator wt1=wtend-4;
6316 #if 1
6317     for (;wt<=wt1;wt+=4){
6318       if (wt[0] | wt[1] | wt[2] | wt[3])
6319 	break;
6320     }
6321 #endif
6322     if (!res){
6323       for (;wt<wtend;++wt){
6324 	modint2 i=*wt;
6325 	if (!i) continue;
6326 	*wt = 0;
6327 	i %= env;
6328 	if (!i) continue;
6329 	unsigned I=unsigned(wt-wt0);
6330 	res=I;
6331 	*(uit+I)=1; // used[i]=1;
6332 	bitmap[I>>5] |= (1<<(I&0x1f));
6333 	lescoeffs.push_back(modint(i));
6334 	break;
6335       }
6336       if (!res)
6337 	res=unsigned(v64.size());
6338     }
6339 #if 1
6340     for (;wt<=wt1;){
6341       modint2 i=*wt;
6342       if (!i){
6343 	if (!wt[1] && !wt[2] && !wt[3]){
6344 	  wt += 4;
6345 	  continue;
6346 	}
6347 	++wt; i=*wt;
6348 	if (!i){
6349 	  ++wt; i=*wt;
6350 	  if (!i){
6351 	    ++wt; i=*wt;
6352 	  }
6353 	}
6354       }
6355       *wt = 0;
6356       i %= env;
6357       if (!i){
6358 	wt++; continue;
6359       }
6360       unsigned I=unsigned(wt-wt0);
6361       *(uit+I)=1; // used[i]=1;
6362       bitmap[I>>5] |= (1<<(I&0x1f));
6363       lescoeffs.push_back(modint(i));
6364       wt++;
6365     }
6366 #endif
6367     for (;wt<wtend;++wt){
6368       modint2 i=*wt;
6369       if (!i) continue;
6370       *wt=0;
6371       i %= env;
6372       if (!i) continue;
6373       unsigned I=unsigned(wt-wt0);
6374       *(uit+I)=1; // used[i]=1;
6375       bitmap[I>>5] |= (1<<(I&0x1f));
6376       lescoeffs.push_back(modint(i));
6377     }
6378     return res;
6379   }
6380 
reducef4buchbergersplit(vector<modint2> & v64,const vector<vector<shifttype>> & M,const vector<unsigned> & firstpos,unsigned firstcol,const vector<vector<modint>> & coeffs,const vector<coeffindex_t> & coeffindex,vector<modint> & lescoeffs,unsigned * bitmap,vector<used_t> & used,modint env)6381   unsigned reducef4buchbergersplit(vector<modint2> &v64,const vector< vector<shifttype> > & M,const vector<unsigned> & firstpos,unsigned firstcol,const vector< vector<modint> > & coeffs,const vector<coeffindex_t> & coeffindex,vector<modint> & lescoeffs,unsigned * bitmap,vector<used_t> & used,modint env){
6382     vector<unsigned>::const_iterator fit=firstpos.begin(),fit0=fit,fitend=firstpos.end(),fit1=fit+firstcol,fit2;
6383     if (fit1>fitend)
6384       fit1=fitend;
6385     vector<modint2>::iterator wt=v64.begin(),wt0=wt,wt1,wtend=v64.end();
6386     unsigned skip=0;
6387     while (fit+1<fit1){
6388       fit2=fit+(fit1-fit)/2;
6389       if (*fit2>firstcol)
6390 	fit1=fit2;
6391       else
6392 	fit=fit2;
6393     }
6394     if (debug_infolevel>2)
6395       CERR << "Firstcol " << firstcol << "/" << v64.size() << " ratio skipped " << (fit-fit0)/double(fitend-fit0) << '\n';
6396     if (env<(1<<24)){
6397 #ifdef PSEUDO_MOD
6398       int nbits=sizeinbase2(env);
6399       unsigned invmodulo=((1ULL<<(2*nbits)))/env+1;
6400 #endif
6401       bool fastcheck = (fitend-fit)<32768;
6402       unsigned redno=0;
6403       for (;fit<fitend;++fit){
6404 	if (*(wt0+*fit)==0){
6405 	  //if (fit<fit4 && *(wt0+fit[1])==0 && *(wt0+fit[2])==0 && *(wt0+fit[3])==0 ) fit += 3;
6406 	  continue;
6407 	}
6408 	unsigned i=unsigned(fit-fit0);
6409 	const vector<shifttype> & mindex=M[i];
6410 	const shifttype * it=&mindex.front();
6411 	unsigned pos=0;
6412 	next_index(pos,it);
6413 	skip=pos;
6414 	wt=wt0+pos;
6415 	//if (*wt==0) continue; // test already done with v64[*fit]==0
6416 	const vector<modint> & mcoeff=coeffs[coeffindex[i].u];
6417 	bool shortshifts=coeffindex[i].b;
6418 	if (mcoeff.empty())
6419 	  continue;
6420 	const modint * jt=&mcoeff.front(),*jtend=jt+mcoeff.size(),*jt_=jtend-8;
6421 	// if (pos>v.size()) CERR << "error" <<'\n';
6422 	// if (*jt!=1) CERR << "not normalized " << i << '\n';
6423 #if 0 // def PSEUDO_MOD, does not work for cyclic8m
6424 	modint c=pseudo_mod(*wt,env,invmodulo,nbits); // *jt should be 1
6425 #else
6426 	modint c=*wt % env; // (modint2(*jt)*(*wt % env))%env;
6427 #endif
6428 	*wt=0;
6429 	if (!c)
6430 	  continue;
6431 	if (!fastcheck){
6432 	  ++redno;
6433 	  if (redno==32768){
6434 	    redno=0;
6435 	    // reduce the line mod env
6436 	    //CERR << "reduce line" << '\n';
6437 	    for (vector<modint2>::iterator wt=v64.begin()+pos;wt!=wtend;++wt){
6438 	      // 2^63-1-p*p*32768 where p:=prevprime(2^24)
6439 	      modint2 tmp=*wt;
6440 	      if (tmp>=3298534588415LL || tmp<=-3298534588415LL)
6441 		*wt = tmp % env;
6442 	      // if (*wt) *wt %= env; // does not work pseudo_mod(*wt,env,invmodulo,nbits);
6443 	    }
6444 	  }
6445 	}
6446 	++jt;
6447 #ifdef GIAC_SHORTSHIFTTYPE
6448 	if (shortshifts){
6449 	  f4_innerloop(&*wt,jt,jtend,c,it);
6450 	}
6451 	else {
6452 	  for (;jt<jt_;){
6453 	    next_index(wt,it);
6454 	    *wt-=modint2(c)*(*jt);
6455 	    ++jt;
6456 	    next_index(wt,it);
6457 	    *wt-=modint2(c)*(*jt);
6458 	    ++jt;
6459 	    next_index(wt,it);
6460 	    *wt-=modint2(c)*(*jt);
6461 	    ++jt;
6462 	    next_index(wt,it);
6463 	    *wt-=modint2(c)*(*jt);
6464 	    ++jt;
6465 	    next_index(wt,it);
6466 	    *wt-=modint2(c)*(*jt);
6467 	    ++jt;
6468 	    next_index(wt,it);
6469 	    *wt-=modint2(c)*(*jt);
6470 	    ++jt;
6471 	    next_index(wt,it);
6472 	    *wt-=modint2(c)*(*jt);
6473 	    ++jt;
6474 	    next_index(wt,it);
6475 	    *wt-=modint2(c)*(*jt);
6476 	    ++jt;
6477 	  }
6478 	  for (;jt!=jtend;++jt){
6479 	    next_index(wt,it);
6480 	    *wt-=modint2(c)*(*jt);
6481 	  }
6482 	}
6483 #else // def GIAC_SHORTSHIFTTYPE
6484 	for (;jt<jt_;){
6485 	  v64[*it]-=modint2(c)*(*jt);
6486 	  ++it; ++jt;
6487 	  v64[*it]-=modint2(c)*(*jt);
6488 	  ++it; ++jt;
6489 	  v64[*it]-=modint2(c)*(*jt);
6490 	  ++it; ++jt;
6491 	  v64[*it]-=modint2(c)*(*jt);
6492 	  ++it; ++jt;
6493 	  v64[*it]-=modint2(c)*(*jt);
6494 	  ++it; ++jt;
6495 	  v64[*it]-=modint2(c)*(*jt);
6496 	  ++it; ++jt;
6497 	  v64[*it]-=modint2(c)*(*jt);
6498 	  ++it; ++jt;
6499 	  v64[*it]-=modint2(c)*(*jt);
6500 	  ++it; ++jt;
6501 	}
6502 	for (;jt!=jtend;++jt){
6503 	  v64[*it]-=modint2(c)*(*jt);
6504 	  ++it; ++jt;
6505 	}
6506 #endif // def GIAC_SHORTSHIFTTYPE
6507       }
6508     }
6509     else { // env > 2^24
6510       modint2 env2=modint2(env)*env;
6511       for (;fit!=fitend;++fit){
6512 	if (v64[*fit]==0)
6513 	  continue;
6514 	unsigned i=unsigned(fit-fit0);
6515 	const vector<shifttype> & mindex=M[i];
6516 	const shifttype * it=&mindex.front();
6517 	unsigned pos=0;
6518 	next_index(pos,it);
6519 	skip=pos;
6520 	wt=wt0+pos;
6521 	// if (*wt==0) continue;
6522 	const vector<modint> & mcoeff=coeffs[coeffindex[i].u];
6523 	bool shortshifts=coeffindex[i].b;
6524 	if (mcoeff.empty())
6525 	  continue;
6526 	const modint * jt=&mcoeff.front(),*jtend=jt+mcoeff.size(),*jt_=jtend-8;
6527 	// if (pos>v.size()) CERR << "error" <<'\n';
6528 	// if (*jt!=1) CERR << "not normalized" << '\n';
6529 	modint c=*wt % env; // (modint2(*jt)*(*wt % env))%env;
6530 	if (c<0) c += env;
6531 	*wt=0;
6532 	if (!c)
6533 	  continue;
6534 	++jt;
6535 #ifdef GIAC_SHORTSHIFTTYPE
6536 	if (shortshifts){
6537 	  f4_innerloop_special_mod(&*wt,jt,jtend,c,it,env);
6538 	}
6539 	else {
6540 	  for (;jt<jt_;){
6541 	    next_index(wt,it);
6542 	    special_mod(*wt,c,*jt,env,env2); // 	    *wt-=modint2(c)*(*jt);
6543 	    ++jt;
6544 	    next_index(wt,it);
6545 	    special_mod(*wt,c,*jt,env,env2);
6546 	    ++jt;
6547 	    next_index(wt,it);
6548 	    special_mod(*wt,c,*jt,env,env2);
6549 	    ++jt;
6550 	    next_index(wt,it);
6551 	    special_mod(*wt,c,*jt,env,env2);
6552 	    ++jt;
6553 	    next_index(wt,it);
6554 	    special_mod(*wt,c,*jt,env,env2);
6555 	    ++jt;
6556 	    next_index(wt,it);
6557 	    special_mod(*wt,c,*jt,env,env2);
6558 	    ++jt;
6559 	    next_index(wt,it);
6560 	    special_mod(*wt,c,*jt,env,env2);
6561 	    ++jt;
6562 	    next_index(wt,it);
6563 	    special_mod(*wt,c,*jt,env,env2);
6564 	    ++jt;
6565 	  }
6566 	  for (;jt!=jtend;++jt){
6567 	    next_index(wt,it);
6568 	    special_mod(*wt,c,*jt,env,env2);
6569 	  }
6570 	}
6571 #else // def GIAC_SHORTSHIFTTYPE
6572 	for (;jt<jt_;){
6573 	  special_mod(v64[*it],c,*jt,env,env2);
6574 	  ++it; ++jt;
6575 	  special_mod(v64[*it],c,*jt,env,env2);
6576 	  ++it; ++jt;
6577 	  special_mod(v64[*it],c,*jt,env,env2);
6578 	  ++it; ++jt;
6579 	  special_mod(v64[*it],c,*jt,env,env2);
6580 	  ++it; ++jt;
6581 	  special_mod(v64[*it],c,*jt,env,env2);
6582 	  ++it; ++jt;
6583 	  special_mod(v64[*it],c,*jt,env,env2);
6584 	  ++it; ++jt;
6585 	  special_mod(v64[*it],c,*jt,env,env2);
6586 	  ++it; ++jt;
6587 	  special_mod(v64[*it],c,*jt,env,env2);
6588 	  ++it; ++jt;
6589 	}
6590 	for (;jt!=jtend;++jt){
6591 	  special_mod(v64[*it],c,*jt,env,env2);
6592 	  ++it; ++jt;
6593 	}
6594 #endif // def GIAC_SHORTSHIFTTYPE
6595       }
6596     }
6597     if (!bitmap)
6598       return 0; // result in v64, for multiple uses
6599     return store_coeffs(v64,firstcol,lescoeffs,bitmap,used,env);
6600   }
6601 
reducef4buchbergersplitdouble(vector<double> & v64,const vector<vector<shifttype>> & M,const vector<unsigned> & firstpos,unsigned firstcol,const vector<vector<modint>> & coeffs,const vector<coeffindex_t> & coeffindex,vector<modint> & lescoeffs,unsigned * bitmap,vector<used_t> & used,modint env)6602   unsigned reducef4buchbergersplitdouble(vector<double> &v64,const vector< vector<shifttype> > & M,const vector<unsigned> & firstpos,unsigned firstcol,const vector< vector<modint> > & coeffs,const vector<coeffindex_t> & coeffindex,vector<modint> & lescoeffs,unsigned * bitmap,vector<used_t> & used,modint env){
6603     vector<unsigned>::const_iterator fit=firstpos.begin(),fit0=fit,fitend=firstpos.end(),fit1=fit+firstcol,fit2;
6604     if (fit1>fitend)
6605       fit1=fitend;
6606     vector<double>::iterator wt=v64.begin(),wt0=wt,wt1,wtend=v64.end();
6607     unsigned skip=0;
6608     while (fit+1<fit1){
6609       fit2=fit+(fit1-fit)/2;
6610       if (*fit2>firstcol)
6611 	fit1=fit2;
6612       else
6613 	fit=fit2;
6614     }
6615     if (debug_infolevel>2)
6616       CERR << "Firstcol " << firstcol << "/" << v64.size() << " ratio skipped " << (fit-fit0)/double(fitend-fit0) << '\n';
6617     double env2=double(env)*env;
6618     for (;fit!=fitend;++fit){
6619       if (v64[*fit]==0)
6620 	continue;
6621       unsigned i=unsigned(fit-fit0);
6622       const vector<shifttype> & mindex=M[i];
6623       const shifttype * it=&mindex.front();
6624       unsigned pos=0;
6625       next_index(pos,it);
6626       skip=pos;
6627       wt=wt0+pos;
6628       // if (*wt==0) continue;
6629       const vector<modint> & mcoeff=coeffs[coeffindex[i].u];
6630       bool shortshifts=coeffindex[i].b;
6631       if (mcoeff.empty())
6632 	continue;
6633       const modint * jt=&mcoeff.front(),*jtend=jt+mcoeff.size(),*jt_=jtend-8;
6634       // if (pos>v.size()) CERR << "error" <<'\n';
6635       // if (*jt!=1) CERR << "not normalized" << '\n';
6636       modint c=modint2(*wt) % env; // (modint2(*jt)*(*wt % env))%env;
6637       if (c<0) c += env;
6638       *wt=0;
6639       if (!c)
6640 	continue;
6641       ++jt;
6642 #ifdef GIAC_SHORTSHIFTTYPE
6643       if (shortshifts){
6644 	f4_innerloop_special_mod(&*wt,jt,jtend,c,it,env);
6645       }
6646       else {
6647 	for (;jt<jt_;){
6648 	  next_index(wt,it);
6649 	  special_mod(*wt,c,*jt,env,env2); // 	    *wt-=modint2(c)*(*jt);
6650 	  ++jt;
6651 	  next_index(wt,it);
6652 	  special_mod(*wt,c,*jt,env,env2);
6653 	  ++jt;
6654 	  next_index(wt,it);
6655 	  special_mod(*wt,c,*jt,env,env2);
6656 	  ++jt;
6657 	  next_index(wt,it);
6658 	  special_mod(*wt,c,*jt,env,env2);
6659 	  ++jt;
6660 	  next_index(wt,it);
6661 	  special_mod(*wt,c,*jt,env,env2);
6662 	  ++jt;
6663 	  next_index(wt,it);
6664 	  special_mod(*wt,c,*jt,env,env2);
6665 	  ++jt;
6666 	  next_index(wt,it);
6667 	  special_mod(*wt,c,*jt,env,env2);
6668 	  ++jt;
6669 	  next_index(wt,it);
6670 	  special_mod(*wt,c,*jt,env,env2);
6671 	  ++jt;
6672 	}
6673 	for (;jt!=jtend;++jt){
6674 	  next_index(wt,it);
6675 	  special_mod(*wt,c,*jt,env,env2);
6676 	}
6677       }
6678 #else // def GIAC_SHORTSHIFTTYPE
6679       for (;jt<jt_;){
6680 	special_mod(v64[*it],c,*jt,env,env2);
6681 	++it; ++jt;
6682 	special_mod(v64[*it],c,*jt,env,env2);
6683 	++it; ++jt;
6684 	special_mod(v64[*it],c,*jt,env,env2);
6685 	++it; ++jt;
6686 	special_mod(v64[*it],c,*jt,env,env2);
6687 	++it; ++jt;
6688 	special_mod(v64[*it],c,*jt,env,env2);
6689 	++it; ++jt;
6690 	special_mod(v64[*it],c,*jt,env,env2);
6691 	++it; ++jt;
6692 	special_mod(v64[*it],c,*jt,env,env2);
6693 	++it; ++jt;
6694 	special_mod(v64[*it],c,*jt,env,env2);
6695 	++it; ++jt;
6696       }
6697       for (;jt!=jtend;++jt){
6698 	special_mod(v64[*it],c,*jt,env,env2);
6699 	++it; ++jt;
6700       }
6701 #endif // def GIAC_SHORTSHIFTTYPE
6702     }
6703     if (!bitmap)
6704       return 0; // result in v64, for multiple uses
6705     unsigned res=0;
6706     used_t * uit=&used.front();
6707     wt=v64.begin()+firstcol;
6708     wt1=wtend-4;
6709 #if 1
6710     for (;wt<=wt1;++wt){
6711       double i=*wt;
6712       if (i) break;
6713       ++wt; i=*wt;
6714       if (i) break;
6715       ++wt; i=*wt;
6716       if (i) break;
6717       ++wt; i=*wt;
6718       if (i) break;
6719     }
6720 #endif
6721     if (!res){
6722       for (;wt<wtend;++wt){
6723 	modint2 i=modint2(*wt);
6724 	if (!i) continue;
6725 	*wt = 0;
6726 	i %= env;
6727 	if (!i) continue;
6728 	unsigned I=unsigned(wt-wt0);
6729 	res=I;
6730 	*(uit+I)=1; // used[i]=1;
6731 	bitmap[I>>5] |= (1<<(I&0x1f));
6732 	lescoeffs.push_back(modint(i));
6733 	break;
6734       }
6735       if (!res)
6736 	res=unsigned(v64.size());
6737     }
6738 #if 1
6739     for (;wt<=wt1;++wt){
6740       modint2 i=modint2(*wt);
6741       if (!i){
6742 	++wt; i=modint2(*wt);
6743 	if (!i){
6744 	  ++wt; i=modint2(*wt);
6745 	  if (!i){
6746 	    ++wt; i=modint2(*wt);
6747 	    if (!i)
6748 	      continue;
6749 	  }
6750 	}
6751       }
6752       *wt = 0;
6753       i %= env;
6754       if (!i) continue;
6755       unsigned I=unsigned(wt-wt0);
6756       *(uit+I)=1; // used[i]=1;
6757       bitmap[I>>5] |= (1<<(I&0x1f));
6758       lescoeffs.push_back(modint(i));
6759     }
6760 #endif
6761     for (;wt<wtend;++wt){
6762       modint2 i=modint2(*wt);
6763       if (!i) continue;
6764       *wt=0;
6765       i %= env;
6766       if (!i) continue;
6767       unsigned I=unsigned(wt-wt0);
6768       *(uit+I)=1; // used[i]=1;
6769       bitmap[I>>5] |= (1<<(I&0x1f));
6770       lescoeffs.push_back(modint(i));
6771     }
6772     return res;
6773   }
6774 
reducef4buchbergersplitu(vector<modint> & v,const vector<vector<unsigned>> & M,vector<vector<modint>> & coeffs,vector<coeffindex_t> & coeffindex,modint env,vector<modint2> & v64)6775   unsigned reducef4buchbergersplitu(vector<modint> &v,const vector< vector<unsigned> > & M,vector< vector<modint> > & coeffs,vector<coeffindex_t> & coeffindex,modint env,vector<modint2> & v64){
6776     vector<modint>::iterator vt=v.begin(),vtend=v.end();
6777     if (env<(1<<24)){
6778       v64.resize(v.size());
6779       vector<modint2>::iterator wt=v64.begin(),wtend=v64.end();
6780       for (;vt!=vtend;++wt,++vt)
6781 	*wt=*vt;
6782       for (unsigned i=0;i<M.size();++i){
6783 	if ((i&0xffff)==0xffff){
6784 	  // reduce the line mod env
6785 	  for (wt=v64.begin();wt!=wtend;++wt){
6786 	    if (*wt)
6787 	      *wt %= env;
6788 	  }
6789 	}
6790 	const vector<modint> & mcoeff=coeffs[coeffindex[i].u];
6791 	if (mcoeff.empty())
6792 	  continue;
6793 	const modint * jt=&mcoeff.front(),*jtend=jt+mcoeff.size(),*jt_=jtend-8;
6794 	const vector<unsigned> & mindex=M[i];
6795 	const unsigned * it=&mindex.front();
6796 	unsigned pos=*it;
6797 	// if (pos>v.size()) CERR << "error" <<'\n';
6798 	// if (*jt!=1) CERR << "not normalized" << '\n';
6799 	modint c=(modint2(invmod(*jt,env))*(v64[pos] % env))%env;
6800 	v64[pos]=0;
6801 	if (!c)
6802 	  continue;
6803 	++it; ++jt;
6804 	for (;jt<jt_;){
6805 	  v64[*it]-=modint2(c)*(*jt);
6806 	  ++it; ++jt;
6807 	  v64[*it]-=modint2(c)*(*jt);
6808 	  ++it; ++jt;
6809 	  v64[*it]-=modint2(c)*(*jt);
6810 	  ++it; ++jt;
6811 	  v64[*it]-=modint2(c)*(*jt);
6812 	  ++it; ++jt;
6813 	  v64[*it]-=modint2(c)*(*jt);
6814 	  ++it; ++jt;
6815 	  v64[*it]-=modint2(c)*(*jt);
6816 	  ++it; ++jt;
6817 	  v64[*it]-=modint2(c)*(*jt);
6818 	  ++it; ++jt;
6819 	  v64[*it]-=modint2(c)*(*jt);
6820 	  ++it; ++jt;
6821 	}
6822 	for (;jt!=jtend;++it,++jt){
6823 	  v64[*it]-=modint2(c)*(*jt);
6824 	}
6825       }
6826       for (vt=v.begin(),wt=v64.begin();vt!=vtend;++wt,++vt){
6827 	if (*wt)
6828 	  *vt = *wt % env;
6829 	else
6830 	  *vt=0;
6831       }
6832     }
6833     else { // large modulo
6834 #ifdef PSEUDO_MOD
6835       int nbits=sizeinbase2(env);
6836       unsigned invmodulo=((1ULL<<(2*nbits)))/env+1;
6837 #endif
6838       for (unsigned i=0;i<M.size();++i){
6839 	const vector<modint> & mcoeff=coeffs[coeffindex[i].u];
6840 	vector<modint>::const_iterator jt=mcoeff.begin(),jtend=mcoeff.end();
6841 	if (jt==jtend)
6842 	  continue;
6843 	const vector<unsigned> & mindex=M[i];
6844 	const unsigned * it=&mindex.front();
6845 	unsigned pos=*it;
6846 	// if (pos>v.size()) CERR << "error" <<'\n';
6847 	modint c=(modint2(invmod(*jt,env))*v[pos])%env;
6848 	v[pos]=0;
6849 	if (!c)
6850 	  continue;
6851 	++it; ++jt;
6852 #ifdef PSEUDO_MOD
6853 	if (env<(1<<29)){
6854 	  c=-c;
6855 	  for (;jt!=jtend;++jt){
6856 	    // if (pos>v.size()) CERR << "error" <<'\n';
6857 	    pseudo_mod(v[*it],c,*jt,env,invmodulo,nbits);
6858 	    ++it;
6859 	  }
6860 	  continue;
6861 	}
6862 #endif
6863 	for (;jt!=jtend;++jt){
6864 	  modint &x=v[*it];
6865 	  ++it;
6866 	  x=(x-modint2(c)*(*jt))%env;
6867 	}
6868       }
6869       vector<modint>::iterator vt=v.begin(),vtend=v.end();
6870 #ifdef PSEUDO_MOD
6871       for (vt=v.begin();vt!=vtend;++vt){
6872 	if (*vt)
6873 	  *vt %= env;
6874       }
6875 #endif
6876     } // end else based on modulo size
6877     for (vt=v.begin();vt!=vtend;++vt){
6878       if (*vt)
6879 	return unsigned(vt-v.begin());
6880     }
6881     return unsigned(v.size());
6882   }
6883 
reducef4buchbergersplits(vector<modint> & v,const vector<vector<unsigned short>> & M,vector<vector<modint>> & coeffs,vector<coeffindex_t> & coeffindex,modint env,vector<modint2> & v64)6884   unsigned reducef4buchbergersplits(vector<modint> &v,const vector< vector<unsigned short> > & M,vector< vector<modint> > & coeffs,vector<coeffindex_t> & coeffindex,modint env,vector<modint2> & v64){
6885     vector<modint>::iterator vt=v.begin(),vtend=v.end();
6886     if (env<(1<<24)){
6887       v64.resize(v.size());
6888       vector<modint2>::iterator wt=v64.begin(),wtend=v64.end();
6889       for (;vt!=vtend;++wt,++vt)
6890 	*wt=*vt;
6891       for (unsigned i=0;i<M.size();++i){
6892 	if ((i&0xffff)==0xffff){
6893 	  // reduce the line mod env
6894 	  for (wt=v64.begin();wt!=wtend;++wt){
6895 	    if (*wt)
6896 	      *wt %= env;
6897 	  }
6898 	}
6899 	const vector<modint> & mcoeff=coeffs[coeffindex[i].u];
6900 	if (mcoeff.empty())
6901 	  continue;
6902 	const modint * jt=&mcoeff.front(),*jtend=jt+mcoeff.size(),*jt_=jtend-8;
6903 	const vector<unsigned short> & mindex=M[i];
6904 	const unsigned short * it=&mindex.front();
6905 	unsigned pos=*it;
6906 	// if (pos>v.size()) CERR << "error" <<'\n';
6907 	// if (*jt!=1) CERR << "not normalized" << '\n';
6908 	modint c=(modint2(invmod(*jt,env))*(v64[pos] % env))%env;
6909 	v64[pos]=0;
6910 	if (!c)
6911 	  continue;
6912 	++it; ++jt;
6913 	for (;jt<jt_;){
6914 	  v64[*it]-=modint2(c)*(*jt);
6915 	  ++it; ++jt;
6916 	  v64[*it]-=modint2(c)*(*jt);
6917 	  ++it; ++jt;
6918 	  v64[*it]-=modint2(c)*(*jt);
6919 	  ++it; ++jt;
6920 	  v64[*it]-=modint2(c)*(*jt);
6921 	  ++it; ++jt;
6922 	  v64[*it]-=modint2(c)*(*jt);
6923 	  ++it; ++jt;
6924 	  v64[*it]-=modint2(c)*(*jt);
6925 	  ++it; ++jt;
6926 	  v64[*it]-=modint2(c)*(*jt);
6927 	  ++it; ++jt;
6928 	  v64[*it]-=modint2(c)*(*jt);
6929 	  ++it; ++jt;
6930 	}
6931 	for (;jt!=jtend;++it,++jt){
6932 	  v64[*it]-=modint2(c)*(*jt);
6933 	}
6934       }
6935       for (vt=v.begin(),wt=v64.begin();vt!=vtend;++wt,++vt){
6936 	if (*wt)
6937 	  *vt = *wt % env;
6938 	else
6939 	  *vt=0;
6940       }
6941     }
6942     else { // large modulo
6943 #ifdef PSEUDO_MOD
6944       int nbits=sizeinbase2(env);
6945       unsigned invmodulo=((1ULL<<(2*nbits)))/env+1;
6946 #endif
6947       for (unsigned i=0;i<M.size();++i){
6948 	const vector<modint> & mcoeff=coeffs[coeffindex[i].u];
6949 	vector<modint>::const_iterator jt=mcoeff.begin(),jtend=mcoeff.end();
6950 	if (jt==jtend)
6951 	  continue;
6952 	const vector<unsigned short> & mindex=M[i];
6953 	const unsigned short * it=&mindex.front();
6954 	unsigned pos=*it;
6955 	// if (pos>v.size()) CERR << "error" <<'\n';
6956 	modint c=(modint2(invmod(*jt,env))*v[pos])%env;
6957 	v[pos]=0;
6958 	if (!c)
6959 	  continue;
6960 	++it; ++jt;
6961 #ifdef PSEUDO_MOD
6962 	if (env<(1<<29)){
6963 	  c=-c;
6964 	  for (;jt!=jtend;++jt){
6965 	    // if (pos>v.size()) CERR << "error" <<'\n';
6966 	    pseudo_mod(v[*it],c,*jt,env,invmodulo,nbits);
6967 	    ++it;
6968 	  }
6969 	  continue;
6970 	}
6971 #endif
6972 	for (;jt!=jtend;++jt){
6973 	  modint &x=v[*it];
6974 	  ++it;
6975 	  x=(x-modint2(c)*(*jt))%env;
6976 	}
6977       }
6978       vector<modint>::iterator vt=v.begin(),vtend=v.end();
6979 #ifdef PSEUDO_MOD
6980       for (vt=v.begin();vt!=vtend;++vt){
6981 	if (*vt)
6982 	  *vt %= env;
6983       }
6984 #endif
6985     } // end else based on modulo size
6986     for (vt=v.begin();vt!=vtend;++vt){
6987       if (*vt)
6988 	return unsigned(vt-v.begin());
6989     }
6990     return unsigned(v.size());
6991   }
6992 
tri(const vector<sparse_element> & v1,const vector<sparse_element> & v2)6993   bool tri(const vector<sparse_element> & v1,const vector<sparse_element> & v2){
6994     return v1.front().pos<v2.front().pos;
6995   }
6996 
6997   struct sparse_element_tri1 {
sparse_element_tri1giac::sparse_element_tri16998     sparse_element_tri1(){}
operator ()giac::sparse_element_tri16999     bool operator() (const sparse_element & v1,const sparse_element & v2){
7000       return v1.val<v2.val;
7001     }
7002   };
7003 
sort_vector_sparse_element(vector<sparse_element>::iterator it,vector<sparse_element>::iterator itend)7004   void sort_vector_sparse_element(vector<sparse_element>::iterator it,vector<sparse_element>::iterator itend){
7005     sort(it,itend,sparse_element_tri1());
7006   }
7007 
7008   // if sorting with presumed size, adding reconstructed generators will
7009   // not work...
7010   template <class poly>
7011   struct tripolymod_tri {
7012     int sort_by_logz_age;
tripolymod_trigiac::tripolymod_tri7013     tripolymod_tri(int b):sort_by_logz_age(b){}
operator ()giac::tripolymod_tri7014     bool operator() (const poly & v1,const poly & v2){
7015       if (sort_by_logz_age==1 && v1.logz!=v2.logz)
7016 	return v1.logz<v2.logz;
7017       if (sort_by_logz_age==2 && v1.age!=v2.age)
7018 	return v1.age<v2.age;
7019       return tdeg_t_strictly_greater(v2.coord.front().u,v1.coord.front().u,v1.order);
7020     }
7021   };
7022 
7023   template<class tdeg_t>
makeline(const polymod<tdeg_t> & p,const tdeg_t * shiftptr,const polymod<tdeg_t> & R,vector<modint> & v,int start=0)7024   void makeline(const polymod<tdeg_t> & p,const tdeg_t * shiftptr,const polymod<tdeg_t> & R,vector<modint> & v,int start=0){
7025     v.resize(R.coord.size());
7026     v.assign(R.coord.size(),0);
7027     typename std::vector< T_unsigned<modint,tdeg_t> >::const_iterator it=p.coord.begin()+start,itend=p.coord.end(),jt=R.coord.begin(),jtbeg=jt,jtend=R.coord.end();
7028     if (shiftptr){
7029       for (;it!=itend;++it){
7030 	tdeg_t u=it->u+*shiftptr;
7031 	for (;jt!=jtend;++jt){
7032 	  if (jt->u==u){
7033 	    v[jt-jtbeg]=it->g;
7034 	    ++jt;
7035 	    break;
7036 	  }
7037 	}
7038       }
7039     }
7040     else {
7041       for (;it!=itend;++it){
7042 	const tdeg_t & u=it->u;
7043 	for (;jt!=jtend;++jt){
7044 	  if (jt->u==u){
7045 	    v[jt-jtbeg]=it->g;
7046 	    ++jt;
7047 	    break;
7048 	  }
7049 	}
7050       }
7051     }
7052   }
7053 
7054   template<class tdeg_t>
makelinesub(const polymod<tdeg_t> & p,const tdeg_t * shiftptr,const polymod<tdeg_t> & R,vector<modint> & v,int start,modint env)7055   void makelinesub(const polymod<tdeg_t> & p,const tdeg_t * shiftptr,const polymod<tdeg_t> & R,vector<modint> & v,int start,modint env){
7056     typename std::vector< T_unsigned<modint,tdeg_t> >::const_iterator it=p.coord.begin()+start,itend=p.coord.end(),jt=R.coord.begin(),jtbeg=jt,jtend=R.coord.end();
7057     if (shiftptr){
7058       for (;it!=itend;++it){
7059 	tdeg_t u=it->u+*shiftptr;
7060 	for (;jt!=jtend;++jt){
7061 	  if (jt->u==u){
7062 	    // v[jt-jtbeg] -= it->g;
7063 	    modint & vv=v[jt-jtbeg];
7064 	    vv = (vv-longlong(it->g))%env;
7065 	    ++jt;
7066 	    break;
7067 	  }
7068 	}
7069       }
7070     }
7071     else {
7072       for (;it!=itend;++it){
7073 	const tdeg_t & u=it->u;
7074 	for (;jt!=jtend;++jt){
7075 	  if (jt->u==u){
7076 	    // v[jt-jtbeg]-=it->g;
7077 	    modint & vv=v[jt-jtbeg];
7078 	    vv = (vv-longlong(it->g))%env;
7079 	    ++jt;
7080 	    break;
7081 	  }
7082 	}
7083       }
7084     }
7085   }
7086 
7087   // put in v coeffs of polymod corresponding to R, and in rem those who do not match
7088   // returns false if v is null
7089   template<class tdeg_t>
makelinerem(const polymod<tdeg_t> & p,polymod<tdeg_t> & rem,const polymod<tdeg_t> & R,vector<modint> & v)7090   bool makelinerem(const polymod<tdeg_t> & p,polymod<tdeg_t> & rem,const polymod<tdeg_t> & R,vector<modint> & v){
7091     rem.coord.clear();
7092     v.clear();
7093     v.resize(R.coord.size());
7094     typename std::vector< T_unsigned<modint,tdeg_t> >::const_iterator it=p.coord.begin(),itend=p.coord.end(),jt=R.coord.begin(),jtend=R.coord.end();
7095     bool res=false;
7096     for (;it!=itend;++it){
7097       const tdeg_t & u=it->u;
7098       for (;jt!=jtend;++jt){
7099 	if (tdeg_t_greater(u,jt->u,p.order)
7100 	    // u>=jt->u
7101 	    ){
7102 	  if (u==jt->u){
7103 	    res=true;
7104 	    v[jt-R.coord.begin()]=it->g;
7105 	    ++jt;
7106 	  }
7107 	  else
7108 	    rem.coord.push_back(*it);
7109 	  break;
7110 	}
7111       }
7112     }
7113     return res;
7114   }
7115 
7116   template<class tdeg_t>
makeline(const polymod<tdeg_t> & p,const tdeg_t * shiftptr,const polymod<tdeg_t> & R,vector<sparse_element> & v)7117   void makeline(const polymod<tdeg_t> & p,const tdeg_t * shiftptr,const polymod<tdeg_t> & R,vector<sparse_element> & v){
7118     typename std::vector< T_unsigned<modint,tdeg_t> >::const_iterator it=p.coord.begin(),itend=p.coord.end(),jt=R.coord.begin(),jtend=R.coord.end();
7119     if (shiftptr){
7120       for (;it!=itend;++it){
7121 	tdeg_t u=it->u+*shiftptr;
7122 	for (;jt!=jtend;++jt){
7123 	  if (jt->u==u){
7124 	    v.push_back(sparse_element(it->g,jt-R.coord.begin()));
7125 	    ++jt;
7126 	    break;
7127 	  }
7128 	}
7129       }
7130     }
7131     else {
7132       for (;it!=itend;++it){
7133 	const tdeg_t & u=it->u;
7134 	for (;jt!=jtend;++jt){
7135 	  if (jt->u==u){
7136 	    v.push_back(sparse_element(it->g,jt-R.coord.begin()));
7137 	    ++jt;
7138 	    break;
7139 	  }
7140 	}
7141       }
7142     }
7143   }
7144 
7145 
7146 #if 1
convert(const vector<modint> & v,vector<sparse_element> & w,vector<used_t> & used)7147   void convert(const vector<modint> & v,vector<sparse_element> & w,vector<used_t> & used){
7148     unsigned count=0;
7149     vector<modint>::const_iterator it=v.begin(),itend=v.end();
7150     vector<used_t>::iterator ut=used.begin();
7151     for (;it!=itend;++ut,++it){
7152       if (!*it)
7153 	continue;
7154       *ut=1;
7155       ++count;
7156     }
7157     w.clear();
7158     w.reserve(count);
7159     for (count=0,it=v.begin();it!=itend;++count,++it){
7160       if (*it)
7161 	w.push_back(sparse_element(*it,count));
7162     }
7163   }
7164 
7165 #else
convert(const vector<modint> & v,vector<sparse_element> & w,vector<used_t> & used)7166   void convert(const vector<modint> & v,vector<sparse_element> & w,vector<used_t> & used){
7167     unsigned count=0;
7168     vector<modint>::const_iterator it=v.begin(),itend=v.end();
7169     for (;it!=itend;++it){
7170       if (*it){
7171 #if 1
7172 	used[it-v.begin()]=1;
7173 #else
7174 	++used[it-v.begin()];
7175 	if (used[it-v.begin()]>100)
7176 	  used[it-v.begin()]=100;
7177 #endif
7178 	++count;
7179       }
7180     }
7181     w.clear();
7182     w.reserve(count);
7183     for (it=v.begin();it!=itend;++it){
7184       if (*it)
7185 	w.push_back(sparse_element(*it,it-v.begin()));
7186     }
7187   }
7188 #endif
7189 
7190   // add to w non-zero coeffs of v, set bit i in bitmap to 1 if v[i]!=0
7191   // bitmap size is rounded to a multiple of 32
zconvert(const vector<modint> & v,vector<modint>::iterator & coeffit,unsigned * bitmap,vector<used_t> & used)7192   void zconvert(const vector<modint> & v,vector<modint>::iterator & coeffit,unsigned * bitmap,vector<used_t> & used){
7193     vector<modint>::const_iterator it=v.begin(),itend=v.end();
7194     used_t * uit=&used.front();
7195     for (unsigned i=0;it!=itend;++i,++it){
7196       if (!*it)
7197 	continue;
7198       *(uit+i)=1; // used[i]=1;
7199       bitmap[i>>5] |= (1<<(i&0x1f));
7200       *coeffit=*it;
7201       ++coeffit;
7202     }
7203   }
7204 
7205   template<class modint_t>
zconvert_(vector<modint_t> & v,vector<modint> & lescoeffs,unsigned * bitmap,vector<used_t> & used)7206   void zconvert_(vector<modint_t> & v,vector<modint> & lescoeffs,unsigned * bitmap,vector<used_t> & used){
7207     typename vector<modint_t>::iterator it0=v.begin(),it=it0,itend=v.end(),itend4=itend-4;
7208     used_t * uit=&used.front();
7209     for (;it<=itend4;++it){
7210       if (!*it ){
7211 	++it;
7212 	if (!*it){
7213 	  ++it;
7214 	  if (!*it){
7215 	    ++it;
7216 	    if (!*it)
7217 	      continue;
7218 	  }
7219 	}
7220       }
7221       unsigned i=unsigned(it-it0);
7222       *(uit+i)=1; // used[i]=1;
7223       bitmap[i>>5] |= (1<<(i&0x1f));
7224       lescoeffs.push_back(*it);
7225       *it=0;
7226     }
7227     for (;it!=itend;++it){
7228       if (!*it)
7229 	continue;
7230       unsigned i=unsigned(it-it0);
7231       *(uit+i)=1; // used[i]=1;
7232       bitmap[i>>5] |= (1<<(i&0x1f));
7233       lescoeffs.push_back(*it);
7234       *it=0;
7235     }
7236   }
7237 
7238   // create matrix from list of coefficients and bitmap of non-zero positions
7239   // M must already have been created with the right number of rows
create_matrix(const vector<modint> & lescoeffs,const unsigned * bitmap,unsigned bitmapcols,const vector<used_t> & used,vector<vector<modint>> & M)7240   void create_matrix(const vector<modint> & lescoeffs,const unsigned * bitmap,unsigned bitmapcols,const vector<used_t> & used,vector< vector<modint> > & M){
7241     unsigned nrows=unsigned(M.size());
7242     int ncols=0;
7243     vector<used_t>::const_iterator ut=used.begin(),utend=used.end();
7244     unsigned jend=unsigned(utend-ut);
7245     vector<modint>::const_iterator it=lescoeffs.begin();
7246     for (;ut!=utend;++ut){
7247       ncols += *ut;
7248     }
7249     // do all memory allocation at once, trying to speed up threaded execution
7250     for (unsigned i=0;i<nrows;++i)
7251       M[i].resize(ncols);
7252     for (unsigned i=0;i<nrows;++i){
7253       const unsigned * bitmapi = bitmap + i*bitmapcols;
7254       vector<modint>::iterator mi=M[i].begin();
7255       unsigned j=0;
7256       for (;j<jend;++j){
7257 	if (!used[j])
7258 	  continue;
7259 	if (bitmapi[j>>5] & (1<<(j&0x1f))){
7260 	  *mi=*it;
7261 	  ++it;
7262 	}
7263 	++mi;
7264       }
7265     }
7266   }
7267 
create_matrix(const unsigned * bitmap,unsigned bitmapcols,const vector<used_t> & used,vector<vector<modint>> & M)7268   void create_matrix(const unsigned * bitmap,unsigned bitmapcols,const vector<used_t> & used,vector< vector<modint> > & M){
7269     unsigned nrows=unsigned(M.size()),zeros=0;
7270     int ncols=0;
7271     vector<used_t>::const_iterator ut=used.begin(),utend=used.end();
7272     unsigned jend=unsigned(utend-ut);
7273     for (;ut!=utend;++ut){
7274       ncols += *ut;
7275     }
7276     vector<modint> tmp;
7277     for (unsigned i=0;i<nrows;++i){
7278       if (M[i].empty()){ ++zeros; continue; }
7279       const unsigned * bitmapi = bitmap + i*bitmapcols;
7280       tmp.clear();
7281       tmp.resize(ncols);
7282       tmp.swap(M[i]);
7283       vector<modint>::iterator mi=M[i].begin(),it=tmp.begin();
7284       unsigned j=0;
7285       for (;j<jend;++j){
7286 	if (!used[j])
7287 	  continue;
7288 	if (bitmapi[j>>5] & (1<<(j&0x1f))){
7289 	  *mi=*it;
7290 	  ++it;
7291 	}
7292 	++mi;
7293       }
7294     }
7295     if (debug_infolevel>1)
7296       CERR << CLOCK()*1e-6 << " " << zeros << " null lines over " << M.size() << '\n';
7297   }
7298 
push32(vector<sparse32> & v,modint val,unsigned & pos,unsigned newpos)7299   inline void push32(vector<sparse32> & v,modint val,unsigned & pos,unsigned newpos){
7300     unsigned shift=newpos-pos;
7301     if (newpos && (shift <(1<<7)))
7302       v.push_back(sparse32(val,shift));
7303     else {
7304       v.push_back(sparse32(val,0));
7305       v.push_back(sparse32());
7306       * (unsigned *) & v.back() =newpos;
7307     }
7308     pos=newpos;
7309   }
7310 
7311   template <class tdeg_t>
makeline32(const polymod<tdeg_t> & p,const tdeg_t * shiftptr,const polymod<tdeg_t> & R,vector<sparse32> & v)7312   void makeline32(const polymod<tdeg_t> & p,const tdeg_t * shiftptr,const polymod<tdeg_t> & R,vector<sparse32> & v){
7313     typename std::vector< T_unsigned<modint,tdeg_t> >::const_iterator it=p.coord.begin(),itend=p.coord.end(),jt=R.coord.begin(),jtend=R.coord.end();
7314     unsigned pos=0;
7315     if (shiftptr){
7316       for (;it!=itend;++it){
7317 	tdeg_t u=it->u+*shiftptr;
7318 	for (;jt!=jtend;++jt){
7319 	  if (jt->u==u){
7320 	    push32(v,it->g,pos,unsigned(jt-R.coord.begin()));
7321 	    ++jt;
7322 	    break;
7323 	  }
7324 	}
7325       }
7326     }
7327     else {
7328       for (;it!=itend;++it){
7329 	const tdeg_t & u=it->u;
7330 	for (;jt!=jtend;++jt){
7331 	  if (jt->u==u){
7332 	    push32(v,it->g,pos,unsigned(jt-R.coord.begin()));
7333 	    ++jt;
7334 	    break;
7335 	  }
7336 	}
7337       }
7338     }
7339   }
7340 
convert32(const vector<modint> & v,vector<sparse32> & w,vector<used_t> & used)7341   void convert32(const vector<modint> & v,vector<sparse32> & w,vector<used_t> & used){
7342     unsigned count=0;
7343     vector<modint>::const_iterator it=v.begin(),itend=v.end();
7344     for (;it!=itend;++it){
7345       if (*it){
7346 #if 1
7347 	used[it-v.begin()]=1;
7348 #else
7349 	++used[it-v.begin()];
7350 	if (used[it-v.begin()]>100)
7351 	  used[it-v.begin()]=100;
7352 #endif
7353 	++count;
7354       }
7355     }
7356     w.clear();
7357     w.reserve(1+int(count*1.1));
7358     unsigned pos=0;
7359     for (it=v.begin();it!=itend;++it){
7360       if (*it)
7361 	push32(w,*it,pos,unsigned(it-v.begin()));
7362     }
7363   }
7364 
7365   template<class tdeg_t>
rref_f4buchbergermod_interreduce(vectpolymod<tdeg_t> & f4buchbergerv,const vector<unsigned> & f4buchbergervG,vectpolymod<tdeg_t> & res,const vector<unsigned> & G,unsigned excluded,const vectpolymod<tdeg_t> & quo,const polymod<tdeg_t> & R,modint env,vector<int> & permutation)7366   void rref_f4buchbergermod_interreduce(vectpolymod<tdeg_t> & f4buchbergerv,const vector<unsigned> & f4buchbergervG,vectpolymod<tdeg_t> & res,const vector<unsigned> & G,unsigned excluded,const vectpolymod<tdeg_t> & quo,const polymod<tdeg_t> & R,modint env,vector<int> & permutation){
7367     // step2: for each monomials of quo[i], shift res[G[i]] by monomial
7368     // set coefficient in a line of a matrix M, columns are R monomials indices
7369     if (debug_infolevel>1)
7370       CERR << CLOCK()*1e-6 << " begin build M" << '\n';
7371     unsigned N=unsigned(R.coord.size()),i,j=0;
7372     unsigned c=N;
7373     double sknon0=0;
7374     vector<used_t> used(N,0);
7375     unsigned usedcount=0,zerolines=0,Msize=0;
7376     vector< vector<modint> > K(f4buchbergervG.size());
7377     for (i=0;i<G.size();++i){
7378       Msize += unsigned(quo[i].coord.size());
7379     }
7380     if ( env<(1<<24) && env*double(env)*Msize<9.223e18 ){
7381       vector< vector<sparse32> > M;
7382       M.reserve(N);
7383       vector<sparse_element> atrier;
7384       atrier.reserve(N);
7385       for (i=0;i<G.size();++i){
7386 	typename std::vector< T_unsigned<modint,tdeg_t> >::const_iterator jt=quo[i].coord.begin(),jtend=quo[i].coord.end();
7387 	for (;jt!=jtend;++j,++jt){
7388 	  M.push_back(vector<sparse32>(0));
7389 	  M[j].reserve(1+int(1.1*res[G[i]].coord.size()));
7390 	  makeline32(res[G[i]],&jt->u,R,M[j]);
7391 	  // CERR << M[j] << '\n';
7392 	  if (M[j].front().shift)
7393 	    atrier.push_back(sparse_element(M[j].front().shift,j));
7394 	  else
7395 	    atrier.push_back(sparse_element(*(unsigned *) &M[j][1],j));
7396 	}
7397       }
7398       if (debug_infolevel>1)
7399 	CERR << CLOCK()*1e-6 << " end build M32" << '\n';
7400       // should not sort but compare res[G[i]]*quo[i] monomials to build M already sorted
7401       // CERR << "before sort " << M << '\n';
7402       sort_vector_sparse_element(atrier.begin(),atrier.end()); // sort(atrier.begin(),atrier.end(),tri1);
7403       vector< vector<sparse32> > M1(atrier.size());
7404       double mem=0; // mem*4=number of bytes allocated for M1
7405       for (i=0;i<atrier.size();++i){
7406 	swap(M1[i],M[atrier[i].pos]);
7407 	mem += M1[i].size();
7408       }
7409       swap(M,M1);
7410       bool freemem=mem>4e7; // should depend on real memory available
7411       if (debug_infolevel>1)
7412 	CERR << CLOCK()*1e-6 << " M32 sorted, rows " << M.size() << " columns " << N << " terms " << mem << " ratio " << (mem/M.size())/N <<'\n';
7413       // CERR << "after sort " << M << '\n';
7414       // step3 reduce
7415       vector<modint> v(N); vector<modint2> w(N);
7416       vector< vector<sparse32> > SK(f4buchbergerv.size());
7417       for (i=0;i<f4buchbergervG.size();++i){
7418 	if (!f4buchbergerv[f4buchbergervG[i]].coord.empty()){
7419 	  makeline<tdeg_t>(f4buchbergerv[f4buchbergervG[i]],0,R,v);
7420 	  if (freemem){
7421 	    polymod<tdeg_t> clearer; swap(f4buchbergerv[f4buchbergervG[i]].coord,clearer.coord);
7422 	  }
7423 	  c=giacmin(c,reducef4buchberger_32(v,M,env,w));
7424 	  // convert v to a sparse vector in SK and update used
7425 	  convert32(v,SK[i],used);
7426 	  //CERR << v << '\n' << SK[i] << '\n';
7427 	}
7428       }
7429       M.clear();
7430       if (debug_infolevel>1)
7431 	CERR << CLOCK()*1e-6 << " f4buchbergerv reduced " << f4buchbergervG.size() << " polynoms over " << N << " monomials, start at " << c << '\n';
7432       for (i=0;i<N;++i)
7433 	usedcount += (used[i]>0);
7434       if (debug_infolevel>1){
7435 	CERR << CLOCK()*1e-6 << " number of non-zero columns " << usedcount << " over " << N << '\n'; // usedcount should be approx N-M.size()=number of cols of M-number of rows
7436 	if (debug_infolevel>2)
7437 	  CERR << " column32 used " << used << '\n';
7438       }
7439       // create dense matrix K
7440       for (i=0; i<K.size(); ++i){
7441 	vector<modint> & v =K[i];
7442 	if (SK[i].empty()){
7443 	  ++zerolines;
7444 	  continue;
7445 	}
7446 	v.resize(usedcount);
7447 	vector<modint>::iterator vt=v.begin();
7448 	vector<used_t>::const_iterator ut=used.begin(),ut0=ut;
7449 	vector<sparse32>::const_iterator st=SK[i].begin(),stend=SK[i].end();
7450 	unsigned p=0;
7451 	for (j=0;st!=stend;++j,++ut){
7452 	  if (!*ut)
7453 	    continue;
7454 	  if (st->shift){
7455 	    if (j==p + st->shift){
7456 	      p += st->shift;
7457 	      *vt=st->val;
7458 	      ++st;
7459 	      ++sknon0;
7460 	    }
7461 	  }
7462 	  else {
7463 	    if (j==* (unsigned *) &(*(st+1))){
7464 	      *vt=st->val;
7465 	      ++st;
7466 	      p = * (unsigned *) &(*st);
7467 	      ++st;
7468 	      ++sknon0;
7469 	    }
7470 	  }
7471 	  ++vt;
7472 	}
7473 #if 0
7474 	vector<sparse32> clearer;
7475 	swap(SK[i],clearer); // clear SK[i] memory
7476 #endif
7477       }
7478     }
7479     else {
7480       vector< vector<sparse_element> > M;
7481       M.reserve(N);
7482       vector<sparse_element> atrier;
7483       atrier.reserve(N);
7484       for (i=0;i<G.size();++i){
7485 	typename std::vector< T_unsigned<modint,tdeg_t> >::const_iterator jt=quo[i].coord.begin(),jtend=quo[i].coord.end();
7486 	for (;jt!=jtend;++j,++jt){
7487 	  M.push_back(vector<sparse_element>(0));
7488 	  M[j].reserve(res[G[i]].coord.size());
7489 	  makeline(res[G[i]],&jt->u,R,M[j]);
7490 	  atrier.push_back(sparse_element(M[j].front().pos,j));
7491 	}
7492       }
7493       if (debug_infolevel>1)
7494 	CERR << CLOCK()*1e-6 << " end build M" << '\n';
7495       // should not sort but compare res[G[i]]*quo[i] monomials to build M already sorted
7496       // CERR << "before sort " << M << '\n';
7497       sort_vector_sparse_element(atrier.begin(),atrier.end()); // sort(atrier.begin(),atrier.end(),tri1);
7498       vector< vector<sparse_element> > M1(atrier.size());
7499       double mem=0; // mem*8=number of bytes allocated for M1
7500       unsigned firstpart=0;
7501       for (i=0;i<atrier.size();++i){
7502 	swap(M1[i],M[atrier[i].pos]);
7503 	mem += M1[i].size();
7504 	if (!M1[i].empty())
7505 	  firstpart=giacmax(firstpart,M1[i].front().pos);
7506       }
7507       swap(M,M1);
7508       bool freemem=mem>4e7; // should depend on real memory available
7509       // sort(M.begin(),M.end(),tri);
7510       if (debug_infolevel>1)
7511 	CERR << CLOCK()*1e-6 << " M sorted, rows " << M.size() << " columns " << N << "[" << firstpart << "] terms " << mem << " ratio " << (mem/N)/M.size() << '\n';
7512       // CERR << "after sort " << M << '\n';
7513       // step3 reduce
7514       vector<modint> v(N);
7515       vector< vector<sparse_element> > SK(f4buchbergerv.size());
7516 #ifdef x86_64
7517       vector<int128_t> v128(N);
7518       vector<modint> multiplier(M.size()); vector<unsigned> pos(M.size());
7519 #endif
7520       for (i=0;i<f4buchbergervG.size();++i){
7521 	if (!f4buchbergerv[f4buchbergervG[i]].coord.empty()){
7522 	  makeline<tdeg_t>(f4buchbergerv[f4buchbergervG[i]],0,R,v);
7523 	  if (freemem){
7524 	    polymod<tdeg_t> clearer; swap(f4buchbergerv[f4buchbergervG[i]].coord,clearer.coord);
7525 	  }
7526 #ifdef x86_64
7527 	  /* vector<modint> w(v);
7528 	  // CERR << "reduce " << v << '\n' << M << '\n';
7529 	  c=giacmin(c,reducef4buchbergerslice(w,M,env,v128,multiplier,pos));
7530 	  c=giacmin(c,reducef4buchberger_64(v,M,env,v128));
7531 	  if (w!=v) CERR << w << '\n' << v << '\n'; else CERR << "ok" << '\n';
7532 	  */
7533 	  // c=giacmin(c,reducef4buchbergerslice(v,M,env,v128,multiplier,pos));
7534 	  if (0 && env<(1<<29) && N>10000) // it's slower despite v128 not in cache
7535 	    c=giacmin(c,reducef4buchberger(v,M,env));
7536 	  else
7537 	    c=giacmin(c,reducef4buchberger_64(v,M,env,v128));
7538 #else // x86_64
7539 	  c=giacmin(c,reducef4buchberger(v,M,env));
7540 #endif // x86_64
7541 	  // convert v to a sparse vector in SK and update used
7542 	  convert(v,SK[i],used);
7543 	  // CERR << v << '\n' << SK[i] << '\n';
7544 	}
7545       }
7546       M.clear();
7547       if (debug_infolevel>1)
7548 	CERR << CLOCK()*1e-6 << " f4buchbergerv reduced " << f4buchbergervG.size() << " polynoms over " << N << " monomials, start at " << c << '\n';
7549       for (i=0;i<N;++i)
7550 	usedcount += (used[i]>0);
7551       if (debug_infolevel>1){
7552 	CERR << CLOCK()*1e-6 << " number of non-zero columns " << usedcount << " over " << N << '\n'; // usedcount should be approx N-M.size()=number of cols of M-number of rows
7553 	// if (debug_infolevel>2) CERR << " column use " << used << '\n';
7554       }
7555       // create dense matrix K
7556       for (i=0; i<K.size(); ++i){
7557 	vector<modint> & v =K[i];
7558 	if (SK[i].empty()){
7559 	  ++zerolines;
7560 	  continue;
7561 	}
7562 	sknon0 += SK[i].size();
7563 	v.resize(usedcount);
7564 	vector<modint>::iterator vt=v.begin();
7565 	vector<used_t>::const_iterator ut=used.begin(),ut0=ut;
7566 	vector<sparse_element>::const_iterator st=SK[i].begin(),stend=SK[i].end();
7567 	for (j=0;st!=stend;++j,++ut){
7568 	  if (!*ut)
7569 	    continue;
7570 	  if (j==st->pos){
7571 	    *vt=st->val;
7572 	    ++st;
7573 	  }
7574 	  ++vt;
7575 	}
7576 #if 1
7577 	vector<sparse_element> clearer;
7578 	swap(SK[i],clearer); // clear SK[i] memory
7579 #endif
7580 	// CERR << used << '\n' << SK[i] << '\n' << K[i] << '\n';
7581       }
7582     }
7583     if (debug_infolevel>1)
7584       CERR << CLOCK()*1e-6 << " rref " << K.size() << "x" << usedcount << " non0 " << sknon0 << " ratio " << (sknon0/K.size())/usedcount << " nulllines " << zerolines << '\n';
7585     vecteur pivots; vector<int> maxrankcols; longlong idet;
7586     // CERR << K << '\n';
7587     smallmodrref(1,K,pivots,permutation,maxrankcols,idet,0,int(K.size()),0,usedcount,1/* fullreduction*/,0/*dontswapbelow*/,env,0/* rrefordetorlu*/,true,0,true,-1);
7588     //CERR << K << "," << permutation << '\n';
7589     typename vector< T_unsigned<modint,tdeg_t> >::const_iterator it=R.coord.begin(),itend=R.coord.end();
7590     vector<int> permu=perminv(permutation);
7591     if (debug_infolevel>1)
7592       CERR << CLOCK()*1e-6 << " f4buchbergerv interreduced" << '\n';
7593     for (i=0;i<f4buchbergervG.size();++i){
7594 #if 0 // spare memory, keep exactly the right number of monomials in f4buchbergerv[]
7595       polymod<tdeg_t> tmpP(f4buchbergerv[f4buchbergervG[i]].order,f4buchbergerv[f4buchbergervG[i]].dim);
7596       vector<modint> & v =K[permu[i]];
7597       if (v.empty())
7598 	continue;
7599       unsigned vcount=0;
7600       vector<modint>::const_iterator vt=v.begin(),vtend=v.end();
7601       for (;vt!=vtend;++vt){
7602 	if (*vt)
7603 	  ++vcount;
7604       }
7605       vector< T_unsigned<modint,tdeg_t> > & Pcoord=tmpP.coord;
7606       Pcoord.reserve(vcount);
7607       vector<used_t>::const_iterator ut=used.begin();
7608       for (vt=v.begin(),it=R.coord.begin();it!=itend;++ut,++it){
7609 	if (!*ut)
7610 	  continue;
7611 	modint coeff=*vt;
7612 	++vt;
7613 	if (coeff!=0)
7614 	  Pcoord.push_back(T_unsigned<modint,tdeg_t>(coeff,it->u));
7615       }
7616       if (!Pcoord.empty() && Pcoord.front().g!=1){
7617 	smallmultmod(invmod(Pcoord.front().g,env),tmpP,env);
7618 	Pcoord.front().g=1;
7619       }
7620       swap(tmpP.coord,f4buchbergerv[f4buchbergervG[i]].coord);
7621 #else
7622       // CERR << v << '\n';
7623       vector< T_unsigned<modint,tdeg_t> > & Pcoord=f4buchbergerv[f4buchbergervG[i]].coord;
7624       Pcoord.clear();
7625       vector<modint> & v =K[permu[i]];
7626       if (v.empty())
7627 	continue;
7628       unsigned vcount=0;
7629       vector<modint>::const_iterator vt=v.begin(),vtend=v.end();
7630       for (;vt!=vtend;++vt){
7631 	if (*vt)
7632 	  ++vcount;
7633       }
7634       Pcoord.reserve(vcount);
7635       vector<used_t>::const_iterator ut=used.begin();
7636       for (vt=v.begin(),it=R.coord.begin();it!=itend;++ut,++it){
7637 	if (!*ut)
7638 	  continue;
7639 	modint coeff=*vt;
7640 	++vt;
7641 	if (coeff!=0)
7642 	  Pcoord.push_back(T_unsigned<modint,tdeg_t>(coeff,it->u));
7643       }
7644       if (!Pcoord.empty() && Pcoord.front().g!=1){
7645 	smallmultmod(invmod(Pcoord.front().g,env),f4buchbergerv[f4buchbergervG[i]],env);
7646 	Pcoord.front().g=1;
7647       }
7648 #endif
7649     }
7650   }
7651 
7652 
7653   template<class tdeg_t>
copycoeff(const polymod<tdeg_t> & p,vector<modint> & v)7654   void copycoeff(const polymod<tdeg_t> & p,vector<modint> & v){
7655     typename std::vector< T_unsigned<modint,tdeg_t> >::const_iterator it=p.coord.begin(),itend=p.coord.end();
7656     v.clear();
7657     v.reserve(itend-it);
7658     for (;it!=itend;++it)
7659       v.push_back(it->g);
7660   }
7661 
7662   template<class tdeg_t>
copycoeff(const poly8<tdeg_t> & p,vector<gen> & v)7663   void copycoeff(const poly8<tdeg_t> & p,vector<gen> & v){
7664     typename std::vector< T_unsigned<gen,tdeg_t> >::const_iterator it=p.coord.begin(),itend=p.coord.end();
7665     v.clear();
7666     v.reserve(itend-it);
7667     for (;it!=itend;++it)
7668       v.push_back(it->g);
7669   }
7670 
7671   // dichotomic seach for jt->u==u in [jt,jtend[
7672   template <class tdeg_t>
dicho(typename std::vector<T_unsigned<modint,tdeg_t>>::const_iterator & jt,typename std::vector<T_unsigned<modint,tdeg_t>>::const_iterator jtend,const tdeg_t & u,order_t order)7673   bool dicho(typename std::vector< T_unsigned<modint,tdeg_t> >::const_iterator & jt,typename std::vector< T_unsigned<modint,tdeg_t> >::const_iterator jtend,const tdeg_t & u,order_t order){
7674     if (jt->u==u) return true;
7675     for (;;){
7676       int step=int((jtend-jt)/2);
7677       typename std::vector< T_unsigned<modint,tdeg_t> >::const_iterator j=jt+step;
7678       if (j==jt)
7679 	return j->u==u;
7680       //PREFETCH(&*(j+step/2));
7681       //PREFETCH(&*(jt+step/2));
7682       if (int res=tdeg_t_greater(j->u,u,order)){
7683 	jt=j;
7684 	if (res==2)
7685 	  return true;
7686       }
7687       else
7688 	jtend=j;
7689     }
7690   }
7691 
7692   template<class tdeg_t>
makelinesplit(const polymod<tdeg_t> & p,const tdeg_t * shiftptr,const polymod<tdeg_t> & R,vector<shifttype> & v)7693   void makelinesplit(const polymod<tdeg_t> & p,const tdeg_t * shiftptr,const polymod<tdeg_t> & R,vector<shifttype> & v){
7694     typename std::vector< T_unsigned<modint,tdeg_t> >::const_iterator it=p.coord.begin(),itend=p.coord.end(),jt=R.coord.begin(),jtend=R.coord.end();
7695     unsigned pos=0;
7696     double nop1=double(R.coord.size());
7697     double nop2=4*p.coord.size()*std::log(nop1)/std::log(2.0);
7698     bool dodicho=nop2<nop1;
7699     if (shiftptr){
7700       for (;it!=itend;++it){
7701 	tdeg_t u=it->u+*shiftptr;
7702 	/* new faster code */
7703 	if (dodicho && dicho(jt,jtend,u,R.order)){
7704 	  pushsplit(v,pos,unsigned(jt-R.coord.begin()));
7705 	  ++jt;
7706 	  continue;
7707 	}
7708 	/* end new faster code */
7709 	for (;jt!=jtend;++jt){
7710 	  if (jt->u==u){
7711 	    pushsplit(v,pos,unsigned(jt-R.coord.begin()));
7712 	    ++jt;
7713 	    break;
7714 	  }
7715 	}
7716       }
7717     }
7718     else {
7719       for (;it!=itend;++it){
7720 	const tdeg_t & u=it->u;
7721 	/* new faster code */
7722 	if (dodicho && dicho(jt,jtend,u,R.order)){
7723 	  pushsplit(v,pos,unsigned(jt-R.coord.begin()));
7724 	  ++jt;
7725 	  continue;
7726 	}
7727 	/* end new faster code */
7728 	for (;jt!=jtend;++jt){
7729 	  if (jt->u==u){
7730 	    pushsplit(v,pos,unsigned(jt-R.coord.begin()));
7731 	    ++jt;
7732 	    break;
7733 	  }
7734 	}
7735       }
7736     }
7737   }
7738 
7739   // return true if all shifts are <=0xffff
checkshortshifts(const vector<shifttype> & v)7740   bool checkshortshifts(const vector<shifttype> & v){
7741     if (v.empty())
7742       return false;
7743     const shifttype * it=&v.front(),*itend=it+v.size();
7744     // ignore first, it's not a shift
7745     unsigned pos;
7746     next_index(pos,it);
7747     for (;it!=itend;++it){
7748       if (!*it)
7749 	return false;
7750     }
7751     return true;
7752   }
7753 
7754   template<class tdeg_t>
makelinesplit(const poly8<tdeg_t> & p,const tdeg_t * shiftptr,const polymod<tdeg_t> & R,vector<shifttype> & v)7755   void makelinesplit(const poly8<tdeg_t> & p,const tdeg_t * shiftptr,const polymod<tdeg_t> & R,vector<shifttype> & v){
7756     typename std::vector< T_unsigned<gen,tdeg_t> >::const_iterator it=p.coord.begin(),itend=p.coord.end();
7757     typename std::vector< T_unsigned<modint,tdeg_t> >::const_iterator jt=R.coord.begin(),jt0=jt,jtend=R.coord.end();
7758     unsigned pos=0;
7759     if (shiftptr){
7760       for (;it!=itend;++it){
7761 	tdeg_t u=it->u+*shiftptr;
7762 	for (;jt!=jtend;++jt){
7763 	  if (jt->u==u){
7764 	    pushsplit(v,pos,unsigned(jt-jt0));
7765 	    ++jt;
7766 	    break;
7767 	  }
7768 	}
7769       }
7770     }
7771     else {
7772       for (;it!=itend;++it){
7773 	const tdeg_t & u=it->u;
7774 	for (;jt!=jtend;++jt){
7775 	  if (jt->u==u){
7776 	    pushsplit(v,pos,unsigned(jt-jt0));
7777 	    ++jt;
7778 	    break;
7779 	  }
7780 	}
7781       }
7782     }
7783   }
7784 
7785   template<class tdeg_t>
makelinesplitu(const polymod<tdeg_t> & p,const tdeg_t * shiftptr,const polymod<tdeg_t> & R,vector<unsigned> & vu)7786   void makelinesplitu(const polymod<tdeg_t> & p,const tdeg_t * shiftptr,const polymod<tdeg_t> & R,vector<unsigned> & vu){
7787     typename std::vector< T_unsigned<modint,tdeg_t> >::const_iterator it=p.coord.begin(),itend=p.coord.end(),jt=R.coord.begin(),jt0=jt,jtend=R.coord.end();
7788     if (shiftptr){
7789       for (;it!=itend;++it){
7790 	tdeg_t u=it->u+*shiftptr;
7791 	for (;jt!=jtend;++jt){
7792 	  if (jt->u==u){
7793 	    vu.push_back(hashgcd_U(jt-jt0));
7794 	    ++jt;
7795 	    break;
7796 	  }
7797 	}
7798       }
7799     }
7800     else {
7801       for (;it!=itend;++it){
7802 	const tdeg_t & u=it->u;
7803 	for (;jt!=jtend;++jt){
7804 	  if (jt->u==u){
7805 	    vu.push_back(hashgcd_U(jt-jt0));
7806 	    ++jt;
7807 	    break;
7808 	  }
7809 	}
7810       }
7811     }
7812   }
7813 
7814   template<class tdeg_t>
makelinesplits(const polymod<tdeg_t> & p,const tdeg_t * shiftptr,const polymod<tdeg_t> & R,vector<unsigned short> & vu)7815   void makelinesplits(const polymod<tdeg_t> & p,const tdeg_t * shiftptr,const polymod<tdeg_t> & R,vector<unsigned short> & vu){
7816     typename std::vector< T_unsigned<modint,tdeg_t> >::const_iterator it=p.coord.begin(),itend=p.coord.end(),jt=R.coord.begin(),jt0=jt,jtend=R.coord.end();
7817     if (shiftptr){
7818       for (;it!=itend;++it){
7819 	tdeg_t u=it->u+*shiftptr;
7820 	for (;jt!=jtend;++jt){
7821 	  if (jt->u==u){
7822 	    vu.push_back(hashgcd_U(jt-jt0));
7823 	    ++jt;
7824 	    break;
7825 	  }
7826 	}
7827       }
7828     }
7829     else {
7830       for (;it!=itend;++it){
7831 	const tdeg_t & u=it->u;
7832 	for (;jt!=jtend;++jt){
7833 	  if (jt->u==u){
7834 	    vu.push_back(hashgcd_U(jt-jt0));
7835 	    ++jt;
7836 	    break;
7837 	  }
7838 	}
7839       }
7840     }
7841   }
7842 
7843 
7844 #define GIAC_Z
7845 
7846   // perhaps a good idea to lock when memory allocation occur?
7847 #ifdef HAVE_LIBPTHREAD
7848     pthread_mutex_t gbasismutex = PTHREAD_MUTEX_INITIALIZER;
7849 #endif
7850 
7851   template<class tdeg_t>
rref_f4buchbergermodsplit_interreduce(vectpolymod<tdeg_t> & f4buchbergerv,const vector<unsigned> & f4buchbergervG,vectpolymod<tdeg_t> & res,const vector<unsigned> & G,unsigned excluded,const vectpolymod<tdeg_t> & quo,const polymod<tdeg_t> & R,modint env,vector<int> & permutation)7852   void rref_f4buchbergermodsplit_interreduce(vectpolymod<tdeg_t> & f4buchbergerv,const vector<unsigned> & f4buchbergervG,vectpolymod<tdeg_t> & res,const vector<unsigned> & G,unsigned excluded,const vectpolymod<tdeg_t> & quo,const polymod<tdeg_t> & R,modint env,vector<int> & permutation){
7853     // step2: for each monomials of quo[i], shift res[G[i]] by monomial
7854     // set coefficient in a line of a matrix M, columns are R monomials indices
7855     if (debug_infolevel>1)
7856       CERR << CLOCK()*1e-6 << " begin build M" << '\n';
7857     unsigned N=unsigned(R.coord.size()),i,j=0;
7858     if (N==0) return;
7859 #if GIAC_SHORTSHIFTTYPE==16
7860     bool useshort=true;
7861 #else
7862     bool useshort=N<=0xffff;
7863 #endif
7864     unsigned nrows=0;
7865     for (i=0;i<G.size();++i){
7866       nrows += unsigned(quo[i].coord.size());
7867     }
7868     unsigned c=N;
7869     double sknon0=0;
7870     vector<used_t> used(N,0);
7871     unsigned usedcount=0,zerolines=0;
7872     vector< vector<modint> > K(f4buchbergervG.size());
7873     vector<vector<unsigned short> > Mindex;
7874     vector<vector<unsigned> > Muindex;
7875     vector< vector<modint> > Mcoeff(G.size());
7876     vector<coeffindex_t> coeffindex;
7877     if (useshort)
7878       Mindex.reserve(nrows);
7879     else
7880       Muindex.reserve(nrows);
7881     coeffindex.reserve(nrows);
7882     vector<sparse_element> atrier;
7883     atrier.reserve(nrows);
7884     for (i=0;i<G.size();++i){
7885       Mcoeff[i].reserve(res[G[i]].coord.size());
7886       typename std::vector< T_unsigned<modint,tdeg_t> >::const_iterator jt=quo[i].coord.begin(),jtend=quo[i].coord.end();
7887       if (useshort){
7888 	for (;jt!=jtend;++j,++jt){
7889 	  Mindex.push_back(vector<unsigned short>(0));
7890 #if GIAC_SHORTSHIFTTYPE==16
7891 	  Mindex[j].reserve(int(1.1*res[G[i]].coord.size()));
7892 #else
7893 	  Mindex[j].reserve(res[G[i]].coord.size());
7894 #endif
7895 	}
7896       }
7897       else {
7898 	for (;jt!=jtend;++j,++jt){
7899 	  Muindex.push_back(vector<unsigned>(0));
7900 	  Muindex[j].reserve(res[G[i]].coord.size());
7901 	}
7902       }
7903     }
7904     for (i=0,j=0;i<G.size();++i){
7905       // copy coeffs of res[G[i]] in Mcoeff
7906       copycoeff(res[G[i]],Mcoeff[i]);
7907       // for each monomial of quo[i], find indexes and put in Mindex
7908       typename std::vector< T_unsigned<modint,tdeg_t> >::const_iterator jt=quo[i].coord.begin(),jtend=quo[i].coord.end();
7909       for (;jt!=jtend;++j,++jt){
7910 	coeffindex.push_back(coeffindex_t(N<=0xffff,i));
7911 	if (useshort){
7912 #if GIAC_SHORTSHIFTTYPE==16
7913 	  makelinesplit(res[G[i]],&jt->u,R,Mindex[j]);
7914 	  if (!coeffindex.back().b)
7915 	    coeffindex.back().b=checkshortshifts(Mindex[j]);
7916 	  atrier.push_back(sparse_element(first_index(Mindex[j]),j));
7917 #else
7918 	  makelinesplits(res[G[i]],&jt->u,R,Mindex[j]);
7919 	  atrier.push_back(sparse_element(Mindex[j].front(),j));
7920 #endif
7921 	}
7922 	else {
7923 	  makelinesplitu(res[G[i]],&jt->u,R,Muindex[j]);
7924 	  atrier.push_back(sparse_element(Muindex[j].front(),j));
7925 	}
7926       }
7927     }
7928     if (debug_infolevel>1)
7929       CERR << CLOCK()*1e-6 << " end build Mindex/Mcoeff rref_f4buchbergermodsplit_interreduce" << '\n';
7930     // should not sort but compare res[G[i]]*quo[i] monomials to build M already sorted
7931     // CERR << "before sort " << M << '\n';
7932     sort_vector_sparse_element(atrier.begin(),atrier.end()); // sort(atrier.begin(),atrier.end(),tri1);
7933     vector<coeffindex_t> coeffindex1(atrier.size());
7934     double mem=0; // mem*4=number of bytes allocated for M1
7935     if (useshort){
7936       vector< vector<unsigned short> > Mindex1(atrier.size());
7937       for (i=0;i<atrier.size();++i){
7938 	swap(Mindex1[i],Mindex[atrier[i].pos]);
7939 	mem += Mindex1[i].size();
7940 	swap(coeffindex1[i],coeffindex[atrier[i].pos]);
7941       }
7942       swap(Mindex,Mindex1);
7943       nrows=unsigned(Mindex.size());
7944     }
7945     else {
7946       vector< vector<unsigned> > Muindex1(atrier.size());
7947       for (i=0;i<atrier.size();++i){
7948 	swap(Muindex1[i],Muindex[atrier[i].pos]);
7949 	mem += Muindex1[i].size();
7950 	swap(coeffindex1[i],coeffindex[atrier[i].pos]);
7951       }
7952       swap(Muindex,Muindex1);
7953       nrows=unsigned(Muindex.size());
7954     }
7955     swap(coeffindex,coeffindex1);
7956     vector<unsigned> firstpos(atrier.size());
7957     for (i=0;i < atrier.size();++i){
7958       firstpos[i]=atrier[i].val;
7959     }
7960     bool freemem=true; // mem>4e7; // should depend on real memory available
7961     if (debug_infolevel>1)
7962       CERR << CLOCK()*1e-6 << " Mindex sorted, rows " << nrows << " columns " << N << " terms " << mem << " ratio " << (mem/nrows)/N <<'\n';
7963     // CERR << "after sort " << M << '\n';
7964     // step3 reduce
7965     vector<modint> v(N);
7966     vector<modint2> v64(N);
7967 #ifdef x86_64
7968     vector<int128_t> v128(N);
7969 #endif
7970 #ifdef GIAC_Z
7971     if (N<nrows){
7972       CERR << "Error " << N << "," << nrows << '\n';
7973       return;
7974     }
7975     unsigned Kcols=N-nrows;
7976     unsigned effectivef4buchbergervGsize=0;
7977     for (unsigned i=0;i<f4buchbergervG.size();++i){
7978       if (!f4buchbergerv[f4buchbergervG[i]].coord.empty())
7979 	++effectivef4buchbergervGsize;
7980     }
7981     vector<modint> lescoeffs;
7982     lescoeffs.reserve(Kcols*effectivef4buchbergervGsize);
7983     // vector<modint> lescoeffs(Kcols*effectivef4buchbergervGsize);
7984     // vector<modint>::iterator coeffit=lescoeffs.begin();
7985     if (debug_infolevel>1)
7986       CERR << "Capacity for coeffs " << lescoeffs.size() << '\n';
7987     vector<unsigned> lebitmap(((N>>5)+1)*effectivef4buchbergervGsize);
7988     unsigned * bitmap=&lebitmap.front();
7989 #else
7990     vector< vector<sparse_element> > SK(f4buchbergerv.size());
7991 #endif
7992     for (i=0;i<f4buchbergervG.size();++i){
7993       if (!f4buchbergerv[f4buchbergervG[i]].coord.empty()){
7994 	makeline<tdeg_t>(f4buchbergerv[f4buchbergervG[i]],0,R,v);
7995 	//CERR << v << '\n';
7996 #ifdef x86_64
7997 	if (useshort){
7998 	  if (env<(1<<24)){
7999 #if GIAC_SHORTSHIFTTYPE==16
8000 	    c=giacmin(c,reducef4buchbergersplit(v,Mindex,firstpos,Mcoeff,coeffindex,env,v64));
8001 #else
8002 	    c=giacmin(c,reducef4buchbergersplits(v,Mindex,Mcoeff,coeffindex,env,v64));
8003 #endif
8004 	  }
8005 	  else {
8006 #if GIAC_SHORTSHIFTTYPE==16
8007 	    c=giacmin(c,reducef4buchbergersplit64(v,Mindex,firstpos,Mcoeff,coeffindex,env,v128));
8008 #else
8009 	    c=giacmin(c,reducef4buchbergersplit64s(v,Mindex,Mcoeff,coeffindex,env,v128));
8010 #endif
8011 	  }
8012 	}
8013 	else {
8014 	  if (env<(1<<24))
8015 	    c=giacmin(c,reducef4buchbergersplitu(v,Muindex,Mcoeff,coeffindex,env,v64));
8016 	  else
8017 	    c=giacmin(c,reducef4buchbergersplit64u(v,Muindex,Mcoeff,coeffindex,env,v128));
8018 	}
8019 #else
8020 	if (useshort){
8021 #if GIAC_SHORTSHIFTTYPE==16
8022 	  c=giacmin(c,reducef4buchbergersplit(v,Mindex,firstpos,Mcoeff,coeffindex,env,v64));
8023 #else
8024 	  c=giacmin(c,reducef4buchbergersplits(v,Mindex,Mcoeff,coeffindex,env,v64));
8025 #endif
8026 	}
8027 	else
8028 	  c=giacmin(c,reducef4buchbergersplitu(v,Muindex,Mcoeff,coeffindex,env,v64));
8029 #endif
8030 	// convert v to a sparse vector in SK and update used
8031 	if (freemem){
8032 	  polymod<tdeg_t> clearer; swap(f4buchbergerv[f4buchbergervG[i]].coord,clearer.coord);
8033 	}
8034 #ifdef GIAC_Z
8035 	// zconvert(v,coeffit,bitmap,used); bitmap += (N>>5)+1;
8036 	zconvert_(v,lescoeffs,bitmap,used); bitmap += (N>>5)+1;
8037 #else
8038 	convert(v,SK[i],used);
8039 #endif
8040 	//CERR << v << '\n' << SK[i] << '\n';
8041       }
8042     }
8043 #if 0 // def GIAC_Z
8044     if (debug_infolevel>1) CERR << "Total size for coeffs " << coeffit-lescoeffs.begin() << '\n';
8045     if (freemem){
8046       for (i=0;i<f4buchbergervG.size();++i){
8047 	polymod<tdeg_t> clearer; swap(f4buchbergerv[f4buchbergervG[i]].coord,clearer.coord);
8048       }
8049     }
8050 #endif
8051     Mindex.clear(); Muindex.clear();
8052     if (debug_infolevel>1)
8053       CERR << CLOCK()*1e-6 << " f4buchbergerv split reduced " << f4buchbergervG.size() << " polynoms over " << N << " monomials, start at " << c << '\n';
8054     for (i=0;i<N;++i)
8055       usedcount += (used[i]>0);
8056     if (debug_infolevel>1){
8057       CERR << CLOCK()*1e-6 << " number of non-zero columns " << usedcount << " over " << N << '\n'; // usedcount should be approx N-M.size()=number of cols of M-number of rows
8058       if (debug_infolevel>3)
8059 	CERR << " column split used " << used << '\n';
8060     }
8061     // create dense matrix K
8062 #ifdef GIAC_Z
8063     bitmap=&lebitmap.front();
8064     create_matrix(lescoeffs,bitmap,(N>>5)+1,used,K);
8065     if (freemem){
8066       // clear memory required for lescoeffs
8067       vector<modint> tmp; lescoeffs.swap(tmp);
8068       vector<unsigned> tmp1; lebitmap.swap(tmp1);
8069     }
8070 #else
8071     for (i=0; i<K.size(); ++i){
8072       vector<modint> & v =K[i];
8073       if (SK[i].empty()){
8074 	++zerolines;
8075 	continue;
8076       }
8077       sknon0 += SK[i].size();
8078       v.resize(usedcount);
8079       vector<modint>::iterator vt=v.begin();
8080       vector<used_t>::const_iterator ut=used.begin(),ut0=ut;
8081       vector<sparse_element>::const_iterator st=SK[i].begin(),stend=SK[i].end();
8082       for (j=0;st!=stend;++j,++ut){
8083 	if (!*ut)
8084 	  continue;
8085 	if (j==st->pos){
8086 	  *vt=st->val;
8087 	  ++st;
8088 	}
8089 	++vt;
8090       }
8091 #if 1
8092       vector<sparse_element> clearer;
8093       swap(SK[i],clearer); // clear SK[i] memory
8094 #endif
8095       // CERR << used << '\n' << SK[i] << '\n' << K[i] << '\n';
8096     } // end create dense matrix K
8097 #endif // GIAC_Z
8098     if (debug_infolevel>1)
8099       CERR << CLOCK()*1e-6 << " rref " << K.size() << "x" << usedcount << " non0 " << sknon0 << " ratio " << (sknon0/K.size())/usedcount << " nulllines " << zerolines << '\n';
8100     vecteur pivots; vector<int> maxrankcols; longlong idet;
8101     //CERR << K << '\n';
8102     smallmodrref(1,K,pivots,permutation,maxrankcols,idet,0,int(K.size()),0,usedcount,1/* fullreduction*/,0/*dontswapbelow*/,env,0/* rrefordetorlu*/,true,0,true,-1);
8103     //CERR << K << "," << permutation << '\n';
8104     typename vector< T_unsigned<modint,tdeg_t> >::const_iterator it=R.coord.begin(),itend=R.coord.end();
8105     vector<int> permu=perminv(permutation);
8106     if (debug_infolevel>1)
8107       CERR << CLOCK()*1e-6 << " f4buchbergerv interreduced" << '\n';
8108     for (i=0;i<f4buchbergervG.size();++i){
8109       // CERR << v << '\n';
8110       vector< T_unsigned<modint,tdeg_t> > & Pcoord=f4buchbergerv[f4buchbergervG[i]].coord;
8111       Pcoord.clear();
8112       vector<modint> & v =K[permu[i]];
8113       if (v.empty())
8114 	continue;
8115       unsigned vcount=0;
8116       vector<modint>::const_iterator vt=v.begin(),vtend=v.end();
8117       for (;vt!=vtend;++vt){
8118 	if (*vt)
8119 	  ++vcount;
8120       }
8121       Pcoord.reserve(vcount);
8122       vector<used_t>::const_iterator ut=used.begin();
8123       for (vt=v.begin(),it=R.coord.begin();it!=itend;++ut,++it){
8124 	if (!*ut)
8125 	  continue;
8126 	modint coeff=*vt;
8127 	++vt;
8128 	if (coeff!=0)
8129 	  Pcoord.push_back(T_unsigned<modint,tdeg_t>(coeff,it->u));
8130       }
8131       if (!Pcoord.empty() && Pcoord.front().g!=1){
8132 	smallmultmod(invmod(Pcoord.front().g,env),f4buchbergerv[f4buchbergervG[i]],env);
8133 	Pcoord.front().g=1;
8134       }
8135     }
8136   }
8137 
8138   template<class tdeg_t>
rref_f4buchbergermod_nointerreduce(vectpolymod<tdeg_t> & f4buchbergerv,const vector<unsigned> & f4buchbergervG,vectpolymod<tdeg_t> & res,const vector<unsigned> & G,unsigned excluded,const vectpolymod<tdeg_t> & quo,const polymod<tdeg_t> & R,modint env,vector<int> & permutation)8139   void rref_f4buchbergermod_nointerreduce(vectpolymod<tdeg_t> & f4buchbergerv,const vector<unsigned> & f4buchbergervG,vectpolymod<tdeg_t> & res,const vector<unsigned> & G,unsigned excluded,const vectpolymod<tdeg_t> & quo,const polymod<tdeg_t> & R,modint env,vector<int> & permutation){
8140     unsigned N=unsigned(R.coord.size()),i,j=0;
8141     for (i=0;i<G.size();++i){
8142       if (!quo[i].coord.empty())
8143 	break;
8144     }
8145     if (i==G.size()){
8146       if (debug_infolevel>1)
8147 	CERR << CLOCK()*1e-6 << " No inter-reduction" << '\n';
8148       return;
8149     }
8150     // step2: for each monomials of quo[i], shift res[G[i]] by monomial
8151     // set coefficient in a line of a matrix M, columns are R monomials indices
8152     if (debug_infolevel>1)
8153       CERR << CLOCK()*1e-6 << " begin build M" << '\n';
8154     vector< vector<sparse_element> > M;
8155     M.reserve(N);
8156     vector<sparse_element> atrier;
8157     atrier.reserve(N);
8158     for (i=0;i<G.size();++i){
8159       typename std::vector< T_unsigned<modint,tdeg_t> >::const_iterator jt=quo[i].coord.begin(),jtend=quo[i].coord.end();
8160       for (;jt!=jtend;++j,++jt){
8161 	M.push_back(vector<sparse_element>(0));
8162 	M[j].reserve(res[G[i]].coord.size());
8163 	makeline(res[G[i]],&jt->u,R,M[j]);
8164 	atrier.push_back(sparse_element(M[j].front().pos,j));
8165       }
8166     }
8167     if (debug_infolevel>1)
8168       CERR << CLOCK()*1e-6 << " end build M" << '\n';
8169     // should not sort but compare res[G[i]]*quo[i] monomials to build M already sorted
8170     // CERR << "before sort " << M << '\n';
8171     sort_vector_sparse_element(atrier.begin(),atrier.end()); // sort(atrier.begin(),atrier.end(),tri1);
8172     vector< vector<sparse_element> > M1(atrier.size());
8173     for (i=0;i<atrier.size();++i){
8174       swap(M1[i],M[atrier[i].pos]);
8175     }
8176     swap(M,M1);
8177     // sort(M.begin(),M.end(),tri);
8178     if (debug_infolevel>1)
8179       CERR << CLOCK()*1e-6 << " M sorted, rows " << M.size() << " columns " << N << " #basis to reduce" << f4buchbergervG.size() << '\n';
8180     // CERR << "after sort " << M << '\n';
8181     // step3 reduce
8182     unsigned c=N;
8183     vector<modint> v(N);
8184     typename vector< T_unsigned<modint,tdeg_t> >::const_iterator it=R.coord.begin(),itend=R.coord.end();
8185 #ifdef x86_64
8186     vector<int128_t> v128(N);
8187 #endif
8188     for (i=0;i<f4buchbergervG.size();++i){
8189       if (!f4buchbergerv[f4buchbergervG[i]].coord.empty()){
8190 	makeline(f4buchbergerv[f4buchbergervG[i]],0,R,v);
8191 	// CERR << v << '\n';
8192 #ifdef x86_64
8193 	/* if (N>=4096)
8194 	  c=giacmin(c,reducef4buchberger(v,M,env));
8195 	  else */
8196 	  c=giacmin(c,reducef4buchberger_64(v,M,env,v128));
8197 #else
8198 	c=giacmin(c,reducef4buchberger(v,M,env));
8199 #endif
8200 	vector< T_unsigned<modint,tdeg_t> > & Pcoord=f4buchbergerv[f4buchbergervG[i]].coord;
8201 	Pcoord.clear();
8202 	unsigned vcount=0;
8203 	vector<modint>::const_iterator vt=v.begin(),vtend=v.end();
8204 	for (;vt!=vtend;++vt){
8205 	  if (*vt)
8206 	    ++vcount;
8207 	}
8208 	Pcoord.reserve(vcount);
8209 	for (vt=v.begin(),it=R.coord.begin();it!=itend;++it){
8210 	  modint coeff=*vt;
8211 	  ++vt;
8212 	  if (coeff!=0)
8213 	    Pcoord.push_back(T_unsigned<modint,tdeg_t>(coeff,it->u));
8214 	}
8215 	if (!Pcoord.empty() && Pcoord.front().g!=1){
8216 	  smallmultmod(invmod(Pcoord.front().g,env),f4buchbergerv[f4buchbergervG[i]],env);
8217 	  Pcoord.front().g=1;
8218 	}
8219       }
8220     }
8221   }
8222 
8223   template<class tdeg_t>
rref_f4buchbergermod(vectpolymod<tdeg_t> & f4buchbergerv,vectpolymod<tdeg_t> & res,const vector<unsigned> & G,unsigned excluded,const vectpolymod<tdeg_t> & quo,const polymod<tdeg_t> & R,modint env,vector<int> & permutation,bool split)8224   void rref_f4buchbergermod(vectpolymod<tdeg_t> & f4buchbergerv,vectpolymod<tdeg_t> & res,const vector<unsigned> & G,unsigned excluded,const vectpolymod<tdeg_t> & quo,const polymod<tdeg_t> & R,modint env,vector<int> & permutation,bool split){
8225     vector<unsigned> f4buchbergervG(f4buchbergerv.size());
8226     for (unsigned i=0;i<f4buchbergerv.size();++i)
8227       f4buchbergervG[i]=i;
8228 #if 0
8229     rref_f4buchbergermod(f4buchbergerv,f4buchbergervG,res,G,excluded,quo,R,env,permutation,true);
8230 #else
8231     if (//1
8232 	split
8233 	//0
8234 	)
8235       rref_f4buchbergermodsplit_interreduce(f4buchbergerv,f4buchbergervG,res,G,excluded,quo,R,env,permutation);
8236     else
8237       rref_f4buchbergermod_interreduce(f4buchbergerv,f4buchbergervG,res,G,excluded,quo,R,env,permutation);
8238 #endif
8239   }
8240 
8241   template<class tdeg_t>
8242   struct info_t {
8243     vectpolymod<tdeg_t> quo,quo2;
8244     polymod<tdeg_t> R,R2;
8245     vector<int> permu;
8246     vector< paire > B;
8247     vector<unsigned> G;
8248     unsigned nonzero;
8249   };
8250 
8251   template<class tdeg_t>
reducemodf4buchberger(vectpolymod<tdeg_t> & f4buchbergerv,vectpolymod<tdeg_t> & res,const vector<unsigned> & G,unsigned excluded,modint env,info_t<tdeg_t> & info_tmp)8252   void reducemodf4buchberger(vectpolymod<tdeg_t> & f4buchbergerv,vectpolymod<tdeg_t> & res,const vector<unsigned> & G,unsigned excluded, modint env,info_t<tdeg_t> & info_tmp){
8253     polymod<tdeg_t> allf4buchberger(f4buchbergerv.front().order,f4buchbergerv.front().dim),rem(f4buchbergerv.front().order,f4buchbergerv.front().dim);
8254     if (debug_infolevel>1)
8255       CERR << CLOCK()*1e-6 << " f4buchberger begin collect monomials on #polys " << f4buchbergerv.size() << '\n';
8256     // collect all terms in f4buchbergerv
8257     collect(f4buchbergerv,allf4buchberger);
8258     if (debug_infolevel>1)
8259       CERR << CLOCK()*1e-6 << " f4buchberger symbolic preprocess" << '\n';
8260     // find all monomials required to reduce all polymod<tdeg_t> in f4buchberger with res[G[.]]
8261     symbolic_preprocess(allf4buchberger,res,G,excluded,info_tmp.quo,rem,&info_tmp.R);
8262     if (debug_infolevel>1)
8263       CERR << CLOCK()*1e-6 << " f4buchberger end symbolic preprocess" << '\n';
8264     // build a matrix with first lines res[G[.]]*quo[.] in terms of monomials in S
8265     // and finishing with lines of f4buchbergerv
8266     // rref (below) the matrix and find the last lines in f4buchbergerv
8267     rref_f4buchbergermod(f4buchbergerv,res,G,excluded,info_tmp.quo,info_tmp.R,env,info_tmp.permu,true); // do splitting
8268   }
8269 
8270   // v -= v1, assumes that no overflow can happen (modulo must be 2^30)
sub(vector<modint> & v,const vector<modint> & v1,modint env)8271   void sub(vector<modint> & v,const vector<modint> & v1,modint env){
8272     vector<modint>::const_iterator jt=v1.begin();
8273     vector<modint>::iterator it=v.begin(),itend=v.end();
8274     for (;it!=itend;++jt,++it){
8275       *it -= *jt;
8276       if (*it>-env && *it<env)
8277 	continue;
8278       if (*it>env)
8279 	*it -=env;
8280       else
8281 	*it += env;
8282     }
8283 #if 0
8284     // normalize first element to 1
8285     for (it=v.begin();it!=itend;++it){
8286       if (*it)
8287 	break;
8288     }
8289     if (it!=itend){
8290       modint c=invmod(*it,env);
8291       *it=1;
8292       for (++it;it!=itend;++it){
8293 	if (*it)
8294 	  *it=(longlong(c)*(*it))%env;
8295       }
8296     }
8297 #endif
8298   }
8299 
sub(vector<modint2> & v,const vector<modint2> & v1)8300   void sub(vector<modint2> & v,const vector<modint2> & v1){
8301     vector<modint2>::const_iterator jt=v1.begin();
8302     vector<modint2>::iterator it=v.begin(),itend=v.end();
8303     for (;it!=itend;++jt,++it){
8304       *it -= *jt;
8305     }
8306   }
8307 
sub(vector<double> & v,const vector<modint2> & v1)8308   void sub(vector<double> & v,const vector<modint2> & v1){
8309     vector<modint2>::const_iterator jt=v1.begin();
8310     vector<double>::iterator it=v.begin(),itend=v.end();
8311     for (;it!=itend;++jt,++it){
8312       *it -= *jt;
8313     }
8314   }
8315 
8316   template<class tdeg_t>
f4mod(vectpolymod<tdeg_t> & res,const vector<unsigned> & G,modint env,vector<paire> & B,vectpolymod<tdeg_t> & f4buchbergerv,bool learning,unsigned & learned_position,vector<paire> * pairs_reducing_to_zero,vector<info_t<tdeg_t>> * f4buchberger_info,unsigned & f4buchberger_info_position,bool recomputeR)8317   int f4mod(vectpolymod<tdeg_t> & res,const vector<unsigned> & G,modint env,vector< paire > & B,vectpolymod<tdeg_t> & f4buchbergerv,bool learning,unsigned & learned_position,vector< paire > * pairs_reducing_to_zero,vector< info_t<tdeg_t> >* f4buchberger_info,unsigned & f4buchberger_info_position,bool recomputeR){
8318     if (B.empty())
8319       return 0;
8320     vector<tdeg_t> leftshift(B.size());
8321     vector<tdeg_t> rightshift(B.size());
8322     leftright(res,B,leftshift,rightshift);
8323     f4buchbergerv.resize(B.size());
8324     info_t<tdeg_t> info_tmp;
8325     unsigned nonzero=unsigned(B.size());
8326     info_t<tdeg_t> * info_ptr=&info_tmp;
8327     if (!learning && f4buchberger_info && f4buchberger_info_position<f4buchberger_info->size()){
8328       info_ptr=&(*f4buchberger_info)[f4buchberger_info_position];
8329       ++f4buchberger_info_position;
8330       nonzero=info_ptr->nonzero;
8331     }
8332     else {
8333       polymod<tdeg_t> all(res[B[0].first].order,res[B[0].first].dim),rem;
8334       if (debug_infolevel>1)
8335 	CERR << CLOCK()*1e-6 << " f4buchberger begin collect monomials on #polys " << f4buchbergerv.size() << '\n';
8336       collect(res,B,all,leftshift,rightshift);
8337       if (debug_infolevel>1)
8338 	CERR << CLOCK()*1e-6 << " f4buchberger symbolic preprocess" << '\n';
8339       symbolic_preprocess(all,res,G,-1,info_tmp.quo,rem,&info_tmp.R);
8340       if (debug_infolevel>1)
8341 	CERR << CLOCK()*1e-6 << " end symbolic preprocess, rem size " << rem.coord.size() << '\n';
8342     }
8343     polymod<tdeg_t> & R = info_ptr->R;
8344     vectpolymod<tdeg_t> & quo = info_ptr->quo;
8345 	unsigned N = unsigned(R.coord.size()), i, j = 0;
8346     if (N==0){
8347       if (learning && f4buchberger_info)
8348 	f4buchberger_info->push_back(*info_ptr);
8349       return 1;
8350     }
8351 #if GIAC_SHORTSHIFTTYPE==16
8352     bool useshort=true;
8353 #else
8354     bool useshort=N<=0xffff;
8355 #endif
8356     unsigned nrows=0;
8357     for (i=0;i<G.size();++i){
8358 		nrows += unsigned(quo[i].coord.size());
8359     }
8360     unsigned c=N;
8361     double sknon0=0;
8362     vector<used_t> used(N,0);
8363     unsigned usedcount=0,zerolines=0;
8364     vector< vector<modint> > K(B.size());
8365     vector<vector<unsigned short> > Mindex;
8366     vector<vector<unsigned> > Muindex;
8367     vector< vector<modint> > Mcoeff(G.size());
8368     vector<coeffindex_t> coeffindex;
8369     if (useshort)
8370       Mindex.reserve(nrows);
8371     else
8372       Muindex.reserve(nrows);
8373     coeffindex.reserve(nrows);
8374     vector<sparse_element> atrier;
8375     atrier.reserve(nrows);
8376     for (i=0;i<G.size();++i){
8377       Mcoeff[i].reserve(res[G[i]].coord.size());
8378       typename std::vector< T_unsigned<modint,tdeg_t> >::const_iterator jt=quo[i].coord.begin(),jtend=quo[i].coord.end();
8379       if (useshort){
8380 	for (;jt!=jtend;++j,++jt){
8381 	  Mindex.push_back(vector<unsigned short>(0));
8382 #if GIAC_SHORTSHIFTTYPE==16
8383 	  Mindex[j].reserve(int(1.1*res[G[i]].coord.size()));
8384 #else
8385 	  Mindex[j].reserve(res[G[i]].coord.size());
8386 #endif
8387 	}
8388       }
8389       else {
8390 	for (;jt!=jtend;++j,++jt){
8391 	  Muindex.push_back(vector<unsigned>(0));
8392 	  Muindex[j].reserve(res[G[i]].coord.size());
8393 	}
8394       }
8395     }
8396     for (i=0,j=0;i<G.size();++i){
8397       // copy coeffs of res[G[i]] in Mcoeff
8398       copycoeff(res[G[i]],Mcoeff[i]);
8399       // for each monomial of quo[i], find indexes and put in Mindex
8400       typename std::vector< T_unsigned<modint,tdeg_t> >::const_iterator jt=quo[i].coord.begin(),jtend=quo[i].coord.end();
8401       for (;jt!=jtend;++j,++jt){
8402 	coeffindex.push_back(coeffindex_t(N<=0xffff,i));
8403 	if (useshort){
8404 #if GIAC_SHORTSHIFTTYPE==16
8405 	  makelinesplit(res[G[i]],&jt->u,R,Mindex[j]);
8406 	  if (!coeffindex.back().b)
8407 	    coeffindex.back().b=checkshortshifts(Mindex[j]);
8408 	  atrier.push_back(sparse_element(first_index(Mindex[j]),j));
8409 #else
8410 	  makelinesplits(res[G[i]],&jt->u,R,Mindex[j]);
8411 	  atrier.push_back(sparse_element(Mindex[j].front(),j));
8412 #endif
8413 	}
8414 	else {
8415 	  makelinesplitu(res[G[i]],&jt->u,R,Muindex[j]);
8416 	  atrier.push_back(sparse_element(Muindex[j].front(),j));
8417 	}
8418       }
8419     }
8420     if (debug_infolevel>1)
8421       CERR << CLOCK()*1e-6 << " end build Mindex/Mcoeff f4mod" << '\n';
8422     // should not sort but compare res[G[i]]*quo[i] monomials to build M already sorted
8423     // CERR << "before sort " << M << '\n';
8424     sort_vector_sparse_element(atrier.begin(),atrier.end()); // sort(atrier.begin(),atrier.end(),tri1);
8425     vector<coeffindex_t> coeffindex1(atrier.size());
8426     double mem=0; // mem*4=number of bytes allocated for M1
8427     if (useshort){
8428       vector< vector<unsigned short> > Mindex1(atrier.size());
8429       for (i=0;i<atrier.size();++i){
8430 	swap(Mindex1[i],Mindex[atrier[i].pos]);
8431 	mem += Mindex1[i].size();
8432 	swap(coeffindex1[i],coeffindex[atrier[i].pos]);
8433       }
8434       swap(Mindex,Mindex1);
8435 	  nrows = unsigned(Mindex.size());
8436     }
8437     else {
8438       vector< vector<unsigned> > Muindex1(atrier.size());
8439       for (i=0;i<atrier.size();++i){
8440 	swap(Muindex1[i],Muindex[atrier[i].pos]);
8441 	mem += Muindex1[i].size();
8442 	swap(coeffindex1[i],coeffindex[atrier[i].pos]);
8443       }
8444       swap(Muindex,Muindex1);
8445 	  nrows = unsigned(Muindex.size());
8446     }
8447     swap(coeffindex,coeffindex1);
8448     vector<unsigned> firstpos(atrier.size());
8449     for (i=0;i < atrier.size();++i){
8450       firstpos[i]=atrier[i].val;
8451     }
8452     bool freemem=mem>4e7; // should depend on real memory available
8453     if (debug_infolevel>1)
8454       CERR << CLOCK()*1e-6 << " Mindex sorted, rows " << nrows << " columns " << N << " terms " << mem << " ratio " << (mem/nrows)/N <<'\n';
8455     // CERR << "after sort " << M << '\n';
8456     // step3 reduce
8457     vector<modint> v(N);
8458     vector<modint2> v64(N);
8459 #ifdef x86_64
8460     vector<int128_t> v128(N);
8461 #endif
8462     if (N<nrows){
8463       CERR << "Error " << N << "," << nrows << '\n';
8464       return -1;
8465     }
8466     unsigned Kcols=N-nrows;
8467     vector<unsigned> lebitmap(((N>>5)+1)*B.size());
8468     unsigned * bitmap=&lebitmap.front();
8469     for (i=0;i<B.size();++i){
8470       paire bk=B[i];
8471       if (!learning && pairs_reducing_to_zero && learned_position<pairs_reducing_to_zero->size() && bk==(*pairs_reducing_to_zero)[learned_position]){
8472 	if (debug_infolevel>2)
8473 	  CERR << bk << " f4buchberger learned " << learned_position << '\n';
8474 	++learned_position;
8475 	unsigned tofill=(N>>5)+1;
8476 	fill(bitmap,bitmap+tofill,0);
8477 	bitmap += tofill;
8478 	continue;
8479       }
8480       makeline(res[bk.first],&leftshift[i],R,v,1);
8481       makelinesub(res[bk.second],&rightshift[i],R,v,1,env);
8482       // CERR << v << '\n' << v2 << '\n';
8483       // sub(v,v2,env);
8484       // CERR << v << '\n';
8485 #ifdef x86_64
8486       if (useshort){
8487 	if (env<(1<<24)){
8488 #if GIAC_SHORTSHIFTTYPE==16
8489 	  c=giacmin(c,reducef4buchbergersplit(v,Mindex,firstpos,Mcoeff,coeffindex,env,v64));
8490 #else
8491 	  c=giacmin(c,reducef4buchbergersplits(v,Mindex,Mcoeff,coeffindex,env,v64));
8492 #endif
8493 	}
8494 	else {
8495 #if GIAC_SHORTSHIFTTYPE==16
8496 	  c=giacmin(c,reducef4buchbergersplit64(v,Mindex,firstpos,Mcoeff,coeffindex,env,v128));
8497 #else
8498 	  c=giacmin(c,reducef4buchbergersplit64s(v,Mindex,Mcoeff,coeffindex,env,v128));
8499 #endif
8500 	}
8501       }
8502       else {
8503 	if (env<(1<<24))
8504 	  c=giacmin(c,reducef4buchbergersplitu(v,Muindex,Mcoeff,coeffindex,env,v64));
8505 	else
8506 	  c=giacmin(c,reducef4buchbergersplit64u(v,Muindex,Mcoeff,coeffindex,env,v128));
8507       }
8508 #else // x86_64
8509       if (useshort){
8510 #if GIAC_SHORTSHIFTTYPE==16
8511 	c=giacmin(c,reducef4buchbergersplit(v,Mindex,firstpos,Mcoeff,coeffindex,env,v64));
8512 #else
8513 	c=giacmin(c,reducef4buchbergersplits(v,Mindex,Mcoeff,coeffindex,env,v64));
8514 #endif
8515       }
8516       else
8517 	c=giacmin(c,reducef4buchbergersplitu(v,Muindex,Mcoeff,coeffindex,env,v64));
8518 #endif // x86_64
8519       // zconvert(v,coeffit,bitmap,used); bitmap += (N>>5)+1;
8520       K[i].reserve(Kcols);
8521       zconvert_(v,K[i],bitmap,used); bitmap += (N>>5)+1;
8522       //CERR << v << '\n' << SK[i] << '\n';
8523     } // end for (i=0;i<B.size();++i)
8524     Mindex.clear(); Muindex.clear();
8525     if (debug_infolevel>1)
8526       CERR << CLOCK()*1e-6 << " f4buchbergerv split reduced " << B.size() << " polynoms over " << N << " monomials, start at " << c << '\n';
8527     for (i=0;i<N;++i)
8528       usedcount += (used[i]>0);
8529     if (debug_infolevel>1){
8530       CERR << CLOCK()*1e-6 << " number of non-zero columns " << usedcount << " over " << N << '\n'; // usedcount should be approx N-M.size()=number of cols of M-number of rows
8531       if (debug_infolevel>3)
8532 	CERR << " column split used " << used << '\n';
8533     }
8534     // create dense matrix K
8535     bitmap=&lebitmap.front();
8536     create_matrix(bitmap,(N>>5)+1,used,K);
8537     // clear memory required for lescoeffs
8538     //vector<modint> tmp; lescoeffs.swap(tmp);
8539     { vector<unsigned> tmp1; lebitmap.swap(tmp1); }
8540     if (debug_infolevel>1)
8541       CERR << CLOCK()*1e-6 << " rref " << K.size() << "x" << usedcount << '\n';
8542     vecteur pivots; vector<int> permutation,maxrankcols; longlong idet;
8543     // CERR << K << '\n';
8544     smallmodrref(1,K,pivots,permutation,maxrankcols,idet,0,int(K.size()),0,usedcount,1/* fullreduction*/,0/*dontswapbelow*/,env,0/* rrefordetorlu*/,true,0,true,-1);
8545     //CERR << K << '\n';
8546     unsigned first0 = unsigned(pivots.size());
8547     if (first0<K.size() && (learning || !f4buchberger_info)){
8548       vector<modint> & tmpv=K[first0];
8549       for (i=0;i<tmpv.size();++i){
8550 	if (tmpv[i])
8551 	  break;
8552       }
8553       if (i==tmpv.size()){
8554 	unsigned Ksize = unsigned(K.size());
8555 	K.resize(first0);
8556 	K.resize(Ksize);
8557       }
8558     }
8559     //CERR << permutation << K << '\n';
8560     if (!learning && f4buchberger_info){
8561       // check that permutation is the same as learned permutation
8562       for (unsigned j=0;j<permutation.size();++j){
8563 	if (permutation[j]!=info_ptr->permu[j]){
8564 	  CERR << "learning failed"<<'\n';
8565 	  return -1;
8566 	}
8567       }
8568     }
8569     if (learning)
8570       info_ptr->permu=permutation;
8571     // CERR << K << "," << permutation << '\n';
8572     typename vector< T_unsigned<modint,tdeg_t> >::const_iterator it=R.coord.begin(),itend=R.coord.end();
8573     // vector<int> permu=perminv(permutation);
8574     if (debug_infolevel>1)
8575       CERR << CLOCK()*1e-6 << " f4buchbergerv interreduced" << '\n';
8576     for (i=0;i<f4buchbergerv.size();++i){
8577       // CERR << v << '\n';
8578       vector< T_unsigned<modint,tdeg_t> > & Pcoord=f4buchbergerv[permutation[i]].coord;
8579       Pcoord.clear();
8580       vector<modint> & v =K[i];
8581       if (v.empty()){
8582 	continue;
8583       }
8584       unsigned vcount=0;
8585       vector<modint>::const_iterator vt=v.begin(),vtend=v.end();
8586       for (;vt!=vtend;++vt){
8587 	if (*vt)
8588 	  ++vcount;
8589       }
8590       Pcoord.reserve(vcount);
8591       vector<used_t>::const_iterator ut=used.begin();
8592       for (vt=v.begin(),it=R.coord.begin();it!=itend;++ut,++it){
8593 	if (!*ut)
8594 	  continue;
8595 	modint coeff=*vt;
8596 	++vt;
8597 	if (coeff!=0)
8598 	  Pcoord.push_back(T_unsigned<modint,tdeg_t>(coeff,it->u));
8599       }
8600       if (!Pcoord.empty() && Pcoord.front().g!=1){
8601 	smallmultmod(invmod(Pcoord.front().g,env),f4buchbergerv[permutation[i]],env);
8602 	Pcoord.front().g=1;
8603       }
8604       if (freemem){
8605 	vector<modint> tmp; tmp.swap(v);
8606       }
8607     }
8608     if (learning && f4buchberger_info){
8609 #if 0
8610       f4buchberger_info->push_back(*info_ptr);
8611 #else
8612       info_t<tdeg_t> tmp;
8613       f4buchberger_info->push_back(tmp);
8614       info_t<tdeg_t> & i=f4buchberger_info->back();
8615       swap(i.quo,info_ptr->quo);
8616       swap(i.permu,info_ptr->permu);
8617       swap(i.R.coord,info_ptr->R.coord);
8618       i.R.order=info_ptr->R.order;
8619       i.R.dim=info_ptr->R.dim;
8620 #endif
8621     }
8622     return 1;
8623   }
8624 
8625   template<class tdeg_t>
apply(vector<int> permu,vectpolymod<tdeg_t> & res)8626   bool apply(vector<int> permu,vectpolymod<tdeg_t> & res){
8627     vectpolymod<tdeg_t> tmp;
8628     for (unsigned i=0;i<res.size();++i){
8629       tmp.push_back(polymod<tdeg_t>(res.front().order,res.front().dim));
8630       swap(tmp[i].coord,res[permu[i]].coord);
8631       tmp[i].sugar=res[permu[i]].sugar;
8632     }
8633     swap(tmp,res);
8634     return true;
8635   }
8636 
8637   template<class tdeg_t>
f4mod(vectpolymod<tdeg_t> & res,const vector<unsigned> & G,modint env,vector<paire> & smallposp,vectpolymod<tdeg_t> & f4buchbergerv,bool learning,unsigned & learned_position,vector<paire> * pairs_reducing_to_zero,info_t<tdeg_t> & information,vector<info_t<tdeg_t>> * f4buchberger_info,unsigned & f4buchberger_info_position,bool recomputeR,polymod<tdeg_t> & TMP1,polymod<tdeg_t> & TMP2)8638   int f4mod(vectpolymod<tdeg_t> & res,const vector<unsigned> & G,modint env,vector< paire > & smallposp,vectpolymod<tdeg_t> & f4buchbergerv,bool learning,unsigned & learned_position,vector< paire > * pairs_reducing_to_zero,info_t<tdeg_t> & information,vector< info_t<tdeg_t> >* f4buchberger_info,unsigned & f4buchberger_info_position,bool recomputeR, polymod<tdeg_t> & TMP1,polymod<tdeg_t> & TMP2){
8639     // Improve: we don't really need to compute the s-polys here
8640     // it's sufficient to do that at linalg step
8641     if (debug_infolevel>1)
8642       CERR << CLOCK()*1e-6 << " Computing s-polys " << smallposp.size() << '\n';
8643     if (f4buchbergerv.size()<smallposp.size())
8644       f4buchbergerv.clear();
8645     f4buchbergerv.resize(smallposp.size());
8646     for (unsigned i=0;i<smallposp.size();++i){
8647       f4buchbergerv[i].dim=TMP1.dim; f4buchbergerv[i].order=TMP1.order;
8648       paire bk=smallposp[i];
8649       if (!learning && pairs_reducing_to_zero && f4buchberger_info && learned_position<pairs_reducing_to_zero->size() && bk==(*pairs_reducing_to_zero)[learned_position]){
8650 	if (debug_infolevel>2)
8651 	  CERR << bk << " f4buchberger learned " << learned_position << '\n';
8652 	++learned_position;
8653 	f4buchbergerv[i].coord.clear();
8654 	continue;
8655       }
8656       if (debug_infolevel>2)
8657 	CERR << bk << " f4buchberger not learned " << learned_position << '\n';
8658       if (debug_infolevel>2 && (equalposcomp(G,bk.first)==0 || equalposcomp(G,bk.second)==0))
8659 	CERR << CLOCK()*1e-6 << " mod reducing pair with 1 element not in basis " << bk << '\n';
8660       // polymod<tdeg_t> h(res.front().order,res.front().dim);
8661       spolymod<tdeg_t>(res[bk.first],res[bk.second],TMP1,TMP2,env);
8662       f4buchbergerv[i].coord.swap(TMP1.coord);
8663     }
8664     if (f4buchbergerv.empty())
8665       return 0;
8666     // reduce spolys in f4buchbergerv
8667     if (debug_infolevel>1)
8668       CERR << CLOCK()*1e-6 << " base size " << G.size() << " reduce f4buchberger begin on " << f4buchbergerv.size() << " pairs" << '\n';
8669     if (!learning && f4buchberger_info && f4buchberger_info_position<f4buchberger_info->size()){
8670       info_t<tdeg_t> & info=(*f4buchberger_info)[f4buchberger_info_position];
8671       // apply(perminv(info.permu),f4buchbergerv);
8672       if (recomputeR){
8673 	swap(information.permu,info.permu);
8674 	reducemodf4buchberger(f4buchbergerv,res,G,-1,env,info);
8675 	swap(information.permu,info.permu);
8676       }
8677       else
8678 	rref_f4buchbergermod(f4buchbergerv,res,G,-1,info.quo,info.R,env,information.permu,false); // don't split
8679       // apply(info.permu,f4buchbergerv);
8680       // information.permu should be identity, otherwise the whole learning process failed
8681       for (unsigned j=0;j<information.permu.size();++j){
8682 	if (information.permu[j]!=info.permu[j]){
8683 	  CERR << "learning failed"<<'\n';
8684 	  return -1;
8685 	}
8686       }
8687       ++f4buchberger_info_position;
8688     }
8689     else {
8690       reducemodf4buchberger(f4buchbergerv,res,G,-1,env,information);
8691       if (learning && f4buchberger_info){
8692 #if 0
8693 	f4buchberger_info->push_back(information);
8694 #else
8695 	info_t<tdeg_t> tmp;
8696 	f4buchberger_info->push_back(tmp);
8697 	info_t<tdeg_t> & i=f4buchberger_info->back();
8698 	swap(i.quo,information.quo);
8699 	swap(i.permu,information.permu);
8700 	swap(i.R.coord,information.R.coord);
8701 	i.R.order=information.R.order;
8702 	i.R.dim=information.R.dim;
8703 #endif
8704       }
8705     }
8706     return 1;
8707   }
8708 
8709   template<class tdeg_t>
in_gbasisf4buchbergermod(vectpolymod<tdeg_t> & res,unsigned ressize,vector<unsigned> & G,modint env,bool totdeg,vector<paire> * pairs_reducing_to_zero,vector<info_t<tdeg_t>> * f4buchberger_info,bool recomputeR)8710   bool in_gbasisf4buchbergermod(vectpolymod<tdeg_t> &res,unsigned ressize,vector<unsigned> & G,modint env,bool totdeg,vector< paire > * pairs_reducing_to_zero,vector< info_t<tdeg_t> > * f4buchberger_info,bool recomputeR){
8711     unsigned cleared=0;
8712     unsigned learned_position=0,f4buchberger_info_position=0;
8713     bool sugar=false,learning=pairs_reducing_to_zero && pairs_reducing_to_zero->empty();
8714     if (debug_infolevel>1000)
8715       res.dbgprint(); // instantiate dbgprint()
8716     int capa=512;
8717     if (f4buchberger_info)
8718       capa=int(f4buchberger_info->capacity());
8719     polymod<tdeg_t> TMP1(res.front().order,res.front().dim),TMP2(res.front().order,res.front().dim);
8720     vector< paire > B,BB;
8721     B.reserve(256); BB.reserve(256);
8722     vector<unsigned> smallposv;
8723     smallposv.reserve(256);
8724     info_t<tdeg_t> information;
8725     order_t order=res.front().order;
8726     if (order.o==_PLEX_ORDER) // if (order!=_REVLEX_ORDER && order!=_TDEG_ORDER)
8727       totdeg=false;
8728     vector<unsigned> oldG(G);
8729     for (unsigned l=0;l<ressize;++l){
8730 #ifdef GIAC_REDUCEMODULO
8731       reducesmallmod(res[l],res,G,-1,env,TMP2,env!=0);
8732 #endif
8733       gbasis_updatemod(G,B,res,l,TMP2,env,true,oldG);
8734     }
8735     for (int age=1;!B.empty() && !interrupted && !ctrl_c;++age){
8736       if (age+1>=capa)
8737 	return false; // otherwise reallocation will make pointers invalid
8738       oldG=G;
8739       if (debug_infolevel>1)
8740 	CERR << CLOCK()*1e-6 << " begin new iteration mod, " << env << " number of pairs: " << B.size() << ", base size: " << G.size() << '\n';
8741       if (1){
8742 	// mem clear: remove res[i] if i is not in G nor in B
8743 	vector<bool> clean(G.back()+1,true);
8744 	for (unsigned i=0;i<G.size();++i){
8745 	  clean[G[i]]=false;
8746 	}
8747 	for (unsigned i=0;i<B.size();++i){
8748 	  clean[B[i].first]=false;
8749 	  clean[B[i].second]=false;
8750 	}
8751 	for (unsigned i=0;i<clean.size() && i<res.size();++i){
8752 	  if (clean[i] && res[i].coord.capacity()>1 && !res[i].coord.empty()){
8753 	    cleared += unsigned(res[i].coord.capacity()) - 1;
8754 	    polymod<tdeg_t> clearer;
8755 	    clearer.coord.push_back(res[i].coord.front());
8756 	    clearer.coord.swap(res[i].coord);
8757 	  }
8758 	}
8759       }
8760       // find smallest lcm pair in B
8761       tdeg_t small0,cur;
8762       unsigned smallpos,smalltotdeg=0,curtotdeg=0,smallsugar=0,cursugar=0;
8763       smallposv.clear();
8764       for (smallpos=0;smallpos<B.size();++smallpos){
8765 	if (!res[B[smallpos].first].coord.empty() && !res[B[smallpos].second].coord.empty())
8766 	  break;
8767 #ifdef TIMEOUT
8768 	control_c();
8769 #endif
8770 	if (interrupted || ctrl_c)
8771 	  return false;
8772       }
8773       index_lcm(res[B[smallpos].first].coord.front().u,res[B[smallpos].second].coord.front().u,small0,order);
8774       smallsugar=res[B[smallpos].first].sugar+(small0-res[B[smallpos].first].coord.front().u).total_degree(order);
8775       smalltotdeg=small0.total_degree(order);
8776       smallposv.push_back(smallpos);
8777       for (unsigned i=smallpos+1;i<B.size();++i){
8778 #ifdef TIMEOUT
8779 	control_c();
8780 #endif
8781 	if (interrupted || ctrl_c)
8782 	  return false;
8783 	if (res[B[i].first].coord.empty() || res[B[i].second].coord.empty())
8784 	  continue;
8785 	bool doswap=false;
8786 	index_lcm(res[B[i].first].coord.front().u,res[B[i].second].coord.front().u,cur,order);
8787 	cursugar=res[B[smallpos].first].sugar+(cur-res[B[smallpos].first].coord.front().u).total_degree(order);
8788 	curtotdeg=cur.total_degree(order);
8789 	if ( !totdeg || order.o==_PLEX_ORDER)
8790 	  doswap=tdeg_t_strictly_greater(small0,cur,order);
8791 	else {
8792 	  if (sugar){
8793 	    if (smallsugar!=cursugar)
8794 	      doswap = smallsugar > cursugar;
8795 	  }
8796 	  else {
8797 	    if (smalltotdeg!=curtotdeg)
8798 	      doswap = smalltotdeg > curtotdeg;
8799 	  }
8800 	}
8801 	if (doswap){
8802 	  smallsugar=cursugar;
8803 	  smalltotdeg=curtotdeg;
8804 	  // CERR << "swap mod " << curtotdeg << " " << res[B[i].first].coord.front().u << " " << res[B[i].second].coord.front().u << '\n';
8805 	  swap(small0,cur); // small=cur;
8806 	  smallpos=i;
8807 	  smallposv.clear();
8808 	  smallposv.push_back(i);
8809 	}
8810 	else {
8811 	  if (totdeg && curtotdeg==smalltotdeg && (!sugar || cursugar==smallsugar))
8812 	    smallposv.push_back(i);
8813 	}
8814       }
8815       if (smallposv.size()<=GBASISF4_BUCHBERGER){
8816 	unsigned i=smallposv[0];
8817 	paire bk=B[i];
8818 	B.erase(B.begin()+i);
8819 	if (!learning && pairs_reducing_to_zero && learned_position<pairs_reducing_to_zero->size() && bk==(*pairs_reducing_to_zero)[learned_position]){
8820 	  if (debug_infolevel>2)
8821 	    CERR << bk << " learned " << learned_position << '\n';
8822 	  ++learned_position;
8823 	  continue;
8824 	}
8825 	if (debug_infolevel>2)
8826 	  CERR << bk << " not learned " << learned_position << '\n';
8827 	if (debug_infolevel>2 && (equalposcomp(G,bk.first)==0 || equalposcomp(G,bk.second)==0))
8828 	  CERR << CLOCK()*1e-6 << " mod reducing pair with 1 element not in basis " << bk << '\n';
8829 	// polymod<tdeg_t> h(res.front().order,res.front().dim);
8830 	spolymod<tdeg_t>(res[bk.first],res[bk.second],TMP1,TMP2,env);
8831 	if (debug_infolevel>1){
8832 	  CERR << CLOCK()*1e-6 << " mod reduce begin, pair " << bk << " spoly size " << TMP1.coord.size() << " sugar degree " << TMP1.sugar << " totdeg deg " << TMP1.coord.front().u.total_degree(order) << " degree " << TMP1.coord.front().u << '\n';
8833 	}
8834 #if 0 // def GBASIS_HEAP
8835 	heap_reducemod(TMP1,res,G,-1,information.quo,TMP2,env);
8836 	swap(TMP1.coord,TMP2.coord);
8837 #else
8838 	reducemod(TMP1,res,G,-1,TMP1,env);
8839 #endif
8840 	if (debug_infolevel>1){
8841 	  if (debug_infolevel>3){ CERR << TMP1 << '\n'; }
8842 	  CERR << CLOCK()*1e-6 << " mod reduce end, remainder size " << TMP1.coord.size() << " begin gbasis update" << '\n';
8843 	}
8844 	if (!TMP1.coord.empty()){
8845 	  increase(res);
8846 	  if (ressize==res.size())
8847 	    res.push_back(polymod<tdeg_t>(TMP1.order,TMP1.dim));
8848 	  swap(res[ressize].coord,TMP1.coord);
8849 	  ++ressize;
8850 #if GBASIS_POSTF4BUCHBERGER==0
8851 	  // this does not warrant full interreduced answer
8852 	  // because at the final step we assume that each spoly
8853 	  // is reduced by the previous spolys in res
8854 	  // either by the first reduction or by inter-reduction
8855 	  // here at most GBASISF4_BUCHBERGER spolys may not be reduced by the previous ones
8856 	  // it happens for example for cyclic8, element no 97
8857 	  gbasis_updatemod(G,B,res,ressize-1,TMP2,env,false,oldG);
8858 #else
8859 	  gbasis_updatemod(G,B,res,ressize-1,TMP2,env,true,oldG);
8860 #endif
8861 	  if (debug_infolevel>3)
8862 	    CERR << CLOCK()*1e-6 << " mod basis indexes " << G << " pairs indexes " << B << '\n';
8863 	}
8864 	else {
8865 	  if (learning && pairs_reducing_to_zero){
8866 	    if (debug_infolevel>2)
8867 	      CERR << "learning " << bk << '\n';
8868 	    pairs_reducing_to_zero->push_back(bk);
8869 	  }
8870 	}
8871 	continue;
8872       }
8873       vector< paire > smallposp;
8874       if (smallposv.size()==B.size()){
8875 	swap(smallposp,B);
8876 	B.clear();
8877       }
8878       else {
8879 	for (unsigned i=0;i<smallposv.size();++i)
8880 	  smallposp.push_back(B[smallposv[i]]);
8881 	// remove pairs
8882 	for (int i=int(smallposv.size())-1;i>=0;--i)
8883 	  B.erase(B.begin()+smallposv[i]);
8884       }
8885       vectpolymod<tdeg_t> f4buchbergerv; // collect all spolys
8886       int f4res=-1;
8887       if (1 && env<(1<<30))
8888 	f4res=f4mod(res,G,env,smallposp,f4buchbergerv,learning,learned_position,pairs_reducing_to_zero,f4buchberger_info,f4buchberger_info_position,recomputeR);
8889       else
8890 	f4res=f4mod(res,G,env,smallposp,f4buchbergerv,learning,learned_position,pairs_reducing_to_zero,information,f4buchberger_info,f4buchberger_info_position,recomputeR,TMP1,TMP2);
8891       if (f4res==-1)
8892 	return false;
8893       if (f4res==0)
8894 	continue;
8895       // update gbasis and learning
8896       // requires that Gauss pivoting does the same permutation for other primes
8897       if (learning && pairs_reducing_to_zero){
8898 	for (unsigned i=0;i<f4buchbergerv.size();++i){
8899 	  if (f4buchbergerv[i].coord.empty()){
8900 	    if (debug_infolevel>2)
8901 	      CERR << "learning f4buchberger " << smallposp[i] << '\n';
8902 	    pairs_reducing_to_zero->push_back(smallposp[i]);
8903 	  }
8904 	}
8905       }
8906       unsigned added=0;
8907       for (unsigned i=0;i<f4buchbergerv.size();++i){
8908 	if (!f4buchbergerv[i].coord.empty())
8909 	  ++added;
8910       }
8911       if (debug_infolevel>1)
8912 	CERR << CLOCK()*1e-6 << " reduce f4buchberger end on " << added << " from " << f4buchbergerv.size() << " pairs, gbasis update begin" << '\n';
8913       for (unsigned i=0;i<f4buchbergerv.size();++i){
8914 	if (!f4buchbergerv[i].coord.empty()){
8915 	  increase(res);
8916 	  if (ressize==res.size())
8917 	    res.push_back(polymod<tdeg_t>(TMP1.order,TMP1.dim));
8918 	  swap(res[ressize].coord,f4buchbergerv[i].coord);
8919 	  ++ressize;
8920 #ifdef GBASIS_POSTF4BUCHBERGER
8921 #if GBASIS_POSTF4BUCHBERGER==0
8922 	  if (learning || !f4buchberger_info || f4buchberger_info_position-1>=f4buchberger_info->size())
8923 	    gbasis_updatemod(G,B,res,ressize-1,TMP2,env,false,oldG);
8924 #else
8925 	  gbasis_updatemod(G,B,res,ressize-1,TMP2,env,added<=GBASISF4_BUCHBERGER,oldG);
8926 #endif
8927 #else
8928 	  gbasis_updatemod(G,B,res,ressize-1,TMP2,env,true,oldG);
8929 #endif
8930 	}
8931 	else {
8932 	  // if (!learning && pairs_reducing_to_zero)  CERR << " error learning "<< '\n';
8933 	}
8934       }
8935 #if GBASIS_POSTF4BUCHBERGER==0
8936       if (!learning && f4buchberger_info && f4buchberger_info_position-1<f4buchberger_info->size()){
8937 	B=(*f4buchberger_info)[f4buchberger_info_position-1].B;
8938 	G=(*f4buchberger_info)[f4buchberger_info_position-1].G;
8939 	continue;
8940       }
8941       if (learning && f4buchberger_info){
8942 	f4buchberger_info->back().B=B;
8943 	f4buchberger_info->back().G=G;
8944 	f4buchberger_info->back().nonzero=added;
8945       }
8946 #endif
8947 	  unsigned debut = unsigned(G.size()) - added;
8948 #if GBASIS_POSTF4BUCHBERGER>0
8949       if (added>GBASISF4_BUCHBERGER){
8950 	// final interreduce
8951 	vector<unsigned> G1(G.begin(),G.begin()+debut);
8952 	vector<unsigned> G2(G.begin()+debut,G.end());
8953 	vector<int> permu2;
8954 	if (!learning && f4buchberger_info){
8955 	  const info_t & info=(*f4buchberger_info)[f4buchberger_info_position-1];
8956 	  rref_f4buchbergermod_nointerreduce(res,G1,res,G2,-1,info.quo2,info.R2,env,permu2);
8957 	}
8958 	else {
8959 	  information.R2.order=TMP1.order;
8960 	  information.R2.dim=TMP1.dim;
8961 	  TMP1.coord.clear();
8962 	  if (debug_infolevel>1)
8963 	    CERR << CLOCK()*1e-6 << " collect monomials from old basis" << '\n';
8964 	  collect(res,G1,TMP1); // collect all monomials in res[G[0..debut-1]]
8965 	  // in_heap_reducemod(TMP1,res,G2,-1,info_tmp.quo2,TMP2,&info_tmp.R2,env);
8966 	  in_heap_reducemod(TMP1,res,G2,-1,information.quo2,TMP2,&information.R2,env);
8967 	  rref_f4buchbergermod_nointerreduce(res,G1,res,G2,-1,information.quo2,information.R2,env,permu2);
8968 	  if (f4buchberger_info){
8969 	    info_t & i=f4buchberger_info->back();
8970 	    swap(i.quo2,information.quo2);
8971 	    swap(i.R2.coord,information.R2.coord);
8972 	    i.R2.order=TMP1.order;
8973 	    i.R2.dim=TMP1.dim;
8974 	  }
8975 	}
8976       }
8977 #endif
8978       // CERR << "finish loop G.size "<<G.size() << '\n';
8979       // CERR << added << '\n';
8980     }
8981 #if GBASIS_POSTF4BUCHBERGER==0
8982     // final interreduce step2
8983     for (unsigned j=0; j<G.size();++j){
8984       reducesmallmod(res[G[j]],res,G,j,env,TMP2,true);
8985     }
8986 #endif
8987     if (ressize<res.size())
8988       res.resize(ressize);
8989     if (debug_infolevel>1){
8990       unsigned t=0;
8991       for (unsigned i=0;i<res.size();++i)
8992 	t += unsigned(res[i].coord.size());
8993       CERR << CLOCK()*1e-6 << " total number of monomials in res " << t << '\n';
8994       CERR << "Number of monomials cleared " << cleared << '\n';
8995     }
8996     // sort(res.begin(),res.end(),tripolymod<tdeg_t>);
8997     return true;
8998   }
8999 #endif // GBASISF4_BUCHBERGER
9000 
9001   template<class tdeg_t>
in_gbasisf4buchbergermod(vectpoly8<tdeg_t> & res8,vectpolymod<tdeg_t> & res,vector<unsigned> & G,modint env,bool totdeg,vector<paire> * pairs_reducing_to_zero,vector<info_t<tdeg_t>> * f4buchberger_info,bool recomputeR)9002   bool in_gbasisf4buchbergermod(vectpoly8<tdeg_t> & res8,vectpolymod<tdeg_t> &res,vector<unsigned> & G,modint env,bool totdeg,vector< paire > * pairs_reducing_to_zero,vector< info_t<tdeg_t> > * f4buchberger_info,bool recomputeR){
9003     convert(res8,res,env);
9004     unsigned ressize = unsigned(res8.size());
9005     bool b=in_gbasisf4buchbergermod(res,ressize,G,env,totdeg,pairs_reducing_to_zero,f4buchberger_info,recomputeR);
9006     convert(res,res8,env);
9007     return b;
9008   }
9009 
9010   // set P mod p*q to be chinese remainder of P mod p and Q mod q
9011   template<class tdeg_t>
chinrem(poly8<tdeg_t> & P,const gen & pmod,poly8<tdeg_t> & Q,const gen & qmod,poly8<tdeg_t> & tmp)9012   bool chinrem(poly8<tdeg_t> &P,const gen & pmod,poly8<tdeg_t> & Q,const gen & qmod,poly8<tdeg_t> & tmp){
9013     gen u,v,d,pqmod(pmod*qmod);
9014     egcd(pmod,qmod,u,v,d);
9015     if (u.type==_ZINT && qmod.type==_INT_)
9016       u=modulo(*u._ZINTptr,qmod.val);
9017     if (d==-1){ u=-u; v=-v; d=1; }
9018     if (d!=1)
9019       return false;
9020     int qmodval=0,U=0;
9021     mpz_t tmpz;
9022     mpz_init(tmpz);
9023     if (qmod.type==_INT_ && u.type==_INT_ && pmod.type==_ZINT){
9024       qmodval=qmod.val;
9025       U=u.val;
9026     }
9027     typename vector< T_unsigned<gen,tdeg_t> >::iterator it=P.coord.begin(),itend=P.coord.end(),jt=Q.coord.begin(),jtend=Q.coord.end();
9028     if (P.coord.size()==Q.coord.size()){
9029 #ifndef USE_GMP_REPLACEMENTS
9030       if (qmodval){
9031 	for (;it!=itend;++it,++jt){
9032 	  if (it->u!=jt->u || jt->g.type!=_INT_)
9033 	    break;
9034 	}
9035 	if (it==itend){
9036 	  for (it=P.coord.begin(),jt=Q.coord.begin();it!=itend;++jt,++it){
9037 	    if (it->g.type==_ZINT){
9038 	      mpz_set_si(tmpz,jt->g.val);
9039 	      mpz_sub(tmpz,tmpz,*it->g._ZINTptr);
9040 	      mpz_mul_si(tmpz,*pmod._ZINTptr,(longlong(U)*modulo(tmpz,qmodval))%qmodval);
9041 	      mpz_add(*it->g._ZINTptr,*it->g._ZINTptr,tmpz);
9042 	    }
9043 	    else {
9044 	      mpz_mul_si(tmpz,*pmod._ZINTptr,(U*(longlong(jt->g.val)-it->g.val))%qmodval);
9045 	      if (it->g.val>=0)
9046 		mpz_add_ui(tmpz,tmpz,it->g.val);
9047 	      else
9048 		mpz_sub_ui(tmpz,tmpz,-it->g.val);
9049 	      it->g=tmpz;
9050 	    }
9051 	  }
9052 	  return true;
9053 	}
9054 	else {
9055 	  if (debug_infolevel)
9056 	    CERR << "warning chinrem: exponent mismatch " << it->u << "," << jt->u << '\n';
9057 	}
9058       }
9059 #endif
9060     }
9061     else {
9062       if (debug_infolevel)
9063 	CERR << "warning chinrem: sizes differ " << P.coord.size() << "," << Q.coord.size() << '\n';
9064     }
9065     tmp.coord.clear(); tmp.dim=P.dim; tmp.order=P.order;
9066     tmp.coord.reserve(P.coord.size()+3); // allow 3 more terms in Q without realloc
9067     for (it=P.coord.begin(),jt=Q.coord.begin();it!=itend && jt!=jtend;){
9068       if (it->u==jt->u){
9069 	gen g;
9070 #ifndef USE_GMP_REPLACEMENTS
9071 	if (qmodval && jt->g.type==_INT_){
9072 	  if (it->g.type==_ZINT){
9073 	    mpz_set_si(tmpz,jt->g.val);
9074 	    mpz_sub(tmpz,tmpz,*it->g._ZINTptr);
9075 	    mpz_mul_si(tmpz,*pmod._ZINTptr,(longlong(U)*modulo(tmpz,qmodval))%qmodval);
9076 	    mpz_add(tmpz,tmpz,*it->g._ZINTptr);
9077 	  }
9078 	  else {
9079 	    mpz_mul_si(tmpz,*pmod._ZINTptr,(U*(longlong(jt->g.val)-it->g.val))%qmodval);
9080 	    if (it->g.val>=0)
9081 	      mpz_add_ui(tmpz,tmpz,it->g.val);
9082 	    else
9083 	      mpz_sub_ui(tmpz,tmpz,-it->g.val);
9084 	  }
9085 	  g=tmpz;
9086 	}
9087 	else
9088 #endif
9089 	  g=it->g+u*(jt->g-it->g)*pmod;
9090 	tmp.coord.push_back(T_unsigned<gen,tdeg_t>(smod(g,pqmod),it->u));
9091 	++it; ++jt;
9092 	continue;
9093       }
9094       if (tdeg_t_strictly_greater(it->u,jt->u,P.order)){
9095 	if (debug_infolevel)
9096 	  CERR << "chinrem: exponent mismatch using first " << '\n';
9097 	gen g=it->g-u*(it->g)*pmod;
9098 	tmp.coord.push_back(T_unsigned<gen,tdeg_t>(smod(g,pqmod),it->u));
9099 	++it;
9100       }
9101       else {
9102 	if (debug_infolevel)
9103 	  CERR << "chinrem: exponent mismatch using second " << '\n';
9104 	gen g=u*(jt->g)*pmod;
9105 	tmp.coord.push_back(T_unsigned<gen,tdeg_t>(smod(g,pqmod),jt->u));
9106 	++jt;
9107       }
9108     }
9109     if (it!=itend && debug_infolevel)
9110       CERR << "chinrem (gen): exponent mismatch at end using first, # " << itend-it << '\n';
9111     for (;it!=itend;++it){
9112       gen g=it->g-u*(it->g)*pmod;
9113       tmp.coord.push_back(T_unsigned<gen,tdeg_t>(smod(g,pqmod),it->u));
9114     }
9115     if (jt!=jtend && debug_infolevel)
9116       CERR << "chinrem (gen): exponent mismatch at end using second " << jtend-jt << '\n';
9117     for (;jt!=jtend;++jt){
9118       gen g=u*(jt->g)*pmod;
9119       tmp.coord.push_back(T_unsigned<gen,tdeg_t>(smod(g,pqmod),jt->u));
9120     }
9121     swap(P.coord,tmp.coord);
9122     mpz_clear(tmpz);
9123     return true;
9124   }
9125 
9126   // set P mod p*q to be chinese remainder of P mod p and Q mod q
9127   // P and Q must have same leading monomials,
9128   // otherwise returns 0 and leaves P unchanged
9129   template<class tdeg_t>
chinrem(vectpoly8<tdeg_t> & P,const gen & pmod,vectpoly8<tdeg_t> & Q,const gen & qmod,poly8<tdeg_t> & tmp)9130   int chinrem(vectpoly8<tdeg_t> &P,const gen & pmod,vectpoly8<tdeg_t> & Q,const gen & qmod,poly8<tdeg_t> & tmp){
9131     if (P.size()!=Q.size())
9132       return 0;
9133     for (unsigned i=0;i<P.size();++i){
9134       if (P[i].coord.front().u!=Q[i].coord.front().u)
9135 	return 0;
9136     }
9137     // LP(P)==LP(Q), proceed to chinese remaindering
9138     for (unsigned i=0;i<P.size();++i){
9139       if (!chinrem(P[i],pmod,Q[i],qmod,tmp))
9140 	return -1;
9141     }
9142     return 1;
9143   }
9144 
9145 
9146   // set P mod p*q to be chinese remainder of P mod p and Q mod q
9147   template<class tdeg_t>
chinrem(poly8<tdeg_t> & P,const gen & pmod,const polymod<tdeg_t> & Q,int qmodval,poly8<tdeg_t> & tmp)9148   bool chinrem(poly8<tdeg_t> &P,const gen & pmod,const polymod<tdeg_t> & Q,int qmodval,poly8<tdeg_t> & tmp){
9149     gen u,v,d,pqmod(qmodval*pmod);
9150     egcd(pmod,qmodval,u,v,d);
9151     if (u.type==_ZINT)
9152       u=modulo(*u._ZINTptr,qmodval);
9153     if (d==-1){ u=-u; v=-v; d=1; }
9154     if (d!=1)
9155       return false;
9156     int U=u.val;
9157     mpz_t tmpz;
9158     mpz_init(tmpz);
9159     typename vector< T_unsigned<gen,tdeg_t> >::iterator it=P.coord.begin(),itend=P.coord.end();
9160     typename vector< T_unsigned<modint,tdeg_t> >::const_iterator jt=Q.coord.begin(),jtend=Q.coord.end();
9161 #ifndef USE_GMP_REPLACEMENTS
9162     if (P.coord.size()==Q.coord.size()){
9163       for (;it!=itend;++it,++jt){
9164 	if (it->u!=jt->u)
9165 	  break;
9166       }
9167       if (it==itend){
9168 	for (it=P.coord.begin(),jt=Q.coord.begin();it!=itend;++jt,++it){
9169 	  if (pmod.type!=_ZINT){
9170 	    it->g=it->g+u*(jt->g-it->g)*pmod;
9171 	    continue;
9172 	  }
9173 	  if (it->g.type==_ZINT){
9174 #if 1
9175 	    int amodq=modulo(*it->g._ZINTptr,qmodval);
9176 	    if (amodq==jt->g)
9177 	      continue;
9178 	    mpz_mul_si(tmpz,*pmod._ZINTptr,(U*(jt->g-longlong(amodq)))%qmodval);
9179 	    mpz_add(*it->g._ZINTptr,*it->g._ZINTptr,tmpz);
9180 #else
9181 	    mpz_set_si(tmpz,jt->g);
9182 	    mpz_sub(tmpz,tmpz,*it->g._ZINTptr);
9183 	    mpz_mul_si(tmpz,*pmod._ZINTptr,(longlong(U)*modulo(tmpz,qmodval))%qmodval);
9184 	    mpz_add(*it->g._ZINTptr,*it->g._ZINTptr,tmpz);
9185 #endif
9186 	  }
9187 	  else {
9188 	    mpz_mul_si(tmpz,*pmod._ZINTptr,(U*(longlong(jt->g)-it->g.val))%qmodval);
9189 	    if (it->g.val>=0)
9190 	      mpz_add_ui(tmpz,tmpz,it->g.val);
9191 	    else
9192 	      mpz_sub_ui(tmpz,tmpz,-it->g.val);
9193 	    it->g=tmpz;
9194 	  }
9195 	}
9196 	mpz_clear(tmpz);
9197 	return true;
9198       }
9199     }
9200 #endif
9201     tmp.coord.clear(); tmp.dim=P.dim; tmp.order=P.order;
9202     tmp.coord.reserve(P.coord.size()+3); // allow 3 more terms in Q without realloc
9203     for (it=P.coord.begin(),jt=Q.coord.begin();it!=itend && jt!=jtend;){
9204       if (it->u==jt->u){
9205 	gen g;
9206 #ifndef USE_GMP_REPLACEMENTS
9207 	if (pmod.type==_ZINT){
9208 	  if (it->g.type==_ZINT){
9209 	    mpz_set_si(tmpz,jt->g);
9210 	    mpz_sub(tmpz,tmpz,*it->g._ZINTptr);
9211 	    mpz_mul_si(tmpz,*pmod._ZINTptr,(longlong(U)*modulo(tmpz,qmodval))%qmodval);
9212 	    mpz_add(tmpz,tmpz,*it->g._ZINTptr);
9213 	  }
9214 	  else {
9215 	    mpz_mul_si(tmpz,*pmod._ZINTptr,(U*(longlong(jt->g)-it->g.val))%qmodval);
9216 	    if (it->g.val>=0)
9217 	      mpz_add_ui(tmpz,tmpz,it->g.val);
9218 	    else
9219 	      mpz_sub_ui(tmpz,tmpz,-it->g.val);
9220 	  }
9221 	  g=tmpz;
9222 	}
9223 	else
9224 #endif
9225 	  g=it->g+u*(jt->g-it->g)*pmod;
9226 	tmp.coord.push_back(T_unsigned<gen,tdeg_t>(smod(g,pqmod),it->u));
9227 	++it; ++jt;
9228 	continue;
9229       }
9230       if (tdeg_t_strictly_greater(it->u,jt->u,P.order)){
9231 	if (debug_infolevel)
9232 	  CERR << "chinrem: exponent mismatch using first " << '\n';
9233 	gen g=it->g-u*(it->g)*pmod;
9234 	tmp.coord.push_back(T_unsigned<gen,tdeg_t>(smod(g,pqmod),it->u));
9235 	++it;
9236       }
9237       else {
9238 	if (debug_infolevel)
9239 	  CERR << "chinrem: exponent mismatch using second " << '\n';
9240 	gen g=u*((jt->g)*pmod);
9241 	tmp.coord.push_back(T_unsigned<gen,tdeg_t>(smod(g,pqmod),jt->u));
9242 	++jt;
9243       }
9244     }
9245     if (it!=itend && debug_infolevel)
9246       CERR << "chinrem (int): exponent mismatch at end using first #" << itend-it << '\n';
9247     for (;it!=itend;++it){
9248       gen g=it->g-u*(it->g)*pmod;
9249       tmp.coord.push_back(T_unsigned<gen,tdeg_t>(smod(g,pqmod),it->u));
9250     }
9251     if (jt!=jtend && debug_infolevel)
9252       CERR << "chinrem (int): exponent mismatch at end using second #" << jtend-jt << '\n';
9253     for (;jt!=jtend;++jt){
9254       gen g=u*((jt->g)*pmod);
9255       tmp.coord.push_back(T_unsigned<gen,tdeg_t>(smod(g,pqmod),jt->u));
9256     }
9257     swap(P.coord,tmp.coord);
9258     mpz_clear(tmpz);
9259     return true;
9260   }
9261 
9262   // set P mod p*q to be chinese remainder of P mod p and Q mod q
9263   // P and Q must have same leading monomials,
9264   // otherwise returns 0 and leaves P unchanged
9265   template<class tdeg_t>
chinrem(vectpoly8<tdeg_t> & P,const gen & pmod,const vectpolymod<tdeg_t> & Q,int qmod,poly8<tdeg_t> & tmp,int start=0)9266   int chinrem(vectpoly8<tdeg_t> &P,const gen & pmod,const vectpolymod<tdeg_t> & Q,int qmod,poly8<tdeg_t> & tmp,int start=0){
9267     if (P.size()!=Q.size())
9268       return 0;
9269     for (unsigned i=start;i<P.size();++i){
9270       if (P[i].coord.empty() && Q[i].coord.empty())
9271 	continue;
9272       if (P[i].coord.empty())
9273 	return 0;
9274       if (Q[i].coord.empty())
9275 	return 0;
9276       if (P[i].coord.front().u!=Q[i].coord.front().u)
9277 	return 0;
9278     }
9279     // LP(P)==LP(Q), proceed to chinese remaindering
9280     for (unsigned i=start;i<P.size();++i){
9281       if (!chinrem(P[i],pmod,Q[i],qmod,tmp))
9282 	return -1;
9283     }
9284     return 1;
9285   }
9286 
9287   // a mod b = r/u with n and d<sqrt(b)/2
9288   // a*u = r mod b -> a*u+b*v=r, Bezout with a and b
fracmod(int a,int b,int & n,int & d)9289   bool fracmod(int a,int b,int & n,int & d){
9290     if (a<0){
9291       if (!fracmod(-a,b,n,d))
9292 	return false;
9293       n=-n;
9294       return true;
9295     }
9296     int r=b,u=0; // v=1
9297     int r1=a,u1=1,r2,u2,q; // v1=0
9298     for (;double(2*r1)*r1>b;){
9299       q=r/r1;
9300       u2=u-q*u1;
9301       r2=r-q*r1;
9302       u=u1;
9303       u1=u2;
9304       r=r1;
9305       r1=r2;
9306     }
9307     if (double(2*u1)*u1>b)
9308       return false;
9309     if (u1<0){ u1=-u1; r1=-r1; }
9310     n=r1; d=u1;
9311     return true;
9312   }
9313 
9314   // search for d such that d*P mod p has small coefficients
9315   // call with d set to 1,
9316   template<class tdeg_t>
findmultmod(const poly8<tdeg_t> & P,int p,int & d)9317   bool findmultmod(const poly8<tdeg_t> & P,int p,int & d){
9318     int n,s=int(P.coord.size());
9319     for (int i=0;i<s;++i){
9320       int a=smod(longlong(P.coord[i].g.val)*d,p);
9321       if (double(2*a)*a<p)
9322 	continue;
9323       int d1=1;
9324       if (!fracmod(a,p,n,d1) || double(2*d1)*d1>p){
9325 	if (debug_infolevel)
9326 	  COUT << "findmultmod failure " << a << " mod " << p << '\n';
9327 	return false;
9328       }
9329       d=d*d1;
9330     }
9331     if (debug_infolevel){
9332       for (int i=0;i<s;++i){
9333 	int a=smod(longlong(P.coord[i].g.val)*d,p);
9334 	if (double(2*a)*a>=p){
9335 	  COUT << "possible findmultmod failure " << P.coord[i].g.val << " " << d << " " << a << " " << p << '\n';
9336 	  //return false;
9337 	}
9338       }
9339     }
9340     return true;
9341   }
9342 
9343   template<class tdeg_t>
fracmod(const poly8<tdeg_t> & P,const gen & p,mpz_t & d,mpz_t & d1,mpz_t & absd1,mpz_t & u,mpz_t & u1,mpz_t & ur,mpz_t & q,mpz_t & r,mpz_t & sqrtm,mpz_t & tmp,poly8<tdeg_t> & Q)9344   bool fracmod(const poly8<tdeg_t> &P,const gen & p,
9345 	       mpz_t & d,mpz_t & d1,mpz_t & absd1,mpz_t &u,mpz_t & u1,mpz_t & ur,mpz_t & q,mpz_t & r,mpz_t &sqrtm,mpz_t & tmp,
9346 	       poly8<tdeg_t> & Q){
9347     Q.coord.clear();
9348     Q.coord.reserve(P.coord.size());
9349     Q.dim=P.dim;
9350     Q.order=P.order;
9351     Q.sugar=P.sugar;
9352     gen L=1;
9353     bool tryL=true;
9354     for (unsigned i=0;i<P.coord.size();++i){
9355       gen g=P.coord[i].g,num,den;
9356       if (g.type==_INT_)
9357 	g.uncoerce();
9358       if ( (g.type!=_ZINT) || (p.type!=_ZINT) ){
9359 	CERR << "bad type"<<'\n';
9360 	return false;
9361       }
9362       if (tryL && L.type==_ZINT){
9363 	num=smod(L*g,p);
9364 	if (is_greater(p,4*num*num,context0)){
9365 	  g=fraction(num,L);
9366 	  Q.coord.push_back(T_unsigned<gen,tdeg_t>(g,P.coord[i].u));
9367 	  continue;
9368 	}
9369       }
9370       if (!in_fracmod(p,g,d,d1,absd1,u,u1,ur,q,r,sqrtm,tmp,num,den))
9371 	return false;
9372       if (num.type==_ZINT && mpz_sizeinbase(*num._ZINTptr,2)<=30)
9373 	num=int(mpz_get_si(*num._ZINTptr));
9374       if (den.type==_ZINT && mpz_sizeinbase(*den._ZINTptr,2)<=30)
9375 	den=int(mpz_get_si(*den._ZINTptr));
9376       if (!is_positive(den,context0)){ // ok
9377 	den=-den;
9378 	num=-num;
9379       }
9380       g=fraction(num,den);
9381       if (tryL){
9382 	L=lcm(L,den);
9383 	tryL=is_greater(p,L*L,context0);
9384       }
9385       Q.coord.push_back(T_unsigned<gen,tdeg_t>(g,P.coord[i].u));
9386     }
9387     return true;
9388   }
9389 
9390   template<class tdeg_t>
fracmod(const vectpoly8<tdeg_t> & P,const gen & p_,mpz_t & d,mpz_t & d1,mpz_t & absd1,mpz_t & u,mpz_t & u1,mpz_t & ur,mpz_t & q,mpz_t & r,mpz_t & sqrtm,mpz_t & tmp,vectpoly8<tdeg_t> & Q)9391   bool fracmod(const vectpoly8<tdeg_t> & P,const gen & p_,
9392 		      mpz_t & d,mpz_t & d1,mpz_t & absd1,mpz_t &u,mpz_t & u1,mpz_t & ur,mpz_t & q,mpz_t & r,mpz_t &sqrtm,mpz_t & tmp,
9393 		      vectpoly8<tdeg_t> & Q){
9394     Q.resize(P.size());
9395     gen p=p_;
9396     if (p.type==_INT_)
9397       p.uncoerce();
9398     bool ok=true;
9399     for (unsigned i=0;i<P.size();++i){
9400       if (!fracmod(P[i],p,d,d1,absd1,u,u1,ur,q,r,sqrtm,tmp,Q[i])){
9401 	ok=false;
9402 	break;
9403       }
9404     }
9405     return ok;
9406   }
9407 
9408   template <class tdeg_t>
cleardeno(poly8<tdeg_t> & P)9409   void cleardeno(poly8<tdeg_t> &P){
9410     gen g=1;
9411     for (unsigned i=0;i<P.coord.size();++i){
9412       if (P.coord[i].g.type==_FRAC)
9413 	g=lcm(g,P.coord[i].g._FRACptr->den);
9414     }
9415     if (g!=1){
9416       for (unsigned i=0;i<P.coord.size();++i){
9417 	P.coord[i].g=g*P.coord[i].g;
9418       }
9419     }
9420   }
9421 
9422   template<class tdeg_t>
cleardeno(vectpoly8<tdeg_t> & P)9423   void cleardeno(vectpoly8<tdeg_t> & P){
9424     for (unsigned i=0;i<P.size();++i){
9425       cleardeno(P[i]);
9426       if (debug_infolevel){
9427 	if (i%10==9){
9428 	  COUT << "+";
9429 	  COUT.flush();
9430 	}
9431 	if (i%500==499)
9432 	  COUT << " " << CLOCK()*1e-6 << " remaining " << P.size()-i << '\n';
9433       }
9434     }
9435   }
9436 
9437 
9438   template<class tdeg_t>
collect(const vectpoly8<tdeg_t> & f4buchbergerv,polymod<tdeg_t> & allf4buchberger)9439   void collect(const vectpoly8<tdeg_t> & f4buchbergerv,polymod<tdeg_t> & allf4buchberger){
9440     typename vectpoly8<tdeg_t>::const_iterator it=f4buchbergerv.begin(),itend=f4buchbergerv.end();
9441     vector<heap_tt<tdeg_t> > H;
9442     H.reserve(itend-it);
9443     order_t keyorder={_REVLEX_ORDER,0};
9444     for (unsigned i=0;it!=itend;++i,++it){
9445       keyorder=it->order;
9446       if (!it->coord.empty())
9447 	H.push_back(heap_tt<tdeg_t>(i,0,it->coord.front().u));
9448     }
9449     compare_heap_tt<tdeg_t> key(keyorder);
9450     make_heap(H.begin(),H.end(),key);
9451     while (!H.empty()){
9452       std::pop_heap(H.begin(),H.end(),key);
9453       // push root node of the heap in allf4buchberger
9454       heap_tt<tdeg_t> & current =H.back();
9455       if (allf4buchberger.coord.empty() || allf4buchberger.coord.back().u!=current.u)
9456 	allf4buchberger.coord.push_back(T_unsigned<modint,tdeg_t>(1,current.u));
9457       ++current.polymodpos;
9458       if (current.polymodpos>=f4buchbergerv[current.f4buchbergervpos].coord.size()){
9459 	H.pop_back();
9460 	continue;
9461       }
9462       current.u=f4buchbergerv[current.f4buchbergervpos].coord[current.polymodpos].u;
9463       std::push_heap(H.begin(),H.end(),key);
9464     }
9465   }
9466 
9467   template<class tdeg_t>
makeline(const poly8<tdeg_t> & p,const tdeg_t * shiftptr,const polymod<tdeg_t> & R,vecteur & v)9468   void makeline(const poly8<tdeg_t> & p,const tdeg_t * shiftptr,const polymod<tdeg_t> & R,vecteur & v){
9469     v=vecteur(R.coord.size(),0);
9470     typename std::vector< T_unsigned<gen,tdeg_t> >::const_iterator it=p.coord.begin(),itend=p.coord.end();
9471     typename std::vector< T_unsigned<modint,tdeg_t> >::const_iterator jt=R.coord.begin(),jtbeg=jt,jtend=R.coord.end();
9472     if (shiftptr){
9473       for (;it!=itend;++it){
9474 	tdeg_t u=it->u+*shiftptr;
9475 	for (;jt!=jtend;++jt){
9476 	  if (jt->u==u){
9477 	    v[jt-jtbeg]=it->g;
9478 	    ++jt;
9479 	    break;
9480 	  }
9481 	}
9482       }
9483     }
9484     else {
9485       for (;it!=itend;++it){
9486 	const tdeg_t & u=it->u;
9487 	for (;jt!=jtend;++jt){
9488 	  if (jt->u==u){
9489 	    v[jt-jtbeg]=it->g;
9490 	    ++jt;
9491 	    break;
9492 	  }
9493 	}
9494       }
9495     }
9496   }
9497 
firstnonzero(const vecteur & v)9498   unsigned firstnonzero(const vecteur & v){
9499     for (unsigned i=0;i<v.size();++i){
9500       if (v[i]!=0)
9501 	return i;
9502     }
9503     return unsigned(v.size());
9504   }
9505 
9506   struct sparse_gen {
9507     gen val;
9508     unsigned pos;
sparse_gengiac::sparse_gen9509     sparse_gen(const gen & v,unsigned u):val(v),pos(u){};
sparse_gengiac::sparse_gen9510     sparse_gen():val(0),pos(-1){};
9511   };
9512 
9513   template<class tdeg_t>
makeline(const poly8<tdeg_t> & p,const tdeg_t * shiftptr,const polymod<tdeg_t> & R,vector<sparse_gen> & v)9514   void makeline(const poly8<tdeg_t> & p,const tdeg_t * shiftptr,const polymod<tdeg_t> & R,vector<sparse_gen> & v){
9515     typename std::vector< T_unsigned<gen,tdeg_t> >::const_iterator it=p.coord.begin(),itend=p.coord.end();
9516     typename std::vector< T_unsigned<modint,tdeg_t> >::const_iterator jt=R.coord.begin(),jtend=R.coord.end();
9517     if (shiftptr){
9518       for (;it!=itend;++it){
9519 	tdeg_t u=it->u+*shiftptr;
9520 	for (;jt!=jtend;++jt){
9521 	  if (jt->u==u){
9522 	    v.push_back(sparse_gen(it->g,int(jt-R.coord.begin())));
9523 	    ++jt;
9524 	    break;
9525 	  }
9526 	}
9527       }
9528     }
9529     else {
9530       for (;it!=itend;++it){
9531 	const tdeg_t & u=it->u;
9532 	for (;jt!=jtend;++jt){
9533 	  if (jt->u==u){
9534 	    v.push_back(sparse_gen(it->g,int(jt-R.coord.begin())));
9535 	    ++jt;
9536 	    break;
9537 	  }
9538 	}
9539       }
9540     }
9541   }
9542 
9543 #ifdef x86_64
checkreducef4buchberger_64(vector<modint> & v,vector<modint> & coeff,const vector<vector<sparse_element>> & M,modint env,vector<int128_t> & w)9544   bool checkreducef4buchberger_64(vector<modint> &v,vector<modint> & coeff,const vector< vector<sparse_element> > & M,modint env,vector<int128_t> & w){
9545     w.resize(v.size());
9546     vector<modint>::iterator vt=v.begin(),vtend=v.end();
9547     vector<int128_t>::iterator wt=w.begin();
9548     for (;vt!=vtend;++wt,++vt){
9549       *wt=*vt;
9550     }
9551     for (unsigned i=0;i<M.size();++i){
9552       const vector<sparse_element> & m=M[i];
9553       const sparse_element * it=&m.front(),*itend=it+m.size(),*it2;
9554       if (it==itend)
9555 	continue;
9556       int128_t & ww=w[it->pos];
9557       if (ww==0){
9558 	coeff[i]=0;
9559 	continue;
9560       }
9561       modint c=coeff[i]=(modint2(invmod(it->val,env))*ww)%env;
9562       // CERR << "multiplier ok line " << i << " value " << c << " " << w << '\n';
9563       if (!c)
9564 	continue;
9565       ww=0;
9566       ++it;
9567       it2=itend-8;
9568       for (;it<=it2;){
9569 	w[it->pos] -= modint2(c)*(it->val);
9570 	++it;
9571 	w[it->pos] -= modint2(c)*(it->val);
9572 	++it;
9573 	w[it->pos] -= modint2(c)*(it->val);
9574 	++it;
9575 	w[it->pos] -= modint2(c)*(it->val);
9576 	++it;
9577 	w[it->pos] -= modint2(c)*(it->val);
9578 	++it;
9579 	w[it->pos] -= modint2(c)*(it->val);
9580 	++it;
9581 	w[it->pos] -= modint2(c)*(it->val);
9582 	++it;
9583 	w[it->pos] -= modint2(c)*(it->val);
9584 	++it;
9585       }
9586       for (;it!=itend;++it){
9587 	w[it->pos] -= modint2(c)*(it->val);
9588       }
9589     }
9590     for (vt=v.begin(),wt=w.begin();vt!=vtend;++wt,++vt){
9591       if (*wt && (*wt % env))
9592 	return false;
9593     }
9594     return true;
9595   }
9596 
checkreducef4buchbergersplit_64(vector<modint> & v,vector<modint> & coeff,const vector<vector<shifttype>> & M,vector<vector<modint>> & coeffs,vector<coeffindex_t> & coeffindex,modint env,vector<int128_t> & w)9597   bool checkreducef4buchbergersplit_64(vector<modint> &v,vector<modint> & coeff,const vector< vector<shifttype> > & M,vector<vector<modint> > & coeffs,vector<coeffindex_t> & coeffindex,modint env,vector<int128_t> & w){
9598     w.resize(v.size());
9599     vector<modint>::iterator vt=v.begin(),vtend=v.end();
9600     vector<int128_t>::iterator wt=w.begin(),wtend=w.end();
9601     for (;vt!=vtend;++wt,++vt){
9602       *wt=*vt;
9603     }
9604     for (unsigned i=0;i<M.size();++i){
9605       const vector<modint> & mcoeff=coeffs[coeffindex[i].u];
9606       vector<modint>::const_iterator jt=mcoeff.begin(),jtend=mcoeff.end();
9607       if (jt==jtend)
9608 	continue;
9609       const vector<shifttype> & mindex=M[i];
9610       const shifttype * it=&mindex.front();
9611       unsigned pos=0;
9612       next_index(pos,it);
9613       // if (pos>v.size()) CERR << "error" <<'\n';
9614       modint c=coeff[i]=(modint2(invmod(*jt,env))*w[pos])%env;
9615       w[pos]=0;
9616       if (!c)
9617 	continue;
9618       for (++jt;jt!=jtend;++jt){
9619 #ifdef GIAC_SHORTSHIFTTYPE
9620 	next_index(pos,it);
9621 	int128_t &x=w[pos];
9622 	x -= modint2(c)*(*jt);
9623 #else
9624 	w[*it] -= modint2(c)*(*jt);
9625 	++it;
9626 #endif
9627       }
9628     }
9629     for (wt=w.begin();wt!=wtend;++wt){
9630       if (*wt % env)
9631 	return false;
9632     }
9633     return true;
9634   }
9635 
9636 #endif
9637 
9638   // return true if v reduces to 0
9639   // in addition to reducef4buchberger, compute the coeffs
checkreducef4buchberger(vector<modint> & v,vector<modint> & coeff,const vector<vector<sparse_element>> & M,modint env)9640   bool checkreducef4buchberger(vector<modint> &v,vector<modint> & coeff,const vector< vector<sparse_element> > & M,modint env){
9641     for (unsigned i=0;i<M.size();++i){
9642       const vector<sparse_element> & m=M[i];
9643       vector<sparse_element>::const_iterator it=m.begin(),itend=m.end(),it1=itend-8;
9644       if (it==itend)
9645 	continue;
9646       modint c=coeff[i]=v[it->pos];
9647       if (!c)
9648 	continue;
9649       c=coeff[i]=(modint2(invmod(it->val,env))*c)%env;
9650       v[it->pos]=0;
9651       for (++it;it<it1;){
9652 	modint *x=&v[it->pos];
9653 	*x=(*x-modint2(c)*(it->val))%env;
9654 	++it;
9655 	x=&v[it->pos];
9656 	*x=(*x-modint2(c)*(it->val))%env;
9657 	++it;
9658 	x=&v[it->pos];
9659 	*x=(*x-modint2(c)*(it->val))%env;
9660 	++it;
9661 	x=&v[it->pos];
9662 	*x=(*x-modint2(c)*(it->val))%env;
9663 	++it;
9664 	x=&v[it->pos];
9665 	*x=(*x-modint2(c)*(it->val))%env;
9666 	++it;
9667 	x=&v[it->pos];
9668 	*x=(*x-modint2(c)*(it->val))%env;
9669 	++it;
9670 	x=&v[it->pos];
9671 	*x=(*x-modint2(c)*(it->val))%env;
9672 	++it;
9673 	x=&v[it->pos];
9674 	*x=(*x-modint2(c)*(it->val))%env;
9675 	++it;
9676       }
9677       for (;it!=itend;++it){
9678 	modint &x=v[it->pos];
9679 	x=(x-modint2(c)*(it->val))%env;
9680       }
9681     }
9682     vector<modint>::iterator vt=v.begin(),vtend=v.end();
9683     for (vt=v.begin();vt!=vtend;++vt){
9684       if (*vt)
9685 	return false;
9686     }
9687     return true;
9688   }
9689 
9690   // return true if v reduces to 0
9691   // in addition to reducef4buchberger, compute the coeffs
checkreducef4buchbergersplit(vector<modint> & v,vector<modint> & coeff,const vector<vector<shifttype>> & M,vector<vector<modint>> & coeffs,vector<coeffindex_t> & coeffindex,modint env)9692   bool checkreducef4buchbergersplit(vector<modint> &v,vector<modint> & coeff,const vector< vector<shifttype> > & M,vector<vector<modint> > & coeffs,vector<coeffindex_t> & coeffindex,modint env){
9693     for (unsigned i=0;i<M.size();++i){
9694       const vector<modint> & mcoeff=coeffs[coeffindex[i].u];
9695       vector<modint>::const_iterator jt=mcoeff.begin(),jtend=mcoeff.end();
9696       if (jt==jtend)
9697 	continue;
9698       const vector<shifttype> & mindex=M[i];
9699       const shifttype * it=&mindex.front();
9700       unsigned pos=0;
9701       next_index(pos,it);
9702       // if (pos>v.size()) CERR << "error" <<'\n';
9703       modint c=coeff[i]=(modint2(invmod(*jt,env))*v[pos])%env;
9704       v[pos]=0;
9705       if (!c)
9706 	continue;
9707       for (++jt;jt!=jtend;++jt){
9708 #ifdef GIAC_SHORTSHIFTTYPE
9709 	next_index(pos,it);
9710 	modint &x=v[pos];
9711 #else
9712 	modint &x=v[*it];
9713 	++it;
9714 #endif
9715 	x=(x-modint2(c)*(*jt))%env;
9716       }
9717     }
9718     vector<modint>::iterator vt=v.begin(),vtend=v.end();
9719     for (vt=v.begin();vt!=vtend;++vt){
9720       if (*vt)
9721 	return false;
9722     }
9723     return true;
9724   }
9725 
9726   // Find x=a mod amod and =b mod bmod
9727   // We have x=a+A*amod=b+B*Bmod
9728   // hence A*amod-B*bmod=b-a
9729   // let u*amod+v*bmod=1
9730   // then A=(b-a)*u is a solution
9731   // hence x=a+(b-a)*u*amod mod (amod*bmod) is the solution
9732   // hence x=a+((b-a)*u mod bmod)*amod
ichinrem_inplace(matrice & a,const vector<vector<modint>> & b,const gen & amod,int bmod)9733   static bool ichinrem_inplace(matrice & a,const vector< vector<modint> > &b,const gen & amod, int bmod){
9734     gen U,v,d;
9735     egcd(amod,bmod,U,v,d);
9736     if (!is_one(d) || U.type!=_ZINT)
9737       return false;
9738     int u=mpz_get_si(*U._ZINTptr);
9739     longlong q;
9740     for (unsigned i=0;i<a.size();++i){
9741       gen * ai = &a[i]._VECTptr->front(), * aiend=ai+a[i]._VECTptr->size();
9742       const modint * bi = &b[i].front();
9743       for (;ai!=aiend;++bi,++ai){
9744 	if (*bi==0 && ai->type==_INT_ && ai->val==0)
9745 	  continue;
9746 	q=longlong(*bi)-(ai->type==_INT_?ai->val:modulo(*ai->_ZINTptr,bmod));
9747 	q=(q*u) % bmod;
9748 	if (amod.type==_ZINT && ai->type==_ZINT){
9749 	  if (q>=0)
9750 	    mpz_addmul_ui(*ai->_ZINTptr,*amod._ZINTptr,int(q));
9751 	  else
9752 	    mpz_submul_ui(*ai->_ZINTptr,*amod._ZINTptr,-int(q));
9753 	}
9754 	else
9755 	  *ai += int(q)*amod;
9756       }
9757     }
9758     return true;
9759   }
9760 
9761   template<class tdeg_t>
linfnorm(const poly8<tdeg_t> & p,GIAC_CONTEXT)9762   gen linfnorm(const poly8<tdeg_t> & p,GIAC_CONTEXT){
9763     gen B=0;
9764     for (unsigned i=0;i<p.coord.size();++i){
9765       gen b=abs(p.coord[i].g,contextptr);
9766       if (is_strictly_greater(b,B,contextptr))
9767 	B=b;
9768     }
9769     return B;
9770   }
9771 
9772   template<class tdeg_t>
linfnorm(const vectpoly8<tdeg_t> & v,GIAC_CONTEXT)9773   gen linfnorm(const vectpoly8<tdeg_t> & v,GIAC_CONTEXT){
9774     gen B=0;
9775     for (unsigned i=0;i<v.size();++i){
9776       gen b=linfnorm(v[i],contextptr);
9777       if (is_strictly_greater(b,B,contextptr))
9778 	B=b;
9779     }
9780     return B;
9781   }
9782 
chk_equal_mod(const gen & a,const vector<int> & p,int m)9783   bool chk_equal_mod(const gen & a,const vector<int> & p,int m){
9784     if (a.type!=_VECT || a._VECTptr->size()!=p.size())
9785       return false;
9786     const_iterateur it=a._VECTptr->begin(),itend=a._VECTptr->end();
9787     vector<int>::const_iterator jt=p.begin();
9788     for (;it!=itend;++jt,++it){
9789       if (it->type==_INT_ && it->val==*jt) continue;
9790       if (!chk_equal_mod(*it,*jt,m))
9791 	return false;
9792     }
9793     return true;
9794   }
9795 
chk_equal_mod(const vecteur & v,const vector<vector<int>> & p,int m)9796   bool chk_equal_mod(const vecteur & v,const vector< vector<int> >& p,int m){
9797     if (v.size()!=p.size())
9798       return false;
9799     for (unsigned i=0;i<p.size();++i){
9800       if (!chk_equal_mod(v[i],p[i],m))
9801 	return false;
9802     }
9803     return true;
9804   }
9805 
9806   template<class tdeg_t>
chk_equal_mod(const poly8<tdeg_t> & v,const polymod<tdeg_t> & p,int m)9807   bool chk_equal_mod(const poly8<tdeg_t> & v,const polymod<tdeg_t> & p,int m){
9808     // FIXME: sizes may differ if a coeff of v is 0 mod m
9809     if (v.coord.size()!=p.coord.size())
9810       return false;
9811     if (p.coord.empty())
9812       return true;
9813 	unsigned s = unsigned(p.coord.size());
9814     int lc=smod(v.coord[0].g,m).val;
9815     int lcp=p.coord[0].g;
9816     if (lcp!=1){
9817       for (unsigned i=0;i<s;++i){
9818 	if (!chk_equal_mod(lcp*v.coord[i].g,(longlong(lc)*p.coord[i].g)%m,m))
9819 	  return false;
9820       }
9821     }
9822     else {
9823       for (unsigned i=0;i<s;++i){
9824 	if (!chk_equal_mod(v.coord[i].g,(longlong(lc)*p.coord[i].g)%m,m))
9825 	  return false;
9826       }
9827     }
9828     return true;
9829   }
9830 
9831   template<class tdeg_t>
chk_equal_mod(const vectpoly8<tdeg_t> & v,const vectpolymod<tdeg_t> & p,const vector<unsigned> & G,int m)9832   bool chk_equal_mod(const vectpoly8<tdeg_t> & v,const vectpolymod<tdeg_t> & p,const vector<unsigned> & G,int m){
9833     if (v.size()!=G.size())
9834       return false;
9835     for (unsigned i=0;i<G.size();++i){
9836       if (!chk_equal_mod(v[i],p[G[i]],m))
9837 	return false;
9838     }
9839     return true;
9840   }
9841 
9842   template<class tdeg_t>
chk_equal_mod(const poly8<tdeg_t> & v,const poly8<tdeg_t> & p,int m)9843   bool chk_equal_mod(const poly8<tdeg_t> & v,const poly8<tdeg_t> & p,int m){
9844     if (v.coord.size()!=p.coord.size())
9845       return false;
9846     unsigned s=unsigned(p.coord.size());
9847     int lc=smod(v.coord[0].g,m).val;
9848     for (unsigned i=0;i<s;++i){
9849       if (!chk_equal_mod(v.coord[i].g,(longlong(lc)*p.coord[i].g.val)%m,m))
9850 	return false;
9851     }
9852     return true;
9853   }
9854 
9855   template<class tdeg_t>
chk_equal_mod(const vectpoly8<tdeg_t> & v,const vectpoly8<tdeg_t> & p,const vector<unsigned> & G,int m)9856   bool chk_equal_mod(const vectpoly8<tdeg_t> & v,const vectpoly8<tdeg_t> & p,const vector<unsigned> & G,int m){
9857     if (v.size()!=G.size())
9858       return false;
9859     for (unsigned i=0;i<G.size();++i){
9860       if (!chk_equal_mod(v[i],p[G[i]],m))
9861 	return false;
9862     }
9863     return true;
9864   }
9865 
9866   // excluded==-1 and G==identity in calls
9867   // if eps>0 the check is probabilistic
9868   template<class tdeg_t>
checkf4buchberger(vectpoly8<tdeg_t> & f4buchbergerv,const vectpoly8<tdeg_t> & res,vector<unsigned> & G,unsigned excluded,double eps)9869   bool checkf4buchberger(vectpoly8<tdeg_t> & f4buchbergerv,const vectpoly8<tdeg_t> & res,vector<unsigned> & G,unsigned excluded,double eps){
9870     if (f4buchbergerv.empty())
9871       return true;
9872     polymod<tdeg_t> allf4buchberger(f4buchbergerv.front().order,f4buchbergerv.front().dim),rem(allf4buchberger);
9873     vectpolymod<tdeg_t> resmod,quo;
9874     convert(res,resmod,0);
9875     if (debug_infolevel>1)
9876       CERR << CLOCK()*1e-6 << " checkf4buchberger begin collect monomials on #polys " << f4buchbergerv.size() << '\n';
9877     // collect all terms in f4buchbergerv
9878     collect(f4buchbergerv,allf4buchberger);
9879     if (debug_infolevel>1)
9880       CERR << CLOCK()*1e-6 << " checkf4buchberger symbolic preprocess" << '\n';
9881     // find all monomials required to reduce allf4buchberger with res[G[.]]
9882     polymod<tdeg_t> R;
9883     in_heap_reducemod(allf4buchberger,resmod,G,excluded,quo,rem,&R,0);
9884     if (debug_infolevel>1)
9885       CERR << CLOCK()*1e-6 << " checkf4buchberger end symbolic preprocess" << '\n';
9886     // build a matrix with rows res[G[.]]*quo[.] in terms of monomials in allf4buchberger
9887     // sort the matrix
9888     // checking reduction to 0 is equivalent to
9889     // write a line from f4buchbergerv[]
9890     // as a linear combination of the lines of this matrix
9891     // we will do that modulo a list of primes
9892     // and keep track of the coefficients of the linear combination (the quotients)
9893     // we reconstruct the quotients in Q by fracmod
9894     // once they stabilize, we compute the lcm l of the denominators
9895     // we multiply by l to have an equality on Z
9896     // we compute bounds on the coefficients of the products res*quo
9897     // and on l*f4buchbergerv, and we check further the equality modulo additional
9898     // primes until the equality is proved
9899     if (debug_infolevel>1)
9900       CERR << CLOCK()*1e-6 << " begin build M" << '\n';
9901     vector< vector<sparse_gen> > M;
9902     vector<sparse_element> atrier;
9903     unsigned N=unsigned(R.coord.size()),i,j=0,nterms=0;
9904     M.reserve(N); // actual size is at most N (difference is the remainder part size)
9905     for (i=0;i<res.size();++i){
9906       typename std::vector< T_unsigned<modint,tdeg_t> >::const_iterator jt=quo[i].coord.begin(),jtend=quo[i].coord.end();
9907       for (;jt!=jtend;++j,++jt){
9908 	M.push_back(vector<sparse_gen>(0));
9909 	makeline(res[G[i]],&jt->u,R,M[j]);
9910 	nterms += unsigned(M[j].size());
9911 	atrier.push_back(sparse_element(M[j].front().pos,j));
9912       }
9913     }
9914     sort_vector_sparse_element(atrier.begin(),atrier.end()); // sort(atrier.begin(),atrier.end(),tri1);
9915     vector< vector<sparse_gen> > M1(atrier.size());
9916     for (i=0;i<atrier.size();++i){
9917       swap(M1[i],M[atrier[i].pos]);
9918     }
9919     swap(M,M1);
9920     // CERR << M << '\n';
9921     if (debug_infolevel>0)
9922       CERR << CLOCK()*1e-6 << " rows, columns, terms: " << M.size() << "x" << N << "=" << nterms << '\n';
9923     // PSEUDO_MOD is not interesting here since there is no inter-reduction
9924     gen p(int(longlong(1<<31)-1));
9925     gen pip(1);
9926     vectpolymod<tdeg_t> f4buchbergervmod;
9927     matrice coeffmat;
9928     vector< vector<modint> > coeffmatmodp(f4buchbergerv.size(),vector<modint>(M.size()));
9929     gen bres=linfnorm(res,context0);
9930     gen bf4buchberger=linfnorm(f4buchbergerv,context0);
9931     matrice prevmatq;
9932     bool stable=false;
9933     gen bound=0;
9934     for (int iter=0;;++iter){
9935       if (eps>0 && is_greater(eps*pip,1,context0))
9936 	return true;
9937       p=prevprime(p-1);
9938       int env=p.val;
9939       // check that p does not divide a leading monomial in M
9940       unsigned j;
9941       for (j=0;j<M.size();++j){
9942 	if (smod(M[j].front().val,p)==0)
9943 	  break;
9944       }
9945       if (j<M.size())
9946 	continue;
9947       // compute M mod p
9948       vector< vector<sparse_element> > Mp(M.size());
9949       for (unsigned i=0;i<M.size();++i){
9950 	const vector<sparse_gen> & Mi=M[i];
9951 	vector<sparse_element> Ni;
9952 	Ni.reserve(Mi.size());
9953 	for (unsigned j=0;j<Mi.size();++j){
9954 	  const sparse_gen & Mij=Mi[j];
9955 	  modint tmp= Mij.val.type==_ZINT?modulo(*Mij.val._ZINTptr,env):Mij.val.val%env;
9956 	  Ni.push_back(sparse_element(tmp,Mij.pos));
9957 	}
9958 	swap(Mp[i],Ni);
9959       }
9960       // reduce f4buchbergerv and stores coefficients of quotients for f4buchbergerv[i] in coeffmat[i]
9961       convert(f4buchbergerv,f4buchbergervmod,env);
9962       if (debug_infolevel>0)
9963 	CERR << CLOCK()*1e-6 << " checking mod " << p << '\n';
9964       vector<modint> v;
9965       unsigned countres=0;
9966 #ifdef x86_64
9967       vector<int128_t> v128;
9968 #endif
9969       for (unsigned i=0;i<f4buchbergervmod.size();++i){
9970 	makeline<tdeg_t>(f4buchbergervmod[i],0,R,v);
9971 #if 0 // def x86_64
9972 	if (!checkreducef4buchberger_64(v,coeffmatmodp[i],Mp,env,v128))
9973 	  return false;
9974 #else
9975 	if (!checkreducef4buchberger(v,coeffmatmodp[i],Mp,env))
9976 	  return false;
9977 #endif
9978 	if (iter==0){
9979 	  unsigned countrescur=0;
9980 	  vector<modint> & coeffi=coeffmatmodp[i];
9981 	  for (unsigned j=0;j<coeffi.size();++j){
9982 	    if (coeffi[j])
9983 	      ++countrescur;
9984 	  }
9985 	  if (countrescur>countres)
9986 	    countres=countrescur;
9987 	}
9988       }
9989       // if (iter==0) bound=pow(bres,int(countres),context0);
9990       if (stable){
9991 	if (!chk_equal_mod(prevmatq,coeffmatmodp,env))
9992 	  stable=false;
9993 	// if stable compute bounds and compare with product of primes
9994 	// if 2*bounds < product of primes recheck stabilization and return true
9995 	if (is_strictly_greater(pip,bound,context0)){
9996 	  if (debug_infolevel>0)
9997 	    CERR << CLOCK()*1e-6 << " modular check finished " << '\n';
9998 	  return true;
9999 	}
10000       }
10001       // combine coeffmat with previous one by chinese remaindering
10002       if (debug_infolevel>0)
10003 	CERR << CLOCK()*1e-6 << " chinrem mod " << p << '\n';
10004       if (iter)
10005 	ichinrem_inplace(coeffmat,coeffmatmodp,pip,p.val);
10006       else
10007 	vectvector_int2vecteur(coeffmatmodp,coeffmat);
10008       pip=pip*p;
10009       if (is_greater(bound,pip,context0))
10010 	continue;
10011       if (!stable){
10012 	// check stabilization
10013 	matrice checkquo;
10014 	checkquo.reserve(coeffmat.size());
10015 	for (unsigned k=0;k<coeffmat.size();++k){
10016 	  if (prevmatq.size()>k && chk_equal_mod(prevmatq[k],coeffmatmodp[k],env))
10017 	    checkquo.push_back(prevmatq[k]);
10018 	  else
10019 	    checkquo.push_back(fracmod(coeffmat[k],pip));
10020 	  if (prevmatq.size()>k && checkquo[k]!=prevmatq[k])
10021 	    break;
10022 	  if (k>(prevmatq.size()*3)/2+2)
10023 	    break;
10024 	}
10025 	if (checkquo!=prevmatq){
10026 	  swap(prevmatq,checkquo);
10027 	  if (debug_infolevel>0)
10028 	    CERR << CLOCK()*1e-6 << " unstable mod " << p << " reconstructed " << prevmatq.size() << '\n';
10029 	  continue;
10030 	}
10031 	matrice coeffmatq=*_copy(checkquo,context0)._VECTptr;
10032 	if (debug_infolevel>0)
10033 	  CERR << CLOCK()*1e-6 << " full stable mod " << p << '\n';
10034 	stable=true;
10035 	gen lall=1; vecteur l(coeffmatq.size());
10036 	for (unsigned i=0;i<coeffmatq.size();++i){
10037 	  lcmdeno(*coeffmatq[i]._VECTptr,l[i],context0);
10038 	  if (is_strictly_greater(l[i],lall,context0))
10039 	    lall=l[i];
10040 	}
10041 	if (debug_infolevel>0)
10042 	  CERR << CLOCK()*1e-6 << " lcmdeno ok/start bound " << p << '\n';
10043 	gen ball=1,bi; // ball is the max bound of all coeff in coeffmatq
10044 	for (unsigned i=0;i<coeffmatq.size();++i){
10045 	  bi=linfnorm(coeffmatq[i],context0);
10046 	  if (is_strictly_greater(bi,ball,context0))
10047 	    ball=bi;
10048 	}
10049 	// bound for res and f4buchbergerv
10050 	bound=bres*ball;
10051 	gen bound2=lall*bf4buchberger;
10052 	// lcm of deno and max of coeff
10053 	if (is_strictly_greater(bound2,bound,context0))
10054 	  bound=bound2;
10055       }
10056     }
10057     return true;
10058   }
10059 
10060 
10061   // excluded==-1 and G==identity in calls
10062   // if eps>0 the check is probabilistic
10063   template<class tdeg_t>
checkf4buchbergersplit(vectpoly8<tdeg_t> & f4buchbergerv,const vectpoly8<tdeg_t> & res,vector<unsigned> & G,unsigned excluded,double eps)10064   bool checkf4buchbergersplit(vectpoly8<tdeg_t> & f4buchbergerv,const vectpoly8<tdeg_t> & res,vector<unsigned> & G,unsigned excluded,double eps){
10065     if (f4buchbergerv.empty())
10066       return true;
10067     polymod<tdeg_t> allf4buchberger(f4buchbergerv.front().order,f4buchbergerv.front().dim),rem(allf4buchberger);
10068     vectpolymod<tdeg_t> resmod,quo;
10069     convert(res,resmod,0);
10070     if (debug_infolevel>1)
10071       CERR << CLOCK()*1e-6 << " checkf4buchberger split begin collect monomials on #polys " << f4buchbergerv.size() << '\n';
10072     // collect all terms in f4buchbergerv
10073     collect(f4buchbergerv,allf4buchberger);
10074     if (debug_infolevel>1)
10075       CERR << CLOCK()*1e-6 << " checkf4buchberger split symbolic preprocess" << '\n';
10076     // find all monomials required to reduce allf4buchberger with res[G[.]]
10077     polymod<tdeg_t> R;
10078     in_heap_reducemod(allf4buchberger,resmod,G,excluded,quo,rem,&R,0);
10079     if (debug_infolevel>1)
10080       CERR << CLOCK()*1e-6 << " checkf4buchberger split end symbolic preprocess" << '\n';
10081     // build a matrix with rows res[G[.]]*quo[.] in terms of monomials in allf4buchberger
10082     // sort the matrix
10083     // checking reduction to 0 is equivalent to
10084     // write a line from f4buchbergerv[]
10085     // as a linear combination of the lines of this matrix
10086     // we will do that modulo a list of primes
10087     // and keep track of the coefficients of the linear combination (the quotients)
10088     // we reconstruct the quotients in Q by fracmod
10089     // once they stabilize, we compute the lcm l of the denominators
10090     // we multiply by l to have an equality on Z
10091     // we compute bounds on the coefficients of the products res*quo
10092     // and on l*f4buchbergerv, and we check further the equality modulo additional
10093     // primes until the equality is proved
10094     if (debug_infolevel>1)
10095       CERR << CLOCK()*1e-6 << " begin build Mcoeff/Mindex" << '\n';
10096     vector< vector<gen> > Mcoeff(G.size());
10097     vector<vector<shifttype> > Mindex;
10098     vector<coeffindex_t> coeffindex;
10099     vector<sparse_element> atrier;
10100     unsigned N=unsigned(R.coord.size()),i,j=0,nterms=0;
10101     Mindex.reserve(N);
10102     atrier.reserve(N);
10103     coeffindex.reserve(N);
10104     for (i=0;i<G.size();++i){
10105       Mcoeff[i].reserve(res[G[i]].coord.size());
10106       typename std::vector< T_unsigned<modint,tdeg_t> >::const_iterator jt=quo[i].coord.begin(),jtend=quo[i].coord.end();
10107       for (;jt!=jtend;++j,++jt){
10108 	Mindex.push_back(vector<shifttype>(0));
10109 #ifdef GIAC_SHORTSHIFTTYPE
10110 	Mindex[j].reserve(1+int(1.1*res[G[i]].coord.size()));
10111 #else
10112 	Mindex[j].reserve(res[G[i]].coord.size());
10113 #endif
10114       }
10115     }
10116     for (i=0,j=0;i<G.size();++i){
10117       // copy coeffs of res[G[i]] in Mcoeff
10118       copycoeff(res[G[i]],Mcoeff[i]);
10119       // for each monomial of quo[i], find indexes and put in Mindex
10120       typename std::vector< T_unsigned<modint,tdeg_t> >::const_iterator jt=quo[i].coord.begin(),jtend=quo[i].coord.end();
10121       for (;jt!=jtend;++j,++jt){
10122 	coeffindex.push_back(coeffindex_t(N<0xffff,i));
10123 	makelinesplit(res[G[i]],&jt->u,R,Mindex[j]);
10124 	atrier.push_back(sparse_element(first_index(Mindex[j]),j));
10125       }
10126     }
10127     sort_vector_sparse_element(atrier.begin(),atrier.end()); // sort(atrier.begin(),atrier.end(),tri1);
10128     vector< vector<shifttype> > Mindex1(atrier.size());
10129     vector<coeffindex_t> coeffindex1(atrier.size());
10130     for (i=0;i<atrier.size();++i){
10131       swap(Mindex1[i],Mindex[atrier[i].pos]);
10132       swap(coeffindex1[i],coeffindex[atrier[i].pos]);
10133     }
10134     swap(Mindex,Mindex1);
10135     swap(coeffindex,coeffindex1);
10136     // CERR << M << '\n';
10137     if (debug_infolevel>0)
10138       CERR << CLOCK()*1e-6 << " rows, columns, terms: " << Mindex.size() << "x" << N << "=" << nterms << '\n';
10139     // PSEUDO_MOD is not interesting here since there is no inter-reduction
10140     gen p(int(longlong(1<<31)-1));
10141     gen pip(1);
10142     vectpolymod<tdeg_t> f4buchbergervmod;
10143     matrice coeffmat;
10144     vector< vector<modint> > coeffmatmodp(f4buchbergerv.size(),vector<modint>(Mindex.size()));
10145     gen bres=linfnorm(res,context0);
10146     gen bf4buchberger=linfnorm(f4buchbergerv,context0);
10147     matrice prevmatq;
10148     bool stable=false;
10149     gen bound=0;
10150     vector< vector<modint> > Mcoeffp(Mcoeff.size());
10151     for (int iter=0;;++iter){
10152       if (eps>0 && is_greater(eps*pip,1,context0))
10153 	return true;
10154       p=prevprime(p-1);
10155       int env=p.val;
10156       // check that p does not divide a leading monomial in M
10157       unsigned j;
10158       for (j=0;j<Mcoeff.size();++j){
10159 	if (smod(Mcoeff[j].front(),p)==0)
10160 	  break;
10161       }
10162       if (j<Mcoeff.size())
10163 	continue;
10164       // compute Mcoeff mod p
10165       for (unsigned i=0;i<Mcoeff.size();++i){
10166 	const vector<gen> & Mi=Mcoeff[i];
10167 	vector<modint> & Ni=Mcoeffp[i];
10168 	Ni.clear();
10169 	Ni.reserve(Mi.size());
10170 	for (unsigned j=0;j<Mi.size();++j){
10171 	  const gen & Mij=Mi[j];
10172 	  modint tmp= Mij.type==_ZINT?modulo(*Mij._ZINTptr,env):Mij.val%env;
10173 	  Ni.push_back(tmp);
10174 	}
10175       }
10176       // reduce f4buchbergerv and stores coefficients of quotients for f4buchbergerv[i] in coeffmat[i]
10177       convert(f4buchbergerv,f4buchbergervmod,env);
10178       if (debug_infolevel>0)
10179 	CERR << CLOCK()*1e-6 << " checking mod " << p << '\n';
10180       vector<modint> v;
10181       unsigned countres=0;
10182 #ifdef x86_64
10183       vector<int128_t> v128;
10184 #endif
10185       for (unsigned i=0;i<f4buchbergervmod.size();++i){
10186 	makeline(f4buchbergervmod[i],0,R,v);
10187 #ifdef x86_64
10188 	if (!checkreducef4buchbergersplit_64(v,coeffmatmodp[i],Mindex,Mcoeffp,coeffindex,env,v128))
10189 	  return false;
10190 #else
10191 	if (!checkreducef4buchbergersplit(v,coeffmatmodp[i],Mindex,Mcoeffp,coeffindex,env))
10192 	  return false;
10193 #endif
10194 	if (iter==0){
10195 	  unsigned countrescur=0;
10196 	  vector<modint> & coeffi=coeffmatmodp[i];
10197 	  for (unsigned j=0;j<coeffi.size();++j){
10198 	    if (coeffi[j])
10199 	      ++countrescur;
10200 	  }
10201 	  if (countrescur>countres)
10202 	    countres=countrescur;
10203 	}
10204       }
10205       // if (iter==0) bound=pow(bres,int(countres),context0);
10206       if (stable){
10207 	if (!chk_equal_mod(prevmatq,coeffmatmodp,env))
10208 	  stable=false;
10209 	// if stable compute bounds and compare with product of primes
10210 	// if 2*bounds < product of primes recheck stabilization and return true
10211 	if (is_strictly_greater(pip,bound,context0)){
10212 	  if (debug_infolevel>0)
10213 	    CERR << CLOCK()*1e-6 << " modular check finished " << '\n';
10214 	  return true;
10215 	}
10216       }
10217       // combine coeffmat with previous one by chinese remaindering
10218       if (debug_infolevel>0)
10219 	CERR << CLOCK()*1e-6 << " chinrem mod " << p << '\n';
10220       if (iter)
10221 	ichinrem_inplace(coeffmat,coeffmatmodp,pip,p.val);
10222       else
10223 	vectvector_int2vecteur(coeffmatmodp,coeffmat);
10224       pip=pip*p;
10225       if (is_greater(bound,pip,context0))
10226 	continue;
10227       if (!stable){
10228 	// check stabilization
10229 	matrice checkquo;
10230 	checkquo.reserve(coeffmat.size());
10231 	for (unsigned k=0;k<coeffmat.size();++k){
10232 	  if (prevmatq.size()>k && chk_equal_mod(prevmatq[k],coeffmatmodp[k],env))
10233 	    checkquo.push_back(prevmatq[k]);
10234 	  else
10235 	    checkquo.push_back(fracmod(coeffmat[k],pip));
10236 	  if (prevmatq.size()>k && checkquo[k]!=prevmatq[k])
10237 	    break;
10238 	  if (k>(prevmatq.size()*3)/2+2)
10239 	    break;
10240 	}
10241 	if (checkquo!=prevmatq){
10242 	  swap(prevmatq,checkquo);
10243 	  if (debug_infolevel>0)
10244 	    CERR << CLOCK()*1e-6 << " unstable mod " << p << " reconstructed " << prevmatq.size() << '\n';
10245 	  continue;
10246 	}
10247 	matrice coeffmatq=*_copy(checkquo,context0)._VECTptr;
10248 	if (debug_infolevel>0)
10249 	  CERR << CLOCK()*1e-6 << " full stable mod " << p << '\n';
10250 	stable=true;
10251 	gen lall=1; vecteur l(coeffmatq.size());
10252 	for (unsigned i=0;i<coeffmatq.size();++i){
10253 	  lcmdeno(*coeffmatq[i]._VECTptr,l[i],context0);
10254 	  if (is_strictly_greater(l[i],lall,context0))
10255 	    lall=l[i];
10256 	}
10257 	if (debug_infolevel>0)
10258 	  CERR << CLOCK()*1e-6 << " lcmdeno ok/start bound " << p << '\n';
10259 	gen ball=1,bi; // ball is the max bound of all coeff in coeffmatq
10260 	for (unsigned i=0;i<coeffmatq.size();++i){
10261 	  bi=linfnorm(coeffmatq[i],context0);
10262 	  if (is_strictly_greater(bi,ball,context0))
10263 	    ball=bi;
10264 	}
10265 	// bound for res and f4buchbergerv
10266 	bound=bres*ball;
10267 	gen bound2=lall*bf4buchberger;
10268 	// lcm of deno and max of coeff
10269 	if (is_strictly_greater(bound2,bound,context0))
10270 	  bound=bound2;
10271       }
10272     }
10273     return true;
10274   }
10275 
10276   /* ***************
10277      BEGIN ZPOLYMOD
10278      ***************  */
10279 #if GIAC_SHORTSHIFTTYPE==16
10280   // Same algorithms compressing data
10281   // since all spolys reduced at the same time share the same exponents
10282   // we will keep the exponents only once in memory
10283   // sizeof(zmodint)=8 bytes, sizeof(T_unsigned<modint,tdeg_t>)=28 or 36
10284   typedef T_unsigned<modint,unsigned> zmodint;
10285   template <class tdeg_t>
10286   struct zpolymod {
10287     order_t order;
10288     short int dim;
10289     bool in_gbasis; // set to false in zgbasis_updatemod for "small" reductors that we still want to use for reduction
10290     short int age:15;
10291     vector<zmodint> coord;
10292     const vector<tdeg_t> * expo;
10293     tdeg_t ldeg;
10294     int maxtdeg;
10295     int fromleft,fromright;
10296     double logz;
zpolymodgiac::zpolymod10297     zpolymod():in_gbasis(true),dim(0),expo(0),ldeg(),age(0),fromleft(-1),fromright(-1),logz(1) {order.o=0; order.lex=0; order.dim=0; maxtdeg=-1;}
zpolymodgiac::zpolymod10298     zpolymod(order_t o,int d): in_gbasis(true),dim(d),expo(0),ldeg(),age(0),fromleft(-1),fromright(-1),logz(1) {order=o; order.dim=d; maxtdeg=-1;}
zpolymodgiac::zpolymod10299     zpolymod(order_t o,int d,const tdeg_t & l): in_gbasis(true),dim(d),expo(0),ldeg(l),age(0),fromleft(-1),fromright(-1),logz(1) {order=o; order.dim=d; maxtdeg=-1;}
zpolymodgiac::zpolymod10300     zpolymod(order_t o,int d,const vector<tdeg_t> * e,const tdeg_t & l): in_gbasis(true),dim(d),expo(e),ldeg(l),age(0),fromleft(-1),fromright(-1),logz(1) {order=o; order.dim=d; maxtdeg=-1;}
10301     void dbgprint() const;
compute_maxtdeggiac::zpolymod10302     void compute_maxtdeg(){
10303       if (expo){
10304 	std::vector< zmodint >::iterator pt=coord.begin(),ptend=coord.end();
10305 	for (;pt!=ptend;++pt){
10306 	  int tmp=(*expo)[pt->u].total_degree(order);
10307 	  if (tmp>maxtdeg)
10308 	    maxtdeg=tmp;
10309 	}
10310       }
10311     }
10312   };
10313 
10314   template<class tdeg_t>
10315   struct zinfo_t {
10316     vector< vector<tdeg_t> > quo;
10317     vector<tdeg_t> R,rem;
10318     vector<int> permu;
10319     vector< paire > B;
10320     vector<unsigned> G,permuB;
10321     unsigned nonzero,Ksizes;
10322   };
10323 
10324   template<class tdeg_t>
zsmallmultmod(modint a,zpolymod<tdeg_t> & p,modint m)10325   void zsmallmultmod(modint a,zpolymod<tdeg_t> & p,modint m){
10326     std::vector< zmodint >::iterator pt=p.coord.begin(),ptend=p.coord.end();
10327     if (a==1 || a==1-m){
10328       for (;pt!=ptend;++pt){
10329 	modint tmp=pt->g;
10330 	if (tmp<0) tmp += m;
10331 	pt->g=tmp;
10332       }
10333       return;
10334     }
10335     for (;pt!=ptend;++pt){
10336       modint tmp=(longlong(pt->g)*a)%m;
10337       if (tmp<0) tmp += m;
10338       pt->g=tmp;
10339     }
10340   }
10341 
10342   template<class tdeg_t>
operator ==(const zpolymod<tdeg_t> & p,const zpolymod<tdeg_t> & q)10343   bool operator == (const zpolymod<tdeg_t> & p,const zpolymod<tdeg_t> &q){
10344     if (p.coord.size()!=q.coord.size() || p.expo!=q.expo)
10345       return false;
10346     for (unsigned i=0;i<p.coord.size();++i){
10347       if (p.coord[i].u!=q.coord[i].u || p.coord[i].g!=q.coord[i].g)
10348 	return false;
10349     }
10350     return true;
10351   }
10352 
10353 #ifdef NSPIRE
10354   template<class T,class tdeg_t>
operator <<(nio::ios_base<T> & os,const zpolymod<tdeg_t> & p)10355   nio::ios_base<T> & operator << (nio::ios_base<T> & os, const zpolymod<tdeg_t> & p)
10356 #else
10357   template<class tdeg_t>
10358   ostream & operator << (ostream & os, const zpolymod<tdeg_t> & p)
10359 #endif
10360   {
10361     if (!p.expo)
10362       return os << "error, null pointer in expo " ;
10363     std::vector<zmodint>::const_iterator it=p.coord.begin(),itend=p.coord.end();
10364     int t2;
10365     os << "zpolymod(" << p.logz << "," << p.age << ":" << p.fromleft << "," << p.fromright << "): ";
10366     if (it==itend)
10367       return os << 0 ;
10368     for (;it!=itend;){
10369       os << it->g  ;
10370 #ifndef GBASIS_NO_OUTPUT
10371       if ((*p.expo)[it->u].vars64()){
10372 	if ((*p.expo)[it->u].tdeg%2){
10373 	  degtype * i=(degtype *)((*p.expo)[it->u].ui+1);
10374 	  for (int j=0;j<(*p.expo)[it->u].order_.dim;++j){
10375 	    t2=i[j];
10376 	    if (t2)
10377 	      os << "*x"<< j << "^" << t2  ;
10378 	  }
10379 	  ++it;
10380 	  if (it==itend)
10381 	    break;
10382 	  os << " + ";
10383 	  continue;
10384 	}
10385       }
10386 #endif
10387       short tab[GROEBNER_VARS+1];
10388       (*p.expo)[it->u].get_tab(tab,p.order);
10389       switch (p.order.o){
10390       case _PLEX_ORDER:
10391 	for (int i=0;i<=GROEBNER_VARS;++i){
10392 	  t2 = tab[i];
10393 	  if (t2)
10394 	    os << "*x"<< i << "^" << t2  ;
10395 	}
10396 	break;
10397       case _TDEG_ORDER:
10398 	for (int i=1;i<=GROEBNER_VARS;++i){
10399 	  t2 = tab[i];
10400 	  if (t2==0)
10401 	    continue;
10402 	  if (t2)
10403 	    os << "*x"<< i-1 << "^" << t2  ;
10404 	}
10405 	break;
10406       case _REVLEX_ORDER:
10407 	for (int i=1;i<=GROEBNER_VARS;++i){
10408 	  t2 = tab[i];
10409 	  if (t2==0)
10410 	    continue;
10411 	  os << "*x"<< p.dim-i;
10412 	  if (t2!=1)
10413 	    os << "^" << t2;
10414 	}
10415 	break;
10416 #if GROEBNER_VARS==15
10417       case _3VAR_ORDER:
10418 	for (int i=1;i<=3;++i){
10419 	  t2 = tab[i];
10420 	  if (t2==0)
10421 	    continue;
10422 	  os << "*x"<< 3-i;
10423 	  if (t2!=1)
10424 	    os << "^" << t2;
10425 	}
10426 	for (int i=5;i<=15;++i){
10427 	  t2 = tab[i];
10428 	  if (t2==0)
10429 	    continue;
10430 	  os << "*x"<< 7+p.dim-i;
10431 	  if (t2!=1)
10432 	    os << "^" << t2;
10433 	}
10434 	break;
10435       case _7VAR_ORDER:
10436 	for (int i=1;i<=7;++i){
10437 	  t2 = tab[i];
10438 	  if (t2==0)
10439 	    continue;
10440 	  os << "*x"<< 7-i;
10441 	  if (t2!=1)
10442 	    os << "^" << t2;
10443 	}
10444 	for (int i=9;i<=15;++i){
10445 	  t2 = tab[i];
10446 	  if (t2==0)
10447 	    continue;
10448 	  os << "*x"<< 11+p.dim-i;
10449 	  if (t2!=1)
10450 	    os << "^" << t2;
10451 	}
10452 	break;
10453       case _11VAR_ORDER:
10454 	for (int i=1;i<=11;++i){
10455 	  t2 = tab[i];
10456 	  if (t2==0)
10457 	    continue;
10458 	  os << "*x"<< 11-i;
10459 	  if (t2!=1)
10460 	    os << "^" << t2;
10461 	}
10462 	for (int i=13;i<=15;++i){
10463 	  t2 = tab[i];
10464 	  if (t2==0)
10465 	    continue;
10466 	  os << "*x"<< 15+p.dim-i;
10467 	  if (t2!=1)
10468 	    os << "^" << t2;
10469 	}
10470 	break;
10471 #endif
10472       }
10473       ++it;
10474       if (it==itend)
10475 	break;
10476       os << " + ";
10477     }
10478     return os;
10479   }
10480 
10481   template<class tdeg_t>
dbgprint() const10482   void zpolymod<tdeg_t>::dbgprint() const {
10483     CERR << *this << '\n';
10484   }
10485 
10486   template<class tdeg_t>
10487   class vectzpolymod:public vector<zpolymod<tdeg_t> >{
10488   public:
dbgprint() const10489     void dbgprint() const { CERR << *this << '\n'; }
10490   };
10491 
10492   template<class tdeg_t>
zleftright(const vectzpolymod<tdeg_t> & res,const vector<paire> & B,vector<tdeg_t> & leftshift,vector<tdeg_t> & rightshift)10493   void zleftright(const vectzpolymod<tdeg_t> & res,const vector< paire > & B,vector<tdeg_t> & leftshift,vector<tdeg_t> & rightshift){
10494     tdeg_t l;
10495     for (unsigned i=0;i<B.size();++i){
10496       const zpolymod<tdeg_t> & p=res[B[i].first];
10497       const zpolymod<tdeg_t> & q=res[B[i].second];
10498       if (debug_infolevel>2)
10499 	CERR << "zleftright " << p << "," << q << '\n';
10500       index_lcm_overwrite(p.ldeg,q.ldeg,l,p.order);
10501       leftshift[i]=l-p.ldeg;
10502       rightshift[i]=l-q.ldeg;
10503     }
10504   }
10505 
10506   // collect monomials from pairs of res (vector of polymod<tdeg_t>s), shifted by lcm
10507   // does not collect leading monomial (since they cancel)
10508   template<class tdeg_t>
zcollect(const vectzpolymod<tdeg_t> & res,const vector<paire> & B,const vector<unsigned> & permuB,vector<tdeg_t> & allf4buchberger,vector<tdeg_t> & leftshift,vector<tdeg_t> & rightshift)10509   bool zcollect(const vectzpolymod<tdeg_t> & res,const vector< paire > & B,const vector<unsigned> & permuB,vector<tdeg_t> & allf4buchberger,vector<tdeg_t> & leftshift,vector<tdeg_t> & rightshift){
10510     int start=1,countdiscarded=0;
10511     vector<heap_tt<tdeg_t> > Ht;
10512     heap_tt<tdeg_t> heap_elem;
10513     vector<heap_tt_ptr<tdeg_t> > H;
10514     Ht.reserve(2*B.size()+1);
10515     H.reserve(2*B.size());
10516     unsigned s=0;
10517     order_t keyorder={_REVLEX_ORDER,0};
10518     for (unsigned i=0;i<B.size();++i){
10519       unsigned truei=permuB[i];
10520       const paire & Bi=B[truei];
10521       const zpolymod<tdeg_t> & p=res[Bi.first];
10522       const zpolymod<tdeg_t> & q=res[Bi.second];
10523       keyorder=p.order;
10524       bool eq=i>0 && Bi.second==B[permuB[i-1]].second && rightshift[truei]==rightshift[permuB[i-1]];
10525       if (int(p.coord.size())>start){
10526 	s = giacmax(s, unsigned(p.coord.size()));
10527 	Ht.push_back(heap_tt<tdeg_t>(true,truei,start,(*p.expo)[p.coord[start].u]+leftshift[truei]));
10528 	H.push_back(heap_tt_ptr<tdeg_t>(&Ht.back()));
10529       }
10530       if (!eq && int(q.coord.size())>start){
10531 	s = giacmax(s, unsigned(q.coord.size()));
10532 	Ht.push_back(heap_tt<tdeg_t>(false,truei,start,(*q.expo)[q.coord[start].u]+rightshift[truei]));
10533 	H.push_back(heap_tt_ptr<tdeg_t>(&Ht.back()));
10534       }
10535     }
10536     allf4buchberger.reserve(s); // int(s*std::log(1+H.size())));
10537     compare_heap_tt_ptr<tdeg_t> key(keyorder);
10538     make_heap(H.begin(),H.end(),key);
10539     while (!H.empty()){
10540       // push root node of the heap in allf4buchberger
10541       heap_tt<tdeg_t> & current = *H.front().ptr;
10542       if (int(current.u.total_degree(keyorder))>GBASISF4_MAX_TOTALDEG){
10543 	CERR << "Error zcollect total degree too large" << current.u.total_degree(keyorder) << '\n';
10544 	return false;
10545       }
10546       if (allf4buchberger.empty() || allf4buchberger.back()!=current.u)
10547 	allf4buchberger.push_back(current.u);
10548       unsigned vpos;
10549       if (current.left)
10550 	vpos=B[current.f4buchbergervpos].first;
10551       else
10552 	vpos=B[current.f4buchbergervpos].second;
10553       ++current.polymodpos;
10554       const zpolymod<tdeg_t> & resvpos=res[vpos];
10555       for (int startheappos=1;current.polymodpos<resvpos.coord.size();++current.polymodpos){
10556 	add((*resvpos.expo)[resvpos.coord[current.polymodpos].u],current.left?leftshift[current.f4buchbergervpos]:rightshift[current.f4buchbergervpos],current.u,keyorder.dim);
10557 	// if (current.left) current.u=(*resvpos.expo)[resvpos.coord[current.polymodpos].u]+leftshift[current.f4buchbergervpos]; else current.u=(*resvpos.expo)[resvpos.coord[current.polymodpos].u]+rightshift[current.f4buchbergervpos];
10558 	int newtdeg=current.u.total_degree(keyorder);
10559 	// quick look in part of heap: if monomial is already there, increment current.polymodpos
10560 	int heappos=startheappos,ntests=int(H.size()); // giacmin(8,H.size());
10561 	for (;heappos<ntests;){
10562 	  heap_tt<tdeg_t> & heapcurrent=*H[heappos].ptr;
10563 	  int heapcurtdeg=heapcurrent.u.total_degree(keyorder);
10564 	  if (heapcurtdeg<newtdeg){
10565 	    heappos=ntests; break;
10566 	  }
10567 	  if (heapcurtdeg==newtdeg && heapcurrent.u==current.u)
10568 	    break;
10569 	  //if (heappos<8) ++heappos; else
10570 	    heappos=2*heappos+1;
10571 	}
10572 	if (heappos<ntests){
10573 	  ++countdiscarded;
10574 	  startheappos=2*heappos+1;
10575 	  continue;
10576 	}
10577 	break;
10578       }
10579       // push_back &current into heap so that pop_heap will bubble out the
10580       // modified root node (initialization will exchange two identical pointers)
10581       if (current.polymodpos<resvpos.coord.size())
10582 	H.push_back(heap_tt_ptr<tdeg_t>(&current));
10583       std::pop_heap(H.begin(),H.end(),key);
10584       H.pop_back();
10585     }
10586     if (debug_infolevel>1)
10587       CERR << "pairs " << B.size() << ", discarded monomials " << countdiscarded << '\n';
10588     return true;
10589   }
10590 
10591   // returns heap actual size, 0 means no quotients (all elements of q empty())
10592   template<class tdeg_t>
zsymbolic_preprocess(const vector<tdeg_t> & f,const vectzpolymod<tdeg_t> & g,const vector<unsigned> & G,unsigned excluded,vector<vector<tdeg_t>> & q,vector<tdeg_t> & rem,vector<tdeg_t> & R)10593   size_t zsymbolic_preprocess(const vector<tdeg_t> & f,const vectzpolymod<tdeg_t> & g,const vector<unsigned> & G,unsigned excluded,vector< vector<tdeg_t> > & q,vector<tdeg_t> & rem,vector<tdeg_t> & R){
10594     int countdiscarded=0;
10595     // divides f by g[G[0]] to g[G[G.size()-1]] except maybe g[G[excluded]]
10596     // CERR << f << "/" << g << '\n';
10597     // first implementation: use quotient heap for all quotient/divisor
10598     // do not use heap chain
10599     // ref Monaghan Pearce if g.size()==1
10600     // R is the list of all monomials
10601     if (f.empty() || G.empty())
10602       return 0;
10603     int dim=g[G.front()].dim;
10604     order_t order=g[G.front()].order;
10605 #ifdef GIAC_GBASIS_PERMUTATION
10606     // First reorder G in order to use the "best" possible reductor
10607     // This is done using the ldegree of g[G[i]] (should be minmal)
10608     // and the number of terms (should be minimal)
10609     vector<zsymb_data<tdeg_t> > GG(G.size());
10610     for (unsigned i=0;i<G.size();++i){
10611       zsymb_data<tdeg_t> zz={i,g[G[i]].ldeg,g[G[i]].order,unsigned(g[G[i]].coord.size()),g[G[i]].age};
10612       GG[i]=zz;
10613     }
10614     sort(GG.begin(),GG.end());
10615 #endif
10616     tdeg_t minldeg(g[G.front()].ldeg);
10617     R.clear();
10618     rem.clear();
10619     // if (G.size()>q.size()) q.clear();
10620     q.resize(G.size());
10621     unsigned guess=0;
10622     for (unsigned i=0;i<G.size();++i){
10623       q[i].clear();
10624       guess += unsigned(g[G[i]].coord.size());
10625       if (!tdeg_t_greater(g[G[i]].ldeg,minldeg,order))
10626 	minldeg=g[G[i]].ldeg;
10627     }
10628     vector<heap_t<tdeg_t> > H_;
10629     vector<unsigned> H;
10630     if (debug_infolevel>1)
10631       CERR << CLOCK()*1e-6 << " Heap reserve " << 3*f.size() << " * " << sizeof(heap_t<deg_t>)+sizeof(unsigned) << ", number of monomials in basis " << guess  << '\n';
10632     // H_.reserve(guess);
10633     // H.reserve(guess);
10634     H_.reserve(3*f.size());
10635     H.reserve(3*f.size());
10636     heap_t_compare<tdeg_t> key(H_,order);
10637     unsigned k=0,i; // k=position in f
10638     tdeg_t m;
10639     bool finish=false;
10640     while (!H.empty() || k<f.size()){
10641       // is highest remaining degree in f or heap?
10642       if (k<f.size() && (H.empty() || tdeg_t_greater(f[k],H_[H.front()].u,order)) ){
10643 	// it's in f or both
10644 	m=f[k];
10645 	++k;
10646       }
10647       else {
10648 	m=H_[H.front()].u;
10649       }
10650       //CERR << m << '\n';
10651       R.push_back(m);
10652       // extract from heap all terms having m as monomials, substract from c
10653       while (!H.empty() && H_[H.front()].u==m){
10654 	heap_t<tdeg_t> & current=H_[H.front()]; // was root node of the heap
10655 	const zpolymod<tdeg_t> & gcurrent = g[G[current.i]];
10656 	++current.gj;
10657 	for (int startheappos=1;current.gj<gcurrent.coord.size();++current.gj){
10658 	  //current.u=q[current.i][current.qi]+(*gcurrent.expo)[gcurrent.coord[current.gj].u];
10659 	  add(q[current.i][current.qi],(*gcurrent.expo)[gcurrent.coord[current.gj].u],current.u,dim);
10660 	  int newtdeg=current.u.total_degree(order);
10661 	  // quick look in part of heap: is monomial already there?
10662 	  int heappos=startheappos,ntests=int(H.size()); // giacmin(8,H.size());
10663 	  for (;heappos<ntests;){
10664 	    heap_t<tdeg_t> & heapcurrent=H_[H[heappos]];
10665 	    int heapcurtdeg=heapcurrent.u.total_degree(order);
10666 	    if (heapcurtdeg<newtdeg){
10667 	      heappos=ntests; break;
10668 	    }
10669 	    if (heapcurtdeg==newtdeg && heapcurrent.u==current.u)
10670 	      break;
10671 	    //if (heappos<8) ++heappos; else
10672 	      heappos=2*heappos+1;
10673 	  }
10674 	  if (heappos<ntests){
10675 	    ++countdiscarded;
10676 	    startheappos=2*heappos+1;
10677 	    continue;
10678 	  }
10679 	  break;
10680 	}
10681 	if (current.gj<gcurrent.coord.size()){
10682 	  H.push_back(H.front());
10683 	  std::pop_heap(H.begin(),H.end(),key);
10684 	  H.pop_back();
10685 	}
10686 	else {
10687 	  std::pop_heap(H.begin(),H.end(),key);
10688 	  H.pop_back();
10689 	}
10690       } // end while !H.empty()
10691       // divide (c,m) by one of the g if possible, otherwise push in remainder
10692       if (finish){
10693 	rem.push_back(m); // add to remainder
10694 	continue;
10695       }
10696 #ifdef GIAC_DEG_FIRST
10697       int mtot=m.total_degree(order);
10698 #endif
10699       unsigned ii;
10700       for (ii=0;ii<G.size();++ii){
10701 #ifdef GIAC_GBASIS_PERMUTATION
10702 	i=GG[ii].pos; // we can use any permutation of 0..G.size()-1 here
10703 #else
10704 	i=ii;
10705 #endif
10706 	if (i==excluded)
10707 	  continue;
10708 	const tdeg_t & deg=g[G[i]].ldeg;
10709 #ifdef GIAC_DEG_FIRST
10710 	if (deg.total_degree(order)>mtot){
10711 	  ii=G.size(); break;
10712 	}
10713 #endif
10714 	if (tdeg_t_all_greater(m,deg,order))
10715 	  break;
10716       }
10717       if (ii==G.size()){
10718 	rem.push_back(m); // add to remainder
10719 	// no monomial divide m, check if m is greater than one of the monomial of G
10720 	// if not we can push all remaining monomials in rem
10721 	finish=!tdeg_t_greater(m,minldeg,order);
10722 	continue;
10723       }
10724       // add m/leading monomial of g[G[i]] to q[i]
10725       const zpolymod<tdeg_t> & gGi=g[G[i]];
10726       tdeg_t monom=m-gGi.ldeg;
10727       q[i].push_back(monom);
10728       // CERR << i << " " << q[i] << '\n';
10729       // push in heap
10730       int startheappos=0;
10731       for (int pos=1;pos<gGi.coord.size();++pos){
10732 #if 0 // not useful here, but would be above!
10733 	tdeg_t newmonom=(*gGi.expo)[gGi.coord[pos].u] + monom;
10734 	int newtdeg=newmonom.total_degree(order);
10735 	// quick look in part of heap is monomial already there
10736 	int heappos=startheappos,ntests=H.size(); // giacmin(8,H.size());
10737 	for (;heappos<ntests;heappos=2*heappos+1){
10738 	  heap_t<tdeg_t> & current=H_[H[heappos]];
10739 	  int curtdeg=current.u.total_degree(order);
10740 	  if (curtdeg<newtdeg){
10741 	    heappos=ntests; break;
10742 	  }
10743 	  if (curtdeg==newtdeg && current.u==newmonom)
10744 	    break;
10745 	}
10746 	if (heappos<ntests){
10747 	  ++countdiscarded;
10748 	  startheappos=2*heappos+1;
10749 	  continue;
10750 	}
10751 	heap_t<tdeg_t> current = { i, unsigned(q[i].size()) - 1, pos, newmonom };
10752 #else
10753 	heap_t<tdeg_t> current = { i, unsigned(q[i].size()) - 1, unsigned(pos), (*gGi.expo)[gGi.coord[pos].u] + monom };
10754 #endif
10755 	H.push_back(hashgcd_U(H_.size()));
10756 	H_.push_back(current);
10757 	key.ptr=&H_.front();
10758 	std::push_heap(H.begin(),H.end(),key);
10759 	break;
10760       }
10761     } // end main heap pseudo-division loop
10762     if (debug_infolevel>1)
10763       CERR << CLOCK()*1e-6 << " Heap actual size was " << H_.size() << " discarded monomials " << countdiscarded << '\n';
10764     return H_.size();
10765   }
10766 
10767   template<class tdeg_t,class modint_t>
zcopycoeff(const zpolymod<tdeg_t> & p,vector<modint_t> & v,modint env,int start)10768   void zcopycoeff(const zpolymod<tdeg_t> & p,vector<modint_t> & v,modint env,int start){
10769     std::vector< zmodint >::const_iterator it=p.coord.begin()+start,itend=p.coord.end();
10770     v.clear();
10771     v.reserve(itend-it);
10772     for (;it!=itend;++it){
10773       modint g=it->g;
10774       if (g<0) g += env;
10775       v.push_back(g);
10776     }
10777   }
10778 
10779 template<class tdeg_t,class modint_t>
zcopycoeff(const zpolymod<tdeg_t> & p,vector<modint_t> & v,int start)10780   void zcopycoeff(const zpolymod<tdeg_t> & p,vector<modint_t> & v,int start){
10781     std::vector< zmodint >::const_iterator it=p.coord.begin()+start,itend=p.coord.end();
10782     v.clear();
10783     v.reserve(itend-it);
10784     for (;it!=itend;++it){
10785       modint g=it->g;
10786       v.push_back(g);
10787     }
10788   }
10789 
10790   // dichotomic seach for jt->u==u in [jt,jtend[
10791   template<class tdeg_t>
dicho(typename std::vector<tdeg_t>::const_iterator & jt,typename std::vector<tdeg_t>::const_iterator jtend,const tdeg_t & u,order_t order)10792   bool dicho(typename std::vector<tdeg_t>::const_iterator & jt,typename std::vector<tdeg_t>::const_iterator jtend,const tdeg_t & u,order_t order){
10793     if (*jt==u) return true;
10794     if (jtend-jt<=6){ ++jt; return false; }// == test faster
10795     for (;;){
10796       int step=int((jtend-jt)/2);
10797       typename std::vector<tdeg_t>::const_iterator j=jt+step;
10798       if (j==jt)
10799 	return *j==u;
10800       //PREFETCH(&*(j+step/2));
10801       //PREFETCH(&*(jt+step/2));
10802       if (int res=tdeg_t_greater(*j,u,order)){
10803 	jt=j;
10804 	if (res==2)
10805 	  return true;
10806       }
10807       else
10808 	jtend=j;
10809     }
10810   }
10811 
10812 #if 1 // #if 0 for old versions of gcc
10813   template<>
dicho(std::vector<tdeg_t64>::const_iterator & jt,std::vector<tdeg_t64>::const_iterator jtend,const tdeg_t64 & u,order_t order)10814   bool dicho(std::vector<tdeg_t64>::const_iterator & jt,std::vector<tdeg_t64>::const_iterator jtend,const tdeg_t64 & u,order_t order){
10815     if (*jt==u) return true;
10816     if (jtend-jt<=6){ ++jt; return false; }// == test faster
10817 #ifdef GIAC_ELIM
10818     if (u.tab[0]%2){
10819       int utdeg=u.tab[0],utdeg2=u.tdeg2;
10820       ulonglong uelim=u.elim;
10821       for (;;){
10822 	int step=(jtend-jt)/2;
10823 	std::vector<tdeg_t64>::const_iterator j=jt+step;
10824 	if (j==jt)
10825 	  return *j==u;
10826 	if (j->tab[0]!=utdeg){
10827 	  if (j->tdeg>utdeg)
10828 	    jt=j;
10829 	  else
10830 	    jtend=j;
10831 	  continue;
10832 	}
10833 	if (j->tdeg2!=utdeg2){
10834 	  if (j->tdeg2>utdeg2)
10835 	    jt=j;
10836 	  else
10837 	    jtend=j;
10838 	  continue;
10839 	}
10840 	if (j->elim!=uelim){
10841 	  if (j->elim<uelim)
10842 	    jt=j;
10843 	  else
10844 	    jtend=j;
10845 	  continue;
10846 	}
10847 	if (int res=tdeg_t_greater(*j,u,order)){
10848 	  jt=j;
10849 	  if (res==2)
10850 	    return true;
10851 	}
10852 	else
10853 	  jtend=j;
10854       }
10855     }
10856 #endif
10857     for (;;){
10858       int step=int((jtend-jt)/2);
10859       std::vector<tdeg_t64>::const_iterator j=jt+step;
10860       if (j==jt)
10861 	return *j==u;
10862       if (int res=tdeg_t_greater(*j,u,order)){
10863 	jt=j;
10864 	if (res==2)
10865 	  return true;
10866       }
10867       else
10868 	jtend=j;
10869     }
10870   }
10871 #endif
10872 
10873   template<class tdeg_t>
zmakelinesplit(const zpolymod<tdeg_t> & p,const tdeg_t * shiftptr,const vector<tdeg_t> & R,void * Rhashptr,const vector<int> & Rdegpos,vector<shifttype> & v,vector<shifttype> * prevline,int start=0)10874   void zmakelinesplit(const zpolymod<tdeg_t> & p,const tdeg_t * shiftptr,const vector<tdeg_t> & R,void * Rhashptr,const vector<int> & Rdegpos,vector<shifttype> & v,vector<shifttype> * prevline,int start=0){
10875     std::vector<zmodint>::const_iterator it=p.coord.begin()+start,itend=p.coord.end();
10876     typename std::vector<tdeg_t>::const_iterator Rbegin=R.begin(),jt=Rbegin,jtend=R.end();
10877     double nop1=double(R.size());
10878     double nop2=2*p.coord.size()*std::log(nop1)/std::log(2.0);
10879     bool dodicho=nop2<nop1;
10880     const vector<tdeg_t> & expo=*p.expo;
10881     unsigned pos=0,Rpos=0;
10882     if (shiftptr){
10883       tdeg_t u=*shiftptr+*shiftptr; // create a new memory slot
10884       const shifttype * st=prevline?&prevline->front():0;
10885       for (;it!=itend;++it){
10886 	add(expo[it->u],*shiftptr,u,p.dim);
10887 #ifdef GIAC_RHASH
10888 	int hashi=u.hash_index(Rhashptr);
10889 	if (hashi>=0){
10890 	  pushsplit(v,pos,hashi);
10891 	  ++jt;
10892 	  continue;
10893 	}
10894 #endif
10895 	if (dodicho){
10896 	  typename std::vector<tdeg_t>::const_iterator end=jtend;
10897 	  if (st){
10898 	    next_index(Rpos,st);
10899 	    end=Rbegin+Rpos;
10900 	  }
10901 #ifdef GIAC_RDEG
10902 	  int a=Rdegpos[u.tdeg+1],b=Rdegpos[u.tdeg];
10903 	  if (jt-Rbegin<a)
10904 	    jt=Rbegin+a;
10905 	  if (end-Rbegin>b)
10906 	    end=Rbegin+b;
10907 #endif
10908 	  if (dicho(jt,end,u,p.order)){
10909 	    pushsplit(v,pos,unsigned(jt-Rbegin));
10910 	    ++jt;
10911 	    continue;
10912 	  }
10913 	}
10914 	for (;jt!=jtend;++jt){
10915 	  if (*jt==u){
10916 	    pushsplit(v,pos,int(jt-Rbegin));
10917 	    ++jt;
10918 	    break;
10919 	  }
10920 	}
10921       }
10922     }
10923     else {
10924       for (;it!=itend;++it){
10925 	const tdeg_t & u=expo[it->u];
10926 #ifdef GIAC_RHASH
10927 	int hashi=u.hash_index(Rhashptr);
10928 	if (hashi>=0){
10929 	  pushsplit(v,pos,hashi);
10930 	  ++jt;
10931 	  continue;
10932 	}
10933 #endif
10934 #if 1
10935 	if (dodicho && dicho(jt,jtend,u,p.order)){
10936 	  pushsplit(v,pos,unsigned(jt-Rbegin));
10937 	  ++jt;
10938 	  continue;
10939 	}
10940 #endif
10941 	for (;jt!=jtend;++jt){
10942 	  if (*jt==u){
10943 	    pushsplit(v,pos,int(jt-Rbegin));
10944 	    ++jt;
10945 	    break;
10946 	  }
10947 	}
10948       }
10949     }
10950   }
10951 
10952   template<class tdeg_t,class modint_t>
zmakeline(const zpolymod<tdeg_t> & p,const tdeg_t * shiftptr,const vector<tdeg_t> & R,vector<modint_t> & v,int start=0)10953   void zmakeline(const zpolymod<tdeg_t> & p,const tdeg_t * shiftptr,const vector<tdeg_t> & R,vector<modint_t> & v,int start=0){
10954     int Rs=int(R.size());
10955     // if (v.size()!=Rs) v.resize(Rs);
10956     // v.assign(Rs,0);
10957     std::vector<zmodint>::const_iterator it=p.coord.begin()+start,itend=p.coord.end();
10958     typename std::vector<tdeg_t>::const_iterator jt=R.begin(),jtbeg=jt,jtend=R.end();
10959     double nop1=double(R.size());
10960     double nop2=2*p.coord.size()*std::log(nop1)/std::log(2.0);
10961     bool dodicho=nop2<nop1;
10962     const std::vector<tdeg_t> & expo=*p.expo;
10963     if (shiftptr){
10964       tdeg_t u=R.front()+R.front(); // create u with refcount 1
10965       for (;it!=itend;++it){
10966 	add(expo[it->u],*shiftptr,u,p.dim);
10967 	if (dodicho && dicho(jt,jtend,u,p.order)){
10968 	  v[jt-jtbeg]=it->g;
10969 	  ++jt;
10970 	  continue;
10971 	}
10972 	for (;jt!=jtend;++jt){
10973 	  if (*jt==u){
10974 	    v[jt-jtbeg]=it->g;
10975 	    ++jt;
10976 	    break;
10977 	  }
10978 	}
10979       }
10980     }
10981     else {
10982       for (;it!=itend;++it){
10983 	const tdeg_t & u=expo[it->u];
10984 	if (dodicho && dicho(jt,jtend,u,p.order)){
10985 	  v[jt-jtbeg]=it->g;
10986 	  ++jt;
10987 	  continue;
10988 	}
10989 	for (;jt!=jtend;++jt){
10990 	  if (*jt==u){
10991 	    v[jt-jtbeg]=it->g;
10992 	    ++jt;
10993 	    break;
10994 	  }
10995 	}
10996       }
10997     }
10998   }
10999 
11000   template<class tdeg_t,class modint_t>
zmakelinesub(const zpolymod<tdeg_t> & p,const tdeg_t * leftshift,const zpolymod<tdeg_t> & q,const tdeg_t * rightshift,const vector<tdeg_t> & R,vector<modint_t> & v,int start,modint env)11001   void zmakelinesub(const zpolymod<tdeg_t> & p,const tdeg_t * leftshift,const zpolymod<tdeg_t> & q,const tdeg_t * rightshift,const vector<tdeg_t> & R,vector<modint_t> & v,int start,modint env){
11002     std::vector< zmodint >::const_iterator pt=p.coord.begin()+start,ptend=p.coord.end();
11003     std::vector< zmodint >::const_iterator qt=q.coord.begin()+start,qtend=q.coord.end();
11004     typename std::vector<tdeg_t>::const_iterator jt=R.begin(),jtbeg=jt,jtend=R.end();
11005     const std::vector<tdeg_t> & pexpo=*p.expo;
11006     const std::vector<tdeg_t> & qexpo=*q.expo;
11007     double nop1=double(R.size());
11008     double nop2=2*p.coord.size()*std::log(nop1)/std::log(2.0);
11009     bool dodicho=nop2<nop1;
11010     int dim=p.dim;
11011     order_t order=p.order;
11012     if (leftshift && rightshift){
11013       tdeg_t ul=R.front()+R.front();
11014       tdeg_t ur=R.front()+R.front();
11015       bool updatep=true,updateq=true;
11016       for (;pt!=ptend && qt!=qtend;){
11017 	if (updatep){
11018 	  add(pexpo[pt->u],*leftshift,ul,dim);
11019 	  updatep=false;
11020 	}
11021 	if (updateq){
11022 	  add(qexpo[qt->u],*rightshift,ur,dim);
11023 	  updateq=false;
11024 	}
11025 	if (tdeg_t_greater(ul,ur,order)){
11026 	  if (dodicho && dicho(jt,jtend,ul,order)){
11027 	    if (ul==ur){
11028 	      v[jt-jtbeg] = (pt->g-longlong(qt->g)); // %env;
11029 	      ++jt; ++pt; ++qt;
11030 	      updatep=updateq=true;
11031 	      continue;
11032 	    }
11033 	    v[jt-jtbeg] = pt->g;
11034 	    ++jt; ++pt;
11035 	    updatep=true;
11036 	    continue;
11037 	  }
11038 	  for (;jt!=jtend;++jt){
11039 	    if (*jt==ul){
11040 	      if (ul==ur){
11041 		v[jt-jtbeg] = (pt->g-longlong(qt->g)); // %env;
11042 		++jt; ++pt; ++qt;
11043 		updatep=updateq=true;
11044 	      }
11045 	      else {
11046 		v[jt-jtbeg] = pt->g;
11047 		++jt; ++pt;
11048 		updatep=true;
11049 	      }
11050 	      break;
11051 	    }
11052 	  }
11053 	  continue;
11054 	} // end if ul>=ur
11055 	if (dodicho && dicho(jt,jtend,ur,order)){
11056 	  v[jt-jtbeg] = -qt->g;
11057 	  ++jt; ++qt;
11058 	  updateq=true;
11059 	  continue;
11060 	}
11061 	for (;jt!=jtend;++jt){
11062 	  if (*jt==ur){
11063 	    v[jt-jtbeg] = -qt->g;
11064 	    ++jt; ++qt;
11065 	    updateq=true;
11066 	    break;
11067 	  }
11068 	}
11069       } // for (pt!=ptend && qt!=qtend)
11070       for (;pt!=ptend;){
11071 	add(pexpo[pt->u],*leftshift,ul,dim);
11072 	if (dodicho && dicho(jt,jtend,ul,order)){
11073 	  v[jt-jtbeg] = pt->g;
11074 	  ++jt; ++pt;
11075 	  continue;
11076 	}
11077 	for (;jt!=jtend;++jt){
11078 	  if (*jt==ul){
11079 	    v[jt-jtbeg] = pt->g;
11080 	    ++jt; ++pt;
11081 	    break;
11082 	  }
11083 	}
11084       }
11085       for (;qt!=qtend;){
11086 	add(qexpo[qt->u],*rightshift,ur,dim);
11087 	if (dodicho && dicho(jt,jtend,ur,order)){
11088 	  v[jt-jtbeg] = -qt->g;
11089 	  ++jt; ++qt;
11090 	  continue;
11091 	}
11092 	for (;jt!=jtend;++jt){
11093 	  if (*jt==ur){
11094 	    v[jt-jtbeg] = -qt->g;
11095 	    ++jt; ++qt;
11096 	    break;
11097 	  }
11098 	}
11099       }
11100     }
11101   }
11102 
11103   template<class tdeg_t,class modint_t>
zmakelinesub(const zpolymod<tdeg_t> & p,const tdeg_t * shiftptr,const vector<tdeg_t> & R,vector<modint_t> & v,int start,modint env)11104   void zmakelinesub(const zpolymod<tdeg_t> & p,const tdeg_t * shiftptr,const vector<tdeg_t> & R,vector<modint_t> & v,int start,modint env){
11105     std::vector< zmodint >::const_iterator it=p.coord.begin()+start,itend=p.coord.end();
11106     typename std::vector<tdeg_t>::const_iterator jt=R.begin(),jtbeg=jt,jtend=R.end();
11107     const std::vector<tdeg_t> & expo=*p.expo;
11108     double nop1=double(R.size());
11109     double nop2=2*p.coord.size()*std::log(nop1)/std::log(2.0);
11110     bool dodicho=nop2<nop1;
11111     if (shiftptr){
11112       tdeg_t u=R.front()+R.front();
11113       for (;it!=itend;++it){
11114 	add(expo[it->u],*shiftptr,u,p.dim);
11115 	if (dodicho && dicho(jt,jtend,u,p.order)){
11116 #if 1
11117 	  v[jt-jtbeg] -= it->g;
11118 #else
11119 	  modint_t & vv=v[jt-jtbeg];
11120 	  if (vv)
11121 	    vv = (vv-longlong(it->g))%env;
11122 	  else
11123 	    vv=-it->g;
11124 #endif
11125 	  ++jt;
11126 	  continue;
11127 	}
11128 	for (;jt!=jtend;++jt){
11129 	  if (*jt==u){
11130 #if 1
11131 	    v[jt-jtbeg] -= it->g;
11132 #else
11133 	    modint_t & vv=v[jt-jtbeg];
11134 	    if (vv)
11135 	      vv = (vv-longlong(it->g));//%env;
11136 	    else
11137 	      vv = -it->g;
11138 #endif
11139 	    ++jt;
11140 	    break;
11141 	  }
11142 	}
11143       }
11144     }
11145     else {
11146       for (;it!=itend;++it){
11147 	const tdeg_t & u=expo[it->u];
11148 	if (dodicho && dicho(jt,jtend,u,p.order)){
11149 #if 1
11150 	  v[jt-jtbeg] -= it->g;
11151 #else
11152 	  modint_t & vv=v[jt-jtbeg];
11153 	  vv = (vv-longlong(it->g))%env;
11154 #endif
11155 	  ++jt;
11156 	  continue;
11157 	}
11158 	for (;jt!=jtend;++jt){
11159 	  if (*jt==u){
11160 #if 1
11161 	    v[jt-jtbeg]-=it->g;
11162 #else
11163 	    modint_t & vv=v[jt-jtbeg];
11164 	    vv = (vv-longlong(it->g))%env;
11165 #endif
11166 	    ++jt;
11167 	    break;
11168 	  }
11169 	}
11170       }
11171     }
11172   }
11173 
11174 template<class modint_t,class modint_u>
zsub(vector<modint_t> & v64,const vector<modint_u> & subcoeff,const vector<shifttype> & subindex)11175   void zsub(vector<modint_t> & v64,const vector<modint_u> & subcoeff,const vector<shifttype> & subindex){
11176     if (subcoeff.empty()) return;
11177     typename vector<modint_t>::iterator wt=v64.begin();
11178     const modint_u * jt=&subcoeff.front(),*jtend=jt+subcoeff.size(),*jt_=jtend-8;
11179     const shifttype * it=&subindex.front();
11180     // first shift
11181     unsigned pos=0; next_index(pos,it); wt += pos;
11182     *wt -= (*jt); ++jt;
11183     bool shortshifts=v64.size()<0xffff?true:checkshortshifts(subindex);
11184 #ifdef GIAC_SHORTSHIFTTYPE
11185     if (shortshifts){
11186       for (;jt!=jtend;++jt){
11187 	wt += *it; ++it;
11188 	*wt -= (*jt);
11189       }
11190     }
11191     else {
11192       for (;jt!=jtend;++jt){
11193 	next_index(wt,it);
11194 	*wt -= (*jt);
11195       }
11196     }
11197 #else // def GIAC_SHORTSHIFTTYPE
11198     for (;jt!=jtend;++jt){
11199       v64[*it] -= (*jt);
11200       ++it; ++jt;
11201     }
11202 #endif // def GIAC_SHORTSHIFTTYPE
11203   }
11204 
11205 
zadd(vector<modint2> & v64,const vector<modint> & subcoeff,const vector<shifttype> & subindex)11206   void zadd(vector<modint2> & v64,const vector<modint> & subcoeff,const vector<shifttype> & subindex){
11207     if (subcoeff.empty()) return;
11208     vector<modint2>::iterator wt=v64.begin();
11209     const modint * jt=&subcoeff.front(),*jtend=jt+subcoeff.size();
11210     const shifttype * it=&subindex.front();
11211     // first shift
11212     unsigned pos=0; next_index(pos,it); wt += pos;
11213     *wt += (*jt); ++jt;
11214     bool shortshifts=v64.size()<0xffff?true:checkshortshifts(subindex);
11215 #ifdef GIAC_SHORTSHIFTTYPE
11216     if (shortshifts){
11217       for (;jt!=jtend;++jt){
11218 	wt += *it; ++it;
11219 	*wt += (*jt);
11220       }
11221     }
11222     else {
11223       for (;jt!=jtend;++jt){
11224 	next_index(wt,it);
11225 	*wt += (*jt);
11226       }
11227     }
11228 #else // def GIAC_SHORTSHIFTTYPE
11229     for (;jt!=jtend;++jt){
11230       v64[*it] += (*jt);
11231       ++it; ++jt;
11232     }
11233 #endif // def GIAC_SHORTSHIFTTYPE
11234   }
11235 
makepositive(modint a,modint n)11236   inline modint makepositive(modint a,modint n){
11237     return a-(a>>31)*n; // return a<0?a+n:a;
11238   }
11239 
11240   template<class tdeg_t,class modint_t>
zadd(vector<modint_t> & v64,const zpolymod<tdeg_t> & subcoeff,const vector<shifttype> & subindex,int start,modint env)11241   void zadd(vector<modint_t> & v64,const zpolymod<tdeg_t> & subcoeff,const vector<shifttype> & subindex,int start,modint env){
11242     if (subcoeff.coord.size()<=start) return;
11243     typename vector<modint_t>::iterator wt=v64.begin();
11244     const zmodint * jt=&subcoeff.coord.front(),*jtend=jt+subcoeff.coord.size();
11245     jt += start;
11246     const shifttype * it=&subindex.front();
11247     // first shift
11248     unsigned pos=0; next_index(pos,it); wt += pos;
11249     *wt = makepositive(jt->g,env); ++jt;
11250     bool shortshifts=v64.size()<0xffff?true:checkshortshifts(subindex);
11251 #ifdef GIAC_SHORTSHIFTTYPE
11252     if (shortshifts){
11253       for (;jt!=jtend;++jt){
11254 	wt += *it; ++it;
11255 	*wt = makepositive(jt->g,env);
11256       }
11257     }
11258     else {
11259       for (;jt!=jtend;++jt){
11260 	next_index(wt,it);
11261 	*wt = makepositive(jt->g,env);
11262       }
11263     }
11264 #else // def GIAC_SHORTSHIFTTYPE
11265     for (;jt!=jtend;++jt){
11266       v64[*it] = makepositive(jt->g,env);
11267       ++it; ++jt;
11268     }
11269 #endif // def GIAC_SHORTSHIFTTYPE
11270   }
11271 
11272   template<class tdeg_t>
zcollect_interreduce(const vectzpolymod<tdeg_t> & res,const vector<unsigned> & G,vector<tdeg_t> & allf4buchberger,int start)11273   void zcollect_interreduce(const vectzpolymod<tdeg_t> & res,const vector< unsigned > & G,vector<tdeg_t> & allf4buchberger,int start){
11274     vector< heap_tt<tdeg_t> > Ht;
11275     heap_tt<tdeg_t> heap_elem;
11276     vector< heap_tt_ptr<tdeg_t> > H;
11277     Ht.reserve(2*G.size()+1);
11278     H.reserve(2*G.size());
11279     unsigned s=0;
11280     order_t keyorder={_REVLEX_ORDER,0};
11281     for (unsigned i=0;i<G.size();++i){
11282       const zpolymod<tdeg_t> & p=res[G[i]];
11283       keyorder=p.order;
11284       if (int(p.coord.size())>start){
11285 	s = giacmax(s, unsigned(p.coord.size()));
11286 	Ht.push_back(heap_tt<tdeg_t>(true,i,start,(*p.expo)[p.coord[start].u]));
11287 	H.push_back(heap_tt_ptr<tdeg_t>(&Ht.back()));
11288       }
11289     }
11290     allf4buchberger.reserve(s); // int(s*std::log(1+H.size())));
11291     compare_heap_tt_ptr<tdeg_t> key(keyorder);
11292     make_heap(H.begin(),H.end(),key);
11293     while (!H.empty()){
11294       // push root node of the heap in allf4buchberger
11295       heap_tt<tdeg_t> & current = *H.front().ptr;
11296       if (allf4buchberger.empty() || allf4buchberger.back()!=current.u)
11297 	allf4buchberger.push_back(current.u);
11298       ++current.polymodpos;
11299       unsigned vpos;
11300       vpos=G[current.f4buchbergervpos];
11301       if (current.polymodpos>=res[vpos].coord.size()){
11302 	std::pop_heap(H.begin(),H.end(),key);
11303 	H.pop_back();
11304 	continue;
11305       }
11306       const zpolymod<tdeg_t> & resvpos=res[vpos];
11307       current.u=(*resvpos.expo)[resvpos.coord[current.polymodpos].u];
11308       // push_back &current into heap so that pop_heap will bubble out the
11309       // modified root node (initialization will exchange two identical pointers)
11310       H.push_back(heap_tt_ptr<tdeg_t>(&current));
11311       std::pop_heap(H.begin(),H.end(),key);
11312       H.pop_back();
11313     }
11314   }
11315 
11316   template<class tdeg_t>
11317   int zf4mod(vectzpolymod<tdeg_t> & res,const vector<unsigned> & G,modint env,const vector< paire > & B,const vector<unsigned> * & permuBptr,vectzpolymod<tdeg_t> & f4buchbergerv,bool learning,unsigned & learned_position,vector< paire > * pairs_reducing_to_zero,vector<zinfo_t<tdeg_t> > & f4buchberger_info,unsigned & f4buchberger_info_position,bool recomputeR,int age,bool multimodular,int parallel,bool interreduce);
11318 
11319   template<class tdeg_t>
zinterreduce_convert(vectzpolymod<tdeg_t> & res,vector<unsigned> & G,int env,bool learning,unsigned & learned_position,vector<paire> * pairs_reducing_to_zero,vector<zinfo_t<tdeg_t>> & f4buchberger_info,unsigned & f4buchberger_info_position,bool recomputeR,int age,bool multimodular,int parallel,vectpolymod<tdeg_t> & resmod,bool interred)11320   int zinterreduce_convert(vectzpolymod<tdeg_t> & res,vector< unsigned > & G,int env,bool learning,unsigned & learned_position,vector< paire > * pairs_reducing_to_zero,vector<zinfo_t<tdeg_t> > & f4buchberger_info,unsigned & f4buchberger_info_position,bool recomputeR,int age,bool multimodular,int parallel,vectpolymod<tdeg_t> & resmod,bool interred){
11321     if (!interred)
11322       return 12345;
11323     if (res.empty()){ resmod.clear(); return 0; }
11324     order_t order=res.front().order;
11325     int dim=res.front().dim;
11326     unsigned Gs=G.size();
11327     // if (parallel<2 || Gs<200 || !threads_allowed ) return -1; // or fix in computeK1 non parallel case
11328     vector<paire> B; // not used
11329     const vector<unsigned> * permuBptr=0; // not used
11330     vectzpolymod<tdeg_t> f4buchbergerv;
11331     int tmp=zf4mod(res,G,env,B,permuBptr,f4buchbergerv,learning,learned_position,pairs_reducing_to_zero,f4buchberger_info,f4buchberger_info_position,recomputeR,age,multimodular,parallel,true);
11332     //CERR << "interreduce " << tmp << '\n';
11333     if (tmp<0 || tmp==12345)
11334       return tmp;
11335     // build resmod from res leading monomial of res and f4buchbergerv
11336     ulonglong tot=0;
11337     for (unsigned i=0;i<Gs;++i)
11338       tot += f4buchbergerv[i].coord.size();
11339     // if (tot==0) return -1;
11340     for (unsigned i=0;i<Gs;++i){
11341       polymod<tdeg_t> & q=resmod[G[i]];
11342       zpolymod<tdeg_t> & p=f4buchbergerv[i];
11343       const vector<tdeg_t> & expo=*p.expo;
11344       q.dim=res[G[i]].dim;
11345       q.order=res[G[i]].order;
11346       q.fromleft=res[G[i]].fromleft;
11347       q.fromright=res[G[i]].fromright;
11348       q.age=res[G[i]].age;
11349       q.logz=res[G[i]].logz;
11350       q.coord.clear();
11351       q.coord.reserve(1+p.coord.size());
11352       if (res[G[i]].coord.empty())
11353 	return -1;
11354       q.coord.push_back(T_unsigned<modint,tdeg_t>(res[G[i]].coord[0].g,(*res[G[i]].expo)[res[G[i]].coord[0].u]));
11355       for (unsigned j=0;j<p.coord.size();++j){
11356 	modint g=p.coord[j].g;
11357 	// g=(modint2(g)*coeff)%env;
11358 	q.coord.push_back(T_unsigned<modint,tdeg_t>(g,expo[p.coord[j].u]));
11359       }
11360     }
11361     return 0;
11362   }
11363 
11364   template<class tdeg_t>
Rtorem(const vector<tdeg_t> & R,const vector<tdeg_t> & rem,vector<unsigned> & v)11365   void Rtorem(const vector<tdeg_t> & R,const vector<tdeg_t> & rem,vector<unsigned> & v){
11366     v.resize(R.size());
11367     typename vector<tdeg_t>::const_iterator it=R.begin(),itend=R.end(),jt=rem.begin(),jt0=jt,jtend=rem.end();
11368     vector<unsigned>::iterator vt=v.begin();
11369     for (;jt!=jtend;++jt){
11370       const tdeg_t & t=*jt;
11371       for (;it!=itend;++vt,++it){
11372 	if (*it==t)
11373 	  break;
11374       }
11375       *vt=hashgcd_U(jt-jt0);
11376     }
11377   }
11378 
11379   template <class tdeg_t>
11380   struct thread_buchberger_t {
11381     const vectzpolymod<tdeg_t> * resptr;
11382     vector< vector< modint> > * Kptr;
11383     const vector<unsigned> * G;
11384     const vector< paire > * Bptr;
11385     const vector<unsigned> * permuBptr;
11386     const vector<tdeg_t> *leftshiftptr,*rightshiftptr,*Rptr;
11387     void * Rhashptr;
11388     const vector<int> * Rdegposptr;
11389     int env,debut,fin,N,colonnes;
11390     const vector<unsigned> * firstposptr;
11391     const vector<vector<unsigned short> > * Mindexptr;
11392     const vector< vector<modint> > * Mcoeffptr;
11393     const vector<coeffindex_t> * coeffindexptr;
11394     vector< vector<shifttype> > * indexesptr;
11395     vector<used_t> * usedptr;
11396     unsigned * bitmap;
11397     bool displayinfo;
11398     bool learning;
11399     bool interreduce;
11400     const vector<paire> * pairs_reducing_to_zero; // read-only!
11401     int learned_position;
11402   };
11403 
11404   template <class tdeg_t>
thread_buchberger(void * ptr_)11405   void * thread_buchberger(void * ptr_){
11406     thread_buchberger_t<tdeg_t> * ptr=(thread_buchberger_t<tdeg_t> *) ptr_;
11407     const vectzpolymod<tdeg_t> & res=*ptr->resptr;
11408     vector< vector<modint> > & K =*ptr->Kptr;
11409     const vector< paire > & B = *ptr->Bptr;
11410     const vector<unsigned> & G = *ptr->G;
11411     const vector<unsigned> & permuB = *ptr->permuBptr;
11412     const vector<tdeg_t> & leftshift=*ptr->leftshiftptr;
11413     const vector<tdeg_t> & rightshift=*ptr->rightshiftptr;
11414     const vector<tdeg_t> & R=*ptr->Rptr;
11415     void * Rhashptr=ptr->Rhashptr;
11416     const vector<int> & Rdegpos=*ptr->Rdegposptr;
11417     int env=ptr->env,debut=ptr->debut,fin=ptr->fin,N=ptr->N;
11418     const vector<unsigned> & firstpos=*ptr->firstposptr;
11419     int & colonnes=ptr->colonnes;
11420     const vector<vector<unsigned short> > &Mindex = *ptr->Mindexptr;
11421     const vector< vector<modint> > &Mcoeff = *ptr->Mcoeffptr;
11422     const vector<coeffindex_t> &coeffindex = *ptr->coeffindexptr;
11423     vector< vector<shifttype> > & indexes=*ptr->indexesptr;
11424     vector<used_t> & used = *ptr->usedptr;
11425     bool learning=ptr->learning;
11426     bool interreduce=ptr->interreduce;
11427     int pos=ptr->learned_position;
11428     const vector<paire> * pairs_reducing_to_zero=ptr->pairs_reducing_to_zero;
11429     bool displayinfo=ptr->displayinfo;
11430     unsigned * bitmap=ptr->bitmap+debut*((N>>5)+1);
11431     vector<modint2> v64(N);
11432     unsigned bk_prev=-1;
11433     const tdeg_t * rightshift_prev =0;
11434     vector<modint> subcoeff2;
11435     int effi=-1,Bs=int(B.size());
11436     if (interreduce){
11437       // tdeg_t nullshift(res[G[0]].dim);
11438       for (int i=debut;i<fin;++i){
11439 	if (interrupted || ctrl_c)
11440 	  return 0;
11441 	zmakelinesplit(res[G[i]],(const tdeg_t *) 0,R,Rhashptr,Rdegpos,indexes[i],0,1);
11442 	zadd(v64,res[G[i]],indexes[i],1,env);
11443 	K[i].clear();
11444 	int firstcol=indexes[i].empty()?0:indexes[i].front();
11445 	colonnes=giacmin(colonnes,reducef4buchbergersplit(v64,Mindex,firstpos,firstcol,Mcoeff,coeffindex,K[i],bitmap,used,env));
11446 	bitmap += (N>>5)+1;
11447       }
11448       return ptr_;
11449     }
11450     for (int i=debut;i<fin;++i){
11451       if (interrupted || ctrl_c)
11452 	return 0;
11453       paire bk=B[permuB[i]];
11454       if (!learning && pairs_reducing_to_zero && pos<pairs_reducing_to_zero->size() && bk==(*pairs_reducing_to_zero)[pos]){
11455 	++pos;
11456 	continue;
11457       }
11458       // no learning with parallel
11459       zmakelinesplit(res[bk.first],&leftshift[permuB[i]],R,Rhashptr,Rdegpos,indexes[i],0,1);
11460       if (bk_prev!=bk.second || !rightshift_prev || *rightshift_prev!=rightshift[permuB[i]]){
11461 	zmakelinesplit(res[bk.second],&rightshift[permuB[i]],R,Rhashptr,Rdegpos,indexes[Bs+i],0,1);
11462 	bk_prev=bk.second;
11463 	rightshift_prev=&rightshift[permuB[i]];
11464       }
11465     }
11466     bk_prev=-1; rightshift_prev=0;
11467     pos=ptr->learned_position;
11468     for (int i=debut;i<fin;++i){
11469       if (interrupted || ctrl_c)
11470 	return 0;
11471       if (displayinfo){
11472 	if (i%10==9) {COUT << "+"; COUT.flush(); }
11473 	if (i%500==499) COUT << " " << CLOCK()*1e-6 << " remaining " << fin-i << '\n';
11474       }
11475       paire bk=B[permuB[i]];
11476       if (!learning && pairs_reducing_to_zero && pos<pairs_reducing_to_zero->size() && bk==(*pairs_reducing_to_zero)[pos]){
11477 	++pos;
11478 	unsigned tofill=(N>>5)+1;
11479 	fill(bitmap,bitmap+tofill,0);
11480 	bitmap += tofill;
11481 	continue;
11482       }
11483       if (bk.second!=bk_prev || !rightshift_prev || *rightshift_prev!=rightshift[permuB[i]]){
11484 	subcoeff2.clear();
11485 	zcopycoeff(res[bk.second],subcoeff2,1);
11486 	bk_prev=bk.second;
11487 	rightshift_prev=&rightshift[permuB[i]];
11488       }
11489       // zcopycoeff(res[bk.first],subcoeff1,1);zadd(v64,subcoeff1,indexes[i]);
11490       zadd(v64,res[bk.first],indexes[i],1,env);
11491       effi=Bs+i;
11492       while (indexes[effi].empty() && effi)
11493 	--effi;
11494       zsub(v64,subcoeff2,indexes[effi]);
11495       int firstcol=indexes[i].empty()?0:indexes[i].front();
11496       if (effi>=0 && !indexes[effi].empty())
11497 	firstcol=giacmin(firstcol,indexes[effi].front());
11498       K[i].clear();
11499       colonnes=giacmin(colonnes,reducef4buchbergersplit(v64,Mindex,firstpos,firstcol,Mcoeff,coeffindex,K[i],bitmap,used,env));
11500       bitmap += (N>>5)+1;
11501     }
11502     return ptr_;
11503   }
11504 
11505   template<class tdeg_t>
11506   struct pair_compare {
11507     const vector< paire > * Bptr;
11508     const vectzpolymod<tdeg_t> * resptr ;
11509     const vector<tdeg_t> * leftshiftptr;
11510     const vector<tdeg_t> * rightshiftptr;
11511     order_t o;
operator ()giac::pair_compare11512     inline bool operator ()(unsigned a,unsigned b){
11513       unsigned Ba=(*Bptr)[a].second,Bb=(*Bptr)[b].second;
11514       const tdeg_t & adeg=(*resptr)[Ba].ldeg;
11515       const tdeg_t & bdeg=(*resptr)[Bb].ldeg;
11516       if (adeg!=bdeg)
11517 	return tdeg_t_greater(bdeg,adeg,o)!=0; // return tdeg_t_greater(adeg,bdeg,o);
11518       const tdeg_t & aleft=(*rightshiftptr)[a];
11519       const tdeg_t & bleft=(*rightshiftptr)[b];
11520       return tdeg_t_strictly_greater(bleft,aleft,o);// return tdeg_t_strictly_greater(aleft,bleft,o);
11521     }
pair_comparegiac::pair_compare11522     pair_compare(const vector< paire > * Bptr_,
11523 		 const vectzpolymod<tdeg_t> * resptr_ ,
11524 		 const vector<tdeg_t> * leftshiftptr_,
11525 		 const vector<tdeg_t> * rightshiftptr_,
11526 		 const order_t & o_):Bptr(Bptr_),resptr(resptr_),rightshiftptr(rightshiftptr_),leftshiftptr(leftshiftptr_),o(o_){}
11527   };
11528 
memory_usage()11529   longlong memory_usage(){
11530 #if defined HAVE_SYS_RESOURCE_H && !defined NSPIRE && !defined NSPIRE_NEWLIB
11531     struct rusage r_usage;
11532     getrusage(RUSAGE_SELF,&r_usage);
11533 #ifdef __APPLE__
11534     return r_usage.ru_maxrss;
11535 #else
11536     return r_usage.ru_maxrss*1000;
11537 #endif
11538 #endif
11539     return -1;
11540   }
11541 
11542    // #define GIAC_CACHE2ND 1; // cache 2nd pair reduction, slower
11543 
11544   template<class tdeg_t>
zf4computeK1(const unsigned N,const unsigned nrows,const double mem,const unsigned Bs,vectzpolymod<tdeg_t> & res,const vector<unsigned> & G,modint env,const vector<paire> & B,const vector<unsigned> & permuB,bool learning,unsigned & learned_position,vector<paire> * pairs_reducing_to_zero,const vector<tdeg_t> & leftshift,const vector<tdeg_t> & rightshift,const vector<tdeg_t> & R,void * Rhashptr,const vector<int> & Rdegpos,const vector<unsigned> & firstpos,vector<vector<unsigned short>> & Mindex,const vector<coeffindex_t> & coeffindex,vector<vector<modint>> & Mcoeff,zinfo_t<tdeg_t> * info_ptr,vector<used_t> & used,unsigned & usedcount,unsigned * bitmap,vector<vector<modint>> & K,int parallel,bool interreduce)11545   int zf4computeK1(const unsigned N,const unsigned nrows,const double mem,const unsigned Bs,vectzpolymod<tdeg_t> & res,const vector<unsigned> & G,modint env,const vector< paire > & B,const vector<unsigned> & permuB,bool learning,unsigned & learned_position,vector< paire > * pairs_reducing_to_zero,const vector<tdeg_t> & leftshift,const vector<tdeg_t> & rightshift, const vector<tdeg_t> & R ,void * Rhashptr,const vector<int> & Rdegpos,const vector<unsigned> &firstpos,vector<vector<unsigned short> > & Mindex, const vector<coeffindex_t> & coeffindex,vector< vector<modint> > & Mcoeff,zinfo_t<tdeg_t> * info_ptr,vector<used_t> &used,unsigned & usedcount,unsigned * bitmap,vector< vector<modint> > & K,int parallel,bool interreduce){
11546     bool freemem=mem>4e7; // should depend on real memory available
11547     bool large=N>8000;
11548     // CERR << "after sort " << Mindex << '\n';
11549     // step3 reduce
11550     unsigned colonnes=N;
11551     vector<modint> v(N);
11552     vector<modint2> v64(N);
11553     vector<double> v64d(N);
11554 #ifdef x86_64
11555     vector<int128_t> v128;
11556     if (!large)
11557       v128.resize(N);
11558 #endif
11559     unsigned Kcols=N-nrows;
11560     unsigned Ksizes=Kcols;
11561     if (info_ptr && !learning)
11562       Ksizes=giacmin(info_ptr->Ksizes+3,Kcols);
11563     bool Kdone=false;
11564     int th=parallel-1; // giacmin(threads,64)-1;
11565 #ifdef GIAC_CACHE2ND
11566     vector<modint2> subcoeff2;
11567 #else
11568     vector<modint> subcoeff2;
11569 #endif
11570     vector< vector<shifttype> > indexes(2*Bs);
11571 #ifdef HAVE_LIBPTHREAD
11572     if (Bs>=200 && threads_allowed && parallel>1
11573 	//&& (learning || !pairs_reducing_to_zero)
11574 	/*parallel*/){
11575       vector<int> positions(1),learned_parallel(1);
11576       if (interreduce){
11577 	for (unsigned i=0;i<Bs;++i){
11578 	  indexes[i].reserve(res[G[i]].coord.size()+16);
11579 	  K[i].reserve(Ksizes);
11580 	}
11581 	for (int i=1;i<parallel;++i){
11582 	  positions.push_back((i*longlong(Bs))/parallel);
11583 	}
11584 	positions.push_back(Bs);
11585 	learned_parallel=positions; // not used
11586       }
11587       else {
11588 	// prepare memory and positions
11589 	int pos=learned_position;
11590 	for (unsigned i=0;i<Bs;++i){
11591 	  if (pairs_reducing_to_zero && !learning && (*pairs_reducing_to_zero)[learned_position]==B[permuB[i]]){
11592 	    ++learned_position;
11593 	    continue;
11594 	  }
11595 	}
11596 	// effective number of pairs to reduce is Bs-(learned_position-pos)
11597 	int effBs=Bs-(learned_position-pos),effstep=effBs/parallel+1,effi=0,effend=effstep;
11598 	learned_parallel[0]=pos;
11599 	// scan again pairs to set end positions and learned_position
11600 	for (unsigned i=0;i<Bs;++i){
11601 	  if (pairs_reducing_to_zero && !learning && (*pairs_reducing_to_zero)[pos]==B[permuB[i]]){
11602 	    ++pos;
11603 	    continue;
11604 	  }
11605 	  indexes[i].reserve(res[B[permuB[i]].first].coord.size()+16);
11606 	  indexes[Bs+i].reserve(res[B[permuB[i]].second].coord.size()+16);
11607 	  K[i].reserve(Ksizes);
11608 	  ++effi;
11609 	  if (effi>=effend){
11610 	    positions.push_back(i); // end position for this thread
11611 	    learned_parallel.push_back(pos); // learned position for next thread
11612 	    effend += effstep;
11613 	  }
11614 	}
11615 	// fix last pair number
11616 	while (positions.size()<parallel)
11617 	  positions.push_back(Bs);
11618 	while (learned_parallel.size()<parallel)
11619 	  learned_parallel.push_back(pos);
11620 	if (positions.size()<parallel || learned_parallel.size()<parallel){
11621 	  COUT << "BUG " << parallel << " " << positions.size() << " " << learned_parallel.size() << '\n' << positions << '\n' << learned_parallel << '\n';
11622 	}
11623 	if (positions.size()==parallel)
11624 	  positions.push_back(Bs);
11625 	else
11626 	  positions.back()=Bs;
11627       } // end else interreduce
11628       pthread_t tab[64];
11629       thread_buchberger_t<tdeg_t> buchberger_param[64];
11630       int colonnes=N;
11631       for (int j=0;j<=th;++j){
11632 	thread_buchberger_t<tdeg_t> tmp={&res,&K,&G,&B,&permuB,&leftshift,&rightshift,&R,Rhashptr,&Rdegpos,env,positions[j],positions[j+1],int(N),int(Kcols),&firstpos,&Mindex,&Mcoeff,&coeffindex,&indexes,&used,bitmap,j==th && debug_infolevel>1,learning,interreduce,pairs_reducing_to_zero,learned_parallel[j]};
11633 	buchberger_param[j]=tmp;
11634 	bool res=true;
11635 	// CERR << "write " << j << " " << p << '\n';
11636 	if (j<th)
11637 	  res=pthread_create(&tab[j],(pthread_attr_t *) NULL,thread_buchberger<tdeg_t>,(void *) &buchberger_param[j]);
11638 	if (res)
11639 	  thread_buchberger<tdeg_t>((void *)&buchberger_param[j]);
11640       }
11641       Kdone=true;
11642       colonnes=buchberger_param[th].colonnes;
11643       for (unsigned j=0;j<th;++j){
11644 	void * ptr_=(void *)&th; // non-zero initialisation
11645 	pthread_join(tab[j],&ptr_);
11646 	if (!ptr_)
11647 	  Kdone=false;
11648 	thread_buchberger_t<tdeg_t> * ptr = (thread_buchberger_t<tdeg_t> *) ptr_;
11649 	colonnes=giacmin(colonnes,ptr->colonnes);
11650       }
11651     } // end parallelization
11652 #endif
11653     if (!Kdone){
11654       if (interreduce){
11655 	for (unsigned i=0;i<Bs;++i){
11656 	  indexes[i].reserve(res[G[i]].coord.size()+16);
11657 	  K[i].reserve(Ksizes);
11658 	}
11659 	thread_buchberger_t<tdeg_t> tmp={&res,&K,&G,&B,&permuB,&leftshift,&rightshift,&R,Rhashptr,&Rdegpos,env,0,(int)Bs,int(N),int(Kcols),&firstpos,&Mindex,&Mcoeff,&coeffindex,&indexes,&used,bitmap,debug_infolevel>1,learning,interreduce,pairs_reducing_to_zero,0};
11660 	thread_buchberger<tdeg_t>((void *)&tmp);
11661 	return 0;
11662       }
11663       unsigned bk_prev=-1;
11664       const tdeg_t * rightshift_prev=0;
11665       int pos=learned_position;
11666       for (unsigned i=0;i<Bs;i++){
11667 	if (interrupted || ctrl_c)
11668 	  return -1;
11669 	paire bk=B[permuB[i]];
11670 	if (!learning && pairs_reducing_to_zero && pos<pairs_reducing_to_zero->size() && bk==(*pairs_reducing_to_zero)[pos]){
11671 	  ++pos;
11672 	  continue;
11673 	}
11674 	bool done=false;
11675 	const tdeg_t & curleft=leftshift[permuB[i]];
11676 #ifdef GIAC_MAKELINECACHE // does not seem faster
11677 	pair<int,int> ij=zmakelinecache[bk.first];
11678 	if (ij.first!=-1){
11679 	  // look in quo[ij.first] if leftshift[permuB[i]] is there, if true copy from Mindex
11680 	  // except first index
11681 	  typename std::vector<tdeg_t>::const_iterator cache_it=quo[ij.first].begin(),cache_end=quo[ij.first].end();
11682 	  if (cache_it<cache_end && !dicho(cache_it,cache_end,curleft,order)){
11683 	    if (cache_end-cache_it>5)
11684 	      cache_it=cache_end;
11685 	    else {
11686 	      for (;cache_it<cache_end;++cache_it){
11687 		if (*cache_it==curleft)
11688 		  break;
11689 	      }
11690 	    }
11691 	  }
11692 	  if (cache_it<cache_end){
11693 	    if (debug_infolevel>2)
11694 	      CERR << "cached " << ij << '\n';
11695 	    int pos=ij.second+cache_it-quo[ij.first].begin();
11696 	    pos=permuM[pos];
11697 	    vector<shifttype> & source=Mindex[pos];
11698 	    vector<shifttype> & target=indexes[i];
11699 	    target.reserve(source.size());
11700 	    unsigned sourcepos=0,targetpos=0;
11701 	    const shifttype * sourceptr=&source.front(),*sourceend=sourceptr+source.size();
11702 	    next_index(sourcepos,sourceptr); // skip position 0
11703 	    next_index(sourcepos,sourceptr);
11704 	    pushsplit(target,targetpos,sourcepos);
11705 	    for (;sourceptr<sourceend;++sourceptr){
11706 	      target.push_back(*sourceptr);
11707 	    }
11708 	    //CERR << Mindex << '\n' << target << '\n';
11709 	    done=true;
11710 	  }
11711 	}
11712 #endif // GIAC_MAKELINECACHE
11713 	if (!done){
11714 	  indexes[i].reserve(res[bk.first].coord.size()+16);
11715 	  zmakelinesplit(res[bk.first],&curleft,R,Rhashptr,Rdegpos,indexes[i],0,1);
11716 	  //CERR << indexes[i] << '\n';
11717 	}
11718 	if (bk_prev!=bk.second || !rightshift_prev || *rightshift_prev!=rightshift[permuB[i]]){
11719 	  indexes[Bs+i].reserve(res[bk.second].coord.size()+16);
11720 	  zmakelinesplit(res[bk.second],&rightshift[permuB[i]],R,Rhashptr,Rdegpos,indexes[Bs+i],0,1);
11721 	  bk_prev=bk.second;
11722 	  rightshift_prev=&rightshift[permuB[i]];
11723 	}
11724       } // end for (unsigned i=0;i<Bs;++i)
11725       if (debug_infolevel>1)
11726 	CERR << CLOCK()*1e-6 << " pairs indexes computed over " << R.size() << " monomials"<<'\n';
11727       bk_prev=-1; rightshift_prev=0;
11728       vector<modint> Ki; Ki.reserve(Ksizes);
11729       int effi=-1;
11730       for (unsigned i=0;i<Bs;++i){
11731 	if (interrupted || ctrl_c)
11732 	  return -1;
11733 	if (debug_infolevel>1){
11734 	  if (i%10==9) {COUT << "+"; COUT.flush(); }
11735 	  if (i%500==499) COUT << " " << CLOCK()*1e-6 << " remaining " << Bs-i << '\n';
11736 	}
11737 	paire bk=B[permuB[i]];
11738 	if (!learning && pairs_reducing_to_zero && learned_position<pairs_reducing_to_zero->size() && bk==(*pairs_reducing_to_zero)[learned_position]){
11739 	  if (debug_infolevel>2)
11740 	    CERR << bk << " f4buchberger learned " << learned_position << '\n';
11741 	  ++learned_position;
11742 	  unsigned tofill=(N>>5)+1;
11743 	  fill(bitmap,bitmap+tofill,0);
11744 	  bitmap += tofill;
11745 	  continue;
11746 	}
11747 	// zmakelinesub(res[bk.first],&leftshift[i],res[bk.second],&rightshift[i],R,v,1,env);
11748 	// CERR << bk.first << " " << leftshift[i] << '\n';
11749 	// v64.assign(N,0); // + reset v64 to 0, already done by zconvert_
11750 	if (bk.second!=bk_prev || !rightshift_prev || *rightshift_prev!=rightshift[permuB[i]]){
11751 	  subcoeff2.clear();
11752 #ifdef GIAC_CACHE2ND
11753 	  subcoeff2.resize(N);
11754 	  zadd(subcoeff2,res[bk.second],indexes[i+Bs],1,env);
11755 	  reducef4buchbergersplit(subcoeff2,Mindex,firstpos,0,Mcoeff,coeffindex,Ki,0 /* no bitmap, answer in subcoeff2 */,used,env);
11756 #else
11757 	  zcopycoeff(res[bk.second],subcoeff2,1);
11758 #endif
11759 	  bk_prev=bk.second;
11760 	  rightshift_prev=&rightshift[permuB[i]];
11761 	  if (effi>=0)
11762 	    indexes[effi].clear();
11763 	  effi=i+Bs;
11764 	}
11765 	int firstcol=indexes[i].empty()?0:indexes[i].front();
11766 	if (effi>=0 && !indexes[effi].empty())
11767 	  firstcol=giacmin(firstcol,indexes[effi].front());
11768 	// zcopycoeff(res[bk.first],subcoeff1,1);zadd(v64,subcoeff1,indexes[i]);
11769 	if (
11770 #ifdef EMCC
11771 	    env>(1<<24) && env<=94906249
11772 #else
11773 	    0
11774 #endif
11775 	    ){
11776 	  // using doubles instead of 64 bits integer not supported in JS
11777 	  zadd(v64d,res[bk.first],indexes[i],1,env);
11778 	  indexes[i].clear();
11779 #ifdef GIAC_CACHE2ND
11780 	  sub(v64d,subcoeff2);
11781 #else
11782 	  zsub(v64d,subcoeff2,indexes[effi]);
11783 #endif
11784 	  Ki.clear();
11785 	  colonnes=giacmin(colonnes,reducef4buchbergersplitdouble(v64d,Mindex,firstpos,firstcol,Mcoeff,coeffindex,Ki,bitmap,used,env));
11786 	}
11787 	else {
11788 	  zadd(v64,res[bk.first],indexes[i],1,env);
11789 	  indexes[i].clear();
11790 #ifdef GIAC_CACHE2ND
11791 	  sub(v64,subcoeff2);
11792 #else
11793 	  zsub(v64,subcoeff2,indexes[effi]);
11794 #endif
11795 	  Ki.clear();
11796 	  colonnes=giacmin(colonnes,reducef4buchbergersplit(v64,Mindex,firstpos,firstcol,Mcoeff,coeffindex,Ki,bitmap,used,env));
11797 	}
11798 	bitmap += (N>>5)+1;
11799 	if (Ksizes<Kcols){
11800 	  K[i].swap(Ki);
11801 	  Ki.reserve(Ksizes);
11802 	  continue;
11803 	}
11804 	size_t Kis=Ki.size();
11805 	if (Kis>Ki.capacity()*.8){
11806 	  K[i].swap(Ki);
11807 	  Ki.reserve(giacmin(Kcols,int(Kis*1.1)));
11808 	}
11809 	else {
11810 #if 0
11811 	  vector<modint> & target=K[i];
11812 	  target.reserve(giacmin(Kcols,int(Kis*1.1)));
11813 	  vector<modint>::const_iterator kit=Ki.begin(),kitend=Ki.end();
11814 	  for (;kit!=kitend;++kit)
11815 	    target.push_back(*kit);
11816 #else
11817 	  K[i]=Ki;
11818 #endif
11819 	}
11820 	//CERR << v << '\n' << SK[i] << '\n';
11821       } // end for (i=0;i<B.size();++i)
11822     } // end if (!Kdone)
11823     // CERR << K << '\n';
11824     if (debug_infolevel>1)
11825       CERR << CLOCK()*1e-6 << " f4buchbergerv split reduced " << Bs << " polynoms over " << N << " monomials, start at " << colonnes << '\n';
11826     return 0;
11827   }
11828 
11829 #if 0
11830   void convert(const std::vector<modint2> & source,std::vector<modint> & target,modint env){
11831     target.clear();
11832     std::vector<modint2>::const_iterator it=source.begin(),itend=source.end();
11833     for (;it!=itend;++it){
11834       if (*it)
11835 	target.push_back((*it)%env);
11836       else
11837 	target.push_back(0);
11838     }
11839   }
11840 
11841   template<class tdeg_t>
11842   bool operator <(const pair<unsigned,const tdeg_t > & a,
11843 		  const pair<unsigned,const tdeg_t > & b){
11844     if (a.first!=b.first)
11845       return a.first<b.first;
11846     order_t tmp={_REVLEX_ORDER,0};
11847     return !tdeg_t_greater(b.second,a.second,tmp);
11848   }
11849 
11850   template<class tdeg_t>
11851   int zf4computeK2(const unsigned N,const unsigned nrows,const double mem,const unsigned Bs,vectzpolymod<tdeg_t> & res,const vector<unsigned> & G,modint env,const vector< paire > & B,const vector<unsigned> & permuB,bool learning,unsigned & learned_position,vector< paire > * pairs_reducing_to_zero,const vector<tdeg_t> & leftshift,const vector<tdeg_t> & rightshift, const vector<tdeg_t> & R ,void * Rhashptr,const vector<int> & Rdegpos,const vector<unsigned> &firstpos,vector<vector<unsigned short> > & Mindex, const vector<coeffindex_t> & coeffindex,vector< vector<modint> > & Mcoeff,zinfo_t<tdeg_t> * info_ptr,vector<used_t> &used,unsigned & usedcount,unsigned * bitmap,vector< vector<modint> > & K,int parallel){
11852     map< pair<unsigned,const tdeg_t >,int > cache;
11853     vector< vector<modint> > cachecoeffs;
11854     cachecoeffs.reserve(2*Bs);
11855     vector<int> leftpos(Bs,-1),rightpos(Bs,-1);
11856     unsigned n=0;
11857     for (unsigned i=0;i<Bs;++i){
11858       paire bk=B[permuB[i]];
11859       pair<unsigned,const tdeg_t > pleft(bk.first,leftshift[permuB[i]]);
11860       typename map< pair<unsigned,const tdeg_t >,int >::const_iterator it=cache.find(pleft),itend=cache.end();
11861       if (it!=itend)
11862 	leftpos[i]=it->second;
11863       else {
11864 	leftpos[i]=n;
11865 	++n;
11866 	cachecoeffs.push_back(vector<modint>());
11867 	cache[pleft]=n;
11868       }
11869       pair<unsigned,const tdeg_t > pright(bk.second,rightshift[permuB[i]]);
11870       it=cache.find(pright);
11871       itend=cache.end();
11872       if (it!=itend)
11873 	rightpos[i]=it->second;
11874       else {
11875 	rightpos[i]=n;
11876 	++n;
11877 	cachecoeffs.push_back(vector<modint>());
11878 	cache[pright]=n;
11879       }
11880     }
11881     // compare n to 2*Bs, if caching is efficient compute cache
11882     CERR << "Cache relative occupation " << n/(2.*Bs) << " pairs " << Bs << '\n';
11883     return zf4computeK1(N,nrows,mem,Bs,res,G,env, B,permuB,learning,learned_position,pairs_reducing_to_zero,leftshift,rightshift,  R ,Rhashptr,Rdegpos,firstpos,Mindex, coeffindex,Mcoeff,info_ptr,used,usedcount,bitmap,K,parallel,interreduce);
11884     vector<shifttype> index;
11885     vector<modint> Ki;
11886     vector<modint2> v64(N);
11887     for (unsigned i=0;i<Bs;++i){
11888       if (interrupted || ctrl_c)
11889 	return 0;
11890       paire bk=B[permuB[i]];
11891       pair<unsigned,const tdeg_t > pleft(bk.first,leftshift[permuB[i]]);
11892       unsigned j=leftpos[i];
11893       if (cachecoeffs[j].empty()){
11894 	std::fill(v64.begin(),v64.end(),0);
11895 	index.clear();
11896 	Ki.clear();
11897 	zmakelinesplit(res[bk.first],&leftshift[permuB[i]],R,Rhashptr,Rdegpos,index,0,1);
11898 	int firstcol=0; // index.empty()?0:index.front();
11899 	zadd(v64,res[bk.first],index,1,env);
11900 	reducef4buchbergersplit(v64,Mindex,firstpos,firstcol,Mcoeff,coeffindex,Ki,0 /* bitmap set to 0: result in v64*/,used,env);
11901 	// v64->32 bits reduction and push in cache
11902 	convert(v64,cachecoeffs[j],env);
11903       }
11904       vector<modint> vleft(cachecoeffs[j]);
11905       pair<unsigned,const tdeg_t> pright(bk.second,rightshift[permuB[i]]);
11906       j=rightpos[i];
11907       if (cachecoeffs[j].empty()){
11908 	std::fill(v64.begin(),v64.end(),0);
11909 	index.clear();
11910 	Ki.clear();
11911 	zmakelinesplit(res[bk.second],&rightshift[permuB[i]],R,Rhashptr,Rdegpos,index,0,1);
11912 	int firstcol=index.empty()?0:index.front();
11913 	zadd(v64,res[bk.second],index,1,env);
11914 	reducef4buchbergersplit(v64,Mindex,firstpos,firstcol,Mcoeff,coeffindex,Ki,0 /* bitmap set to 0: result in v64*/,used,env);
11915 	// v64->32 bits reduction and push in cache
11916 	cachecoeffs.push_back(vector<modint>());
11917 	convert(v64,cachecoeffs[j],env);
11918       }
11919       sub(vleft,cachecoeffs[j],env);
11920       // v64=vleft
11921       for (unsigned j=0;j<N;++j){
11922 	v64[j]=vleft[j];
11923       }
11924       K.push_back(vector<modint>());
11925       K.back().reserve(N-nrows);
11926       store_coeffs(v64,0,K.back(),bitmap,used,env);
11927       bitmap += (N>>5)+1;
11928     }
11929     return 0;
11930   }
11931 #endif
11932 
11933   template<class tdeg_t>
11934   struct zbuildM_t {
11935     const vectzpolymod<tdeg_t> * res;
11936     const vector<unsigned> * G;
11937     modint env;
11938     bool multimodular;
11939     const vector< vector<tdeg_t> > * quo;
11940     const vector<tdeg_t> * R;
11941     const vector<int> * Rdegpos;
11942     void * Rhashptr;
11943     vector<coeffindex_t> * coeffindex;
11944     unsigned N;
11945     vector<vector<unsigned short> > * Mindex;
11946     vector< vector<modint> > * Mcoeff;
11947     vector<sparse_element> * atrier;
11948     int i,iend,j;
11949   };
11950 
11951   template<class tdeg_t>
do_zbuildM(const vectzpolymod<tdeg_t> & res,const vector<unsigned> & G,modint env,bool multimodular,const vector<vector<tdeg_t>> & quo,const vector<tdeg_t> & R,const vector<int> & Rdegpos,void * Rhashptr,vector<coeffindex_t> & coeffindex,unsigned N,vector<vector<unsigned short>> & Mindex,vector<vector<modint>> & Mcoeff,vector<sparse_element> & atrier,int i,int iend,int j)11952   void do_zbuildM(const vectzpolymod<tdeg_t> & res,const vector<unsigned> & G,modint env,bool multimodular,const vector< vector<tdeg_t> > & quo,const vector<tdeg_t> & R,const vector<int> & Rdegpos,void * Rhashptr,vector<coeffindex_t> & coeffindex,unsigned N,vector<vector<unsigned short> > & Mindex,vector< vector<modint> > & Mcoeff,vector<sparse_element> & atrier,int i,int iend,int j){
11953     for (;i<iend;++i){
11954       // copy coeffs of res[G[i]] in Mcoeff
11955       if (!quo[i].empty())
11956 	zcopycoeff(res[G[i]],Mcoeff[i],0);
11957       // for each monomial of quo[i], find indexes and put in Mindex
11958       // reverse order traversing quo[i]
11959       // In zmakelinesplit locate res[G[i]].coord.u+*jt by dichotomoy
11960       // between position just calculated before and
11961       // and same position in previous Mindex
11962       typename std::vector< tdeg_t >::const_iterator jt=quo[i].end()-1;
11963       int quos=int(quo[i].size());
11964       int Gi=G[i];
11965       for (int k=quos-1;k>=0;--k,--jt){
11966 	zmakelinesplit(res[Gi],&*jt,R,Rhashptr,Rdegpos,Mindex[j+k],k==quos-1?0:&Mindex[j+k+1],0);
11967       }
11968       for (int k=0;k<quos;++j,++k){
11969 	coeffindex[j]=coeffindex_t(N<=0xffff,i);
11970 	if (!coeffindex[j].b)
11971 	  coeffindex[j].b=checkshortshifts(Mindex[j]);
11972 	atrier[j]=sparse_element(first_index(Mindex[j]),j);
11973       }
11974     }
11975   }
11976 
11977   template<class tdeg_t>
zbuildM_(void * ptr_)11978   void * zbuildM_(void * ptr_){
11979     zbuildM_t<tdeg_t> * ptr=(zbuildM_t<tdeg_t> *) ptr_;
11980     do_zbuildM<tdeg_t>(*ptr->res,*ptr->G,ptr->env,ptr->multimodular,*ptr->quo,*ptr->R,*ptr->Rdegpos,ptr->Rhashptr,*ptr->coeffindex,ptr->N,*ptr->Mindex,*ptr->Mcoeff,*ptr->atrier,ptr->i,ptr->iend,ptr->j);
11981     return ptr_;
11982   }
11983 
11984   template<class tdeg_t>
zbuildM(const vectzpolymod<tdeg_t> & res,const vector<unsigned> & G,modint env,bool multimodular,int parallel,const vector<vector<tdeg_t>> & quo,const vector<tdeg_t> & R,const vector<int> & Rdegpos,void * & Rhashptr,vector<coeffindex_t> & coeffindex,unsigned N,vector<vector<unsigned short>> & Mindex,vector<vector<modint>> & Mcoeff,vector<sparse_element> & atrier,int nrows)11985   void zbuildM(const vectzpolymod<tdeg_t> & res,const vector<unsigned> & G,modint env,bool multimodular,int parallel,const vector< vector<tdeg_t> > & quo,const vector<tdeg_t> & R,const vector<int> & Rdegpos,void * & Rhashptr,vector<coeffindex_t> & coeffindex,unsigned N,vector<vector<unsigned short> > & Mindex,vector< vector<modint> > & Mcoeff,vector<sparse_element> & atrier,int nrows){
11986 #ifdef HAVE_LIBPTHREAD
11987     if (nrows<16)
11988       parallel=1;
11989     pthread_t tab[parallel];
11990     zbuildM_t<tdeg_t> zbuildM_param[parallel];
11991     int istart=0,iend=0,jstart=0,jend=0;
11992     for (int j=0;j<parallel;++j){
11993       if (j==parallel-1){
11994 	iend=G.size();
11995       }
11996       else {
11997 	for (iend=istart;iend<G.size();++iend){
11998 	  jend += quo[iend].size();
11999 	  if (jend>((j+1)*nrows/parallel)){
12000 	    ++iend;
12001 	    break;
12002 	  }
12003 	}
12004       }
12005       zbuildM_t<tdeg_t> tmp={&res,&G,env,multimodular,&quo,&R,&Rdegpos,Rhashptr,&coeffindex,N,&Mindex,&Mcoeff,&atrier,istart,iend,jstart};
12006       zbuildM_param[j]=tmp;
12007       bool res=true;
12008       if (j<parallel-1)
12009 	res=pthread_create(&tab[j],(pthread_attr_t *) NULL,zbuildM_<tdeg_t>,(void *) &zbuildM_param[j]);
12010       if (res)
12011 	zbuildM_<tdeg_t>((void *)&zbuildM_param[j]);
12012       istart=iend;
12013       jstart=jend;
12014     }
12015     for (unsigned j=0;j<parallel-1;++j){
12016       void * ptr_=(void *)&parallel; // non-zero initialisation
12017       pthread_join(tab[j],&ptr_);
12018       if (!ptr_)
12019 	CERR << "Error building M" << '\n';
12020     }
12021 #else
12022     zbuildM_t<tdeg_t> tmp={&res,&G,env,multimodular,&quo,&R,&Rdegpos,Rhashptr,&coeffindex,N,&Mindex,&Mcoeff,&atrier,0,int(G.size()),0};
12023     zbuildM_<tdeg_t>((void *)&tmp);
12024 #endif
12025   } // end parallelization
12026 
12027   template<class tdeg_t>
zf4mod(vectzpolymod<tdeg_t> & res,const vector<unsigned> & G,modint env,const vector<paire> & B,const vector<unsigned> * & permuBptr,vectzpolymod<tdeg_t> & f4buchbergerv,bool learning,unsigned & learned_position,vector<paire> * pairs_reducing_to_zero,vector<zinfo_t<tdeg_t>> & f4buchberger_info,unsigned & f4buchberger_info_position,bool recomputeR,int age,bool multimodular,int parallel,bool interreduce)12028   int zf4mod(vectzpolymod<tdeg_t> & res,const vector<unsigned> & G,modint env,const vector< paire > & B,const vector<unsigned> * & permuBptr,vectzpolymod<tdeg_t> & f4buchbergerv,bool learning,unsigned & learned_position,vector< paire > * pairs_reducing_to_zero,vector<zinfo_t<tdeg_t> > & f4buchberger_info,unsigned & f4buchberger_info_position,bool recomputeR,int age,bool multimodular,int parallel,bool interreduce){
12029     unsigned Bs=unsigned(interreduce?G.size():B.size());
12030     if (!Bs)
12031       return 0;
12032     int dim=res.front().dim;
12033     order_t order=res.front().order;
12034     vector<tdeg_t> leftshift(Bs);
12035     vector<tdeg_t> rightshift(Bs);
12036     if (!interreduce)
12037       zleftright(res,B,leftshift,rightshift);
12038     // IMPROVEMENT: sort pairs in B according to right term of the pair
12039     // If several pairs share the same right term,
12040     // reduce the right term without leading monomial once
12041     // reduce corresponding left terms without leading monomial
12042     // substract
12043     f4buchbergerv.resize(Bs);
12044     zinfo_t<tdeg_t> info_tmp;
12045     unsigned nonzero = unsigned(Bs);
12046     zinfo_t<tdeg_t> * info_ptr=0;
12047     if (!learning && f4buchberger_info_position<f4buchberger_info.size()){
12048       info_ptr=&f4buchberger_info[f4buchberger_info_position];
12049       ++f4buchberger_info_position;
12050       nonzero=info_ptr->nonzero;
12051       if (nonzero==0 && !interreduce){
12052 	for (int i=0;i<f4buchbergerv.size();++i){
12053 	  // CERR << v << '\n';
12054 	  f4buchbergerv[i].expo=&info_ptr->rem;
12055 	  f4buchbergerv[i].order=order;
12056 	  f4buchbergerv[i].dim=dim;
12057 	  vector< zmodint > & Pcoord=f4buchbergerv[i].coord;
12058 	  Pcoord.clear();
12059 	}
12060 	return 1;
12061       }
12062     }
12063     else {
12064       vector<tdeg_t> all;
12065       vector<unsigned> permuB(Bs);
12066       for (unsigned i=0;i<Bs;++i)
12067 	permuB[i]=i;
12068 #if 1 // not required for one modular gbasis, but kept for multi-modular
12069       if (!interreduce){
12070 	pair_compare<tdeg_t> trieur(&B,&res,&leftshift,&rightshift,order);
12071 	sort(permuB.begin(),permuB.end(),trieur);
12072 	if (debug_infolevel>2){
12073 	  unsigned egales=0;
12074 	  for (unsigned i=1;i<Bs;++i){
12075 	    if (B[permuB[i-1]].second!=B[permuB[i]].second)
12076 	      continue;
12077 	    if (rightshift[permuB[i-1]]==rightshift[permuB[i]]){
12078 	      egales++;
12079 	      CERR << B[permuB[i-1]] << "=" << B[permuB[i]] << '\n';
12080 	    }
12081 	  }
12082 	  CERR << egales << " right pair elements are the same" << '\n';
12083 	  CERR << CLOCK()*1e-6 << " zf4buchberger begin collect monomials on #polys " << f4buchbergerv.size() << '\n';
12084 	}
12085       }
12086 #endif
12087       if (interreduce){
12088 	zcollect_interreduce(res,G,all,1); // all monomials after leading one
12089       }
12090       else {
12091 	if (!zcollect(res,B,permuB,all,leftshift,rightshift))
12092 	  return -1;
12093       }
12094       if (debug_infolevel>1)
12095 	CERR << CLOCK()*1e-6 << " zf4buchberger symbolic preprocess" << '\n';
12096       zsymbolic_preprocess(all,res,G,-1,info_tmp.quo,info_tmp.rem,info_tmp.R);
12097       if (debug_infolevel>1)
12098 	CERR << CLOCK()*1e-6 << " zend symbolic preprocess" << '\n';
12099 #if 0
12100       f4buchberger_info->push_back(*info_ptr);
12101 #else
12102       zinfo_t<tdeg_t> tmp;
12103       f4buchberger_info.push_back(tmp);
12104       zinfo_t<tdeg_t> & i=f4buchberger_info.back();
12105       swap(i.quo,info_tmp.quo);
12106       swap(i.R,info_tmp.R);
12107       swap(i.rem,info_tmp.rem);
12108       swap(i.permuB,permuB);
12109       info_ptr=&f4buchberger_info.back();
12110 #endif
12111     }
12112     const vector<unsigned> & permuB =info_ptr->permuB ;
12113     permuBptr=&permuB;
12114     const vector<tdeg_t> & R = info_ptr->R;
12115     vector<unsigned> Rtoremv;
12116     Rtorem(R,info_ptr->rem,Rtoremv); // positions of R degrees in rem
12117     const vector< vector<tdeg_t> > & quo = info_ptr->quo;
12118     //CERR << quo << '\n';
12119     unsigned N = unsigned(R.size()), i, j = 0;
12120     if (N==0) return 1;
12121     void * Rhashptr=0;
12122 #ifdef GIAC_RHASH // default disabled
12123     tdeg_t64_hash_t Rhash;
12124     if (R.front().vars64()){
12125       Rhashptr=&Rhash;
12126       //Rhash.reserve(N);
12127       for (unsigned i=0;i<N;++i){
12128 	R[i].add_to_hash(Rhashptr,i);
12129       }
12130     }
12131 #endif
12132     int Rcurdeg=R.front().tdeg;
12133     vector<int> Rdegpos(Rcurdeg+2);
12134 #ifdef GIAC_RDEG // default enabled
12135     for (unsigned i=0;i<N;++i){
12136       int tmp=R[i].tdeg;
12137       if (tmp==Rcurdeg)
12138 	continue;
12139       for (;Rcurdeg>tmp;--Rcurdeg){
12140 	Rdegpos[Rcurdeg]=i;
12141       }
12142     }
12143     for (;Rcurdeg>=0;--Rcurdeg){
12144       Rdegpos[Rcurdeg]=N;
12145     }
12146 #endif
12147     unsigned nrows=0;
12148     for (i=0;i<G.size();++i){
12149       nrows += unsigned(quo[i].size());
12150     }
12151     if (nrows==0 && interreduce){
12152       // allready interreduced, nothing to do...
12153       info_ptr->nonzero=G.size();
12154       return 12345; // special code, already interreduced
12155     }
12156     double sknon0=0;
12157     unsigned usedcount=0,zerolines=0;
12158     vector< vector<modint> > K(Bs);
12159     vector<vector<unsigned short> > Mindex;
12160     vector< vector<modint> > Mcoeff(G.size());
12161     vector<coeffindex_t> coeffindex(nrows);
12162     Mindex.reserve(nrows);
12163     vector<sparse_element> atrier(nrows);
12164     // atrier.reserve(nrows);
12165     for (i=0;i<G.size();++i){
12166       typename std::vector<tdeg_t>::const_iterator jt=quo[i].begin(),jtend=quo[i].end();
12167       if (jt!=jtend)
12168 	Mcoeff[i].reserve(res[G[i]].coord.size());
12169       for (;jt!=jtend;++j,++jt){
12170 	Mindex.push_back(vector<unsigned short>(0));
12171 	Mindex[j].reserve(int(1.1*res[G[i]].coord.size()));
12172       }
12173     }
12174 #ifndef GIAC_MAKELINECACHE
12175     zbuildM(res,G,env,multimodular,parallel,quo,R,Rdegpos,Rhashptr,coeffindex,N,Mindex,Mcoeff,atrier,nrows);
12176 #else // ZBUILDM
12177 #ifdef GIAC_MAKELINECACHE
12178     vector< pair<int,int> > zmakelinecache(res.size(),pair<int,int>(-1,-1)); // -1 if res[k] is not in G, (i,j) if k==G[i] where j is the first index in Mindex of the part corresponding to res[G[i]]
12179 #endif
12180     for (i=0,j=0;i<G.size();++i){
12181       // copy coeffs of res[G[i]] in Mcoeff
12182       if (1 || env<(1<<24)){
12183 	if (!quo[i].empty())
12184 	  zcopycoeff(res[G[i]],Mcoeff[i],0);
12185       }
12186       else
12187 	zcopycoeff(res[G[i]],Mcoeff[i],env,0);
12188       // if (!Mcoeff[i].empty()) Mcoeff[i].front()=invmod(Mcoeff[i].front(),env);
12189       // for each monomial of quo[i], find indexes and put in Mindex
12190       // Improvement idea: reverse order traversing quo[i]
12191       // In zmakelinesplit locate res[G[i]].coord.u+*jt by dichotomoy
12192       // between position just calculated before and
12193       // and same position in previous Mindex
12194 #if 1
12195       typename std::vector< tdeg_t >::const_iterator jt=quo[i].end()-1;
12196       int quos=int(quo[i].size());
12197       int Gi=G[i];
12198 #ifdef GIAC_MAKELINECACHE
12199       zmakelinecache[Gi]=pair<int,int>(i,j);
12200 #endif
12201       for (int k=quos-1;k>=0;--k,--jt){
12202 	zmakelinesplit(res[Gi],&*jt,R,Rhashptr,Rdegpos,Mindex[j+k],k==quos-1?0:&Mindex[j+k+1],0);
12203       }
12204       for (int k=0;k<quos;++j,++k){
12205 	coeffindex[j]=coeffindex_t(N<=0xffff,i);
12206 	if (!coeffindex[j].b)
12207 	  coeffindex[j].b=checkshortshifts(Mindex[j]);
12208 	// atrier.push_back(sparse_element(first_index(Mindex[j]),j));
12209 	atrier[j]=sparse_element(first_index(Mindex[j]),j);
12210       }
12211 #else
12212       typename std::vector< tdeg_t >::const_iterator jt=quo[i].begin(),jtend=quo[i].end();
12213       for (;jt!=jtend;++j,++jt){
12214 	coeffindex[j]=coeffindex_t(N<=0xffff,i);
12215 	zmakelinesplit(res[G[i]],&*jt,R,Rhashptr,Rdegpos,Mindex[j],0,0);
12216 	if (!coeffindex[j].b)
12217 	  coeffindex[j].b=checkshortshifts(Mindex[j]);
12218 	// atrier.push_back(sparse_element(first_index(Mindex[j]),j));
12219 	atrier[j]=sparse_element(first_index(Mindex[j]),j);
12220       }
12221 #endif
12222     }
12223 #endif // ZBUILM
12224     if (debug_infolevel>1)
12225       CERR << CLOCK()*1e-6 << " end build Mindex/Mcoeff zf4mod" << '\n';
12226     // should not sort but compare res[G[i]]*quo[i] monomials to build M already sorted
12227     // CERR << "before sort " << Mindex << '\n';
12228     sort_vector_sparse_element(atrier.begin(),atrier.end()); // sort(atrier.begin(),atrier.end(),tri1);
12229     vector<coeffindex_t> coeffindex1(atrier.size());
12230     double mem=0; // mem*4=number of bytes allocated for M1
12231     vector< vector<unsigned short> > Mindex1(atrier.size());
12232 #ifdef GIAC_MAKELINECACHE
12233     vector<int> permuM(atrier.size());
12234 #endif
12235     for (i=0;i<atrier.size();++i){
12236       swap(Mindex1[i],Mindex[atrier[i].pos]);
12237       mem += Mindex1[i].size();
12238       swap(coeffindex1[i],coeffindex[atrier[i].pos]);
12239 #ifdef GIAC_MAKELINECACHE
12240       permuM[atrier[i].pos]=i;
12241 #endif
12242     }
12243     swap(Mindex,Mindex1);
12244     nrows = unsigned(Mindex.size());
12245     swap(coeffindex,coeffindex1);
12246     vector<unsigned> firstpos(atrier.size());
12247     for (i=0;i < atrier.size();++i){
12248       firstpos[i]=atrier[i].val;
12249     }
12250     double ratio=(mem/nrows)/N;
12251     if (debug_infolevel>1)
12252       CERR << CLOCK()*1e-6 << " Mindex sorted, rows " << nrows << " columns " << N << " terms " << mem << " ratio " << ratio <<'\n';
12253     if (N<nrows){
12254       CERR << "Error " << N << "," << nrows << '\n';
12255       return -1;
12256     }
12257     // ((N>>5)+1)*Bs should not exceed 2e9 otherwise this will segfault
12258     if (double(Bs)*(N>>5)>2e9){
12259       CERR << "Error, problem too large. Try again after running gbasis_max_pairs(n) with n<" << 2e9/(N>>5) << '\n';
12260       return -1;
12261     }
12262     vector<used_t> used(N,0);
12263     vector<unsigned> lebitmap(((N>>5)+1)*Bs);
12264     unsigned * bitmap=&lebitmap.front();
12265     int zres=zf4computeK1(N,nrows,mem,Bs,res,G,env, B,permuB,learning,learned_position,pairs_reducing_to_zero,leftshift,rightshift,  R ,Rhashptr,Rdegpos,firstpos,Mindex, coeffindex,Mcoeff,info_ptr,used,usedcount,bitmap,K,parallel,interreduce);
12266     if (zres!=0)
12267       return zres;
12268     if (debug_infolevel>1){
12269       CERR << '\n' << CLOCK()*1e-6 << " Memory usage: " << memory_usage()*1e-6 << "M" << '\n';
12270     }
12271     size_t Mindexsize=Mindex.size();
12272     Mindex.clear();
12273     Mcoeff.clear();
12274     {
12275       vector<vector<unsigned short> > Mindexclear;
12276       vector< vector<modint> > Mcoeffclear;
12277       Mindex.swap(Mindexclear);
12278       Mcoeff.swap(Mcoeffclear);
12279     }
12280     if (!pairs_reducing_to_zero){
12281       vector<tdeg_t> clearer;
12282       info_ptr->R.swap(clearer);
12283     }
12284     for (unsigned i=0;i<N;++i)
12285       usedcount += (used[i]>0);
12286     if (learning && info_ptr)
12287       info_ptr->Ksizes=usedcount;
12288     if (debug_infolevel>1){
12289       CERR << CLOCK()*1e-6 << " number of non-zero columns " << usedcount << " over " << N-Mindexsize << " (N " << N  << ", Mindex size " << Mindexsize << ")" << '\n'; // usedcount should be approx N-M.size()=number of cols of M-number of rows
12290       if (debug_infolevel>3)
12291 	CERR << " column split used " << used << '\n';
12292     }
12293     // create dense matrix K
12294     bitmap=&lebitmap.front();
12295     create_matrix(bitmap,(N>>5)+1,used,K);
12296     // clear memory required for lescoeffs
12297     //vector<modint> tmp; lescoeffs.swap(tmp);
12298     { vector<unsigned> tmp1; lebitmap.swap(tmp1); }
12299     if (debug_infolevel>1){
12300       CERR << CLOCK()*1e-6 << " rref " << K.size() << "x" << usedcount << '\n';
12301       double nz=0;
12302       for (unsigned i=0;i<K.size();++i){
12303 	vector<int> & Ki=K[i];
12304 	for (unsigned j=0;j<Ki.size();++j){
12305 	  if (Ki[j]) ++nz;
12306 	}
12307       }
12308       CERR << "non-0 percentage " << (nz/K.size())/K.front().size() << '\n';
12309     }
12310     vecteur pivots; vector<int> permutation,maxrankcols; longlong idet;
12311     if (0 && !learning && info_ptr->permu.size()==Bs){
12312       permutation=info_ptr->permu;
12313       vector< vector<modint> > K1(Bs);
12314       for (unsigned i=0;i<Bs;++i){
12315 	swap(K1[i],K[permutation[i]]);
12316       }
12317       swap(K1,K);
12318     }
12319     int th=parallel-1; // giacmin(threads,64)-1;
12320     if (interreduce){ // interreduce==true means final interreduction
12321       ;
12322     }
12323     else {
12324 #if 0
12325       // vector< vector<modint> > Kcopy(K);
12326       smallmodrref(parallel,K,pivots,permutation,maxrankcols,idet,0,int(K.size()),0,usedcount,1/* fullreduction*/,0/*dontswapbelow*/,env,0/* rrefordetorlu*/,permutation.empty(),0,!multimodular,0,-1); // disable rref optimization in multi-modular mode otherwise cyclic92 fails
12327 #else
12328       smallmodrref(parallel,K,pivots,permutation,maxrankcols,idet,0,int(K.size()),0,usedcount,0/* lower reduction*/,0/*dontswapbelow*/,env,0/* rrefordetorlu*/,permutation.empty()/* reset */,0,!multimodular,-1);
12329       if (1){
12330 	if (debug_infolevel>1)
12331 	  CERR << CLOCK()*1e-6 << " rref_upper " << '\n';
12332 	int Ksize=int(K.size());
12333 	if (//1
12334 	    usedcount<=2*Ksize
12335 	    || parallel==1 || Ksize<50
12336 	    )
12337 	  smallmodrref_upper(K,0,Ksize,0,usedcount,env);
12338 	else {
12339 	  thread_smallmodrref_upper(K,0,Ksize,0,usedcount,env,parallel);
12340 	}
12341       }
12342     } // end if !interreduce
12343 #endif
12344     unsigned Kcols=N-nrows;
12345     free_null_lines(K,0,Bs,0,Kcols);
12346     unsigned first0 = unsigned(pivots.size());
12347     if (!interreduce && first0<K.size() && learning){
12348       vector<modint> & tmpv=K[first0];
12349       for (i=0;i<tmpv.size();++i){
12350 	if (tmpv[i])
12351 	  break;
12352       }
12353       if (i==tmpv.size()){
12354 	unsigned Ksize = unsigned(K.size());
12355 	K.resize(first0);
12356 	K.resize(Ksize);
12357       }
12358     }
12359     //CERR << permutation << K << '\n';
12360     if (!learning){
12361       // check that permutation is the same as learned permutation
12362       bool copy=false;
12363       for (unsigned j=0;j<permutation.size();++j){
12364 	if (permutation[j]!=info_ptr->permu[j]){
12365 	  copy=true;
12366 	  if (K[permutation[j]].empty() && K[info_ptr->permu[j]].empty())
12367 	    continue;
12368 	  CERR << "learning failed"<<'\n';
12369 	  return -1;
12370 	}
12371       }
12372       if (copy)
12373 	permutation=info_ptr->permu;
12374     }
12375     if (learning)
12376       info_ptr->permu=permutation;
12377     // CERR << K << "," << permutation << '\n';
12378     // vector<int> permu=perminv(permutation);
12379     if (debug_infolevel>1)
12380       CERR << CLOCK()*1e-6 << " f4buchbergerv interreduced" << '\n';
12381     for (i=0;i<f4buchbergerv.size();++i){
12382       // CERR << v << '\n';
12383       int pi=interreduce?i:permutation[i];
12384       f4buchbergerv[pi].expo=&info_ptr->rem;
12385       f4buchbergerv[pi].order=order;
12386       f4buchbergerv[pi].dim=dim;
12387       f4buchbergerv[pi].age=age;
12388       vector< zmodint > & Pcoord=f4buchbergerv[pi].coord;
12389       Pcoord.clear();
12390       vector<modint> & v =K[i];
12391       if (v.empty()){
12392 	continue;
12393       }
12394       unsigned vcount=0;
12395       vector<modint>::const_iterator vt=v.begin(),vtend=v.end();
12396       for (;vt!=vtend;++vt){
12397 	if (*vt)
12398 	  ++vcount;
12399       }
12400       Pcoord.reserve(vcount);
12401       vector<used_t>::const_iterator ut=used.begin();
12402       unsigned pos=0;
12403       for (vt=v.begin();pos<N;++ut,++pos){
12404 	if (!*ut)
12405 	  continue;
12406 	modint coeff=*vt;
12407 	++vt;
12408 	if (coeff!=0)
12409 	  Pcoord.push_back(zmodint(coeff,Rtoremv[pos]));
12410       }
12411       if (!Pcoord.empty())
12412 	f4buchbergerv[pi].ldeg=(*f4buchbergerv[pi].expo)[Pcoord.front().u];
12413       if (!interreduce && !Pcoord.empty() && ( (env > (1<< 24)) || Pcoord.front().g!=1) ){
12414 	zsmallmultmod(invmod(Pcoord.front().g,env),f4buchbergerv[pi],env);
12415 	Pcoord.front().g=1;
12416       }
12417       bool freemem=mem>4e7; // should depend on real memory available
12418       if (freemem){
12419 	vector<modint> tmp; tmp.swap(v);
12420       }
12421     }
12422     if (debug_infolevel>1)
12423       CERR << CLOCK()*1e-6 << " f4buchbergerv stored" << '\n';
12424     return 1;
12425   }
12426 
12427   /*
12428 Let {f1, ..., fr} be a set of polynomials. The Gebauer-Moller Criteria are as follows:
12429 1. Criterion M holds for a pair (fi, fk) if ∃ j < k, such that
12430    LCM{LM(fj),LM(fk)} properly divides LCM{LM(fi),LM(fk)}
12431 2. Criterion F holds for a pair (fi, fk) if ∃ j < i, such that
12432    LCM{LM(fj),LM(fk)} = LCM{LM(fi),LM(fk)}.
12433 3. Criterion Bk holds for a pair (fi, fj) if ∃ j < k and
12434    LM(fk) | LCM{LM(fi),LM(fj)},
12435    LCM{LM(fi),LM(fk)} != LCM{LM(fi),LM(fj)}, and
12436    LCM{LM(fi),LM(fj)} != LCM{LM(fj, fk)
12437   */
12438 
12439   // oldG is the Gbasis before the first line of f4buchbergerv is added
12440   // otherwise we might miss some new pairs to be added
12441   // f:=(1387482169552326*s*t1*t2^2-25694114250969*s*t1*t2+240071563017*s*t1+579168836143704*t1*t2^2-10725348817476*t1*t2+100212766488*t1):;fb:=(-7035747399*s*t1^2*t2^2+118865637*s*t1^2*t2-793881*s*t1^2+118865637*s*t1*t2^2-1167858*s*t1*t2+1944*s*t1-1089126*s*t2^2+1944*s*t2+18*s-2936742966*t1^2*t2^2+49601160*t1^2*t2-328050*t1^2+49601160*t1*t2^2-485514*t1*t2+972*t1-446148*t2^2+972*t2+36):;rmp:=s^2+10*s+4:;gbasis([f,fb,rmp],[s,t1,t2],revlex);
12442   template<class tdeg_t>
zgbasis_updatemod(vector<unsigned> & G,vector<paire> & B,vectzpolymod<tdeg_t> & res,unsigned pos,vector<unsigned> & oldG,bool multimodular)12443   void zgbasis_updatemod(vector<unsigned> & G,vector< paire > & B,vectzpolymod<tdeg_t> & res,unsigned pos,vector<unsigned> & oldG,bool multimodular){
12444     if (debug_infolevel>2)
12445       CERR << CLOCK()*1e-6 << " zmod begin gbasis update " << G.size() << '\n';
12446     if (debug_infolevel>3)
12447       CERR << "G=" << G << "B=" << B << '\n';
12448     const zpolymod<tdeg_t> & h = res[pos];
12449     order_t order=h.order;
12450     short dim=h.dim;
12451     vector<unsigned> C,Ccancel;
12452     C.reserve(G.size()+1);
12453     const tdeg_t & h0=h.ldeg;
12454     for (unsigned i=0;i<oldG.size();++i){
12455       if (tdeg_t_all_greater(h0,res[oldG[i]].ldeg,order))
12456 	return;
12457     }
12458     tdeg_t tmp1,tmp2;
12459     // C is used to construct new pairs
12460     // create pairs with h and elements g of G, then remove
12461     // -> if g leading monomial is prime with h, remove the pair
12462     // -> if g leading monomial is not disjoint from h leading monomial
12463     //    keep it only if lcm of leading monomial is not divisible by another one
12464 #if 1
12465     unsigned tmpsize = unsigned(G.size());
12466     vector<tdeg_t> tmp(tmpsize);
12467     for (unsigned i=0;i<tmpsize;++i){
12468       if (
12469 #ifdef GIAC_GBASIS_REDUCTOR_MAXSIZE
12470 	  res[G[i]].in_gbasis
12471 #else
12472 	  1
12473 #endif
12474 	  )
12475 	index_lcm(h0,res[G[i]].ldeg,tmp[i],order);
12476       else
12477 	tmp[i].tab[0]=-1;
12478     }
12479 #else
12480     // this would be faster but it does not work for
12481     // gbasis([25*y^2*x^6-10*y^2*x^5+59*y^2*x^4-20*y^2*x^3+43*y^2*x^2-10*y^2*x+9*y^2-80*y*x^6+136*y*x^5+56*y*x^4-240*y*x^3+104*y*x^2+64*x^6-192*x^5+192*x^4-64*x^3,25*y^2*6*x^5-10*y^2*5*x^4+59*y^2*4*x^3-20*y^2*3*x^2+43*y^2*2*x-10*y^2-80*y*6*x^5+136*y*5*x^4+56*y*4*x^3-240*y*3*x^2+104*y*2*x+64*6*x^5-192*5*x^4+192*4*x^3-64*3*x^2,25*2*y*x^6-10*2*y*x^5+59*2*y*x^4-20*2*y*x^3+43*2*y*x^2-10*2*y*x+9*2*y-80*x^6+136*x^5+56*x^4-240*x^3+104*x^2],[x,y],revlex);
12482     // pair <4,3> is not generated
12483     unsigned tmpsize=G.empty()?0:G.back()+1;
12484     vector<tdeg_t> tmp(tmpsize);
12485     for (unsigned i=0;i<tmpsize;++i){
12486       index_lcm(h0,res[i].ldeg,tmp[i],order);
12487     }
12488 #endif
12489     vector <tdeg_t> cancellables;
12490     for (unsigned i=0;i<G.size();++i){
12491 #ifdef TIMEOUT
12492       control_c();
12493 #endif
12494 #ifdef GIAC_GBASIS_REDUCTOR_MAXSIZE
12495       if (!res[G[i]].in_gbasis)
12496 	continue;
12497 #endif
12498       if (interrupted || ctrl_c)
12499 	return;
12500       if (disjoint(h0,res[G[i]].ldeg,order,dim)){
12501 #ifdef GIAC_GBASIS_DELAYPAIRS
12502 	Ccancel.push_back(G[i]);
12503 #endif
12504 	//cancellables.push_back(tmp[i]);
12505 	continue;
12506       }
12507       //if (equalposcomp(cancellables,tmp[i])){ CERR << "cancelled!" << '\n'; continue; }
12508       // h0 and G[i] leading monomial not prime together
12509 #if 1
12510       tdeg_t * tmp1=&tmp[i];
12511 #else
12512       tdeg_t * tmp1=&tmp[G[i]];
12513 #endif
12514       tdeg_t * tmp2=&tmp[0],*tmpend=tmp2+tmpsize;
12515       for (;tmp2!=tmp1;++tmp2){
12516 	if (tmp2->tab[0]==-1)
12517 	  continue;
12518 	if (tdeg_t_all_greater(*tmp1,*tmp2,order))
12519 	  break; // found another pair, keep the smallest, or the first if equal
12520       }
12521       if (tmp2!=tmp1){
12522 	tmp1->tab[0]=-1; // desactivate tmp1 since it is >=tmp2
12523 	continue;
12524       }
12525       for (++tmp2;tmp2<tmpend;++tmp2){
12526 	if (tmp2->tab[0]==-1)
12527 	  continue;
12528 	if (tdeg_t_all_greater(*tmp1,*tmp2,order) && *tmp1!=*tmp2){
12529 	  tmp1->tab[0]=-1; // desactivate tmp1 since it is >tmp2
12530 	  break;
12531 	}
12532       }
12533       if (tmp2==tmpend)
12534 	C.push_back(G[i]);
12535     }
12536     vector< paire > B1;
12537     B1.reserve(B.size()+C.size());
12538     for (unsigned i=0;i<B.size();++i){
12539 #ifdef TIMEOUT
12540       control_c();
12541 #endif
12542       if (interrupted || ctrl_c)
12543 	return;
12544       if (res[B[i].first].coord.empty() || res[B[i].second].coord.empty())
12545 	continue;
12546       index_lcm_overwrite(res[B[i].first].ldeg,res[B[i].second].ldeg,tmp1,order);
12547 #ifdef GIAC_GBASIS_DELAYPAIRS
12548       if (!multimodular){
12549 	// look for the pair B[i].second,pos compared to B[i].first/B[i].second
12550 	// and delay pair (seems slower in multimodular mode)
12551 	// this speeds up problems with symmetries like cyclic*
12552 	// comparisons below seem reversed but they increase speed probably
12553 	// because they detect symmetries
12554 	tdeg_t tmpBi2;
12555 	index_lcm(h0,res[B[i].second].ldeg,tmpBi2,order);
12556 	if (int p=equalposcomp(C,B[i].second)){
12557 	  if (
12558 	      0 && tmp1==tmpBi2
12559 	      // tdeg_t_all_greater(tmp1,tmpBi2,order)
12560 	      ){
12561 	    C[p-1]=C[p-1]|0x80000000;
12562 	    B1.push_back(B[i]);
12563 	    continue;
12564 	  }
12565 	  if (
12566 	      //tmp1==tmpBi2
12567 	      tdeg_t_all_greater(tmpBi2,tmp1,order)
12568 	      //tdeg_t_all_greater(tmp1,tmpBi2,order)
12569 	      ){
12570 	    // set B[i] for later reduction
12571 	    B[i].live=false;
12572 	    B1.push_back(B[i]);
12573 	    continue;
12574 	  }
12575 	}
12576 #if 1
12577 	if (int p=equalposcomp(Ccancel,B[i].second)){
12578 	  if (
12579 	      //tmp1==tmpBi2
12580 	      tdeg_t_all_greater(tmpBi2,tmp1,order)
12581 	      //tdeg_t_all_greater(tmp1,tmpBi2,order)
12582              ){
12583 	    B[i].live=false;
12584 	    B1.push_back(B[i]);
12585 	    continue;
12586 	  }
12587 	}
12588 #endif
12589       }
12590 #endif // GIAC_GBASIS_DELAYPAIRS
12591       if (!tdeg_t_all_greater(tmp1,h0,order)){
12592 	B1.push_back(B[i]);
12593 	continue;
12594       }
12595       index_lcm_overwrite(res[B[i].first].ldeg,h0,tmp2,order);
12596       if (tmp2==tmp1){
12597 	B1.push_back(B[i]);
12598 	continue;
12599       }
12600       index_lcm_overwrite(res[B[i].second].ldeg,h0,tmp2,order);
12601       if (tmp2==tmp1){
12602 	B1.push_back(B[i]);
12603 	continue;
12604       }
12605     }
12606     // B <- B1 union pairs(h,g) with g in C
12607     for (unsigned i=0;i<C.size();++i){
12608       B1.push_back(paire(pos,C[i]&0x7fffffff));
12609       if (C[i] & 0x80000000)
12610 	B1.back().live=false;
12611     }
12612     swap(B1,B);
12613     // Update G by removing elements with leading monomial >= leading monomial of h
12614     if (debug_infolevel>2){
12615       CERR << CLOCK()*1e-6 << " end, pairs:"<< '\n';
12616       if (debug_infolevel>3)
12617 	CERR << B << '\n';
12618       CERR << "mod begin Groebner interreduce " << '\n';
12619     }
12620     C.clear();
12621     C.reserve(G.size()+1);
12622     // bool pos_pushed=false;
12623     for (unsigned i=0;i<G.size();++i){
12624 #ifdef TIMEOUT
12625       control_c();
12626 #endif
12627       if (interrupted || ctrl_c)
12628 	return;
12629 #ifdef GIAC_GBASIS_REDUCTOR_MAXSIZE
12630       if (!res[G[i]].in_gbasis)
12631 	continue;
12632 #endif
12633       if (!res[G[i]].coord.empty() && !tdeg_t_all_greater(res[G[i]].ldeg,h0,order)){
12634 	C.push_back(G[i]);
12635 	continue;
12636       }
12637 #ifdef GIAC_GBASIS_REDUCTOR_MAXSIZE
12638       if (res[G[i]].coord.size()<=GIAC_GBASIS_REDUCTOR_MAXSIZE){
12639 	res[G[i]].in_gbasis=false;
12640 	C.push_back(G[i]);
12641       }
12642 #endif
12643       // NB: removing all pairs containing i in it does not work
12644     }
12645     if (debug_infolevel>2)
12646       CERR << CLOCK()*1e-6 << " zmod end gbasis update " << '\n';
12647     for (unsigned i=0;i<C.size();++i){
12648       if (!res[C[i]].coord.empty() && tdeg_t_all_greater(h0,res[C[i]].ldeg,order)){
12649 	swap(C,G); return;
12650       }
12651     }
12652     C.push_back(pos);
12653     swap(C,G);
12654   }
12655 
12656   template<class tdeg_t>
convert(const polymod<tdeg_t> & p,zpolymod<tdeg_t> & q,const vector<tdeg_t> & R)12657   void convert(const polymod<tdeg_t> & p,zpolymod<tdeg_t> & q,const vector<tdeg_t> & R){
12658     q.order=p.order;
12659     q.dim=p.dim;
12660     q.coord.clear();
12661     q.coord.reserve(p.coord.size());
12662     typename vector< T_unsigned<modint,tdeg_t> >::const_iterator it=p.coord.begin(),itend=p.coord.end();
12663     typename vector<tdeg_t>::const_iterator jt=R.begin(),jt0=jt,jtend=R.end();
12664     for (;it!=itend;++it){
12665       const tdeg_t & u=it->u;
12666       for (;jt!=jtend;++jt){
12667 	if (*jt==u)
12668 	  break;
12669       }
12670       if (jt!=jtend){
12671 	q.coord.push_back(zmodint(it->g,int(jt-jt0)));
12672 	++jt;
12673       }
12674       else
12675 	COUT << "not found" << '\n';
12676     }
12677     q.expo=&R;
12678     if (!q.coord.empty())
12679       q.ldeg=R[q.coord.front().u];
12680     q.fromleft=p.fromleft;
12681     q.fromright=p.fromright;
12682     q.age=p.age;
12683     q.logz=p.logz;
12684   }
12685 
12686   template<class tdeg_t>
convert(const zpolymod<tdeg_t> & p,polymod<tdeg_t> & q)12687   void convert(const zpolymod<tdeg_t> & p,polymod<tdeg_t> & q){
12688     q.dim=p.dim;
12689     q.order=p.order;
12690     q.coord.clear();
12691     q.coord.reserve(p.coord.size());
12692     vector< zmodint >::const_iterator it=p.coord.begin(),itend=p.coord.end();
12693     const vector<tdeg_t> & expo=*p.expo;
12694     for (;it!=itend;++it){
12695       q.coord.push_back(T_unsigned<modint,tdeg_t>(it->g,expo[it->u]));
12696     }
12697     q.fromleft=p.fromleft;
12698     q.fromright=p.fromright;
12699     q.age=p.age;
12700     q.logz=p.logz;
12701   }
12702 
12703   template<class tdeg_t>
zincrease(vector<zpolymod<tdeg_t>> & v)12704   void zincrease(vector<zpolymod<tdeg_t> > &v){
12705     if (v.size()!=v.capacity())
12706       return;
12707     vector<zpolymod<tdeg_t> > w;
12708     w.reserve(v.size()*2);
12709     for (unsigned i=0;i<v.size();++i){
12710       w.push_back(zpolymod<tdeg_t>(v[i].order,v[i].dim,v[i].expo,v[i].ldeg));
12711       w[i].coord.swap(v[i].coord);
12712       w[i].age=v[i].age;
12713       w[i].fromleft=v[i].fromleft;
12714       w[i].fromright=v[i].fromright;
12715       w[i].age=v[i].age;
12716       w[i].logz=v[i].logz;
12717     }
12718     v.swap(w);
12719   }
12720 
12721   template<class tdeg_t>
smod(polymod<tdeg_t> & resmod,modint env)12722   void smod(polymod<tdeg_t> & resmod,modint env){
12723     typename std::vector< T_unsigned<modint,tdeg_t> >::iterator it=resmod.coord.begin(),itend=resmod.coord.end();
12724     for (;it!=itend;++it){
12725       modint n=it->g;
12726 #if 0
12727       n %= env;
12728 #endif
12729       if (n*2LL>env)
12730 	it->g -= env;
12731       else {
12732 	if (n*2LL<=-env)
12733 	  it->g += env;
12734       }
12735     }
12736   }
12737 
12738   template<class tdeg_t>
smod(vectpolymod<tdeg_t> & resmod,modint env)12739   void smod(vectpolymod<tdeg_t> & resmod,modint env){
12740     for (unsigned i=0;i<resmod.size();++i)
12741       smod(resmod[i],env);
12742   }
12743 
12744 #if 0 // def HAVE_LIBPTHREAD // too slow because of mem locks
12745   template<class tdeg_t>
12746   struct zfinal_interreduce_t {
12747     vectpolymod<tdeg_t> * res,*resmod;
12748     vector<unsigned> * G;
12749     modint env;
12750     int start,end;
12751   };
12752 
12753   template<class tdeg_t>
12754   void * do_zfinal_interreduce(void * ptr_){
12755     zfinal_interreduce_t<tdeg_t> * ptr=(zfinal_interreduce_t<tdeg_t> *) ptr_;
12756     vectpolymod<tdeg_t> &res=*ptr->res;
12757     const vectpolymod<tdeg_t> &resmod=*ptr->resmod;
12758     vector<unsigned> & G=*ptr->G;
12759     int end=giacmin(G.size(),ptr->end);
12760     polymod<tdeg_t> TMP1(res[G[0]].order,res[G[0]].dim);
12761     for (int j=ptr->start; j<end;++j){
12762       reducesmallmod(res[G[j]],resmod,G,j,ptr->env,TMP1,true,0);
12763     }
12764     return ptr;
12765   }
12766 
12767   template<class tdeg_t>
12768   void zfinal_interreduce(vectpolymod<tdeg_t> &resmod,vector<unsigned> & G,modint env,int parallel){
12769     if (resmod.empty() || G.empty())
12770       return;
12771     vectpolymod<tdeg_t> res(resmod);
12772     pthread_t tab[parallel];
12773     zfinal_interreduce_t<tdeg_t> interreduceparam[parallel];
12774     int kstep=int(std::ceil(G.size()/double(parallel))),start=0,end=kstep;
12775     for (int j=0;j<parallel;++j){
12776       zfinal_interreduce_t<tdeg_t> tmp={&res,&resmod,&G,env,start,end};
12777       start=end;
12778       end += kstep;
12779       interreduceparam[j]=tmp;
12780       bool res=true;
12781       if (j<parallel-1)
12782 	res=pthread_create(&tab[j],(pthread_attr_t *) NULL,do_zfinal_interreduce<tdeg_t>,(void *) &interreduceparam[j]);
12783       if (res)
12784 	do_zfinal_interreduce<tdeg_t>((void *)&interreduceparam[j]);
12785     }
12786     for (int j=0;j<parallel;++j){
12787       void * ptr=(void *)&parallel; // non-zero initialisation
12788       if (j<parallel-1)
12789 	pthread_join(tab[j],&ptr);
12790     }
12791     res.swap(resmod);
12792   }
12793 #endif
12794 
12795   template<class tdeg_t>
in_zgbasis(vectpolymod<tdeg_t> & resmod,unsigned ressize,vector<unsigned> & G,modint env,bool totdeg,vector<paire> * pairs_reducing_to_zero,vector<zinfo_t<tdeg_t>> & f4buchberger_info,bool recomputeR,bool eliminate_flag,bool multimodular,int parallel,bool interred)12796   bool in_zgbasis(vectpolymod<tdeg_t> &resmod,unsigned ressize,vector<unsigned> & G,modint env,bool totdeg,vector< paire > * pairs_reducing_to_zero,vector< zinfo_t<tdeg_t> > & f4buchberger_info,bool recomputeR,bool eliminate_flag,bool multimodular,int parallel,bool interred){
12797     unsigned generators=ressize;
12798     bool seldeg=true; int sel1=0;
12799     ulonglong cleared=0;
12800     unsigned learned_position=0,f4buchberger_info_position=0;
12801     bool learning=f4buchberger_info.empty();
12802     unsigned capa = unsigned(f4buchberger_info.capacity());
12803     order_t order=resmod.front().order;
12804     short dim=resmod.front().dim;
12805     // if (order.dim-order.o==1) seldeg=false;
12806     polymod<tdeg_t> TMP2(order,dim);
12807     vector< paire > B,BB;
12808     B.reserve(256); BB.reserve(256);
12809     vector<unsigned> smallposv;
12810     smallposv.reserve(256);
12811     info_t<tdeg_t> information;
12812     if (order.o!=_REVLEX_ORDER && order.o!=_TDEG_ORDER)
12813       totdeg=false;
12814     vector<unsigned> oldG(G);
12815     if (debug_infolevel>1)
12816       CERR << CLOCK()*1e-6 << " initial reduction: " << ressize << " memory " << memory_usage()*1e-6 << '\n';
12817     for (unsigned l=0;l<ressize;++l){
12818 #ifdef GIAC_REDUCEMODULO
12819       reducesmallmod(resmod[l],resmod,G,-1,env,TMP2,env!=0);
12820 #endif
12821       gbasis_updatemod(G,B,resmod,l,TMP2,env,true,oldG);
12822     }
12823     if (debug_infolevel>1)
12824       CERR << CLOCK()*1e-6 << " initial collect, pairs " << B.size() << '\n';
12825     // init zpolymod<tdeg_t> before main loop
12826     collect(resmod,TMP2);
12827     // R0 stores monomials for the initial basis
12828     vector<tdeg_t> R0(TMP2.coord.size());
12829     for (unsigned l=0;l<TMP2.coord.size();++l)
12830       R0[l]=TMP2.coord[l].u;
12831     // Rbuchberger stores monomials for pairs that are not handled by f4
12832     vector< vector<tdeg_t> > Rbuchberger;
12833     const int maxage=65535;
12834     Rbuchberger.reserve(maxage+1);
12835     vectzpolymod<tdeg_t> res;
12836     res.resize(ressize);
12837     for (unsigned l=0;l<ressize;++l){
12838       convert(resmod[l],res[l],R0);
12839       zsmallmultmod(1,res[l],env);
12840     }
12841     resmod.clear();
12842     if (debug_infolevel>1000){
12843       res.dbgprint(); res[0].dbgprint(); // instantiate
12844     }
12845     double timebeg=CLOCK(),autodebug=5e8;
12846     vector<int> start_index_v;
12847     if (debug_infolevel>1)
12848       CERR << CLOCK()*1e-6 << " begin loop, mem " << memory_usage()*1e-6 << '\n';
12849     for (int age=1;!B.empty() && !interrupted && !ctrl_c;++age){
12850       if (f4buchberger_info.size()>=capa-2 || age>maxage){
12851 	CERR << "Error zgbasis too many iterations" << '\n';
12852 	return false; // otherwise reallocation will make pointers invalid
12853       }
12854       if (debug_infolevel<2 && (CLOCK()-timebeg)>autodebug)
12855 	debug_infolevel=multimodular?1:2;
12856       start_index_v.push_back(int(res.size())); // store size for final interreduction
12857 #ifdef TIMEOUT
12858       control_c();
12859 #endif
12860       if (f4buchberger_info_position>=capa-1){
12861 	CERR << "Error f4 info exhausted" << '\n';
12862 	return false;
12863       }
12864       if (debug_infolevel>1)
12865 	CERR << CLOCK()*1e-6 << " begin new iteration " << age << " zmod, " << env << " number of pairs: " << B.size() << ", base size: " << G.size() << '\n';
12866       vector<bool> clean(res.size(),true);
12867       for (unsigned i=0;i<int(G.size());++i){
12868 	clean[G[i]]=false;
12869       }
12870       if (!totdeg){
12871 	for (unsigned i=0;i<int(res.size());++i){
12872 	  if (res[i].maxtdeg==-1)
12873 	    res[i].compute_maxtdeg();
12874 	}
12875       }
12876       vector<tdeg_t> Blcm(B.size());
12877       vector<int> Blcmdeg(B.size());
12878       vector<unsigned> nterms(B.size());
12879       for (unsigned i=0;i<B.size();++i){
12880 	clean[B[i].first]=false;
12881 	clean[B[i].second]=false;
12882 	index_lcm(res[B[i].first].ldeg,res[B[i].second].ldeg,Blcm[i],order);
12883 	if (!totdeg)
12884 	  Blcmdeg[i]=giacmax(res[B[i].first].maxtdeg+(Blcm[i]-res[B[i].first].ldeg).total_degree(order),res[B[i].second].maxtdeg+(Blcm[i]-res[B[i].second].ldeg).total_degree(order));
12885 	nterms[i]=unsigned(res[B[i].first].coord.size()+res[B[i].second].coord.size());
12886       }
12887 #if 1
12888       for (unsigned i=0;i<clean.size();++i){
12889 	if (clean[i] && res[i].coord.capacity()>1){
12890 	  cleared += int(res[i].coord.capacity())-1;
12891 	  zpolymod<tdeg_t> clearer;
12892 	  clearer.coord.swap(res[i].coord);
12893 	}
12894       }
12895 #endif
12896       vector< paire > smallposp;
12897       vector<unsigned> smallposv;
12898       if (!totdeg){
12899 	// find smallest lcm pair in B
12900 	// could also take nterms[i] in account
12901 	unsigned firstdeg=RAND_MAX-1;
12902 	for (unsigned i=0;i<B.size();++i){
12903 	  if (!B[i].live) continue;
12904 	  unsigned f=seldeg?Blcmdeg[i]:Blcm[i].selection_degree(order);
12905 	  //unsigned f=Blcmdeg[i];
12906 	  if (f>firstdeg)
12907 	    continue;
12908 	  if (f<firstdeg){
12909 	    firstdeg=f;
12910 	    continue;
12911 	  }
12912 	}
12913 	for (unsigned i=0;i<B.size();++i){
12914 	  if (!B[i].live) continue;
12915 	  if (
12916 	      (seldeg?Blcmdeg[i]:Blcm[i].selection_degree(order))==firstdeg
12917 	      //Blcmdeg[i]==firstdeg
12918 	      ){
12919 	    smallposv.push_back(i);
12920 	  }
12921 	}
12922 	if (smallposv.empty()) smallposv.resize(B.size());
12923 	if (debug_infolevel>1)
12924 	  CERR << CLOCK()*1e-6 << " zpairs min " << (seldeg?"total degree":"elimination degree ") << firstdeg << " #pairs " << smallposv.size() << '\n';
12925 	if ( seldeg && (smallposv.size()<giacmin(order.o,3))
12926 	    ){
12927 	  ++sel1;
12928 	  if (sel1%5==0){
12929 	    seldeg=!seldeg;
12930 	    if (debug_infolevel)
12931 	      CERR << "Switching pair selection strategy to " << (seldeg?"total degree":"elimination degree") << '\n';
12932 	  }
12933 	}
12934 	else
12935 	  sel1=0;
12936 	if (int(firstdeg)>GBASISF4_MAX_TOTALDEG){
12937 	  CERR << "Error zgbasis degree too large" << '\n';
12938 	  return false;
12939 	}
12940       }
12941       else {
12942 	// find smallest lcm pair in B
12943 	unsigned smallnterms=RAND_MAX,firstdeg=RAND_MAX-1;
12944 	for (unsigned i=0;i<B.size();++i){
12945 	  if (!B[i].live) continue;
12946 	  unsigned f=Blcm[i].total_degree(order);
12947 	  if (f>firstdeg)
12948 	    continue;
12949 	  if (f<firstdeg){
12950 	    firstdeg=f;
12951 	    smallnterms=nterms[i];
12952 	    continue;
12953 	  }
12954 	  if (nterms[i]<smallnterms)
12955 	    smallnterms=nterms[i];
12956 	}
12957 	smallnterms *= 5;
12958 	for (unsigned i=0;i<B.size();++i){
12959 	  if (!B[i].live) continue;
12960 	  if (
12961 	      //nterms[i]<=smallnterms &&
12962 	      Blcm[i].total_degree(order)==firstdeg){
12963 	    smallposv.push_back(i);
12964 	  }
12965 	}
12966 	if (smallposv.empty()) smallposv.resize(B.size());
12967 	if (debug_infolevel>1)
12968 	  CERR << CLOCK()*1e-6 << " zpairs min total degrees, nterms " << firstdeg << "," << smallnterms << " #pairs " << smallposv.size() << '\n';
12969       }
12970       if (debug_infolevel>3)
12971 	CERR << "pairs reduced " << B << " indices " << smallposv << '\n';
12972       if (order.o!=_REVLEX_ORDER && smallposv.size()<=GBASISF4_BUCHBERGER){
12973 	// pairs not handled by f4
12974 	int modsize=int(resmod.size());
12975 	if (modsize<res.size())
12976 	  resmod.resize(res.size());
12977 	for (int i=0;i<int(G.size());++i){
12978 	  int Gi=G[i];
12979 	  if (resmod[Gi].coord.empty())
12980 	    convert(res[Gi],resmod[Gi]);
12981 	}
12982 	polymod<tdeg_t> TMP1(order,dim),TMP2(order,dim);
12983 	zpolymod<tdeg_t> TMP;
12984 	paire bk=B[smallposv.back()];
12985 	B.erase(B.begin()+smallposv.back());
12986 	if (!learning && pairs_reducing_to_zero && learned_position<pairs_reducing_to_zero->size() && bk==(*pairs_reducing_to_zero)[learned_position]){
12987 	  if (debug_infolevel>2)
12988 	    CERR << bk << " learned " << learned_position << '\n';
12989 	  ++learned_position;
12990 	  continue;
12991 	}
12992 	if (debug_infolevel>2)
12993 	  CERR << bk << " not learned " << learned_position << '\n';
12994 	if (resmod[bk.first].coord.empty())
12995 	  convert(res[bk.first],resmod[bk.first]);
12996 	if (resmod[bk.second].coord.empty())
12997 	  convert(res[bk.second],resmod[bk.second]);
12998 	spolymod<tdeg_t>(resmod[bk.first],resmod[bk.second],TMP1,TMP2,env);
12999 	if (debug_infolevel>1){
13000 	  CERR << CLOCK()*1e-6 << " mod reduce begin, pair " << bk << " spoly size " << TMP1.coord.size() << " totdeg deg " << TMP1.coord.front().u.total_degree(order) << " degree " << TMP1.coord.front().u << ", pair degree " << resmod[bk.first].coord.front().u << resmod[bk.second].coord.front().u << '\n';
13001 	}
13002 #if 1
13003 	reducesmallmod(TMP1,resmod,G,-1,env,TMP2,true,0,true);
13004 	// insure that new basis element has positive coord, required by zf4mod
13005 	typename vector< T_unsigned<modint,tdeg_t> >::iterator it=TMP1.coord.begin(),itend=TMP1.coord.end();
13006 	for (;it!=itend;++it){
13007 	  if (it->g<0)
13008 	    it->g += env;
13009 	}
13010 	// reducemod(TMP1,resmod,G,-1,TMP1,env,true);
13011 #else
13012 	polymod<tdeg_t> TMP3(TMP1);
13013 	reducemod(TMP1,resmod,G,-1,TMP1,env,true);
13014 	reducesmallmod(TMP3,resmod,G,-1,env,TMP2,true,0,true);
13015 	typename vector< T_unsigned<modint,tdeg_t> >::iterator it=TMP3.coord.begin(),itend=TMP3.coord.end();
13016 	for (;it!=itend;++it){
13017 	  if (it->g<0)
13018 	    it->g += env;
13019 	}
13020 	if (TMP3.coord!=TMP1.coord){
13021 	  CERR << "Bug" << '\n';
13022 	}
13023 #endif
13024 	if (debug_infolevel>1){
13025 	  if (debug_infolevel>3){ CERR << TMP1 << '\n'; }
13026 	  CERR << CLOCK()*1e-6 << " mod reduce end, remainder degree " << TMP1.coord.front().u << " size " << TMP1.coord.size() << " begin gbasis update" << '\n';
13027 	}
13028 	if (!TMP1.coord.empty()){
13029 	  resmod.push_back(TMP1);
13030 	  Rbuchberger.push_back(vector<tdeg_t>(TMP1.coord.size()));
13031 	  vector<tdeg_t> & R0=Rbuchberger.back();
13032 	  for (unsigned l=0;l<unsigned(TMP1.coord.size());++l)
13033 	    R0[l]=TMP1.coord[l].u;
13034 	  convert(TMP1,TMP,R0);
13035 	  zincrease(res);
13036 	  if (ressize==res.size())
13037 	    res.push_back(zpolymod<tdeg_t>(order,dim,TMP.ldeg));
13038 	  res[ressize].expo=TMP.expo;
13039 	  swap(res[ressize].coord,TMP.coord);
13040 	  ++ressize;
13041 	  zgbasis_updatemod(G,B,res,ressize-1,oldG,multimodular);
13042 	  if (debug_infolevel>3)
13043 	    CERR << CLOCK()*1e-6 << " mod basis indexes " << G << " pairs indexes " << B << '\n';
13044 	}
13045 	else {
13046 	  if (learning && pairs_reducing_to_zero){
13047 	    if (debug_infolevel>2)
13048 	      CERR << "learning " << bk << '\n';
13049 	    pairs_reducing_to_zero->push_back(bk);
13050 	  }
13051 	}
13052 	continue;
13053       } // end if smallposp.size() small
13054       unsigned np=smallposv.size();
13055       if (np==B.size() && np<=max_pairs_by_iteration){
13056 	swap(smallposp,B);
13057 	B.clear();
13058       }
13059       else {
13060 	// multiply by parallel?
13061 	if (//!pairs_reducing_to_zero &&
13062 	    np>max_pairs_by_iteration)
13063 	  np=max_pairs_by_iteration;
13064 	for (unsigned i=0;i<np;++i)
13065 	  smallposp.push_back(B[smallposv[i]]);
13066 	// remove pairs
13067 	for (int i=int(np)-1;i>=0;--i)
13068 	  B.erase(B.begin()+smallposv[i]);
13069       }
13070       vectzpolymod<tdeg_t> f4buchbergerv; // collect all spolys
13071       int f4res=-1;
13072       const vector<unsigned> * permuBptr=0;
13073 #if 0
13074       unsigned Galls=G.back();
13075       vector<unsigned> Gall;
13076       Gall.reserve(Galls);
13077       for (unsigned i=0;i<Galls;++i){
13078 	if (!clean[i])
13079 	  Gall.push_back(i);
13080       }
13081       f4res=zf4mod(res,Gall,env,smallposp,permuBptr,f4buchbergerv,learning,learned_position,pairs_reducing_to_zero,f4buchberger_info,f4buchberger_info_position,recomputeR,age,multimodular,parallel,false);
13082 #else
13083       f4res=zf4mod(res,G,env,smallposp,permuBptr,f4buchbergerv,learning,learned_position,pairs_reducing_to_zero,f4buchberger_info,f4buchberger_info_position,recomputeR,age,multimodular,parallel,false);
13084 #endif
13085       if (f4res==-1)
13086 	return false;
13087       if (f4res==0)
13088 	continue;
13089       if (!permuBptr && !learning && f4buchberger_info_position-1<f4buchberger_info.size())
13090 	permuBptr=&f4buchberger_info[f4buchberger_info_position-1].permuB;
13091       if (permuBptr){
13092 	for (unsigned i=0;i<f4buchbergerv.size();++i){
13093 	  f4buchbergerv[i].fromleft=smallposp[(*permuBptr)[i]].first;
13094 	  f4buchbergerv[i].fromright=smallposp[(*permuBptr)[i]].second;
13095 	  f4buchbergerv[i].logz=res[f4buchbergerv[i].fromleft].logz+res[f4buchbergerv[i].fromright].logz;
13096 	}
13097       }
13098       // update gbasis and learning
13099       // requires that Gauss pivoting does the same permutation for other primes
13100       if (multimodular && learning && pairs_reducing_to_zero){
13101 	for (unsigned i=0;i<f4buchbergerv.size();++i){
13102 	  if (f4buchbergerv[i].coord.empty()){
13103 	    if (debug_infolevel>2)
13104 	      CERR << "learning f4buchberger " << smallposp[(*permuBptr)[i]] << '\n';
13105 	    pairs_reducing_to_zero->push_back(smallposp[(*permuBptr)[i]]);
13106 	  }
13107 	}
13108       }
13109       unsigned added=0;
13110       for (unsigned i=0;i<f4buchbergerv.size();++i){
13111 	if (!f4buchbergerv[i].coord.empty())
13112 	  ++added;
13113       }
13114       if (debug_infolevel>1)
13115 	CERR << CLOCK()*1e-6 << " reduce f4buchberger end on " << added << " from " << f4buchbergerv.size() << " pairs, gbasis update begin" << '\n';
13116       vector<unsigned> oldG(G);
13117       for (int i=0;i<f4buchbergerv.size();++i){
13118 	// for (int i=f4buchbergerv.size()-1;i>=0;--i){
13119 	if (!f4buchbergerv[i].coord.empty()){
13120 	  zincrease(res);
13121 	  if (debug_infolevel>2)
13122 	    CERR << CLOCK()*1e-6 << " adding to basis leading degree " << f4buchbergerv[i].ldeg << '\n';
13123 	  if (ressize==res.size())
13124 	    res.push_back(zpolymod<tdeg_t>(order,dim,f4buchbergerv[i].ldeg));
13125 	  res[ressize].expo=f4buchbergerv[i].expo;
13126 	  swap(res[ressize].coord,f4buchbergerv[i].coord);
13127 	  res[ressize].age=f4buchbergerv[i].age;
13128 	  res[ressize].fromleft=f4buchbergerv[i].fromleft;
13129 	  res[ressize].fromright=f4buchbergerv[i].fromright;
13130 	  res[ressize].logz=f4buchbergerv[i].logz;
13131 	  ++ressize;
13132 	  if (!multimodular || learning || f4buchberger_info_position-1>=f4buchberger_info.size())
13133 	    zgbasis_updatemod(G,B,res,ressize-1,oldG,multimodular);
13134 	}
13135 	else {
13136 	  // if (!learning && pairs_reducing_to_zero)  CERR << " error learning "<< '\n';
13137 	}
13138       }
13139       if (!multimodular) continue;
13140       if (!learning && f4buchberger_info_position-1<f4buchberger_info.size()){
13141 	B=f4buchberger_info[f4buchberger_info_position-1].B;
13142 	G=f4buchberger_info[f4buchberger_info_position-1].G;
13143 	continue;
13144       }
13145       if (learning){
13146 	f4buchberger_info.back().B=B;
13147 	f4buchberger_info.back().G=G;
13148 	f4buchberger_info.back().nonzero=added;
13149       }
13150       //unsigned debut=G.size()-added;
13151       // CERR << "finish loop G.size "<<G.size() << '\n';
13152       // CERR << added << '\n';
13153     } // end main loop
13154 #ifdef GIAC_GBASIS_REDUCTOR_MAXSIZE
13155     // remove small size reductors that were kept despite not being in gbasis
13156     vector<unsigned> G1;
13157     for (unsigned i=0;i<G.size();++i){
13158       if (res[G[i]].in_gbasis)
13159 	G1.push_back(G[i]);
13160     }
13161     G.swap(G1);
13162 #endif
13163     // convert back zpolymod<tdeg_t> to polymod<tdeg_t>
13164     // if eliminate_flag is true, keep only basis element that do not depend
13165     // on variables to eliminate
13166     if (eliminate_flag && (order.o==_3VAR_ORDER || order.o>=_7VAR_ORDER)){
13167       resmod.clear();
13168       resmod.reserve(res.size());
13169       for (unsigned l=0;l<res.size();++l){
13170 	tdeg_t d=res[l].ldeg;
13171 #ifndef GBASIS_NO_OUTPUT
13172 	if (d.vars64()){
13173 	  if (d.tab[0]%2){
13174 	    if (d.tab[0]/2)
13175 	      continue;
13176 	  }
13177 	  else {
13178 	    if (d.tdeg)
13179 	      continue;
13180 	  }
13181 	}
13182 	else {
13183 	  if (d.tab[0])
13184 	    continue;
13185 	}
13186 #endif
13187 	resmod.resize(resmod.size()+1);
13188 	convert(res[l],resmod.back());
13189       }
13190       res.clear();
13191       G.resize(resmod.size());
13192       for (unsigned j=0; j<resmod.size();++j)
13193 	G[j]=j;
13194       // final interreduce step2
13195       polymod<tdeg_t> TMP1(order,dim);
13196       for (unsigned j=0; j<resmod.size();++j){
13197 	reducesmallmod(resmod[j],resmod,G,j,env,TMP1,true);
13198       }
13199     }
13200     else {
13201       if (debug_infolevel>1)
13202 	CERR << CLOCK()*1e-6 << " zfinal interreduction begin " << G.size() << '\n';
13203       resmod.resize(res.size());
13204       for (unsigned l=0;l<res.size();++l){
13205 	resmod[l].coord.clear();
13206       }
13207       int val=-1;
13208       if (1//generators<100
13209 	  //parallel>1 && threads_allowed && G.size()>=200
13210 	  ){
13211 	val=zinterreduce_convert(res,G,env,learning,learned_position,pairs_reducing_to_zero,f4buchberger_info,f4buchberger_info_position,recomputeR,-1/* age*/,multimodular,parallel,resmod,interred);
13212 	if (debug_infolevel && val<0)
13213 	  CERR << "zinterreduce failure" << '\n';
13214 	// zfinal_interreduce(resmod,G,env,parallel); // res->resmod must be done. discarded because too slow mem locks
13215       }
13216       if (val<0 || val==12345){
13217 	for (unsigned l=0;l<G.size();++l){
13218 	  convert(res[G[l]],resmod[G[l]]);
13219 	}
13220 	res.clear();
13221       }
13222       if (val<0){
13223 	// final interreduce step2
13224 	// by construction resmod[G[j]] is already interreduced by resmod[G[k]] for k<j
13225 	polymod<tdeg_t> TMP1(order,dim);
13226 	for (int j=int(G.size())-1; j>=0;--j){
13227 	  if (debug_infolevel>1){
13228 	    if (j%10==0){ CERR << "+"; CERR.flush();}
13229 	    if (j%500==0){ CERR << CLOCK()*1e-6 << " remaining " << j << '\n';}
13230 	  }
13231 	  if (!start_index_v.empty() && G[j]<start_index_v.back())
13232 	    start_index_v.pop_back();
13233 	  if (0 && order.o==_REVLEX_ORDER) // this optimization did not work for cyclic10mod (at least when max_pairs=4096)
13234 	    reducesmallmod(resmod[G[j]],resmod,G,j,env,TMP1,true,start_index_v.empty()?0:start_index_v.back());
13235 	  else // full interreduction since Buchberger steps do not interreduce
13236 	    reducesmallmod(resmod[G[j]],resmod,G,j,env,TMP1,true,0);
13237 	}
13238       }
13239       if (debug_infolevel>1)
13240 	CERR << CLOCK()*1e-6 << " zfinal interreduction end " << G.size() << '\n';
13241     }
13242     if (ressize<resmod.size())
13243       res.resize(ressize);
13244     if (debug_infolevel){ // was debug_infolevel>1
13245       unsigned t=0;
13246       for (unsigned i=0;i<resmod.size();++i)
13247 	t += unsigned(resmod[i].coord.size());
13248       CERR << CLOCK()*1e-6 << " total number of monomials in res " << t << " basis size " << G.size() << '\n';
13249       CERR << "Number of monomials cleared " << cleared << '\n';
13250     }
13251     smod(resmod,env);
13252     return true;
13253   }
13254 
13255   template<class tdeg_t>
zgbasis(vectpoly8<tdeg_t> & res8,vectpolymod<tdeg_t> & resmod,vector<unsigned> & G,modint env,bool totdeg,vector<paire> * pairs_reducing_to_zero,vector<zinfo_t<tdeg_t>> & f4buchberger_info,bool recomputeR,bool convertpoly8,bool eliminate_flag,bool multimodular,int parallel,bool interred)13256   bool zgbasis(vectpoly8<tdeg_t> & res8,vectpolymod<tdeg_t> &resmod,vector<unsigned> & G,modint env,bool totdeg,vector< paire > * pairs_reducing_to_zero,vector< zinfo_t<tdeg_t> > & f4buchberger_info,bool recomputeR,bool convertpoly8,bool eliminate_flag,bool multimodular,int parallel,bool interred){
13257     for (unsigned i=0;i<resmod.size();++i)
13258       resmod[i].coord.clear();
13259     convert(res8,resmod,env);
13260     unsigned ressize = unsigned(res8.size());
13261     bool b=in_zgbasis(resmod,ressize,G,env,totdeg,pairs_reducing_to_zero,f4buchberger_info,recomputeR,eliminate_flag,multimodular,parallel,interred);
13262     if (convertpoly8)
13263       convert(resmod,res8,env);
13264     return b;
13265   }
13266 
13267 #endif // GIAC_SHORTSHIFTTYPE==16
13268   /* *************
13269      END ZPOLYMOD
13270      ************* */
13271   template<class tdeg_t>
is_gbasis(const vectpoly8<tdeg_t> & res,double eps,bool modularcheck)13272   bool is_gbasis(const vectpoly8<tdeg_t> & res,double eps,bool modularcheck){
13273     if (res.empty())
13274       return false;
13275     if (debug_infolevel>0)
13276       CERR << "basis size " << res.size() << '\n';
13277     // build possible pairs (i,j) with i<j
13278     vector< vector<tdeg_t> > lcmpairs(res.size());
13279     vector<unsigned> G(res.size());
13280     for (unsigned i=0;i<res.size();++i)
13281       G[i]=i;
13282     vectpoly8<tdeg_t> vtmp,tocheck;
13283     vector< paire > tocheckpairs;
13284     if (eps>0 && eps<2e-9)
13285       modularcheck=true;
13286     if (modularcheck)
13287       tocheck.reserve(res.size()*10); // wild guess
13288     else
13289       tocheckpairs.reserve(res.size()*10);
13290     order_t order=res.front().order;
13291     int dim=res.front().dim;
13292     poly8<tdeg_t> TMP1(order,res.front().dim),TMP2(TMP1),
13293       spol(TMP1),spolred(TMP1);
13294     polymod<tdeg_t> spolmod(order,dim),TMP1mod(order,dim);
13295     vectpolymod<tdeg_t> resmod;
13296     for (unsigned i=0;i<res.size();++i){
13297       const poly8<tdeg_t> & h = res[i];
13298       const tdeg_t & h0=h.coord.front().u;
13299       vector<tdeg_t> tmp(res.size());
13300       for (unsigned j=i+1;j<res.size();++j){
13301 	index_lcm(h0,res[j].coord.front().u,tmp[j],h.order);
13302       }
13303       swap(lcmpairs[i],tmp);
13304     }
13305     for (unsigned i=0;i<res.size();++i){
13306       if (debug_infolevel>1)
13307 	CERR << "checking pairs for i="<<i<<", j=";
13308       const poly8<tdeg_t> & resi = res[i];
13309       const tdeg_t & resi0=resi.coord.front().u;
13310       for (unsigned j=i+1;j<res.size();++j){
13311 	if (disjoint(resi0,res[j].coord.front().u,order,dim))
13312 	  continue;
13313 	// criterion M, F
13314 	unsigned J=0;
13315 	tdeg_t & lcmij=lcmpairs[i][j];
13316 	for (;J<i;++J){
13317 	  if (tdeg_t_all_greater(lcmij,lcmpairs[J][j],order))
13318 	    break;
13319 	}
13320 	if (J<i)
13321 	  continue;
13322 	for (++J;J<j;++J){
13323 	  tdeg_t & lcmJj=lcmpairs[J][j];
13324 	  if (tdeg_t_all_greater(lcmij,lcmJj,order) && lcmij!=lcmJj)
13325 	    break;
13326 	}
13327 	if (J<j)
13328 	  continue;
13329 	// last criterion
13330 	unsigned k;
13331 	for (k=j+1;k<res.size();++k){
13332 	  if (lcmpairs[i][k]!=lcmij && lcmpairs[j][k]!=lcmij
13333 	      && tdeg_t_all_greater(lcmij,res[k].coord.front().u,order))
13334 	    break;
13335 	}
13336 	if (k<res.size())
13337 	  continue;
13338 	// compute and reduce s-poly
13339 	if (debug_infolevel>1)
13340 	  CERR <<  j << ",";
13341 	if (modularcheck){
13342 	  spoly(resi,res[j],spol,TMP1,0);
13343 	  tocheck.push_back(poly8<tdeg_t>(order,dim));
13344 	  swap(tocheck.back(),spol);
13345 	}
13346 	else
13347 	  tocheckpairs.push_back(paire(i,j));
13348       } // end j loop
13349       if (debug_infolevel>1)
13350 	CERR << '\n';
13351     }
13352     if (debug_infolevel>0)
13353       CERR << "Number of critical pairs to check " << (modularcheck?tocheck.size():tocheckpairs.size()) << '\n';
13354     if (modularcheck) // modular check is sometimes slow
13355       return checkf4buchberger(tocheck,res,G,-1,eps); // split version is slower!
13356     // integer check or modular check for one modulus (!= from first prime already used)
13357     modint p=(prevprime((1<<29)-30000000)).val;
13358     if (eps>0)
13359       convert(res,resmod,p);
13360     // FIXME should be parallelized
13361     for (unsigned i=0;i<tocheckpairs.size();++i){
13362 #ifdef TIMEOUT
13363       control_c();
13364 #endif
13365       if (interrupted || ctrl_c){
13366 	CERR << "Check interrupted, assuming Groebner basis. Press Ctrl-C again to interrupt computation" << '\n';
13367 	interrupted=ctrl_c=false;
13368 	return true;
13369       }
13370       if (eps>0){
13371 	spolymod<tdeg_t>(resmod[tocheckpairs[i].first],resmod[tocheckpairs[i].second],spolmod,TMP1mod,p);
13372 	reducemod(spolmod,resmod,G,-1,TMP1mod,p);
13373 	// gen den; heap_reduce(spol,res,G,-1,vtmp,spolred,TMP1,den,0);
13374 	if (!TMP1mod.coord.empty())
13375 	  return false;
13376       }
13377       else {
13378 	spoly(res[tocheckpairs[i].first],res[tocheckpairs[i].second],spol,TMP1,0);
13379 	reduce(spol,res,G,-1,vtmp,spolred,TMP1,TMP2,0);
13380 	// gen den; heap_reduce(spol,res,G,-1,vtmp,spolred,TMP1,den,0);
13381 	if (!spolred.coord.empty())
13382 	  return false;
13383       }
13384       if (debug_infolevel>0){
13385 	CERR << "+";
13386 	if (i%512==511)
13387 	  CERR << tocheckpairs.size()-i << " remaining" << '\n';
13388       }
13389     }
13390     if (debug_infolevel)
13391       CERR << '\n' << "Successful check of " << tocheckpairs.size() << " critical pairs" << '\n';
13392     return true;
13393   }
13394 
13395 
13396   /* *************
13397      RUR UTILITIES (rational univariate representation for 0 dimension ideals)
13398      ************* */
rur_dim(int dim,order_t order)13399   int rur_dim(int dim,order_t order){
13400     if (order.o==_3VAR_ORDER) return 3;
13401     if (order.o==_7VAR_ORDER) return 7;
13402     if (order.o==_11VAR_ORDER) return 11;
13403     if (order.o==_16VAR_ORDER) return 16;
13404     if (order.o==_32VAR_ORDER) return 32;
13405     if (order.o==_48VAR_ORDER) return 48;
13406     if (order.o==_64VAR_ORDER) return 64;
13407     return dim;
13408   }
13409 
13410   // returns -1 if not 0 dimensional, -RAND_MAX if overflow
13411   // otherwise returns dimension of quotient and sets lm to the list of
13412   // leading monomials generating the quotient ideal
13413   template<class tdeg_t>
rur_quotient_ideal_dimension(const vectpolymod<tdeg_t> & gbmod,polymod<tdeg_t> & lm)13414   int rur_quotient_ideal_dimension(const vectpolymod<tdeg_t> & gbmod,polymod<tdeg_t> & lm){
13415     if (gbmod.empty())
13416       return -1;
13417     order_t order=gbmod.front().order;
13418     int dim=gbmod.front().dim;
13419     lm.order=order; lm.dim=dim; lm.coord.clear();
13420     polymod<tdeg_t> gblm(order,dim);
13421     unsigned S = unsigned(gbmod.size());
13422     for (unsigned i=0;i<S;++i){
13423       if (gbmod[i].coord.empty())
13424 	continue;
13425       gblm.coord.push_back(gbmod[i].coord.front());
13426     }
13427     // for 3var, 7var, 11 var search in the first 3 var, 7 var or 11 var
13428     // for revlex search for all variables
13429     // we must find a leading monomial in gbmod that contains only this variable
13430     int d=rur_dim(dim,order);
13431     vector<int> v(d);
13432     for (unsigned i=0;i<S;++i){
13433       index_t l;
13434       get_index(gblm.coord[i].u,l,order,dim);
13435       unsigned j,k;
13436       for (j=0;int(j)<d;++j){
13437 	if (l[j]){
13438 	  for (k=j+1;int(k)<d;++k){
13439 	    if (l[k])
13440 	      break;
13441 	  }
13442 	  if (k==d)
13443 	    v[j]=l[j];
13444 	  break;
13445 	}
13446       }
13447     }
13448     // now all indices of v must be non 0
13449     double M=1;
13450     for (unsigned i=0;i<v.size();++i){
13451       if (v[i]==0)
13452 	return -1;
13453       M *= v[i];
13454     }
13455     if (M>1e6)
13456       return -RAND_MAX; // overflow
13457     // the ideal is finite dimension, now we will compute the exact dimension
13458     // a monomial degree is associated to an integer with
13459     // [l_0,l_1,...,l_{d-1}] -> ((l_0*v1+l_1)*v2+...+l_{d-1} < v0*v1*...
13460     // perhaps a sieve would be faster, but it's harder to implement
13461     // and we won't consider too high order anyway...
13462     index_t cur(d);
13463     for (int I=0;I<M;++I){
13464       int i=I;
13465       // i-> cur -> tdeg_t
13466       for (int j=int(v.size())-1;j>=0;--j){
13467 	cur[j]=i%v[j];
13468 	i/=v[j];
13469       }
13470       tdeg_t curu(cur,order);
13471       // then search if > to one of the leading monomials for all indices
13472       unsigned j=-1;
13473       if (order.o==_3VAR_ORDER){
13474 	for (j=0;j<S;++j){
13475 	  tdeg_t u=gblm.coord[j].u;
13476 	  if (curu.tab[1]>=u.tab[1] && curu.tab[2]>=u.tab[2] && curu.tab[3]>=u.tab[3])
13477 	    break;
13478 	}
13479       }
13480       if (order.o==_7VAR_ORDER){
13481       }
13482       if (order.o==_11VAR_ORDER){
13483       }
13484       if (order.o==_REVLEX_ORDER){
13485 	for (j=0;j<S;++j){
13486 	  if (tdeg_t_all_greater(curu,gblm.coord[j].u,order))
13487 	    break;
13488 	}
13489       }
13490       // if found continue, else add cur to the list of monomials
13491       if (j==gbmod.size())
13492 	lm.coord.push_back(T_unsigned<modint,tdeg_t>(1,curu));
13493     }
13494     sort(lm.coord.begin(),lm.coord.end(),tdeg_t_sort_t<tdeg_t>(order));
13495     return unsigned(lm.coord.size());
13496   }
13497 
13498   // multiply a by b mod p in res
13499   // b is supposed to have small length
13500   template<class tdeg_t>
rur_mult(const polymod<tdeg_t> & a,const polymod<tdeg_t> & b,modint p,polymod<tdeg_t> & res)13501   void rur_mult(const polymod<tdeg_t> & a,const polymod<tdeg_t> & b,modint p,polymod<tdeg_t> & res){
13502     res.coord.clear();
13503     polymod<tdeg_t> tmp(b.order,b.dim);
13504     for (unsigned i=0;i<b.coord.size();++i){
13505       smallmultsubmodshift(res,0,(-b.coord[i].g) % p,a,b.coord[i].u,tmp,p);
13506       tmp.coord.swap(res.coord);
13507     }
13508   }
13509 
13510   // coordinates of cur w.r.t. lm
13511   template<class tdeg_t>
rur_coordinates(const polymod<tdeg_t> & cur,const polymod<tdeg_t> & lm,vecteur & tmp)13512   void rur_coordinates(const polymod<tdeg_t> & cur,const polymod<tdeg_t> & lm,vecteur & tmp){
13513     unsigned k=0,j=0;
13514     for (;j<lm.coord.size() && k<cur.coord.size();++j){
13515       if (lm.coord[j].u!=cur.coord[k].u)
13516 	tmp[j]=0;
13517       else {
13518 	tmp[j]=cur.coord[k].g;
13519 	++k;
13520       }
13521     }
13522     for (;j<lm.coord.size();++j){
13523       tmp[j]=0;
13524     }
13525   }
13526 
13527   // s*coordinates reduced as a linear combination of the lines of M
13528   template<class tdeg_t>
rur_linsolve(const vectpolymod<tdeg_t> & gbmod,const polymod<tdeg_t> & lm,const polymod<tdeg_t> & s,const matrice & M,modint p,matrice & res)13529   bool rur_linsolve(const vectpolymod<tdeg_t> & gbmod,const polymod<tdeg_t> & lm,const polymod<tdeg_t> & s,const matrice & M,modint p,matrice & res){
13530     int S=int(lm.coord.size()),dim=lm.dim;
13531     order_t order=lm.order;
13532     polymod<tdeg_t> TMP1(order,dim);
13533     vector<unsigned> G(gbmod.size());
13534     for (unsigned i=0;i<G.size();++i)
13535       G[i]=i;
13536     matrice N(M);
13537     polymod<tdeg_t> si(order,dim);
13538     int d=rur_dim(dim,order);
13539     vecteur tmp(lm.coord.size());
13540     for (unsigned i=0;int(i)<d;++i){
13541       index_t l(dim);
13542       l[i]=1;
13543       smallshift(s.coord,tdeg_t(l,order),si.coord);
13544       reducesmallmod(si,gbmod,G,-1,p,TMP1,false);
13545       // get coordinates of cur in tmp (make them mod p)
13546       rur_coordinates(si,lm,tmp);
13547       N.push_back(tmp);
13548     }
13549     N=mtran(N);
13550     if (debug_infolevel)
13551       CERR << CLOCK()*1e-6 << " rur rref" << '\n';
13552     gen n=_rref(N,context0);
13553     if (!ckmatrix(n))
13554       return false;
13555     N=mtran(*n._VECTptr);
13556     // check that first line are idn
13557     for (unsigned i=0;i<lm.coord.size();++i){
13558       vecteur & Ni=*N[i]._VECTptr;
13559       for (unsigned j=0;j<lm.coord.size();++j){
13560 	if (i==j && !is_one(Ni[j]))
13561 	  return false;
13562 	if (i!=j && !is_zero(Ni[j]))
13563 	  return false;
13564       }
13565     }
13566     N=vecteur(N.begin()+lm.coord.size(),N.end());
13567     for (unsigned i=0;i<N.size();++i){
13568       vecteur & m =*N[i]._VECTptr;
13569       for (unsigned j=0;j<m.size();++j){
13570 	if (m[j].type==_MOD)
13571 	  m[j]=*m[j]._MODptr;
13572       }
13573       reverse(m.begin(),m.end());
13574       m=trim(m,0);
13575     }
13576     res=N;
13577     return true;
13578   }
13579 
13580   // Compute minimal polynomial of s
13581   template<class tdeg_t>
rur_minpoly(const vectpolymod<tdeg_t> & gbmod,const polymod<tdeg_t> & lm,const polymod<tdeg_t> & s,modint p,vecteur & m,matrice & M)13582   bool rur_minpoly(const vectpolymod<tdeg_t> & gbmod,const polymod<tdeg_t> & lm,const polymod<tdeg_t> & s,modint p,vecteur & m,matrice & M){
13583     int S=int(lm.coord.size()),dim=lm.dim;
13584     order_t order=lm.order;
13585     polymod<tdeg_t> TMP1(order,dim);
13586     vector<unsigned> G(gbmod.size());
13587     for (unsigned i=0;i<G.size();++i)
13588       G[i]=i;
13589     M.clear();
13590     // set th i-th row of M with coordinates of s^i reduced/gbmod in terms of lm
13591     vecteur tmp(S);
13592     tmp[0]=makemod(0,p);
13593     tmp[S-1]=1;
13594     M.push_back(tmp);
13595     polymod<tdeg_t> cur(s);
13596     for (unsigned i=1;i<=lm.coord.size();++i){
13597       reducesmallmod(cur,gbmod,G,-1,p,TMP1,false);
13598       // get coordinates of cur in tmp (make them mod p)
13599       rur_coordinates(cur,lm,tmp);
13600       M.push_back(tmp);
13601       // multiply cur and s
13602       rur_mult(cur,s,p,TMP1);
13603       cur.coord.swap(TMP1.coord);
13604     }
13605     matrice N(M);
13606     M.pop_back(); // remove the last one (for further computations, assuming max rank)
13607     if (!N.empty() && !N.front()._VECTptr->empty()) N=mtran(N);
13608     vecteur K;
13609     if (debug_infolevel)
13610       CERR << CLOCK()*1e-6 << " begin rur ker" << '\n';
13611     if (!mker(N,K,1,context0) || K.empty() || K.front().type!=_VECT)
13612       return false;
13613     if (debug_infolevel)
13614       CERR << CLOCK()*1e-6 << " end rur ker" << '\n';
13615     m=*K.front()._VECTptr;
13616     for (unsigned i=0;i<m.size();++i){
13617       if (m[i].type==_MOD)
13618 	m[i]=*m[i]._MODptr;
13619     }
13620     reverse(m.begin(),m.end());
13621     m=trim(m,0);
13622     if (debug_infolevel>1)
13623       CERR << "Minpoly for " << s << ":" << m << '\n';
13624     return true;
13625   }
13626 
13627   template<class tdeg_t>
rur_convert_univariate(const vecteur & v,int varno,polymod<tdeg_t> & tmp)13628   void rur_convert_univariate(const vecteur & v,int varno,polymod<tdeg_t> & tmp){
13629     int vs=int(v.size());
13630     order_t order=tmp.order;
13631     tmp.coord.clear();
13632     index_t l(tmp.dim);
13633     for (unsigned j=0;int(j)<vs;++j){
13634       l[varno]=vs-1-j;
13635       if (v[j].val)
13636 	tmp.coord.push_back(T_unsigned<modint,tdeg_t>(v[j].val,tdeg_t(index_m(l),order)));
13637     }
13638   }
13639 
13640   // if radical==-1, shrink the ideal to radical part
13641   // if radical==1, the ideal is already radical
13642   // if radical==0, also tries with radical ideal
13643   // find a separating element, given the groebner basis and the list of leading
13644   // monomials of a basis of the quotient ideal
13645   // if true, then separating element is s
13646   // and s has m as minimal polynomial,
13647   // M is the list of rows coordinates of powers of s in lm
13648   // This will not work if the ideal is not a radical ideal
13649   // In that case, if we get a minimal pol of degree M > lm.size()/2 for one coord.
13650   // we search for each coordinate a relation polynomial1*coordinate-polynomial2=0
13651   // where degree(polynomial2)<M and degree(polynomial1) <= lm.size()-M
13652   // then we must consider particular values of t that cancel gcd(polynomial1,minpoly)
13653   template<class tdeg_t>
rur_separate(vectpolymod<tdeg_t> & gbmod,polymod<tdeg_t> & lm,modint p,polymod<tdeg_t> & s,vecteur & m,matrice & M,int radical)13654   bool rur_separate(vectpolymod<tdeg_t> & gbmod,polymod<tdeg_t> & lm,modint p,polymod<tdeg_t> & s,vecteur & m,matrice & M,int radical){
13655     order_t order=lm.order;
13656     int dim=lm.dim,d=rur_dim(dim,order);
13657     s.order=order; s.dim=dim;
13658     // first try coordinates
13659     vecteur minp(d);
13660     for (int i=d-1;i>=0;--i){
13661       s.coord.clear(); m.clear(); M.clear();
13662       index_t l(dim);
13663       l[i]=1;
13664       s.coord.push_back(T_unsigned<modint,tdeg_t>(1,tdeg_t(l,order)));
13665       if (!rur_minpoly(gbmod,lm,s,p,m,M))
13666 	return false;
13667       if (m.size()==lm.coord.size()+1)
13668 	return true;
13669       // keep m in order to shrink to the radical ideal if separation fails
13670       if (radical<=0)
13671 	minp[i]=m;
13672     }
13673     // now try a random small integer linear combination
13674     if (radical!=-1){
13675       // 6 july 2020: # of tries 40->100 for
13676       // eqs:=[c^2 - 3, -a^14 + 85/6*a^12 - 13465/144*a^10 + 54523/144*a^8 - 20819/18*a^6 + 8831/3*a^4 - 7384*a^2 + 10800, -b^14 + 59/4*b^12 - 459/4*b^10 + 8159/16*b^8 - 11777/8*b^6 + 40395/16*b^4 - 10971/4*b^2 + 3267, -1/599040*(53136*b^14 - 692236*b^12 + 4886796*b^10 - 20593959*b^8 + 57747314*b^6 - 116274195*b^4 + 186055404*b^2 - 162887472)*(1008*a^13 - 12240*a^11 + 67325*a^9 - 218092*a^7 + 499656*a^5 - 847776*a^3 + 1063296*a) - 1/112320*(111024*a^14 - 1310760*a^12 + 7843395*a^10 - 35101603*a^8 + 158038072*a^6 - 630801328*a^4 + 1561088256*a^2 - 1489593600)*(56*b^13 - 708*b^11 + 4590*b^9 - 16318*b^7 + 35331*b^5 - 40395*b^3 + 21942*b)];
13677       // pour j de 1 jusque 100 faire gb:=gbasis(eqs,[c,a,b],rur);fpour;
13678       // 40 was insufficient for the 11th gbasis rur computation
13679       for (unsigned essai=0;essai<100;++essai){
13680 	s.coord.clear(); m.clear(); M.clear();
13681 	int n=(3+essai/5);
13682 	int r=int(std_rand()*std::pow(double(n),double(d))/RAND_MAX),r1;
13683 	for (unsigned i=0;int(i)<d;++i){
13684 	  index_t l(dim);
13685 	  l[i]=1;
13686 	  r1=(r%n)-n/2;
13687 	  r/=n;
13688 	  if (r1)
13689 	    s.coord.push_back(T_unsigned<modint,tdeg_t>(r1,tdeg_t(l,order)));
13690 	}
13691 	if (!rur_minpoly(gbmod,lm,s,p,m,M))
13692 	  return false;
13693 	if (m.size()==lm.coord.size()+1)
13694 	  return true;
13695       }
13696       if (radical==1)
13697 	return false;
13698     }
13699     // shrink ideal and try again
13700     bool shrinkit=false;
13701     environment env;
13702     env.modulo=p;
13703     env.moduloon=true;
13704     for (unsigned i=0;int(i)<d;++i){
13705       if (minp[i].type!=_VECT)
13706 	continue;
13707       m=*minp[i]._VECTptr;
13708       if (m.empty())
13709 	continue;
13710       vecteur m1=derivative(m,&env);
13711       m1=gcd(m,m1,&env);
13712       if (m1.size()>1){
13713 	if (debug_infolevel)
13714 	  CERR << "Adding sqrfree part " << m1 << " coordinate " << i << '\n';
13715 	m1=operator_div(m,m1,&env); // m1 is the square free part
13716 	polymod<tdeg_t> m1mod(order,dim);
13717 	rur_convert_univariate(m1,i,m1mod);
13718 	unsigned j;
13719 	for (j=0;j<gbmod.size();++j){
13720 	  if (tdeg_t_greater(m1mod.coord.front().u,gbmod[j].coord.front().u,order))
13721 	    break;
13722 	}
13723 	gbmod.insert(gbmod.begin()+j,m1mod);
13724 	shrinkit=true;
13725       }
13726     }
13727     if (!shrinkit)
13728       return false;
13729     vector<unsigned> G;
13730     if (!in_gbasisf4buchbergermod<tdeg_t>(gbmod,unsigned(gbmod.size()),G,p,/* totdeg */ true,0,0,true))
13731       return false;
13732     vectpolymod<tdeg_t> newgb;
13733     for (unsigned i=0;i<G.size();++i)
13734       newgb.push_back(gbmod[G[i]]);
13735     newgb.swap(gbmod);
13736     lm.coord.clear();
13737     if (rur_quotient_ideal_dimension(gbmod,lm)<0)
13738       return false;
13739     if (radical==-1)
13740       return true;
13741     return rur_separate(gbmod,lm,p,s,m,M,1);
13742   }
13743 
13744   template<class tdeg_t>
rur_convert(const vecteur & v,const polymod<tdeg_t> & lm,polymod<tdeg_t> & res)13745   bool rur_convert(const vecteur & v,const polymod<tdeg_t> & lm,polymod<tdeg_t> & res){
13746     res.coord.clear();
13747     res.order=lm.order; res.dim=lm.dim;
13748     if (v.size()>lm.coord.size())
13749       return false;
13750     for (unsigned i=0;i<v.size();++i){
13751       gen coeff=v[i];
13752       if (!is_zero(coeff))
13753 	res.coord.push_back(T_unsigned<modint,tdeg_t>(coeff.val,lm.coord[i].u));
13754     }
13755     return true;
13756   }
13757 
13758   // set rur to be the list of s,
13759   // m the minimal polynomial of s as a polymod<tdeg_t> wrt the 1st var
13760   // and for each coordinate (sqrfree part of m) * coordinate
13761   // expressed as a polynomial in s (stored in a polymod<tdeg_t> wrt 1st var)
13762   template<class tdeg_t>
rur_compute(vectpolymod<tdeg_t> & gbmod,polymod<tdeg_t> & lm,polymod<tdeg_t> & lmmodradical,int p,polymod<tdeg_t> & s,vectpolymod<tdeg_t> & rur)13763   bool rur_compute(vectpolymod<tdeg_t> & gbmod,polymod<tdeg_t> & lm,polymod<tdeg_t> & lmmodradical,int p,polymod<tdeg_t> & s,vectpolymod<tdeg_t> & rur){
13764     vecteur m,M,res;
13765     int dim=lm.dim;
13766     order_t order=lm.order;
13767     if (s.coord.empty()){
13768       // find separating element
13769       if (!rur_separate(gbmod,lm,p,s,m,M,0))
13770 	return false;
13771     }
13772     else {
13773       // if lm!=lmmodradical, ideal is not radical, recompute radical part
13774       if (!(lm==lmmodradical)){
13775 	polymod<tdeg_t> s1(s.order,s.dim);
13776 	if (!rur_separate(gbmod,lm,p,s1,m,M,-1))
13777 	  return false;
13778       }
13779       // separating element is already known
13780       if (!rur_minpoly(gbmod,lm,s,p,m,M) || m.size()!=lm.coord.size()+1)
13781 	return false;
13782     }
13783     // find the square-free part of m, express it as a polymod<tdeg_t> using M
13784     environment env;
13785     env.modulo=p;
13786     env.moduloon=true;
13787     vecteur m1=derivative(m,&env);
13788     m1=gcd(m,m1,&env);
13789     if (debug_infolevel && m1.size()>1)
13790       CERR << CLOCK()*1e-6 << " sqrfree mod " << p << ":" << m1 << '\n';
13791     m1=operator_div(m,m1,&env); // m1 is the square free part
13792     vecteur m2=derivative(m1,&env); // m2 is the derivative, prime with m1
13793     // make the "product" with M (rows of M are powers of t)
13794     gen m3;
13795     for (unsigned i=0;i<m2.size();++i){
13796       gen coeff=m2[m2.size()-1-i];
13797       m3 += smod(coeff*M[i],p);
13798     }
13799     m3=smod(m3,p);
13800     polymod<tdeg_t> mprime(order,dim);
13801     if (m3.type==_VECT && m3._VECTptr->size()<=lm.coord.size())
13802       rur_convert(*m3._VECTptr,lm,mprime);
13803     else
13804       return false;
13805     if (debug_infolevel)
13806       CERR << CLOCK()*1e-6 << " rur linsolve" << '\n';
13807     if (!rur_linsolve(gbmod,lm,mprime,M,p,res))
13808       return false;
13809     // rur=[separating element,sqrfree part of minpoly,derivative of sqrfree part,
13810     // derivative of sqrfree part*other coordinates]
13811     rur.clear();
13812     rur.push_back(s);
13813     polymod<tdeg_t> tmp(order,dim);
13814     rur_convert_univariate(m1,0,tmp);
13815     rur.push_back(tmp);
13816     rur_convert_univariate(m2,0,tmp);
13817     rur.push_back(tmp);
13818     // convert res to rur
13819     for (unsigned i=0;i<res.size();++i){
13820       index_t l(dim);
13821       vecteur & v = *res[i]._VECTptr;
13822       rur_convert_univariate(v,0,tmp);
13823       rur.push_back(tmp);
13824     }
13825     return true;
13826   }
13827 
13828   // returns -1 if lm1 is not contained in lm2 and lm2 is not contained in lm1
13829   // returns 0 if lm1==lm2
13830   // returns 1 if lm1 contains lm2
13831   // returns 2 if lm2 contains lm1
13832   template<class tdeg_t>
rur_compare(polymod<tdeg_t> & lm1,polymod<tdeg_t> & lm2)13833   int rur_compare(polymod<tdeg_t> & lm1,polymod<tdeg_t> & lm2){
13834     unsigned s1=unsigned(lm1.coord.size()),s2=unsigned(lm2.coord.size());
13835     if (s1==s2){
13836       if (lm1==lm2)
13837 	return 0;
13838       return -1;
13839     }
13840     if (s1>s2){
13841       unsigned i=0;
13842       for (unsigned j=0;j<s2;++i,++j){
13843 	for (;i<s1;++i){
13844 	  if (lm1.coord[i].u==lm2.coord[j].u)
13845 	    break;
13846 	}
13847 	if (i==s1)
13848 	  return -1;
13849       }
13850       return 1;
13851     }
13852     unsigned j=0;
13853     for (unsigned i=0;i<s1;++i,++j){
13854       for (;j<s2;++j){
13855 	if (lm1.coord[i].u==lm2.coord[j].u)
13856 	  break;
13857       }
13858       if (j==s2)
13859 	return -1;
13860     }
13861     return 2;
13862   }
13863 
13864   /* ******************
13865      END RUR UTILITIES
13866      ****************** */
13867 
13868 #ifdef HAVE_LIBPTHREAD
13869   template<class tdeg_t>
13870   struct thread_gbasis_t {
13871     vectpoly8<tdeg_t> current;
13872     vectpolymod<tdeg_t> resmod;
13873     vector<unsigned> G;
13874     int p;
13875     vector< paire > * reduceto0;
13876     vector< info_t<tdeg_t> > * f4buchberger_info;
13877     vector< zinfo_t<tdeg_t> > * zf4buchberger_info;
13878     bool zdata;
13879     bool eliminate_flag; // if true, for double revlex order returns only the gbasis part made of polynomials that do not depend on variables to eliminate
13880     bool interred;
13881     int parallel; // max number of parallel threads for 1 modular computation
13882   };
13883 
13884   template<class tdeg_t>
thread_gbasis(void * ptr_)13885   void * thread_gbasis(void * ptr_){
13886     thread_gbasis_t<tdeg_t> * ptr=(thread_gbasis_t<tdeg_t> *) ptr_;
13887     ptr->G.clear();
13888     if (ptr->zdata){
13889       if (!zgbasis(ptr->current,ptr->resmod,ptr->G,ptr->p,true,
13890 		   ptr->reduceto0,*ptr->zf4buchberger_info,false,false,ptr->eliminate_flag,true,ptr->parallel,ptr->interred))
13891 	return 0;
13892     }
13893     else {
13894       if (!in_gbasisf4buchbergermod(ptr->current,ptr->resmod,ptr->G,ptr->p,true/*totaldeg*/,
13895 				    ptr->reduceto0,ptr->f4buchberger_info,false))
13896 	return 0;
13897     }
13898     return ptr_;
13899   }
13900 #endif
13901 
13902   template<class tdeg_t>
check_initial_generators(vectpoly8<tdeg_t> & res,const vectpoly8<tdeg_t> & Wi,vector<unsigned> & G,double eps)13903   bool check_initial_generators(vectpoly8<tdeg_t> & res,const vectpoly8<tdeg_t> & Wi,vector<unsigned> & G,double eps){
13904     int initial=int(res.size());
13905     poly8<tdeg_t> tmp0,tmp1,tmp2;
13906     vectpoly8<tdeg_t> wtmp;
13907     unsigned j=0,finalchecks=initial;
13908     if (eps>0)
13909       finalchecks=giacmin(2*Wi.front().dim,initial);
13910     if (debug_infolevel)
13911       CERR << CLOCK()*1e-6 << " begin final check, checking that " << finalchecks << " initial generators belongs to the ideal" << '\n';
13912     G.resize(Wi.size());
13913     for (j=0;j<Wi.size();++j)
13914       G[j]=j;
13915     vector<bool> Gused(G.size());
13916     for (j=0;j<finalchecks;++j){
13917       if (debug_infolevel)
13918 	CERR << "+";
13919       sort(res[j].coord.begin(),res[j].coord.end(),tdeg_t_sort_t<tdeg_t>(res[j].order));
13920       reduce(res[j],Wi,G,-1,wtmp,tmp0,tmp1,tmp2,0,&Gused);
13921       if (!tmp0.coord.empty()){
13922 	break;
13923       }
13924       if (debug_infolevel && (j%10==9))
13925 	CERR << j+1 << '\n';
13926     }
13927     if (debug_infolevel){
13928       CERR << '\n' << " Elements used for reduction ";
13929       for (size_t i=0;i<G.size();++i){
13930 	CERR << (Gused[i]?'+':'-');
13931       }
13932       CERR << '\n';
13933     }
13934     if (j!=finalchecks){
13935       if (debug_infolevel){
13936 	CERR << CLOCK()*1e-6 << " final check failure, retrying with another prime " << '\n';
13937 	CERR << "Non-zero remainder " << tmp0 << '\n';
13938 	CERR << "checking res[j], " << j << "<" << initial << '\n';
13939 	CERR << "res[j]=" << res[j] << '\n';
13940 	CERR << "basis candidate " << Wi << '\n';
13941       }
13942       return false;
13943     }
13944     return true;
13945   }
13946 
13947   // return 0 (failure), 1 (success), -1: parts of the gbasis reconstructed
13948   template<class tdeg_t>
in_mod_gbasis(vectpoly8<tdeg_t> & res,bool modularcheck,bool zdata,int & rur,GIAC_CONTEXT,gbasis_param_t gbasis_par,int gbasis_logz_age)13949   int in_mod_gbasis(vectpoly8<tdeg_t> & res,bool modularcheck,bool zdata,int & rur,GIAC_CONTEXT,gbasis_param_t gbasis_par,int gbasis_logz_age){
13950     if (debug_infolevel)
13951       CERR << CLOCK()*1e-6 << " modular gbasis algorithm start, mem " << memory_usage() << '\n';
13952     bool & eliminate_flag=gbasis_par.eliminate_flag;
13953     bool interred=gbasis_logz_age==0; // final interreduce
13954     unsigned initial=unsigned(res.size());
13955     double eps=proba_epsilon(contextptr); int rechecked=0;
13956     order_t order={0,0};
13957     bool multithread_enabled=true;
13958     // multithread disabled for more than 14 vars because otherwise
13959     // threads:=2; n:=9;P:=mul(1+x[j]*t,j=0..n-1);
13960     // X:=[seq(x[j],j=0..n-1)];
13961     // S:=seq(p[j]-coeff(P,t,j), j=1..n-1);
13962     //  N:=sum(x[j]^(n-1),j=0..n-1);
13963     // I:=[N,S]:;eliminate(I,X)
13964     // segfaults and valgrind does not help...
13965     for (unsigned i=0;i<res.size();++i){
13966       const poly8<tdeg_t> & P=res[i];
13967       if (multithread_enabled && !P.coord.empty())
13968 	multithread_enabled=!P.coord.front().u.vars64();
13969       order=P.order;
13970       for (unsigned j=0;j<P.coord.size();++j){
13971 	if (!is_integer(P.coord[j].g)) // improve: accept complex numbers
13972 	  return 0;
13973       }
13974     }
13975     if (order.o!=_REVLEX_ORDER && order.o!=_3VAR_ORDER && order.o!=_7VAR_ORDER && order.o!=_11VAR_ORDER && order.o!=_16VAR_ORDER && order.o!=_32VAR_ORDER && order.o!=_48VAR_ORDER && order.o!=_64VAR_ORDER)
13976       return 0;
13977     vectpoly8<tdeg_t> toreinject;
13978     if (gbasis_par.reinject_begin>=0 && gbasis_par.reinject_end>gbasis_par.reinject_begin){
13979       toreinject=res; //vectpoly8<tdeg_t>(res.begin()+gbasis_par.reinject_begin,res.begin()+gbasis_par.reinject_end);
13980       if (gbasis_par.reinject_for_calc>0 && gbasis_par.reinject_for_calc<res.size())
13981 	res.resize(gbasis_par.reinject_for_calc);
13982       sort(res.begin(),res.end(),tripolymod_tri<poly8<tdeg_t> >(gbasis_logz_age));
13983     }
13984     // if (order!=_REVLEX_ORDER) zdata=false;
13985     vectpoly8<tdeg_t> current,current_orig,current_gbasis,vtmp,afewpolys;
13986     vectpolymod<tdeg_t> resmod,gbmod;
13987     poly8<tdeg_t> poly8tmp;
13988 #ifdef EMCC
13989     // use smaller primes
13990     gen p=94906249-_floor(giac_rand(contextptr)/32e3,contextptr);
13991     // gen p=(1<<24)-_floor(giac_rand(contextptr)/32e3,contextptr);
13992 #else
13993     gen p=(1<<29)-_floor(giac_rand(contextptr)/1e3,contextptr);
13994 #endif
13995     // unless we are unlucky these lists should contain only 1 element
13996     vector< vectpoly8<tdeg_t> > V; // list of (chinrem reconstructed) modular groebner basis
13997     vector< vectpoly8<tdeg_t> > W; // list of rational reconstructed groebner basis
13998     vector< vectpoly8<tdeg_t> > Wlast;
13999     vecteur P; // list of associate (product of) modulo
14000     polymod<tdeg_t> lmmod,lmmodradical,s; vectpolymod<tdeg_t> rurv; // variables for rational univar. reconstr.
14001     // environment env;
14002     // env.moduloon=true;
14003     vector<unsigned> G;
14004     vector< paire > reduceto0;
14005     vector< info_t<tdeg_t> > f4buchberger_info;
14006     f4buchberger_info.reserve(GBASISF4_MAXITER);
14007     vector<zinfo_t<tdeg_t> > zf4buchberger_info;
14008     zf4buchberger_info.reserve(GBASISF4_MAXITER);
14009     mpz_t zu,zd,zu1,zd1,zabsd1,zsqrtm,zq,zur,zr,ztmp;
14010     mpz_init(zu);
14011     mpz_init(zd);
14012     mpz_init(zu1);
14013     mpz_init(zd1);
14014     mpz_init(zabsd1);
14015     mpz_init(zsqrtm);
14016     mpz_init(zq);
14017     mpz_init(zur);
14018     mpz_init(zr);
14019     mpz_init(ztmp);
14020     bool ok=true;
14021 #ifdef HAVE_LIBPTHREAD
14022     int nthreads=(threads_allowed && multithread_enabled)?threads:1,th,parallel=1;
14023     pthread_t tab[64];
14024     thread_gbasis_t<tdeg_t> gbasis_param[64];
14025 #else
14026     int nthreads=1,th,parallel=1;
14027 #endif
14028     int pend=p.val,p0;
14029     int recon_n2=-1,recon_n1=-1,recon_n0=-1,recon_added=0,recon_count=0; // reconstr. gbasis element number history
14030     double augmentgbasis=gbasis_reinject_ratio,prevreconpart=1.0,time1strun=-1.0,time2ndrun=-1.0; current_orig=res; current_gbasis=res;
14031     // if the ratio of reconstructed is more than augmentgbasis,
14032     // we clear info and add reconstruction to the gbasis
14033     for (int count=0;ok;++count,++recon_count){
14034       p=pend;
14035       if (count==0 || nthreads==1 || (zdata && augmentgbasis && reduceto0.empty())){
14036 	th=0;
14037 	parallel=nthreads;
14038       }
14039       else {
14040 	unsigned sp=simult_primes;
14041 	if (count>=simult_primes_seuil2)
14042 	  sp=simult_primes2;
14043 	if (count>=simult_primes_seuil3)
14044 	  sp=simult_primes3;
14045 	th=giacmin(nthreads-1,sp-1); // no more than simult_primes
14046 	th=giacmin(th,63);
14047 	parallel=nthreads/(th+1);
14048       }
14049 #ifndef EMCC
14050       if (count==1 && p.val<(1<<24)){
14051 #ifdef PSEUDO_MOD
14052 	p=(1<<29)-1;
14053 #else
14054 	p=(1<<30)+((1<<30)-1);
14055 #endif
14056       }
14057 #endif
14058       // FIXME we should avoid primes that divide one of leading coeff of current_gbasis
14059       p=prevprime(p-1);
14060       p0=p.val; // 1st prime used by all threads
14061       // compute gbasis mod p
14062       // env.modulo=p;
14063 #ifdef HAVE_LIBPTHREAD
14064       for (unsigned j=0;j<th;++j){
14065 	gbasis_param[j].current=current_gbasis;
14066 	gbasis_param[j].p=p.val;
14067 	gbasis_param[j].reduceto0=&reduceto0;
14068 	gbasis_param[j].f4buchberger_info=&f4buchberger_info;
14069 	gbasis_param[j].zf4buchberger_info=&zf4buchberger_info;
14070 	gbasis_param[j].zdata=zdata;
14071 	gbasis_param[j].eliminate_flag=eliminate_flag;
14072 	gbasis_param[j].parallel=parallel;
14073 	gbasis_param[j].interred=interred;
14074 	if (count==1)
14075 	  gbasis_param[j].resmod.reserve(resmod.size());
14076 	bool res=true;
14077 	// CERR << "write " << j << " " << p << '\n';
14078 	res=pthread_create(&tab[j],(pthread_attr_t *) NULL,thread_gbasis<tdeg_t>,(void *) &gbasis_param[j]);
14079 	if (res)
14080 	  thread_gbasis<tdeg_t>((void *)&gbasis_param[j]);
14081 #if 1
14082 	p=prevprime(p-1);
14083 #else
14084 	p=nextprime(p+1);
14085 #endif
14086       }
14087 #endif // thread
14088       current=current_gbasis;
14089       G.clear();
14090       double t_0=CLOCK()*1e-6;
14091 #ifndef KHICAS
14092       if (debug_infolevel)
14093 	CERR << std::setprecision(15) << t_0 << " begin computing basis modulo " << p << " batch/threads " << th+1 << "/" << parallel << '\n';
14094 #endif
14095       // CERR << "write " << th << " " << p << '\n';
14096 #ifdef GBASISF4_BUCHBERGER
14097       if (zdata){
14098 	if (!zgbasis(current,resmod,G,p.val,true,&reduceto0,zf4buchberger_info,false,false,eliminate_flag,true,parallel,interred)){
14099 	  if (augmentgbasis>0)
14100 	    augmentgbasis=2;
14101 	  reduceto0.clear();
14102 	  zf4buchberger_info.clear();
14103 	  zf4buchberger_info.reserve(4*zf4buchberger_info.capacity());
14104 	  G.clear();
14105 	  if (!zgbasis(current,resmod,G,p.val,true/*totaldeg*/,&reduceto0,zf4buchberger_info,false,false,eliminate_flag,true,parallel,interred)){
14106 	    ok=false;
14107 	    break;
14108 	  }
14109 	}
14110       }
14111       else {
14112 	resmod.clear();
14113 	if (!in_gbasisf4buchbergermod(current,resmod,G,p.val,true/*totaldeg*/,
14114 				      //		  0,0
14115 				      &reduceto0,&f4buchberger_info,
14116 #if 1
14117 				      false /* not useful */
14118 #else
14119 				      (count==1) /* recompute R and quo at 2nd iteration*/
14120 #endif
14121 				      )){
14122 	  // retry
14123 	  reduceto0.clear();
14124 	  f4buchberger_info.clear(); G.clear();
14125 	  if (!in_gbasisf4buchbergermod(current,resmod,G,p.val,true/*totaldeg*/,&reduceto0,&f4buchberger_info,false)){
14126 	    ok=false;
14127 	    break;
14128 	  }
14129 	  reduceto0.clear();
14130 	  f4buchberger_info.clear();
14131 	}
14132       }
14133 #else
14134       if (!in_gbasismod(current,resmod,G,p.val,true,&reduceto0)){
14135 	ok=false;
14136 	break;
14137       }
14138       // CERR << "reduceto0 " << reduceto0.size() << '\n';
14139       //if (!in_gbasis(current,G,&env)) return false;
14140 #endif
14141 #ifdef HAVE_LIBPTHREAD
14142       // finish threads before chinese remaindering
14143       void * threadretval[64];
14144       for (int t=0;t<th;++t){
14145 	threadretval[t]=&threadretval; // non-0 initialization
14146 	pthread_join(tab[t],&threadretval[t]);
14147       }
14148 #endif
14149       // cleanup G
14150       for (unsigned i=0;i<G.size();++i){
14151 	if (resmod[G[i]].coord.empty()){
14152 	  G.erase(G.begin()+i);
14153 	  --i;
14154 	}
14155       }
14156       double t_1=CLOCK()*1e-6;
14157       if (time1strun<0){
14158 	time1strun=t_1-t_0;
14159 	prevreconpart=0.0; // (1.0+res.size())/G.size();
14160       }
14161       else {
14162 	if (time2ndrun<0){
14163 	  time2ndrun=(t_1-t_0)/(th+1); // we are computing th+1 primes
14164 	  if (debug_infolevel)
14165 	    CERR << "2nd run " << time2ndrun << " 1st run " << time1strun << '\n';
14166 	  if (time2ndrun<time1strun*gbasis_reinject_speed_ratio
14167 	      || gbasis_par.reinject_for_calc>0
14168 	      //|| time2ndrun<0.5
14169 	      ){
14170 	    // learning is fast enough
14171 	    if (augmentgbasis>0)
14172 	      augmentgbasis=2;
14173 	  }
14174 	}
14175       }
14176       pend=p.val; // last prime used
14177       if (debug_infolevel){
14178 	CERR << t_1 << " end, basis size " << G.size() << " prime number " << count+1 << '\n';
14179       }
14180       unsigned i=0;
14181       for (int t=0;t<=th;++t){
14182 	if (t==th){
14183 	  // extract from current
14184 	  if (rur || gbmod.size()<G.size())
14185 	    gbmod.resize(G.size());
14186 	  for (i=0;i<G.size();++i){
14187 	    gbmod[i]=resmod[G[i]];
14188 	  }
14189 	  p=pend;
14190 	  // CERR << "read " << t << " " << p << '\n';
14191 	}
14192 #ifdef HAVE_LIBPTHREAD
14193 	else {
14194 	  void * ptr_=(void *)threadretval[t]; // saved value from ptr_join
14195 	  if (!ptr_)
14196 	    continue;
14197 	  thread_gbasis_t<tdeg_t> * ptr = (thread_gbasis_t<tdeg_t> *) ptr_;
14198 	  // extract from current
14199 	  if (rur || gbmod.size()<ptr->G.size())
14200 	    gbmod.resize(ptr->G.size());
14201 	  for (i=0;i<ptr->G.size();++i)
14202 	    gbmod[i]=ptr->resmod[ptr->G[i]];
14203 	  p=ptr->p;
14204 	  // CERR << "read " << t << " " << p << '\n';
14205 	  ++count;
14206 	  ++recon_count;
14207 	}
14208 #endif
14209 	if (!ok)
14210 	  continue;
14211 	// remove 0 from gbmod
14212 	for (i=0;i<gbmod.size();){
14213 	  if (gbmod[i].coord.empty())
14214 	    gbmod.erase(gbmod.begin()+i);
14215 	  else
14216 	    ++i;
14217 	}
14218 	// if augmentgbasis>0 (at least) gbmod must be sorted
14219 	//if (augmentgbasis>0)
14220 	sort(gbmod.begin(),gbmod.end(),tripolymod_tri<polymod<tdeg_t> >(gbasis_logz_age));
14221 	if (!rur && gbasis_stop<0)
14222 	  gbmod.resize(-gbasis_stop);
14223 	if (count==0 && V.empty() && gbasis_par.reinject_begin>=0 && gbasis_par.reinject_end>gbasis_par.reinject_begin){
14224 	  // initial reinjection
14225 	  int K=gbasis_par.reinject_end-gbasis_par.reinject_begin;
14226 	  Wlast.push_back(vectpoly8<tdeg_t>());
14227 	  reverse(toreinject.begin(),toreinject.end());
14228 	  toreinject.resize(K);
14229 	  Wlast[0].swap(toreinject);
14230 	  for (int k=0;k<K;++k){
14231 	    if (!chk_equal_mod(Wlast[0][k],gbmod[k],p.val)){
14232 	      *logptr(contextptr) << CLOCK() << " reinjection failure at position " << k << '\n';
14233 	      Wlast.clear();
14234 	      break;
14235 	    }
14236 	  }
14237 	  if (!Wlast.empty()){ // reinjection ok
14238 	    *logptr(contextptr) << CLOCK() << " reinjection success " << K << '\n';
14239 	    V.push_back(vectpoly8<tdeg_t>());
14240 	    W.push_back(vectpoly8<tdeg_t>());
14241 	    convert(gbmod,V.back(),p.val);
14242 	    recon_added=gbasis_par.reinject_end-gbasis_par.reinject_begin;
14243 	    prevreconpart=recon_added/double(gbmod.size());
14244 	    for (int k=0;k<K;++k){
14245 	      V[0][k].coord.clear();
14246 	    }
14247 	    P.push_back(p);
14248 	    continue; // next prime
14249 	  }
14250 	}
14251 	if (debug_infolevel && count==0){
14252 	  CERR << "G= ";
14253 	  for (size_t i=0;i<G.size();++i){
14254 	    CERR << i << ":" << G[i] << "(" << resmod[G[i]].age<<"," << resmod[G[i]].logz << ":" << resmod[G[i]].fromleft << "," << resmod[G[i]].fromright << ")" << '\n';
14255 	  }
14256 	  CERR << "sorted" << '\n';
14257 	  ulonglong nmonoms=0;
14258 	  for (size_t i=0;i<gbmod.size();++i){
14259 	    CERR << i << "(" << gbmod[i].age << "," << gbmod[i].logz << ":" << gbmod[i].fromleft << "," << gbmod[i].fromright << ")" << '\n';
14260 	    nmonoms += gbmod[i].coord.size();
14261 	  }
14262 	  CERR << '\n' << "Partial number of monoms " << nmonoms << '\n';
14263 	}
14264 	// compare gb to existing computed basis
14265 #if 1
14266 	if (rur){
14267 	  gbmod.resize(G.size());
14268 	  int dim=res.front().dim;
14269 	  polymod<tdeg_t> lmtmp(lmmodradical.order,dim);
14270 	  // FIXME rur_quotient_ideal etc. should take care of parameters!
14271 	  if (rur_quotient_ideal_dimension(gbmod,lmtmp)<0){
14272 	    rur=0;
14273 	    continue;
14274 	  }
14275 	  if (debug_infolevel)
14276 	    CERR << CLOCK()*1e-6 << " begin modular rur computation" << '\n';
14277 	  if (rur==2){
14278 	    vecteur m,M,res;
14279 	    polymod<tdeg_t> s(order,dim);
14280 	    index_t l(dim);
14281 	    l[dim-1]=1;
14282 	    s.coord.push_back(T_unsigned<modint,tdeg_t>(1,tdeg_t(l,order)));
14283 	    ok=rur_minpoly(gbmod,lmtmp,s,p.val,m,M);
14284 	    rur_convert_univariate(m,dim-1,gbmod[0]);
14285 	    gbmod.resize(1);
14286 	  }
14287 	  else {
14288 	    if (!rur_compute(gbmod,lmtmp,lmmodradical,p.val,s,rurv)){
14289 	      CERR << CLOCK()*1e-6 << "Unable to compute modular rur\n";
14290 	      ok = false; rur = 0;
14291 	      continue;
14292 	    }
14293 	    if (debug_infolevel)
14294 	      CERR << CLOCK()*1e-6 << " end modular rur computation" << '\n';
14295 	    gbmod.swap(rurv); // reconstruct the rur instead of the gbasis
14296 	  } // check for bad primes
14297 	  if (lmmodradical.coord.empty())
14298 	    lmmodradical=lmtmp;
14299 	  else {
14300 	    int i=rur_compare(lmmodradical,lmtmp);
14301 	    if (i!=0){
14302 	      if (i==1) // lmmodradical!=lmtmp and contains lmtmp, bad prime
14303 		continue;
14304 	      // clear existing reconstruction
14305 	      f4buchberger_info.clear();
14306 	      zf4buchberger_info.clear();
14307 	      reduceto0.clear();
14308 	      V.clear(); W.clear(); Wlast.clear(); P.clear();
14309 	      if (i==-1)
14310 		continue;
14311 	      // restart with this prime
14312 	    }
14313 	  }
14314 	} // end if (rur)
14315 	unsigned jpos; gen num,den;
14316 	if (debug_infolevel>2)
14317 	  CERR << "p=" << p << ":" << gbmod << '\n';
14318 	for (i=0;i<V.size();++i){
14319 	  if (W.size()<V.size())
14320 	    W.resize(V.size());
14321 	  if (Wlast.size()<V.size()){
14322 	    Wlast.resize(V.size());
14323 	    Wlast.back().reserve(gbmod.size());
14324 	  }
14325 	  if (V[i].size()!=gbmod.size())
14326 	    continue;
14327 	  for (jpos=recon_added;jpos<gbmod.size();++jpos){
14328 	    if (V[i][jpos].coord.empty() && gbmod[jpos].coord.empty())
14329 	      continue;
14330 	    if (V[i][jpos].coord.empty())
14331 	      break;
14332 	    if (gbmod[jpos].coord.empty())
14333 	      break;
14334 	    if (V[i][jpos].coord.front().u!=gbmod[jpos].coord.front().u)
14335 	      break;
14336 	  }
14337 	  if (jpos!=gbmod.size()){
14338 	    rechecked=0;
14339 	    continue;
14340 	  }
14341 	  jpos=recon_added; // 0 or recon_added (do not check already reconstructed)
14342 	  // check existing Wlast
14343 	  for (;jpos<Wlast[i].size();++jpos){
14344 	    if (!chk_equal_mod(Wlast[i][jpos],gbmod[jpos],p.val)){
14345 	      Wlast[i].resize(jpos);
14346 	      rechecked=0;
14347 	      break;
14348 	    }
14349 	  }
14350 	  if (jpos!=Wlast[i].size() || P[i].type==_INT_){
14351 	    // CERR << jpos << '\n';
14352 	    // IMPROVE: make it work for rur!
14353 	    if (!rur && eps>0 && P[i].type==_INT_ && recon_added==0 && gbasis_stop!=0){
14354 	      // check for non modular gb with early reconstruction */
14355 	      // first build a candidate in early with V[i]
14356 	      vectpoly8<tdeg_t> early(V[i]);
14357 	      int d;
14358 	      for (jpos=0;jpos<early.size();++jpos){
14359 		d=1;
14360 		if (!findmultmod(early[jpos],P[i].val,d)){
14361 		  if (debug_infolevel>1)
14362 		    COUT << "early reconstr. failure pos " << jpos << " P=" << early[jpos] << " d=" << d << " modulo " << P[i].val << '\n';
14363 		  break;
14364 		}
14365 		int s=int(early[jpos].coord.size());
14366 		for (int k=0;k<s;++k){
14367 		  early[jpos].coord[k].g=smod(longlong(early[jpos].coord[k].g.val)*d,P[i].val);
14368 		}
14369 	      }
14370 	      // then check
14371 	      if (jpos==early.size()){
14372 		for (jpos=0;jpos<early.size();++jpos){
14373 		  polymod<tdeg_t> tmp(gbmod[jpos]);
14374 		  smallmultmod(early[jpos].coord.front().g.val,tmp,p.val);
14375 		  if (!chk_equal_mod(early[jpos],tmp,p.val)){
14376 		    if (debug_infolevel>1)
14377 		      COUT << "early recons. failure jpos=" << jpos << " " << early[jpos] << " " << tmp << " modulo " << p.val << '\n';
14378 		    break;
14379 		  }
14380 		}
14381 		rechecked=0;
14382 		if (jpos==early.size() && (eliminate_flag || check_initial_generators(res,early,G,eps))){
14383 		  if (debug_infolevel)
14384 		    CERR << CLOCK()*1e-6 << " end final check " << '\n';
14385 		  swap(res,early);
14386 		  mpz_clear(zd);
14387 		  mpz_clear(zu);
14388 		  mpz_clear(zu1);
14389 		  mpz_clear(zd1);
14390 		  mpz_clear(zabsd1);
14391 		  mpz_clear(zsqrtm);
14392 		  mpz_clear(zq);
14393 		  mpz_clear(zur);
14394 		  mpz_clear(zr);
14395 		  mpz_clear(ztmp);
14396 		  return 1;
14397 		}
14398 	      } // end jpos==early.size()
14399 	    }
14400 	    break; // find another prime
14401 	  }
14402 	  for (;jpos<V[i].size();++jpos){
14403 	    unsigned Vijs=unsigned(V[i][jpos].coord.size());
14404 	    if (Vijs!=gbmod[jpos].coord.size()){
14405 	      rechecked=0;
14406 	      if (debug_infolevel>1)
14407 		CERR << jpos << '\n';
14408 	      break;
14409 	    }
14410 	    //Vijs=1;
14411 	    Vijs/=2;
14412 	    if (Vijs && V[i][jpos].coord[Vijs].g.type==_ZINT){
14413 	      if (!in_fracmod(P[i],V[i][jpos].coord[Vijs].g,
14414 			      zd,zd1,zabsd1,zu,zu1,zur,zq,zr,zsqrtm,ztmp,num,den)){
14415 		rechecked=0;
14416 		if (debug_infolevel>1)
14417 		  CERR << jpos << '\n';
14418 		break;
14419 	      }
14420 	      modint gg=gbmod[jpos].coord[Vijs].g;
14421 	      if (!chk_equal_mod(num/den,gg,p.val)){
14422 		rechecked=0;
14423 		if (debug_infolevel>1)
14424 		  CERR << jpos << '\n';
14425 		break;
14426 	      }
14427 	    }
14428 	    if (!fracmod(V[i][jpos],P[i],
14429 			 zd,zd1,zabsd1,zu,zu1,zur,zq,zr,zsqrtm,ztmp,
14430 			 poly8tmp)){
14431 	      rechecked=0;
14432 	      CERR << CLOCK()*1e-6 << " reconstruction failure at position " << jpos << '\n';
14433 	      break;
14434 	    }
14435 	    if (rur && !poly8tmp.coord.empty() && !chk_equal_mod(poly8tmp.coord.front().g,gbmod[jpos].coord.front().g,p.val)){
14436 	      rechecked=0;
14437 	      break;
14438 	    }
14439 	    if (!chk_equal_mod(poly8tmp,gbmod[jpos],p.val)){
14440 	      rechecked=0;
14441 	      break;
14442 	    }
14443 	    poly8<tdeg_t> tmptmp(poly8tmp.order,poly8tmp.dim);
14444 	    Wlast[i].push_back(tmptmp);
14445 	    Wlast[i].back().coord.swap(poly8tmp.coord);
14446 	  }
14447 	  if (debug_infolevel>0)
14448 	    CERR << CLOCK()*1e-6 << " unstable mod " << p << " from " << V[i].size() << " reconstructed " << Wlast[i].size() << " (#" << i << ")" << '\n';
14449 	  // possible improvement: if t==th and i==0 and Wlast.size()/V[i].size()
14450 	  // has increased significantly
14451 	  // it might be a good idea to add it's component
14452 	  // to current, and clear info (if zdata: reduceto0, zf4buchberger_info)
14453 	  recon_n2=recon_n1;
14454 	  recon_n1=recon_n0;
14455 	  recon_n0=Wlast[i].size();
14456 	  if (eps>1e-20 &&
14457 	      // recon_n2==recon_n1 && recon_n1==recon_n0 &&
14458 	      zdata && augmentgbasis && t==th && i==0){
14459 	    double reconpart=recon_n2/double(V[i].size());
14460 	    if (!rur && recon_n0/double(V[i].size())<0.95 &&
14461 		(reconpart-prevreconpart>augmentgbasis
14462 		 // || (reconpart>prevreconpart && recon_count>=giacmax(128,th*4))
14463 		 )
14464 		){
14465 	      CERR << CLOCK()*1e-6 << " adding reconstructed ideal generators " << recon_n2 << " (reconpart " << reconpart << " prev " << prevreconpart << " augment " << augmentgbasis << " recon_count " << recon_count << " th " << th << " recon_n2 " << recon_n2 << " V[i] " << V[i].size() << ")" << '\n';
14466 	      recon_count=0;
14467 	      prevreconpart=reconpart;
14468 	      //current_gbasis=current_orig;
14469 	      int insertpos=0;
14470 	      for (int k=recon_added;k<recon_n2;++k){
14471 		V[i][k].coord.clear();
14472 		poly8<tdeg_t> tmp=Wlast[i][k];
14473 		cleardeno(tmp);
14474 		for (;insertpos<current_gbasis.size();++insertpos){
14475 		  if (tdeg_t_greater(current_gbasis[insertpos].coord.front().u,tmp.coord.front().u,order)){
14476 		    if (!(current_gbasis[insertpos]==tmp)){
14477 		      current_gbasis.insert(current_gbasis.begin()+insertpos,tmp);
14478 		      ++insertpos;
14479 		    }
14480 		    break;
14481 		  }
14482 		}
14483 		if (insertpos==current_gbasis.size()){
14484 		  current_gbasis.push_back(tmp);
14485 		  ++insertpos;
14486 		}
14487 	      }
14488 	      recon_added=recon_n2; // Wlast[i].size();
14489 	      CERR << CLOCK()*1e-6 << " # new ideal generators " << current_gbasis.size() << '\n';
14490 	      reduceto0.clear();
14491 	      zf4buchberger_info.clear();
14492 	      if (gbasis_logz_age){
14493 		res.swap(current_gbasis);
14494 		mpz_clear(zd);
14495 		mpz_clear(zu);
14496 		mpz_clear(zu1);
14497 		mpz_clear(zd1);
14498 		mpz_clear(zabsd1);
14499 		mpz_clear(zsqrtm);
14500 		mpz_clear(zq);
14501 		mpz_clear(zur);
14502 		mpz_clear(zr);
14503 		mpz_clear(ztmp);
14504 		return -1;
14505 	      }
14506 	    }
14507 	  }
14508 	  break;
14509 	} // end for loop on i
14510 	if (i==V.size()){
14511 	  if (debug_infolevel)
14512 	    CERR << CLOCK()*1e-6 << " creating reconstruction #" << i << '\n';
14513 	  // not found
14514 	  V.push_back(vectpoly8<tdeg_t>());
14515 	  convert(gbmod,V.back(),p.val);
14516 	  W.push_back(vectpoly8<tdeg_t>()); // no reconstruction yet, wait at least another prime
14517 	  Wlast.push_back(vectpoly8<tdeg_t>());
14518 	  P.push_back(p);
14519 	  continue; // next prime
14520 	}
14521 	if (!rur && gbasis_stop<0 && recon_n0>=-gbasis_stop){
14522 	  if (recon_n2<-gbasis_stop)
14523 	    continue;
14524 	  // stop here
14525 	  W[i]=Wlast[i];
14526 	  W[i].resize(recon_n2);
14527 	  cleardeno(W[i]); // clear denominators
14528 	  CERR << CLOCK()*1e-6 << " Max number of generators reconstructed " << jpos << ">=" << -gbasis_stop << '\n';
14529 	  swap(res,W[i]);
14530 	  mpz_clear(zd);
14531 	  mpz_clear(zu);
14532 	  mpz_clear(zu1);
14533 	  mpz_clear(zd1);
14534 	  mpz_clear(zabsd1);
14535 	  mpz_clear(zsqrtm);
14536 	  mpz_clear(zq);
14537 	  mpz_clear(zur);
14538 	  mpz_clear(zr);
14539 	  mpz_clear(ztmp);
14540 	  return 1;
14541 	}
14542 	if (jpos<gbmod.size()){
14543 	  if (debug_infolevel)
14544 	    CERR << CLOCK()*1e-6 << " i=" << i << " begin chinese remaindering " << p << " (" << count+(t==th) << ")" << '\n';
14545 	  int r=chinrem(V[i],P[i],gbmod,p.val,poly8tmp,recon_added); // IMPROVE: maybe start at jpos in V[i]? at least start at recon_added
14546 	  if (debug_infolevel)
14547 	    CERR << CLOCK()*1e-6 << " end chinese remaindering" << '\n';
14548 	  if (r==-1){
14549 	    ok=false;
14550 	    continue;
14551 	  }
14552 	  P[i]=P[i]*p;
14553 	  continue; // next prime
14554 	}
14555 	else { // final check
14556 	  W[i]=Wlast[i];
14557 	  if (!rur){
14558 	    if (debug_infolevel)
14559 	      CERR << CLOCK()*1e-6 << " stable, clearing denominators " << '\n';
14560 	    cleardeno(W[i]); // clear denominators
14561 	  }
14562 	  ++rechecked;
14563 	  if (debug_infolevel)
14564 	    CERR << CLOCK()*1e-6 << " end rational reconstruction " << '\n';
14565 	  // now check if W[i] is a Groebner basis over Q, if so it's the answer
14566 	  if (rur){
14567 	    // a final check could be performed by replacing
14568 	    // res[3..end]/res[2] in the initial gbasis element and check if it's 0
14569 	    swap(res,W[i]);
14570 	    mpz_clear(zd);
14571 	    mpz_clear(zu);
14572 	    mpz_clear(zu1);
14573 	    mpz_clear(zd1);
14574 	    mpz_clear(zabsd1);
14575 	    mpz_clear(zsqrtm);
14576 	    mpz_clear(zq);
14577 	    mpz_clear(zur);
14578 	    mpz_clear(zr);
14579 	    mpz_clear(ztmp);
14580 	    return 1;
14581 	  }
14582 	  // first verify that the initial generators reduce to 0
14583 	  if (!eliminate_flag && !check_initial_generators(res,W[i],G,eps))
14584 	    continue;
14585 	  if (int(W[i].size())<=GBASIS_DETERMINISTIC)
14586 	    eps=0;
14587 	  if (eliminate_flag && eps==0)
14588 	    eps=1e-7;
14589 	  double eps2=std::pow(double(p.val),double(rechecked))*eps;
14590 	  // recheck by computing gbasis modulo another prime
14591 	  if (eps2>0 && eps2<1){
14592 	    if (debug_infolevel)
14593 	      CERR << CLOCK()*1e-6 << " Final check successful, running another prime to increase confidence." << '\n';
14594 	    continue;
14595 	  }
14596 	  if (eps>0){
14597 	    double terms=0;
14598 	    int termsmin=RAND_MAX; // estimate of the number of terms of a reduced non-0 spoly
14599 	    for (unsigned k=0;k<W[i].size();++k){
14600 	      terms += W[i][k].coord.size();
14601 	      termsmin = giacmin(termsmin,unsigned(W[i][k].coord.size()));
14602 	    }
14603 	    termsmin = 7*(2*termsmin-1);
14604 	    int epsp=P[i].type==_ZINT?mpz_sizeinbase(*P[i]._ZINTptr,10):8-int(std::ceil(2*std::log10(terms)));
14605 	    if (epsp>termsmin)
14606 	      epsp=termsmin;
14607 	    *logptr(contextptr) << gettext("Running a probabilistic check for the reconstructed Groebner basis. If successfull, error probability is less than ") << eps << gettext(" and is estimated to be less than 10^-") << epsp << gettext(". Use proba_epsilon:=0 to certify (this takes more time).") << '\n';
14608 	  }
14609 	  G.clear();
14610 	  if (eps<1.01e-10){
14611 	    // check modulo another prime that W[i] is a gbasis
14612 	    vector<unsigned> G;
14613 	    vectpoly8<tdeg_t> res_(W[i]);
14614 	    vectpolymod<tdeg_t> resmod;
14615 	    vector< zinfo_t<tdeg_t> > zf4buchberger_info;
14616 	    int p=268435399;
14617 	    if (debug_infolevel)
14618 	      CERR << CLOCK()*1e-6 << " Checking that the basis is a gbasis modulo " << p << '\n';
14619 	    if (!zgbasis<tdeg_t>(res_,resmod,G,p,true,0,zf4buchberger_info,false,false,false,false,threads /* parallel*/,true))
14620 	      return 0;
14621 	    sort(resmod.begin(),resmod.end(),tripolymod_tri<polymod<tdeg_t> >(false));
14622 	    sort(W[i].begin(),W[i].end(),tripolymod_tri<poly8<tdeg_t> >(false));
14623 	    for (size_t jpos=0;jpos<G.size();++jpos){
14624 	      if (!chk_equal_mod(W[i][jpos],resmod[jpos],p))
14625 		return 0;
14626 	    }
14627 	    if (debug_infolevel)
14628 	      CERR << CLOCK()*1e-6 << " Check successful mod " << p << '\n';
14629 	  }
14630 	  if (eps2<1 && !is_gbasis(W[i],eps2,modularcheck)){
14631 	    ok=false;
14632 	    continue; // in_gbasis(W[i],G,0,true);
14633 	  }
14634 	  if (debug_infolevel)
14635 	    CERR << CLOCK()*1e-6 << " end final check " << '\n';
14636 	  swap(res,W[i]);
14637 	  mpz_clear(zd);
14638 	  mpz_clear(zu);
14639 	  mpz_clear(zu1);
14640 	  mpz_clear(zd1);
14641 	  mpz_clear(zabsd1);
14642 	  mpz_clear(zsqrtm);
14643 	  mpz_clear(zq);
14644 	  mpz_clear(zur);
14645 	  mpz_clear(zr);
14646 	  mpz_clear(ztmp);
14647 	  return 1;
14648 	}
14649 #else
14650 	for (i=0;i<V.size();++i){
14651 	  if (debug_infolevel)
14652 	    CERR << CLOCK()*1e-6 << " i= " << i << " begin chinese remaindering" << '\n';
14653 	  int r=chinrem(V[i],P[i],gbmod,p.val,poly8tmp);
14654 	  if (debug_infolevel)
14655 	    CERR << CLOCK()*1e-6 << " end chinese remaindering" << '\n';
14656 	  if (r==-1){
14657 	    ok=false;
14658 	    break;
14659 	  }
14660 	  if (r==0){
14661 	    CERR << CLOCK()*1e-6 << " leading terms do not match with reconstruction " << i << " modulo " << p << '\n';
14662 	    continue;
14663 	  }
14664 	  // found one! V is already updated, update W
14665 	  if (W.size()<V.size())
14666 	    W.resize(V.size());
14667 	  if (Wlast.size()<V.size())
14668 	    Wlast.resize(V.size());
14669 	  P[i]=P[i]*p;
14670 	  unsigned jpos=0;
14671 	  // afewpolys.clear();
14672 	  for (;jpos<V[i].size();++jpos){
14673 	    if (int(Wlast[i].size())>jpos && chk_equal_mod(Wlast[i][jpos],gb[jpos],p.val)){
14674 	      if (afewpolys.size()<=jpos)
14675 		afewpolys.push_back(Wlast[i][jpos]);
14676 	      else {
14677 		if (!(afewpolys[jpos]==Wlast[i][jpos]))
14678 		  afewpolys[jpos]=Wlast[i][jpos];
14679 	      }
14680 	    }
14681 	    else {
14682 	      if (!fracmod(V[i][jpos],P[i],
14683 			   zd,zd1,zabsd1,zu,zu1,zur,zq,zr,zsqrtm,ztmp,
14684 			   poly8tmp)){
14685 		CERR << CLOCK()*1e-6 << " reconstruction failure at position " << jpos << '\n';
14686 		break;
14687 	      }
14688 	      if (afewpolys.size()<=jpos){
14689 		poly8<tdeg_t> tmp(poly8tmp.order,poly8tmp.dim);
14690 		afewpolys.push_back(tmp);
14691 	      }
14692 	      afewpolys[jpos].coord.swap(poly8tmp.coord);
14693 	    }
14694 	    if (Wlast[i].size()>jpos && !(afewpolys[jpos]==Wlast[i][jpos])){
14695 	      if (debug_infolevel){
14696 		unsigned j=0,js=giacmin(afewpolys[jpos].coord.size(),Wlast[i][jpos].coord.size());
14697 		for (;j<js;++j){
14698 		  if (!(afewpolys[jpos].coord[j]==Wlast[i][jpos].coord[j]))
14699 		    break;
14700 		}
14701 		CERR << "Diagnostic: chinrem reconstruction mismatch at positions " << jpos << "," << j << '\n';
14702 		if (j<js)
14703 		  CERR << gb[jpos].coord[j].g << "*" << gb[jpos].coord[j].u << '\n';
14704 		else
14705 		  CERR << afewpolys[jpos].coord.size() << "," << Wlast[i][jpos].coord.size() << '\n';
14706 	      }
14707 	      afewpolys.resize(jpos+1);
14708 	      break;
14709 	    }
14710 	    if (jpos > Wlast[i].size()*1.35+2 )
14711 	      break;
14712 	  }
14713 	  if (afewpolys!=Wlast[i]){
14714 	    swap(afewpolys,Wlast[i]);
14715 	    if (debug_infolevel>0)
14716 	      CERR << CLOCK()*1e-6 << " unstable mod " << p << " from " << V[i].size() << " reconstructed " << Wlast[i].size() << '\n';
14717 	    break;
14718 	  }
14719 	  if (debug_infolevel)
14720 	    CERR << CLOCK()*1e-6 << " stable, clearing denominators " << '\n';
14721 	  W[i]=Wlast[i];
14722 	  cleardeno(W[i]); // clear denominators
14723 	  if (debug_infolevel)
14724 	    CERR << CLOCK()*1e-6 << " end rational reconstruction " << '\n';
14725 	  // now check if W[i] is a Groebner basis over Q, if so it's the answer
14726 	  // first verify that the initial generators reduce to 0
14727 	  poly8<tdeg_t> tmp0,tmp1,tmp2;
14728 	  vectpoly8<tdeg_t> wtmp;
14729 	  unsigned j=0,finalchecks=initial;
14730 	  if (eps>0)
14731 	    finalchecks=giacmin(2*W[i].front().dim,initial);
14732 	  if (debug_infolevel)
14733 	    CERR << CLOCK()*1e-6 << " begin final check, checking that " << finalchecks << " initial generators belongs to the ideal" << '\n';
14734 	  G.resize(W[i].size());
14735 	  for (j=0;j<W[i].size();++j)
14736 	    G[j]=j;
14737 	  for (j=0;j<finalchecks;++j){
14738 	    if (debug_infolevel)
14739 	      CERR << "+";
14740 	    reduce(res[j],W[i],G,-1,wtmp,tmp0,tmp1,tmp2,0);
14741 	    if (!tmp0.coord.empty()){
14742 	      break;
14743 	    }
14744 	    if (debug_infolevel	&& (j%10==9))
14745 	      CERR << j+1 << '\n';
14746 	  }
14747 	  if (j!=finalchecks){
14748 	    if (debug_infolevel){
14749 	      CERR << CLOCK()*1e-6 << " final check failure, retrying with another prime " << '\n';
14750 	      CERR << "Non-zero remainder " << tmp0 << '\n';
14751 	      CERR << "checking res[j], " << j << "<" << initial << '\n';
14752 	      CERR << "res[j]=" << res[j] << '\n';
14753 	      CERR << "basis candidate " << W[i] << '\n';
14754 	    }
14755 	    break;
14756 	}
14757 	  /* (final check requires that we have reconstructed a Groebner basis,
14758 	     Modular algorithms for computing Groebner bases Elizabeth A. Arnold
14759 	     Journal of Symbolic Computation 35 (2003) 403–419)
14760 	  */
14761 #if 1
14762 	  if (int(W[i].size())<=GBASIS_DETERMINISTIC)
14763 	    eps=0;
14764 	  if (eps>0){
14765 	    double terms=0;
14766 	    int termsmin=RAND_MAX; // estimate of the number of terms of a reduced non-0 spoly
14767 	    for (unsigned k=0;k<W[i].size();++k){
14768 	      terms += W[i][k].coord.size();
14769 	      termsmin = giacmin(termsmin,W[i][k].coord.size());
14770 	    }
14771 	    termsmin = 7*(2*termsmin-1);
14772 	    int epsp=mpz_sizeinbase(*P[i]._ZINTptr,10)-int(std::ceil(2*std::log10(terms)));
14773 	    if (epsp>termsmin)
14774 	      epsp=termsmin;
14775 	    *logptr(contextptr) << gettext("Running a probabilistic check for the reconstructed Groebner basis. If successfull, error probability is less than ") << eps << gettext(" and is estimated to be less than 10^-") << epsp << gettext(". Use proba_epsilon:=0 to certify (this takes more time).") << '\n';
14776 	  }
14777 	  G.clear();
14778 	  if (eps<6e-8 && !is_gbasis(W[i],eps*1.677e7,modularcheck)){
14779 	    ok=false;
14780 	    break; // in_gbasis(W[i],G,0,true);
14781 	  }
14782 #endif
14783 	  if (debug_infolevel)
14784 	    CERR << CLOCK()*1e-6 << " end final check " << '\n';
14785 	  swap(res,W[i]);
14786 	  mpz_clear(zd);
14787 	  mpz_clear(zu);
14788 	  mpz_clear(zu1);
14789 	  mpz_clear(zd1);
14790 	  mpz_clear(zabsd1);
14791 	  mpz_clear(zsqrtm);
14792 	  mpz_clear(zq);
14793 	  mpz_clear(zur);
14794 	  mpz_clear(zr);
14795 	  mpz_clear(ztmp);
14796 	  return 1;
14797 	} // end for (i<V.size())
14798 	if (i==V.size()){
14799 	  if (debug_infolevel)
14800 	    CERR << CLOCK()*1e-6 << " creating reconstruction #" << i << '\n';
14801 	  // not found
14802 	  V.push_back(gb);
14803 	  W.push_back(vectpoly8<tdeg_t>()); // no reconstruction yet, wait at least another prime
14804 	  Wlast.push_back(vectpoly8<tdeg_t>());
14805 	  P.push_back(p);
14806 	}
14807 #endif
14808       } // end loop on threads
14809     } //end for int count
14810     mpz_clear(zd);
14811     mpz_clear(zu);
14812     mpz_clear(zu1);
14813     mpz_clear(zd1);
14814     mpz_clear(zabsd1);
14815     mpz_clear(zsqrtm);
14816     mpz_clear(zq);
14817     mpz_clear(zur);
14818     mpz_clear(zr);
14819     mpz_clear(ztmp);
14820     return 0;
14821   }
14822 
14823   template<class tdeg_t>
mod_gbasis(vectpoly8<tdeg_t> & res,bool modularcheck,bool zdata,int & rur,GIAC_CONTEXT,gbasis_param_t gbasis_param)14824   bool mod_gbasis(vectpoly8<tdeg_t> & res,bool modularcheck,bool zdata,int & rur,GIAC_CONTEXT,gbasis_param_t gbasis_param){
14825     int gbasis_logz_age=gbasis_logz_age_sort;
14826     for (;;){
14827       int tmp=in_mod_gbasis(res,modularcheck,zdata,rur,contextptr,gbasis_param,gbasis_logz_age);
14828       if (tmp!=-1) // -1 means part of the gbasis has been reconstructed
14829 	return tmp;
14830       if (gbasis_logz_age)
14831 	gbasis_logz_age=0; // special sorting is not meaningfull after 1 reinjection, and we want to have interreduction
14832     }
14833   }
14834 #ifndef BIGENDIAN
14835 #define GBASIS_SWAP
14836 #endif
14837 
14838 #if !defined NO_STDEXCEPT && !defined BIGENDIAN
14839   #define GIAC_TDEG_T14
14840 #endif
14841 
14842   // other tdeg_t types
14843 #ifdef GIAC_TDEG_T14
14844 #undef INT128 // it's slower!
14845   struct tdeg_t14 {
vars64giac::tdeg_t1414846     bool vars64() const { return false;}
hash_indexgiac::tdeg_t1414847     int hash_index(void * ptr_) const {
14848       // if (!ptr_)
14849 	return -1;
14850     }
add_to_hashgiac::tdeg_t1414851     bool add_to_hash(void *ptr_,int no) const {
14852       return false;
14853     }
14854     void dbgprint() const;
14855     // data
14856     union {
14857       unsigned char tab[16]; // tab[0] and 1 is for total degree
14858       struct {
14859 	unsigned char tdeg;
14860 	unsigned char tdeg2;
14861 	order_t order_;
14862 	longlong * ui;
14863       };
14864     };
frontgiac::tdeg_t1414865     int front(){ return tab[2];}
14866     // methods
selection_degreegiac::tdeg_t1414867     inline unsigned selection_degree(order_t order) const {
14868 #ifdef GBASIS_SELECT_TOTAL_DEGREE
14869       return total_degree(order);
14870 #endif
14871       return tdeg;
14872     }
total_degreegiac::tdeg_t1414873     inline unsigned total_degree(order_t order) const {
14874       return tdeg+tdeg2;
14875     }
14876     // void set_total_degree(unsigned d) { tab[0]=d;}
tdeg_t14giac::tdeg_t1414877     tdeg_t14() {
14878       longlong * ptr = (longlong *) tab;
14879       ptr[1]=ptr[0]=0;
14880     }
tdeg_t14giac::tdeg_t1414881     tdeg_t14(int i){
14882       longlong * ptr = (longlong *) tab;
14883       ptr[1]=ptr[0]=0;
14884     }
get_tabgiac::tdeg_t1414885     void get_tab(short * ptr,order_t order) const {
14886 #ifdef GBASIS_SWAP
14887       tdeg_t14 t(*this);
14888       swap_indices14(t.tab);
14889 #else
14890       const tdeg_t14 & t=*this;
14891 #endif
14892       ptr[0]=t.tab[0];
14893       for (unsigned i=1;i<15;++i)
14894 	ptr[i]=t.tab[i+1];
14895     }
tdeg_t14giac::tdeg_t1414896     tdeg_t14(const index_m & lm,order_t order){
14897       longlong * ptr_ = (longlong *) tab;
14898       ptr_[1]=ptr_[0]=0;
14899       unsigned char * ptr=tab;
14900       vector<deg_t>::const_iterator it=lm.begin(),itend=lm.end();
14901       if (order.o==_REVLEX_ORDER || order.o==_TDEG_ORDER){
14902 	unsigned td=sum_degree(lm);
14903 	if (td>=128)
14904 	  gensizeerr("Degree too large");
14905 	*ptr=td;
14906 	++ptr;
14907 	*ptr=0;
14908 	++ptr;
14909       }
14910       if (order.o==_REVLEX_ORDER){
14911 	for (--itend,--it;it!=itend;++ptr,--itend)
14912 	  *ptr=*itend;
14913       }
14914       else {
14915 	for (;it!=itend;++ptr,++it)
14916 	  *ptr=*it;
14917       }
14918 #ifdef GBASIS_SWAP
14919       swap_indices14(tab);
14920 #endif
14921     }
14922   };
14923 
14924 
14925 #ifdef NSPIRE
14926   template<class T>
operator <<(nio::ios_base<T> & os,const tdeg_t14 & x)14927   nio::ios_base<T> & operator << (nio::ios_base<T> & os,const tdeg_t14 & x){
14928     os << "[";
14929     for (unsigned i=0; i<14;++i){
14930       os << unsigned(x.tab[i+2]) << ",";
14931     }
14932     return os << "]";
14933   }
14934 #else
operator <<(ostream & os,const tdeg_t14 & x)14935   ostream & operator << (ostream & os,const tdeg_t14 & x){
14936     os << "[";
14937     for (unsigned i=0; i<14;++i){
14938       os << unsigned(x.tab[i+2]) << ",";
14939     }
14940     return os << "]";
14941   }
14942 #endif
dbgprint() const14943   void tdeg_t14::dbgprint() const { COUT << * this << '\n'; }
operator +=(tdeg_t14 & x,const tdeg_t14 & y)14944   inline tdeg_t14 & operator += (tdeg_t14 & x,const tdeg_t14 & y){
14945 #ifdef INT128
14946     * (uint128_t *) &x += * (const uint128_t *) &y;
14947 #else
14948     // ulonglong *xtab=(ulonglong *)&x,*ytab=(ulonglong *)&y;
14949     *((ulonglong *)&x) += *((ulonglong *)&y);
14950     ((ulonglong *)&x)[1] += ((ulonglong *)&y)[1];
14951 #endif
14952     if (x.tab[0]>=128){
14953       gensizeerr("Degree too large");
14954     }
14955     return x;
14956   }
operator +(const tdeg_t14 & x,const tdeg_t14 & y)14957   inline tdeg_t14 operator + (const tdeg_t14 & x,const tdeg_t14 & y){
14958     tdeg_t14 res(x);
14959     return res += y;
14960     ulonglong *xtab=(ulonglong *)&x,*ytab=(ulonglong *)&y,*ztab=(ulonglong *)&res;
14961     ztab[0]=xtab[0]+ytab[0];
14962     ztab[1]=xtab[1]+ytab[1];
14963     return res;
14964   }
add(const tdeg_t14 & x,const tdeg_t14 & y,tdeg_t14 & res,int dim)14965   inline void add(const tdeg_t14 & x,const tdeg_t14 & y,tdeg_t14 & res,int dim){
14966 #ifdef INT128
14967     * (uint128_t *) &res = * (const uint128_t *) &x + * (const uint128_t *) &y;
14968 #else
14969     // ulonglong *xtab=(ulonglong *)&x,*ytab=(ulonglong *)&y,*ztab=(ulonglong *)&res;
14970     *((ulonglong *)&res)=*((ulonglong *)&x)+*((ulonglong *)&y);
14971     ((ulonglong *)&res)[1]=((ulonglong *)&x)[1]+((ulonglong *)&y)[1];
14972 #endif
14973     if (res.tab[0]>=128)
14974       gensizeerr("Degree too large");
14975   }
operator -(const tdeg_t14 & x,const tdeg_t14 & y)14976   tdeg_t14 operator - (const tdeg_t14 & x,const tdeg_t14 & y){
14977     tdeg_t14 res;
14978     ulonglong *xtab=(ulonglong *)&x,*ytab=(ulonglong *)&y,*ztab=(ulonglong *)&res;
14979     ztab[0]=xtab[0]-ytab[0];
14980     ztab[1]=xtab[1]-ytab[1];
14981     return res;
14982   }
operator ==(const tdeg_t14 & x,const tdeg_t14 & y)14983   inline bool operator == (const tdeg_t14 & x,const tdeg_t14 & y){
14984 #ifdef INT128
14985     return * (const uint128_t *) &x == * (uint128_t *) &y;
14986 #else
14987     return ((longlong *) x.tab)[0] == ((longlong *) y.tab)[0] && ((longlong *) x.tab)[1] == ((longlong *) y.tab)[1];
14988 #endif
14989   }
operator !=(const tdeg_t14 & x,const tdeg_t14 & y)14990   inline bool operator != (const tdeg_t14 & x,const tdeg_t14 & y){
14991     return !(x==y);
14992   }
14993 
tdeg_t14_revlex_greater(const tdeg_t14 & x,const tdeg_t14 & y)14994   static inline int tdeg_t14_revlex_greater (const tdeg_t14 & x,const tdeg_t14 & y){
14995 #ifdef GBASIS_SWAP
14996 #if 0
14997     longlong *xtab=(longlong *)&x,*ytab=(longlong *)&y;
14998     if (longlong a=*xtab-*ytab) // tdeg test already donne by caller
14999       return a<=0?1:0;
15000     if (longlong a=xtab[1]-ytab[1])
15001       return a<=0?1:0;
15002 #else
15003     ulonglong *xtab=(ulonglong *)&x,*ytab=(ulonglong *)&y;
15004     if (xtab[0]!=ytab[0]) // tdeg test already donne by caller
15005       return xtab[0]<=ytab[0]?1:0;
15006     if (xtab[1]!=ytab[1])
15007       return xtab[1]<=ytab[1]?1:0;
15008 #endif
15009     return 2;
15010 #else // GBASIS_SWAP
15011     if (((longlong *) x.tab)[0] != ((longlong *) y.tab)[0]){
15012       if (x.tab[0]!=y.tab[0])
15013 	return x.tab[0]>=y.tab[0]?1:0;
15014       if (x.tab[1]!=y.tab[1])
15015 	return x.tab[1]<=y.tab[1]?1:0;
15016       if (x.tab[2]!=y.tab[2])
15017 	return x.tab[2]<=y.tab[2]?1:0;
15018       if (x.tab[3]!=y.tab[3])
15019 	return x.tab[3]<=y.tab[3]?1:0;
15020       if (x.tab[4]!=y.tab[4])
15021 	return x.tab[4]<=y.tab[4]?1:0;
15022       if (x.tab[5]!=y.tab[5])
15023 	return x.tab[5]<=y.tab[5]?1:0;
15024       if (x.tab[6]!=y.tab[6])
15025 	return x.tab[6]<=y.tab[6]?1:0;
15026       return x.tab[7]<=y.tab[7]?1:0;
15027     }
15028     if (((longlong *) x.tab)[1] != ((longlong *) y.tab)[1]){
15029       if (x.tab[8]!=y.tab[8])
15030 	return x.tab[8]>=y.tab[8]?1:0;
15031       if (x.tab[9]!=y.tab[9])
15032 	return x.tab[9]<=y.tab[9]?1:0;
15033       if (x.tab[10]!=y.tab[10])
15034 	return x.tab[10]<=y.tab[10]?1:0;
15035       if (x.tab[11]!=y.tab[11])
15036 	return x.tab[11]<=y.tab[11]?1:0;
15037       if (x.tab[12]!=y.tab[12])
15038 	return x.tab[12]<=y.tab[12]?1:0;
15039       if (x.tab[13]!=y.tab[13])
15040 	return x.tab[13]<=y.tab[13]?1:0;
15041       if (x.tab[14]!=y.tab[14])
15042 	return x.tab[14]<=y.tab[14]?1:0;
15043       return x.tab[15]<=y.tab[15]?1:0;
15044     }
15045     return 2;
15046 #endif // GBASIS_SWAP
15047   }
15048 
tdeg_t14_lex_greater(const tdeg_t14 & x,const tdeg_t14 & y)15049   int tdeg_t14_lex_greater (const tdeg_t14 & x,const tdeg_t14 & y){
15050 #ifdef GBASIS_SWAP
15051     ulonglong *xtab=(ulonglong *)&x,*ytab=(ulonglong *)&y;
15052     ulonglong X=*xtab, Y=*ytab;
15053     if (X!=Y){
15054       if ( (X & 0xffff) != (Y &0xffff))
15055 	return (X&0xffff)>=(Y&0xffff)?1:0;
15056       return X>=Y?1:0;
15057     }
15058     if (xtab[1]!=ytab[1])
15059       return xtab[1]>=ytab[1]?1:0;
15060     return 2;
15061 #else
15062     if (((longlong *) x.tab)[0] != ((longlong *) y.tab)[0]){
15063       if (x.tab[0]!=y.tab[0])
15064 	return x.tab[0]>y.tab[0]?1:0;
15065       if (x.tab[1]!=y.tab[1])
15066 	return x.tab[1]>y.tab[1]?1:0;
15067       if (x.tab[2]!=y.tab[2])
15068 	return x.tab[2]>y.tab[2]?1:0;
15069       if (x.tab[3]!=y.tab[3])
15070 	return x.tab[2]>y.tab[2]?1:0;
15071       if (x.tab[4]!=y.tab[4])
15072 	return x.tab[4]>y.tab[4]?1:0;
15073       if (x.tab[5]!=y.tab[5])
15074 	return x.tab[5]>y.tab[5]?1:0;
15075       if (x.tab[6]!=y.tab[6])
15076 	return x.tab[6]>y.tab[6]?1:0;
15077       return x.tab[7]>y.tab[7]?1:0;
15078     }
15079     if (((longlong *) x.tab)[1] != ((longlong *) y.tab)[1]){
15080       if (x.tab[8]!=y.tab[8])
15081 	return x.tab[8]>y.tab[8]?1:0;
15082       if (x.tab[9]!=y.tab[9])
15083 	return x.tab[9]>y.tab[9]?1:0;
15084       if (x.tab[10]!=y.tab[10])
15085 	return x.tab[10]>y.tab[10]?1:0;
15086       if (x.tab[11]!=y.tab[11])
15087 	return x.tab[11]>y.tab[11]?1:0;
15088       if (x.tab[12]!=y.tab[12])
15089 	return x.tab[12]>y.tab[12]?1:0;
15090       if (x.tab[13]!=y.tab[13])
15091 	return x.tab[13]>y.tab[13]?1:0;
15092       if (x.tab[14]!=y.tab[14])
15093 	return x.tab[14]>y.tab[14]?1:0;
15094       return x.tab[15]>y.tab[15]?1:0;
15095     }
15096     return 2;
15097 #endif
15098   }
15099 
tdeg_t_greater(const tdeg_t14 & x,const tdeg_t14 & y,order_t order)15100   inline int tdeg_t_greater(const tdeg_t14 & x,const tdeg_t14 & y,order_t order){
15101     short X=x.tab[0];
15102     if (X!=y.tab[0]) return X>y.tab[0]?1:0; // since tdeg is tab[0] for plex
15103     if (order.o==_REVLEX_ORDER)
15104       return tdeg_t14_revlex_greater(x,y);
15105     return tdeg_t14_lex_greater(x,y);
15106   }
tdeg_t_strictly_greater(const tdeg_t14 & x,const tdeg_t14 & y,order_t order)15107   inline bool tdeg_t_strictly_greater (const tdeg_t14 & x,const tdeg_t14 & y,order_t order){
15108     return !tdeg_t_greater(y,x,order); // total order
15109   }
15110 
15111 #ifdef INT128
15112   uint128_t mask4=(((uint128_t) mask2)<<64)|mask2;
15113 #endif
15114 
tdeg_t_all_greater(const tdeg_t14 & x,const tdeg_t14 & y,order_t order)15115   inline bool tdeg_t_all_greater(const tdeg_t14 & x,const tdeg_t14 & y,order_t order){
15116 #ifdef INT128
15117     return !((* (const uint128_t *) &x - * (const uint128_t *) &y) & mask4);
15118 #else
15119     ulonglong *xtab=(ulonglong *)&x,*ytab=(ulonglong *)&y;
15120     if ((xtab[0]-ytab[0]) & mask2)
15121       return false;
15122     if ((xtab[1]-ytab[1]) & mask2)
15123       return false;
15124     return true;
15125 #endif
15126   }
15127 
15128   // 1 (all greater), 0 (unknown), -1 (all smaller)
tdeg_t_compare_all(const tdeg_t14 & x,const tdeg_t14 & y,order_t order)15129   int tdeg_t_compare_all(const tdeg_t14 & x,const tdeg_t14 & y,order_t order){
15130     int res=0;
15131     ulonglong *xtab=(ulonglong *)&x,*ytab=(ulonglong *)&y;
15132     longlong tmp=xtab[0]-ytab[0];
15133     if (tmp & mask2){
15134       if (res==1 || ((-tmp) & mask2)) return 0;
15135       res=-1;
15136     }
15137     else {
15138       if (res==-1) return 0; else res=1;
15139     }
15140     tmp=xtab[1]-ytab[1];
15141     if (tmp & mask2){
15142       if (res==1 || ((-tmp) & mask2)) return 0;
15143       res=-1;
15144     }
15145     else {
15146       if (res==-1) return 0; else res=1;
15147     }
15148     return res;
15149   }
15150 
index_lcm(const tdeg_t14 & x,const tdeg_t14 & y,tdeg_t14 & z,order_t order)15151   void index_lcm(const tdeg_t14 & x,const tdeg_t14 & y,tdeg_t14 & z,order_t order){
15152     int t=0;
15153     const unsigned char * xtab=&x.tab[2],*ytab=&y.tab[2];
15154     unsigned char *ztab=&z.tab[2];
15155     t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 2
15156     ++xtab; ++ytab; ++ztab;
15157     t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 3
15158     ++xtab; ++ytab; ++ztab;
15159     t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 4
15160     ++xtab; ++ytab; ++ztab;
15161     t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 5
15162     ++xtab; ++ytab; ++ztab;
15163     t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 6
15164     ++xtab; ++ytab; ++ztab;
15165     t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 7
15166     ++xtab; ++ytab; ++ztab;
15167     t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 8
15168     ++xtab; ++ytab; ++ztab;
15169     t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 9
15170     ++xtab; ++ytab; ++ztab;
15171     t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 10
15172     ++xtab; ++ytab; ++ztab;
15173     t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 11
15174     ++xtab; ++ytab; ++ztab;
15175     t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 12
15176     ++xtab; ++ytab; ++ztab;
15177     t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 13
15178     ++xtab; ++ytab; ++ztab;
15179     t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 14
15180     ++xtab; ++ytab; ++ztab;
15181     t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 15
15182     if (t>=128){
15183       gensizeerr("Degree too large");
15184     }
15185     if (order.o==_REVLEX_ORDER || order.o==_TDEG_ORDER){
15186       z.tab[0]=t;
15187     }
15188     else {
15189       z.tab[0]=(x.tab[0]>y.tab[0])?x.tab[0]:y.tab[0];
15190     }
15191   }
15192 
index_lcm_overwrite(const tdeg_t14 & x,const tdeg_t14 & y,tdeg_t14 & z,order_t order)15193   void index_lcm_overwrite(const tdeg_t14 & x,const tdeg_t14 & y,tdeg_t14 & z,order_t order){
15194     index_lcm(x,y,z,order);
15195   }
15196 
get_index(const tdeg_t14 & x_,index_t & idx,order_t order,int dim)15197   void get_index(const tdeg_t14 & x_,index_t & idx,order_t order,int dim){
15198     idx.resize(dim);
15199 #ifdef GBASIS_SWAP
15200     tdeg_t14 x(x_);
15201     swap_indices14(x.tab);
15202 #else
15203     const tdeg_t14 & x= x_;
15204 #endif
15205     const unsigned char * ptr=x.tab+2;
15206     if (order.o==_REVLEX_ORDER){
15207       for (int i=1;i<=dim;++ptr,++i)
15208 	idx[dim-i]=*ptr;
15209     }
15210     else {
15211       for (int i=0;i<dim;++ptr,++i)
15212 	idx[i]=*ptr;
15213     }
15214   }
15215 
disjoint(const tdeg_t14 & a,const tdeg_t14 & b,order_t order,short dim)15216   bool disjoint(const tdeg_t14 & a,const tdeg_t14 & b,order_t order,short dim){
15217     const unsigned char * it=a.tab+2, * jt=b.tab+2;
15218 #ifdef GBASIS_SWAP
15219     const unsigned char * itend=it+14;
15220 #else
15221     const unsigned char * itend=it+dim;
15222 #endif
15223     for (;it<itend;++jt,++it){
15224       if (*it && *jt)
15225 	return false;
15226     }
15227     return true;
15228   }
15229 #endif
15230 
15231 #undef GROEBNER_VARS
15232 #define GROEBNER_VARS 11
15233 
15234   struct tdeg_t11 {
vars64giac::tdeg_t1115235     bool vars64() const { return false;}
hash_indexgiac::tdeg_t1115236     int hash_index(void * ptr_) const {
15237       // if (!ptr_)
15238 	return -1;
15239     }
add_to_hashgiac::tdeg_t1115240     bool add_to_hash(void *ptr_,int no) const {
15241       return false;
15242     }
15243     void dbgprint() const;
15244     // data
15245     union {
15246       short tab[GROEBNER_VARS+1];
15247       struct {
15248 	short tdeg; // actually it's twice the total degree+1
15249 	short tdeg2;
15250 	order_t order_;
15251 	longlong * ui;
15252       };
15253     };
frontgiac::tdeg_t1115254     int front(){ return tab[1];}
15255     // methods
selection_degreegiac::tdeg_t1115256     inline unsigned selection_degree(order_t order) const {
15257       return tab[0];
15258     }
total_degreegiac::tdeg_t1115259     inline unsigned total_degree(order_t order) const {
15260       // works only for revlex and tdeg
15261       return tab[0];
15262     }
15263     // void set_total_degree(unsigned d) { tab[0]=d;}
tdeg_t11giac::tdeg_t1115264     tdeg_t11() {
15265       longlong * ptr = (longlong *) tab;
15266       ptr[2]=ptr[1]=ptr[0]=0;
15267     }
tdeg_t11giac::tdeg_t1115268     tdeg_t11(int i){
15269       longlong * ptr = (longlong *) tab;
15270       ptr[2]=ptr[1]=ptr[0]=0;
15271     }
get_tabgiac::tdeg_t1115272     void get_tab(short * ptr,order_t order) const {
15273       for (unsigned i=0;i<=11;++i)
15274 	ptr[i]=tab[i];
15275 #ifdef GBASIS_SWAP
15276       swap_indices11(ptr);
15277 #endif
15278       ptr[15]=ptr[14]=ptr[13]=ptr[12]=0;
15279     }
tdeg_t11giac::tdeg_t1115280     tdeg_t11(const index_m & lm,order_t order){
15281       longlong * ptr_ = (longlong *) tab;
15282       ptr_[2]=ptr_[1]=ptr_[0]=0;
15283       short * ptr=tab;
15284       // tab[GROEBNER_VARS]=order;
15285       vector<deg_t>::const_iterator it=lm.begin(),itend=lm.end();
15286       if (order.o==_REVLEX_ORDER || order.o==_TDEG_ORDER){
15287 	*ptr=sum_degree(lm);
15288 	++ptr;
15289       }
15290       if (order.o==_REVLEX_ORDER){
15291 	for (--itend,--it;it!=itend;++ptr,--itend)
15292 	  *ptr=*itend;
15293       }
15294       else {
15295 	for (;it!=itend;++ptr,++it)
15296 	  *ptr=*it;
15297       }
15298 #ifdef GBASIS_SWAP
15299       swap_indices11(tab);
15300 #endif
15301     }
15302   };
15303 
15304 
15305 #ifdef NSPIRE
15306   template<class T>
operator <<(nio::ios_base<T> & os,const tdeg_t11 & x)15307   nio::ios_base<T> & operator << (nio::ios_base<T> & os,const tdeg_t11 & x){
15308     os << "[";
15309     for (unsigned i=0; i<=GROEBNER_VARS;++i){
15310       os << x.tab[i] << ",";
15311     }
15312     return os << "]";
15313   }
15314 #else
operator <<(ostream & os,const tdeg_t11 & x)15315   ostream & operator << (ostream & os,const tdeg_t11 & x){
15316     os << "[";
15317     for (unsigned i=0; i<=GROEBNER_VARS;++i){
15318       os << x.tab[i] << ",";
15319     }
15320     return os << "]";
15321   }
15322 #endif
dbgprint() const15323   void tdeg_t11::dbgprint() const { COUT << * this << '\n'; }
15324   tdeg_t11 operator + (const tdeg_t11 & x,const tdeg_t11 & y);
operator +=(tdeg_t11 & x,const tdeg_t11 & y)15325   tdeg_t11 & operator += (tdeg_t11 & x,const tdeg_t11 & y){
15326     ulonglong *xtab=(ulonglong *)&x,*ytab=(ulonglong *)&y;
15327     xtab[0]+=ytab[0];
15328     xtab[1]+=ytab[1];
15329     xtab[2]+=ytab[2];
15330     return x;
15331   }
operator +(const tdeg_t11 & x,const tdeg_t11 & y)15332   tdeg_t11 operator + (const tdeg_t11 & x,const tdeg_t11 & y){
15333     tdeg_t11 res(x);
15334     return res += y;
15335     ulonglong *xtab=(ulonglong *)&x,*ytab=(ulonglong *)&y,*ztab=(ulonglong *)&res;
15336     ztab[0]=xtab[0]+ytab[0];
15337     ztab[1]=xtab[1]+ytab[1];
15338     ztab[2]=xtab[2]+ytab[2];
15339     return res;
15340   }
add(const tdeg_t11 & x,const tdeg_t11 & y,tdeg_t11 & res,int dim)15341   inline void add(const tdeg_t11 & x,const tdeg_t11 & y,tdeg_t11 & res,int dim){
15342     ulonglong *xtab=(ulonglong *)&x,*ytab=(ulonglong *)&y,*ztab=(ulonglong *)&res;
15343     ztab[0]=xtab[0]+ytab[0];
15344     ztab[1]=xtab[1]+ytab[1];
15345     ztab[2]=xtab[2]+ytab[2];
15346   }
operator -(const tdeg_t11 & x,const tdeg_t11 & y)15347   tdeg_t11 operator - (const tdeg_t11 & x,const tdeg_t11 & y){
15348     tdeg_t11 res;
15349     ulonglong *xtab=(ulonglong *)&x,*ytab=(ulonglong *)&y,*ztab=(ulonglong *)&res;
15350     ztab[0]=xtab[0]-ytab[0];
15351     ztab[1]=xtab[1]-ytab[1];
15352     ztab[2]=xtab[2]-ytab[2];
15353     return res;
15354   }
operator ==(const tdeg_t11 & x,const tdeg_t11 & y)15355   inline bool operator == (const tdeg_t11 & x,const tdeg_t11 & y){
15356     return ((longlong *) x.tab)[0] == ((longlong *) y.tab)[0] &&
15357       ((longlong *) x.tab)[1] == ((longlong *) y.tab)[1] &&
15358       ((longlong *) x.tab)[2] == ((longlong *) y.tab)[2]
15359     ;
15360   }
operator !=(const tdeg_t11 & x,const tdeg_t11 & y)15361   inline bool operator != (const tdeg_t11 & x,const tdeg_t11 & y){
15362     return !(x==y);
15363   }
15364 
tdeg_t11_revlex_greater(const tdeg_t11 & x,const tdeg_t11 & y)15365   static inline int tdeg_t11_revlex_greater (const tdeg_t11 & x,const tdeg_t11 & y){
15366 #ifdef GBASIS_SWAP
15367 #if 1
15368     ulonglong *xtab=(ulonglong *)&x,*ytab=(ulonglong *)&y;
15369     if (xtab[0]!=ytab[0]) // tdeg test already donne by caller
15370       return xtab[0]<=ytab[0]?1:0;
15371     if (xtab[1]!=ytab[1])
15372       return xtab[1]<=ytab[1]?1:0;
15373     if (xtab[2]!=ytab[2])
15374       return xtab[2]<=ytab[2]?1:0;
15375 #else
15376     longlong *xtab=(longlong *)&x,*ytab=(longlong *)&y;
15377     if (longlong a=*xtab-*ytab) // tdeg test already donne by caller
15378       return a<=0?1:0;
15379     if (longlong a=xtab[1]-ytab[1])
15380       return a<=0?1:0;
15381     if (longlong a=xtab[2]-ytab[2])
15382       return a<=0?1:0;
15383 #endif
15384     return 2;
15385 #else // GBASIS_SWAP
15386     if (((longlong *) x.tab)[0] != ((longlong *) y.tab)[0]){
15387       if (x.tab[0]!=y.tab[0])
15388 	return x.tab[0]>=y.tab[0]?1:0;
15389       if (x.tab[1]!=y.tab[1])
15390 	return x.tab[1]<=y.tab[1]?1:0;
15391       if (x.tab[2]!=y.tab[2])
15392 	return x.tab[2]<=y.tab[2]?1:0;
15393       return x.tab[3]<=y.tab[3]?1:0;
15394     }
15395     if (((longlong *) x.tab)[1] != ((longlong *) y.tab)[1]){
15396       if (x.tab[4]!=y.tab[4])
15397 	return x.tab[4]<=y.tab[4]?1:0;
15398       if (x.tab[5]!=y.tab[5])
15399 	return x.tab[5]<=y.tab[5]?1:0;
15400       if (x.tab[6]!=y.tab[6])
15401 	return x.tab[6]<=y.tab[6]?1:0;
15402       return x.tab[7]<=y.tab[7]?1:0;
15403     }
15404     if (((longlong *) x.tab)[2] != ((longlong *) y.tab)[2]){
15405       if (x.tab[8]!=y.tab[8])
15406 	return x.tab[8]<=y.tab[8]?1:0;
15407       if (x.tab[9]!=y.tab[9])
15408 	return x.tab[9]<=y.tab[9]?1:0;
15409       if (x.tab[10]!=y.tab[10])
15410 	return x.tab[10]<=y.tab[10]?1:0;
15411       return x.tab[11]<=y.tab[11]?1:0;
15412     }
15413     return 2;
15414 #endif // GBASIS_SWAP
15415   }
15416 
tdeg_t11_lex_greater(const tdeg_t11 & x,const tdeg_t11 & y)15417   int tdeg_t11_lex_greater (const tdeg_t11 & x,const tdeg_t11 & y){
15418 #ifdef GBASIS_SWAP
15419     ulonglong *xtab=(ulonglong *)&x,*ytab=(ulonglong *)&y;
15420     ulonglong X=*xtab, Y=*ytab;
15421     if (X!=Y){
15422       if ( (X & 0xffff) != (Y &0xffff))
15423 	return (X&0xffff)>=(Y&0xffff)?1:0;
15424       return X>=Y?1:0;
15425     }
15426     if (xtab[1]!=ytab[1])
15427       return xtab[1]>=ytab[1]?1:0;
15428     if (xtab[2]!=ytab[2])
15429       return xtab[2]>=ytab[2]?1:0;
15430     return 2;
15431 #else
15432     if (((longlong *) x.tab)[0] != ((longlong *) y.tab)[0]){
15433       if (x.tab[0]!=y.tab[0])
15434 	return x.tab[0]>y.tab[0]?1:0;
15435       if (x.tab[1]!=y.tab[1])
15436 	return x.tab[1]>y.tab[1]?1:0;
15437       if (x.tab[2]!=y.tab[2])
15438 	return x.tab[2]>y.tab[2]?1:0;
15439       return x.tab[3]>y.tab[3]?1:0;
15440     }
15441     if (((longlong *) x.tab)[1] != ((longlong *) y.tab)[1]){
15442       if (x.tab[4]!=y.tab[4])
15443 	return x.tab[4]>y.tab[4]?1:0;
15444       if (x.tab[5]!=y.tab[5])
15445 	return x.tab[5]>y.tab[5]?1:0;
15446       if (x.tab[6]!=y.tab[6])
15447 	return x.tab[6]>y.tab[6]?1:0;
15448       return x.tab[7]>y.tab[7]?1:0;
15449     }
15450     if (((longlong *) x.tab)[2] != ((longlong *) y.tab)[2]){
15451       if (x.tab[8]!=y.tab[8])
15452 	return x.tab[8]>y.tab[8]?1:0;
15453       if (x.tab[9]!=y.tab[9])
15454 	return x.tab[9]>y.tab[9]?1:0;
15455       if (x.tab[10]!=y.tab[10])
15456 	return x.tab[10]>y.tab[10]?1:0;
15457       return x.tab[11]>=y.tab[11]?1:0;
15458     }
15459     return 2;
15460 #endif
15461   }
15462 
tdeg_t_greater(const tdeg_t11 & x,const tdeg_t11 & y,order_t order)15463   inline int tdeg_t_greater(const tdeg_t11 & x,const tdeg_t11 & y,order_t order){
15464     short X=x.tab[0];
15465     if (X!=y.tab[0]) return X>y.tab[0]?1:0; // since tdeg is tab[0] for plex
15466     if (order.o==_REVLEX_ORDER)
15467       return tdeg_t11_revlex_greater(x,y);
15468     return tdeg_t11_lex_greater(x,y);
15469   }
tdeg_t_strictly_greater(const tdeg_t11 & x,const tdeg_t11 & y,order_t order)15470   inline bool tdeg_t_strictly_greater (const tdeg_t11 & x,const tdeg_t11 & y,order_t order){
15471     return !tdeg_t_greater(y,x,order); // total order
15472   }
15473 
tdeg_t_all_greater(const tdeg_t11 & x,const tdeg_t11 & y,order_t order)15474   inline bool tdeg_t_all_greater(const tdeg_t11 & x,const tdeg_t11 & y,order_t order){
15475     ulonglong *xtab=(ulonglong *)&x,*ytab=(ulonglong *)&y;
15476     if ((xtab[0]-ytab[0]) & 0x8000800080008000ULL)
15477       return false;
15478     if ((xtab[1]-ytab[1]) & 0x8000800080008000ULL)
15479       return false;
15480     if ((xtab[2]-ytab[2]) & 0x8000800080008000ULL)
15481       return false;
15482     return true;
15483   }
15484 
15485   // 1 (all greater), 0 (unknown), -1 (all smaller)
tdeg_t_compare_all(const tdeg_t11 & x,const tdeg_t11 & y,order_t order)15486   int tdeg_t_compare_all(const tdeg_t11 & x,const tdeg_t11 & y,order_t order){
15487     int res=0;
15488     ulonglong *xtab=(ulonglong *)&x,*ytab=(ulonglong *)&y;
15489     longlong tmp=xtab[0]-ytab[0];
15490     if (tmp & mask){
15491       if (res==1 || ((-tmp) & mask)) return 0;
15492       res=-1;
15493     }
15494     else {
15495       if (res==-1) return 0; else res=1;
15496     }
15497     tmp=xtab[1]-ytab[1];
15498     if (tmp & mask){
15499       if (res==1 || ((-tmp) & mask)) return 0;
15500       res=-1;
15501     }
15502     else {
15503       if (res==-1) return 0; else res=1;
15504     }
15505     tmp=xtab[2]-ytab[2];
15506     if (tmp & mask){
15507       if (res==1 || ((-tmp) & mask)) return 0;
15508       res=-1;
15509     }
15510     else {
15511       if (res==-1) return 0; else res=1;
15512     }
15513     return res;
15514   }
15515 
index_lcm(const tdeg_t11 & x,const tdeg_t11 & y,tdeg_t11 & z,order_t order)15516   void index_lcm(const tdeg_t11 & x,const tdeg_t11 & y,tdeg_t11 & z,order_t order){
15517     int t=0;
15518     const short * xtab=&x.tab[1],*ytab=&y.tab[1];
15519     short *ztab=&z.tab[1];
15520     t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 1
15521     ++xtab; ++ytab; ++ztab;
15522     t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 2
15523     ++xtab; ++ytab; ++ztab;
15524     t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 3
15525     ++xtab; ++ytab; ++ztab;
15526     t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 4
15527     ++xtab; ++ytab; ++ztab;
15528     t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 5
15529     ++xtab; ++ytab; ++ztab;
15530     t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 6
15531     ++xtab; ++ytab; ++ztab;
15532     t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 7
15533     ++xtab; ++ytab; ++ztab;
15534     t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 8
15535     ++xtab; ++ytab; ++ztab;
15536     t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 9
15537     ++xtab; ++ytab; ++ztab;
15538     t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 10
15539     ++xtab; ++ytab; ++ztab;
15540     t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 11
15541     if (order.o==_REVLEX_ORDER || order.o==_TDEG_ORDER){
15542       z.tab[0]=t;
15543     }
15544     else {
15545       z.tab[0]=(x.tab[0]>y.tab[0])?x.tab[0]:y.tab[0];
15546     }
15547   }
15548 
index_lcm_overwrite(const tdeg_t11 & x,const tdeg_t11 & y,tdeg_t11 & z,order_t order)15549   inline void index_lcm_overwrite(const tdeg_t11 & x,const tdeg_t11 & y,tdeg_t11 & z,order_t order){
15550     index_lcm(x,y,z,order);
15551   }
15552 
get_index(const tdeg_t11 & x_,index_t & idx,order_t order,int dim)15553   void get_index(const tdeg_t11 & x_,index_t & idx,order_t order,int dim){
15554     idx.resize(dim);
15555 #ifdef GBASIS_SWAP
15556     tdeg_t11 x(x_);
15557     swap_indices11(x.tab);
15558 #else
15559     const tdeg_t11 & x= x_;
15560 #endif
15561     const short * ptr=x.tab;
15562     if (order.o==_REVLEX_ORDER || order.o==_TDEG_ORDER)
15563       ++ptr;
15564     if (order.o==_REVLEX_ORDER){
15565       for (int i=1;i<=dim;++ptr,++i)
15566 	idx[dim-i]=*ptr;
15567     }
15568     else {
15569       for (int i=0;i<dim;++ptr,++i)
15570 	idx[i]=*ptr;
15571     }
15572   }
15573 
disjoint(const tdeg_t11 & a,const tdeg_t11 & b,order_t order,short dim)15574   bool disjoint(const tdeg_t11 & a,const tdeg_t11 & b,order_t order,short dim){
15575     const short * it=a.tab, * jt=b.tab;
15576 #ifdef GBASIS_SWAP
15577     const short * itend=it+GROEBNER_VARS+1;
15578 #endif
15579     if (order.o==_REVLEX_ORDER || order.o==_TDEG_ORDER){
15580       ++it; ++jt;
15581     }
15582 #ifndef GBASIS_SWAP
15583     const short * itend=it+dim;
15584 #endif
15585     for (;it<itend;++jt,++it){
15586       if (*it && *jt)
15587 	return false;
15588     }
15589     return true;
15590   }
15591 
15592 #undef GROEBNER_VARS
15593 #define GROEBNER_VARS 15
15594 
15595   struct tdeg_t15 {
vars64giac::tdeg_t1515596     bool vars64() const { return false;}
hash_indexgiac::tdeg_t1515597     int hash_index(void * ptr_) const {
15598       // if (!ptr_)
15599 	return -1;
15600     }
add_to_hashgiac::tdeg_t1515601     bool add_to_hash(void *ptr_,int no) const {
15602       return false;
15603     }
15604     void dbgprint() const;
15605     // data
15606     union {
15607       short tab[GROEBNER_VARS+1];
15608       struct {
15609 	short tdeg; // actually it's twice the total degree+1
15610 	short tdeg2;
15611 	order_t order_;
15612 	longlong * ui;
15613       };
15614     };
frontgiac::tdeg_t1515615     int front(){ return tab[1];}
15616     // methods
selection_degreegiac::tdeg_t1515617     inline unsigned selection_degree(order_t order) const {
15618 #ifdef GBASIS_SELECT_TOTAL_DEGREE
15619       return total_degree(order);
15620 #endif
15621       return tab[0];
15622     }
total_degreegiac::tdeg_t1515623     inline unsigned total_degree(order_t order) const {
15624       if (order.o==_REVLEX_ORDER)
15625 	return tab[0];      // works only for revlex and tdeg
15626       if (order.o==_3VAR_ORDER)
15627 	return tab[0]+tab[4];
15628       if (order.o==_7VAR_ORDER)
15629 	return tab[0]+tab[8];
15630       if (order.o==_11VAR_ORDER)
15631 	return tab[0]+tab[12];
15632       return tab[0];
15633     }
15634     // void set_total_degree(unsigned d) { tab[0]=d;}
tdeg_t15giac::tdeg_t1515635     tdeg_t15() {
15636       longlong * ptr = (longlong *) tab;
15637       ptr[2]=ptr[1]=ptr[0]=0;
15638 #if GROEBNER_VARS>11
15639       ptr[3]=0;
15640 #endif
15641     }
tdeg_t15giac::tdeg_t1515642     tdeg_t15(int i){
15643       longlong * ptr = (longlong *) tab;
15644       ptr[2]=ptr[1]=ptr[0]=0;
15645 #if GROEBNER_VARS>11
15646       ptr[3]=0;
15647 #endif
15648     }
get_tabgiac::tdeg_t1515649     void get_tab(short * ptr,order_t order) const {
15650       for (unsigned i=0;i<=GROEBNER_VARS;++i)
15651 	ptr[i]=tab[i];
15652 #ifdef GBASIS_SWAP
15653       swap_indices15(ptr,order.o);
15654 #endif
15655     }
tdeg_t15giac::tdeg_t1515656     tdeg_t15(const index_m & lm,order_t order){
15657       longlong * ptr_ = (longlong *) tab;
15658       ptr_[2]=ptr_[1]=ptr_[0]=0;
15659       short * ptr=tab;
15660 #if GROEBNER_VARS>11
15661       ptr_[3]=0;
15662 #endif
15663       // tab[GROEBNER_VARS]=order;
15664 #if GROEBNER_VARS==15
15665       if (order.o==_3VAR_ORDER){
15666 	ptr[0]=lm[0]+lm[1]+lm[2];
15667 	ptr[1]=lm[2];
15668 	ptr[2]=lm[1];
15669 	ptr[3]=lm[0];
15670 	ptr +=5;
15671 	short t=0;
15672 	vector<deg_t>::const_iterator it=lm.begin()+3,itend=lm.end();
15673 	for (--itend,--it;it!=itend;++ptr,--itend){
15674 	  t += *itend;
15675 	  *ptr=*itend;
15676 	}
15677 	tab[4]=t;
15678 #ifdef GBASIS_SWAP
15679 	swap_indices15(tab,order.o);
15680 #endif
15681 	return;
15682       }
15683       if (order.o==_7VAR_ORDER){
15684 	ptr[0]=lm[0]+lm[1]+lm[2]+lm[3]+lm[4]+lm[5]+lm[6];
15685 	ptr[1]=lm[6];
15686 	ptr[2]=lm[5];
15687 	ptr[3]=lm[4];
15688 	ptr[4]=lm[3];
15689 	ptr[5]=lm[2];
15690 	ptr[6]=lm[1];
15691 	ptr[7]=lm[0];
15692 	ptr +=9;
15693 	short t=0;
15694 	vector<deg_t>::const_iterator it=lm.begin()+7,itend=lm.end();
15695 	for (--itend,--it;it!=itend;++ptr,--itend){
15696 	  t += *itend;
15697 	  *ptr=*itend;
15698 	}
15699 	tab[8]=t;
15700 #ifdef GBASIS_SWAP
15701 	swap_indices15(tab,order.o);
15702 #endif
15703 	return;
15704       }
15705       if (order.o==_11VAR_ORDER){
15706 	ptr[0]=lm[0]+lm[1]+lm[2]+lm[3]+lm[4]+lm[5]+lm[6]+lm[7]+lm[8]+lm[9]+lm[10];
15707 	ptr[1]=lm[10];
15708 	ptr[2]=lm[9];
15709 	ptr[3]=lm[8];
15710 	ptr[4]=lm[7];
15711 	ptr[5]=lm[6];
15712 	ptr[6]=lm[5];
15713 	ptr[7]=lm[4];
15714 	ptr[8]=lm[3];
15715 	ptr[9]=lm[2];
15716 	ptr[10]=lm[1];
15717 	ptr[11]=lm[0];
15718 	ptr += 13;
15719 	short t=0;
15720 	vector<deg_t>::const_iterator it=lm.begin()+11,itend=lm.end();
15721 	for (--itend,--it;it!=itend;++ptr,--itend){
15722 	  t += *itend;
15723 	  *ptr=*itend;
15724 	}
15725 	tab[12]=t;
15726 #ifdef GBASIS_SWAP
15727 	swap_indices15(tab,order.o);
15728 #endif
15729 	return;
15730       }
15731 #endif
15732       vector<deg_t>::const_iterator it=lm.begin(),itend=lm.end();
15733       if (order.o==_REVLEX_ORDER || order.o==_TDEG_ORDER){
15734 	*ptr=sum_degree(lm);
15735 	++ptr;
15736       }
15737       if (order.o==_REVLEX_ORDER){
15738 	for (--itend,--it;it!=itend;++ptr,--itend)
15739 	  *ptr=*itend;
15740       }
15741       else {
15742 	for (;it!=itend;++ptr,++it)
15743 	  *ptr=*it;
15744       }
15745 #ifdef GBASIS_SWAP
15746       swap_indices15(tab,order.o);
15747 #endif
15748     }
15749   };
15750 
15751 
15752 #ifdef NSPIRE
15753   template<class T>
operator <<(nio::ios_base<T> & os,const tdeg_t15 & x)15754   nio::ios_base<T> & operator << (nio::ios_base<T> & os,const tdeg_t15 & x){
15755     os << "[";
15756     for (unsigned i=0; i<=GROEBNER_VARS;++i){
15757       os << x.tab[i] << ",";
15758     }
15759     return os << "]";
15760   }
15761 #else
operator <<(ostream & os,const tdeg_t15 & x)15762   ostream & operator << (ostream & os,const tdeg_t15 & x){
15763     os << "[";
15764     for (unsigned i=0; i<=GROEBNER_VARS;++i){
15765       os << x.tab[i] << ",";
15766     }
15767     return os << "]";
15768   }
15769 #endif
dbgprint() const15770   void tdeg_t15::dbgprint() const { COUT << * this << '\n'; }
15771   tdeg_t15 operator + (const tdeg_t15 & x,const tdeg_t15 & y);
operator +=(tdeg_t15 & x,const tdeg_t15 & y)15772   tdeg_t15 & operator += (tdeg_t15 & x,const tdeg_t15 & y){
15773     ulonglong *xtab=(ulonglong *)&x,*ytab=(ulonglong *)&y;
15774     xtab[0]+=ytab[0];
15775     xtab[1]+=ytab[1];
15776     xtab[2]+=ytab[2];
15777 #if GROEBNER_VARS>11
15778     xtab[3]+=ytab[3];
15779 #endif
15780     return x;
15781   }
operator +(const tdeg_t15 & x,const tdeg_t15 & y)15782   tdeg_t15 operator + (const tdeg_t15 & x,const tdeg_t15 & y){
15783     tdeg_t15 res(x);
15784     return res += y;
15785 #if 1
15786     ulonglong *xtab=(ulonglong *)&x,*ytab=(ulonglong *)&y,*ztab=(ulonglong *)&res;
15787     ztab[0]=xtab[0]+ytab[0];
15788     ztab[1]=xtab[1]+ytab[1];
15789     ztab[2]=xtab[2]+ytab[2];
15790 #if GROEBNER_VARS>11
15791     ztab[3]=xtab[3]+ytab[3];
15792 #endif
15793 #else
15794     for (unsigned i=0;i<=GROEBNER_VARS;++i)
15795       res.tab[i]=x.tab[i]+y.tab[i];
15796 #endif
15797     return res;
15798   }
add(const tdeg_t15 & x,const tdeg_t15 & y,tdeg_t15 & res,int dim)15799   inline void add(const tdeg_t15 & x,const tdeg_t15 & y,tdeg_t15 & res,int dim){
15800 #if 1
15801     ulonglong *xtab=(ulonglong *)&x,*ytab=(ulonglong *)&y,*ztab=(ulonglong *)&res;
15802     ztab[0]=xtab[0]+ytab[0];
15803     ztab[1]=xtab[1]+ytab[1];
15804     ztab[2]=xtab[2]+ytab[2];
15805 #if GROEBNER_VARS>11
15806     ztab[3]=xtab[3]+ytab[3];
15807 #endif
15808 #else
15809     for (unsigned i=0;i<=dim;++i)
15810       res.tab[i]=x.tab[i]+y.tab[i];
15811 #endif
15812   }
operator -(const tdeg_t15 & x,const tdeg_t15 & y)15813   tdeg_t15 operator - (const tdeg_t15 & x,const tdeg_t15 & y){
15814     tdeg_t15 res;
15815 #if 1
15816     ulonglong *xtab=(ulonglong *)&x,*ytab=(ulonglong *)&y,*ztab=(ulonglong *)&res;
15817     ztab[0]=xtab[0]-ytab[0];
15818     ztab[1]=xtab[1]-ytab[1];
15819     ztab[2]=xtab[2]-ytab[2];
15820 #if GROEBNER_VARS>11
15821     ztab[3]=xtab[3]-ytab[3];
15822 #endif
15823 #else
15824     for (unsigned i=0;i<=GROEBNER_VARS;++i)
15825       res.tab[i]=x.tab[i]-y.tab[i];
15826 #endif
15827     return res;
15828   }
operator ==(const tdeg_t15 & x,const tdeg_t15 & y)15829   inline bool operator == (const tdeg_t15 & x,const tdeg_t15 & y){
15830     return ((longlong *) x.tab)[0] == ((longlong *) y.tab)[0] &&
15831       ((longlong *) x.tab)[1] == ((longlong *) y.tab)[1] &&
15832       ((longlong *) x.tab)[2] == ((longlong *) y.tab)[2]
15833 #if GROEBNER_VARS>11
15834       &&  ((longlong *) x.tab)[3] == ((longlong *) y.tab)[3]
15835 #endif
15836     ;
15837   }
operator !=(const tdeg_t15 & x,const tdeg_t15 & y)15838   inline bool operator != (const tdeg_t15 & x,const tdeg_t15 & y){
15839     return !(x==y);
15840   }
15841 
tdeg_t15_revlex_greater(const tdeg_t15 & x,const tdeg_t15 & y)15842   static inline int tdeg_t15_revlex_greater (const tdeg_t15 & x,const tdeg_t15 & y){
15843 #ifdef GBASIS_SWAP
15844 #if 1
15845     ulonglong *xtab=(ulonglong *)&x,*ytab=(ulonglong *)&y;
15846     if (xtab[0]!=ytab[0]) // tdeg test already donne by caller
15847       return xtab[0]<=ytab[0]?1:0;
15848     if (xtab[1]!=ytab[1])
15849       return xtab[1]<=ytab[1]?1:0;
15850     if (xtab[2]!=ytab[2])
15851       return xtab[2]<=ytab[2]?1:0;
15852 #else
15853     longlong *xtab=(longlong *)&x,*ytab=(longlong *)&y;
15854     if (longlong a=*xtab-*ytab) // tdeg test already donne by caller
15855       return a<=0?1:0;
15856     if (longlong a=xtab[1]-ytab[1])
15857       return a<=0?1:0;
15858     if (longlong a=xtab[2]-ytab[2])
15859       return a<=0?1:0;
15860 #endif
15861 #if GROEBNER_VARS>11
15862     return xtab[3]<=ytab[3]?1:0;
15863 #endif
15864     return 2;
15865 #else // GBASIS_SWAP
15866     if (((longlong *) x.tab)[0] != ((longlong *) y.tab)[0]){
15867       if (x.tab[0]!=y.tab[0])
15868 	return x.tab[0]>=y.tab[0]?1:0;
15869       if (x.tab[1]!=y.tab[1])
15870 	return x.tab[1]<=y.tab[1]?1:0;
15871       if (x.tab[2]!=y.tab[2])
15872 	return x.tab[2]<=y.tab[2]?1:0;
15873       return x.tab[3]<=y.tab[3]?1:0;
15874     }
15875     if (((longlong *) x.tab)[1] != ((longlong *) y.tab)[1]){
15876       if (x.tab[4]!=y.tab[4])
15877 	return x.tab[4]<=y.tab[4]?1:0;
15878       if (x.tab[5]!=y.tab[5])
15879 	return x.tab[5]<=y.tab[5]?1:0;
15880       if (x.tab[6]!=y.tab[6])
15881 	return x.tab[6]<=y.tab[6]?1:0;
15882       return x.tab[7]<=y.tab[7]?1:0;
15883     }
15884     if (((longlong *) x.tab)[2] != ((longlong *) y.tab)[2]){
15885       if (x.tab[8]!=y.tab[8])
15886 	return x.tab[8]<=y.tab[8]?1:0;
15887       if (x.tab[9]!=y.tab[9])
15888 	return x.tab[9]<=y.tab[9]?1:0;
15889       if (x.tab[10]!=y.tab[10])
15890 	return x.tab[10]<=y.tab[10]?1:0;
15891       return x.tab[11]<=y.tab[11]?1:0;
15892     }
15893 #if GROEBNER_VARS>11
15894     if (((longlong *) x.tab)[3] != ((longlong *) y.tab)[3]){
15895       if (x.tab[12]!=y.tab[12])
15896 	return x.tab[12]<=y.tab[12]?1:0;
15897       if (x.tab[13]!=y.tab[13])
15898 	return x.tab[13]<=y.tab[13]?1:0;
15899       if (x.tab[14]!=y.tab[14])
15900 	return x.tab[14]<=y.tab[14]?1:0;
15901       return x.tab[15]<=y.tab[15]?1:0;
15902     }
15903 #endif
15904     return 2;
15905 #endif // GBASIS_SWAP
15906   }
15907 
15908 
15909 #if GROEBNER_VARS==15
15910 
tdeg_t15_3var_greater(const tdeg_t15 & x,const tdeg_t15 & y)15911   int tdeg_t15_3var_greater (const tdeg_t15 & x,const tdeg_t15 & y){
15912     if (x.tab[0]!=y.tab[0])
15913       return x.tab[0]>=y.tab[0]?1:0;
15914     if (x.tab[4]!=y.tab[4])
15915       return x.tab[4]>=y.tab[4]?1:0;
15916     if (((longlong *) x.tab)[0] != ((longlong *) y.tab)[0]){
15917 #ifdef GBASIS_SWAP
15918       return ((longlong *) x.tab)[0] <= ((longlong *) y.tab)[0];
15919 #else
15920       if (x.tab[1]!=y.tab[1])
15921 	return x.tab[1]<=y.tab[1]?1:0;
15922       if (x.tab[2]!=y.tab[2])
15923 	return x.tab[2]<=y.tab[2]?1:0;
15924       return x.tab[3]<=y.tab[3]?1:0;
15925 #endif
15926     }
15927     if (((longlong *) x.tab)[1] != ((longlong *) y.tab)[1]){
15928 #ifdef GBASIS_SWAP
15929       return ((longlong *) x.tab)[1] <= ((longlong *) y.tab)[1];
15930 #else
15931       if (x.tab[5]!=y.tab[5])
15932 	return x.tab[5]<=y.tab[5]?1:0;
15933       if (x.tab[6]!=y.tab[6])
15934 	return x.tab[6]<=y.tab[6]?1:0;
15935       return x.tab[7]<=y.tab[7]?1:0;
15936 #endif
15937     }
15938     if (((longlong *) x.tab)[2] != ((longlong *) y.tab)[2]){
15939 #ifdef GBASIS_SWAP
15940       return ((longlong *) x.tab)[2] <= ((longlong *) y.tab)[2];
15941 #else
15942       if (x.tab[8]!=y.tab[8])
15943 	return x.tab[8]<=y.tab[8]?1:0;
15944       if (x.tab[9]!=y.tab[9])
15945 	return x.tab[9]<=y.tab[9]?1:0;
15946       if (x.tab[10]!=y.tab[10])
15947 	return x.tab[10]<=y.tab[10]?1:0;
15948       return x.tab[11]<=y.tab[11]?1:0;
15949 #endif
15950     }
15951     if (((longlong *) x.tab)[3] != ((longlong *) y.tab)[3]){
15952 #ifdef GBASIS_SWAP
15953       return ((longlong *) x.tab)[3] <= ((longlong *) y.tab)[3];
15954 #else
15955       if (x.tab[12]!=y.tab[12])
15956 	return x.tab[12]<=y.tab[12]?1:0;
15957       if (x.tab[13]!=y.tab[13])
15958 	return x.tab[13]<=y.tab[13]?1:0;
15959       if (x.tab[14]!=y.tab[14])
15960 	return x.tab[14]<=y.tab[14]?1:0;
15961       return x.tab[15]<=y.tab[15]?1:0;
15962 #endif
15963     }
15964     return 2;
15965   }
15966 
tdeg_t15_7var_greater(const tdeg_t15 & x,const tdeg_t15 & y)15967   int tdeg_t15_7var_greater (const tdeg_t15 & x,const tdeg_t15 & y){
15968     if (x.tab[0]!=y.tab[0])
15969       return x.tab[0]>=y.tab[0]?1:0;
15970     if (x.tab[8]!=y.tab[8])
15971       return x.tab[8]>=y.tab[8]?1:0;
15972     if (((longlong *) x.tab)[0] != ((longlong *) y.tab)[0]){
15973 #ifdef GBASIS_SWAP
15974       return ((longlong *) x.tab)[0] <= ((longlong *) y.tab)[0];
15975 #else
15976       if (x.tab[1]!=y.tab[1])
15977 	return x.tab[1]<=y.tab[1]?1:0;
15978       if (x.tab[2]!=y.tab[2])
15979 	return x.tab[2]<=y.tab[2]?1:0;
15980       return x.tab[3]<=y.tab[3]?1:0;
15981 #endif
15982     }
15983     if (((longlong *) x.tab)[1] != ((longlong *) y.tab)[1]){
15984 #ifdef GBASIS_SWAP
15985       return ((longlong *) x.tab)[1] <= ((longlong *) y.tab)[1];
15986 #else
15987       if (x.tab[4]!=y.tab[4])
15988 	return x.tab[4]<=y.tab[4]?1:0;
15989       if (x.tab[5]!=y.tab[5])
15990 	return x.tab[5]<=y.tab[5]?1:0;
15991       if (x.tab[6]!=y.tab[6])
15992 	return x.tab[6]<=y.tab[6]?1:0;
15993       return x.tab[7]<=y.tab[7]?1:0;
15994 #endif
15995     }
15996     if (((longlong *) x.tab)[2] != ((longlong *) y.tab)[2]){
15997 #ifdef GBASIS_SWAP
15998       return ((longlong *) x.tab)[2] <= ((longlong *) y.tab)[2];
15999 #else
16000       if (x.tab[9]!=y.tab[9])
16001 	return x.tab[9]<=y.tab[9]?1:0;
16002       if (x.tab[10]!=y.tab[10])
16003 	return x.tab[10]<=y.tab[10]?1:0;
16004       return x.tab[11]<=y.tab[11]?1:0;
16005 #endif
16006     }
16007     if (((longlong *) x.tab)[3] != ((longlong *) y.tab)[3]){
16008 #ifdef GBASIS_SWAP
16009       return ((longlong *) x.tab)[3] <= ((longlong *) y.tab)[3];
16010 #else
16011       if (x.tab[12]!=y.tab[12])
16012 	return x.tab[12]<=y.tab[12]?1:0;
16013       if (x.tab[13]!=y.tab[13])
16014 	return x.tab[13]<=y.tab[13]?1:0;
16015       if (x.tab[14]!=y.tab[14])
16016 	return x.tab[14]<=y.tab[14]?1:0;
16017       return x.tab[15]<=y.tab[15]?1:0;
16018 #endif
16019     }
16020     return 2;
16021   }
16022 
tdeg_t15_11var_greater(const tdeg_t15 & x,const tdeg_t15 & y)16023   int tdeg_t15_11var_greater (const tdeg_t15 & x,const tdeg_t15 & y){
16024     if (x.tab[0]!=y.tab[0])
16025       return x.tab[0]>=y.tab[0]?1:0;
16026     if (x.tab[12]!=y.tab[12])
16027       return x.tab[12]>=y.tab[12]?1:0;
16028     if (((longlong *) x.tab)[0] != ((longlong *) y.tab)[0]){
16029 #ifdef GBASIS_SWAP
16030       return ((longlong *) x.tab)[0] <= ((longlong *) y.tab)[0];
16031 #else
16032       if (x.tab[1]!=y.tab[1])
16033 	return x.tab[1]<=y.tab[1]?1:0;
16034       if (x.tab[2]!=y.tab[2])
16035 	return x.tab[2]<=y.tab[2]?1:0;
16036       return x.tab[3]<=y.tab[3]?1:0;
16037 #endif
16038     }
16039     if (((longlong *) x.tab)[1] != ((longlong *) y.tab)[1]){
16040 #ifdef GBASIS_SWAP
16041       return ((longlong *) x.tab)[1] <= ((longlong *) y.tab)[1];
16042 #else
16043       if (x.tab[4]!=y.tab[4])
16044 	return x.tab[4]<=y.tab[4]?1:0;
16045       if (x.tab[5]!=y.tab[5])
16046 	return x.tab[5]<=y.tab[5]?1:0;
16047       if (x.tab[6]!=y.tab[6])
16048 	return x.tab[6]<=y.tab[6]?1:0;
16049       return x.tab[7]<=y.tab[7]?1:0;
16050 #endif
16051     }
16052     if (((longlong *) x.tab)[2] != ((longlong *) y.tab)[2]){
16053 #ifdef GBASIS_SWAP
16054       return ((longlong *) x.tab)[2] <= ((longlong *) y.tab)[2];
16055 #else
16056       if (x.tab[8]!=y.tab[8])
16057 	return x.tab[8]<=y.tab[8]?1:0;
16058       if (x.tab[9]!=y.tab[9])
16059 	return x.tab[9]<=y.tab[9]?1:0;
16060       if (x.tab[10]!=y.tab[10])
16061 	return x.tab[10]<=y.tab[10]?1:0;
16062       return x.tab[11]<=y.tab[11]?1:0;
16063 #endif
16064     }
16065     if (((longlong *) x.tab)[3] != ((longlong *) y.tab)[3]){
16066 #ifdef GBASIS_SWAP
16067       return ((longlong *) x.tab)[3] <= ((longlong *) y.tab)[3];
16068 #else
16069       if (x.tab[13]!=y.tab[13])
16070 	return x.tab[13]<=y.tab[13]?1:0;
16071       if (x.tab[14]!=y.tab[14])
16072 	return x.tab[14]<=y.tab[14]?1:0;
16073       return x.tab[15]<=y.tab[15]?1:0;
16074 #endif
16075     }
16076     return 2;
16077   }
16078 #endif // GROEBNER_VARS==15
16079 
tdeg_t15_lex_greater(const tdeg_t15 & x,const tdeg_t15 & y)16080   int tdeg_t15_lex_greater (const tdeg_t15 & x,const tdeg_t15 & y){
16081 #if 0 // def GBASIS_SWAP
16082     ulonglong *xtab=(ulonglong *)&x,*ytab=(ulonglong *)&y;
16083     ulonglong X=*xtab, Y=*ytab;
16084     if (X!=Y){
16085       if ( (X & 0xffff) != (Y &0xffff))
16086 	return (X&0xffff)>=(Y&0xffff)?1:0;
16087       return X>=Y?1:0;
16088     }
16089     if (xtab[1]!=ytab[1])
16090       return xtab[1]>=ytab[1]?1:0;
16091     if (xtab[2]!=ytab[2])
16092       return xtab[2]>=ytab[2]?1:0;
16093 #if GROEBNER_VARS>11
16094     return xtab[3]>=ytab[3]?1:0;
16095 #endif
16096     return 2;
16097 #else
16098     if (((longlong *) x.tab)[0] != ((longlong *) y.tab)[0]){
16099       if (x.tab[0]!=y.tab[0])
16100 	return x.tab[0]>y.tab[0]?1:0;
16101       if (x.tab[1]!=y.tab[1])
16102 	return x.tab[1]>y.tab[1]?1:0;
16103       if (x.tab[2]!=y.tab[2])
16104 	return x.tab[2]>y.tab[2]?1:0;
16105       return x.tab[3]>y.tab[3]?1:0;
16106     }
16107     if (((longlong *) x.tab)[1] != ((longlong *) y.tab)[1]){
16108       if (x.tab[4]!=y.tab[4])
16109 	return x.tab[4]>y.tab[4]?1:0;
16110       if (x.tab[5]!=y.tab[5])
16111 	return x.tab[5]>y.tab[5]?1:0;
16112       if (x.tab[6]!=y.tab[6])
16113 	return x.tab[6]>y.tab[6]?1:0;
16114       return x.tab[7]>y.tab[7]?1:0;
16115     }
16116     if (((longlong *) x.tab)[2] != ((longlong *) y.tab)[2]){
16117       if (x.tab[8]!=y.tab[8])
16118 	return x.tab[8]>y.tab[8]?1:0;
16119       if (x.tab[9]!=y.tab[9])
16120 	return x.tab[9]>y.tab[9]?1:0;
16121       if (x.tab[10]!=y.tab[10])
16122 	return x.tab[10]>y.tab[10]?1:0;
16123       return x.tab[11]>=y.tab[11]?1:0;
16124     }
16125 #if GROEBNER_VARS>11
16126     if (((longlong *) x.tab)[3] != ((longlong *) y.tab)[3]){
16127       if (x.tab[12]!=y.tab[12])
16128 	return x.tab[12]>y.tab[12]?1:0;
16129       if (x.tab[13]!=y.tab[13])
16130 	return x.tab[13]>y.tab[13]?1:0;
16131       if (x.tab[14]!=y.tab[14])
16132 	return x.tab[14]>y.tab[14]?1:0;
16133       return x.tab[15]>=y.tab[15]?1:0;
16134     }
16135 #endif
16136     return 2;
16137 #endif
16138   }
16139 
tdeg_t_greater(const tdeg_t15 & x,const tdeg_t15 & y,order_t order)16140   inline int tdeg_t_greater(const tdeg_t15 & x,const tdeg_t15 & y,order_t order){
16141     short X=x.tab[0];
16142     if (X!=y.tab[0]) return X>y.tab[0]?1:0; // since tdeg is tab[0] for plex
16143     if (order.o==_REVLEX_ORDER)
16144       return tdeg_t15_revlex_greater(x,y);
16145 #if GROEBNER_VARS==15
16146     if (order.o==_3VAR_ORDER)
16147       return tdeg_t15_3var_greater(x,y);
16148     if (order.o==_7VAR_ORDER)
16149       return tdeg_t15_7var_greater(x,y);
16150     if (order.o==_11VAR_ORDER)
16151       return tdeg_t15_11var_greater(x,y);
16152 #endif
16153     return tdeg_t15_lex_greater(x,y);
16154   }
tdeg_t_strictly_greater(const tdeg_t15 & x,const tdeg_t15 & y,order_t order)16155   inline bool tdeg_t_strictly_greater (const tdeg_t15 & x,const tdeg_t15 & y,order_t order){
16156     return !tdeg_t_greater(y,x,order); // total order
16157   }
16158 
tdeg_t_all_greater(const tdeg_t15 & x,const tdeg_t15 & y,order_t order)16159   bool tdeg_t_all_greater(const tdeg_t15 & x,const tdeg_t15 & y,order_t order){
16160     ulonglong *xtab=(ulonglong *)&x,*ytab=(ulonglong *)&y;
16161     if ((xtab[0]-ytab[0]) & 0x8000800080008000ULL)
16162       return false;
16163     if ((xtab[1]-ytab[1]) & 0x8000800080008000ULL)
16164       return false;
16165     if ((xtab[2]-ytab[2]) & 0x8000800080008000ULL)
16166       return false;
16167 #if GROEBNER_VARS>11
16168     if ((xtab[3]-ytab[3]) & 0x8000800080008000ULL)
16169       return false;
16170 #endif
16171     return true;
16172   }
16173 
16174   // 1 (all greater), 0 (unknown), -1 (all smaller)
tdeg_t_compare_all(const tdeg_t15 & x,const tdeg_t15 & y,order_t order)16175   int tdeg_t_compare_all(const tdeg_t15 & x,const tdeg_t15 & y,order_t order){
16176     int res=0;
16177     ulonglong *xtab=(ulonglong *)&x,*ytab=(ulonglong *)&y;
16178     longlong tmp=xtab[0]-ytab[0];
16179     if (tmp & mask){
16180       if (res==1 || ((-tmp) & mask)) return 0;
16181       res=-1;
16182     }
16183     else {
16184       if (res==-1) return 0; else res=1;
16185     }
16186     tmp=xtab[1]-ytab[1];
16187     if (tmp & mask){
16188       if (res==1 || ((-tmp) & mask)) return 0;
16189       res=-1;
16190     }
16191     else {
16192       if (res==-1) return 0; else res=1;
16193     }
16194     tmp=xtab[2]-ytab[2];
16195     if (tmp & mask){
16196       if (res==1 || ((-tmp) & mask)) return 0;
16197       res=-1;
16198     }
16199     else {
16200       if (res==-1) return 0; else res=1;
16201     }
16202 #if GROEBNER_VARS>11
16203     tmp=xtab[3]-ytab[3];
16204     if (tmp & mask){
16205       if (res==1 || ((-tmp) & mask)) return 0;
16206       res=-1;
16207     }
16208     else {
16209       if (res==-1) return 0; else res=1;
16210     }
16211 #endif
16212     return res;
16213   }
16214 
index_lcm(const tdeg_t15 & x,const tdeg_t15 & y,tdeg_t15 & z,order_t order)16215   void index_lcm(const tdeg_t15 & x,const tdeg_t15 & y,tdeg_t15 & z,order_t order){
16216     int t=0;
16217     const short * xtab=&x.tab[1],*ytab=&y.tab[1];
16218     short *ztab=&z.tab[1];
16219     t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 1
16220     ++xtab; ++ytab; ++ztab;
16221     t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 2
16222     ++xtab; ++ytab; ++ztab;
16223     t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 3
16224     ++xtab; ++ytab; ++ztab;
16225 #if GROEBNER_VARS==15
16226     if (order.o==_3VAR_ORDER){
16227       z.tab[0]=t;
16228       t=0;
16229       ++xtab;++ytab;++ztab;
16230       t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 5
16231       ++xtab; ++ytab; ++ztab;
16232       t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 6
16233       ++xtab; ++ytab; ++ztab;
16234       t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 7
16235       ++xtab; ++ytab; ++ztab;
16236       t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 8
16237       ++xtab; ++ytab; ++ztab;
16238       t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 9
16239       ++xtab; ++ytab; ++ztab;
16240       t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 10
16241       ++xtab; ++ytab; ++ztab;
16242       t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 11
16243       ++xtab; ++ytab; ++ztab;
16244       t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 12
16245       ++xtab; ++ytab; ++ztab;
16246       t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 13
16247       ++xtab; ++ytab; ++ztab;
16248       t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 14
16249       ++xtab; ++ytab; ++ztab;
16250       t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 15
16251       z.tab[4]=t; // 4
16252       return;
16253     }
16254 #endif
16255     t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 4
16256     ++xtab; ++ytab; ++ztab;
16257     t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 5
16258     ++xtab; ++ytab; ++ztab;
16259     t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 6
16260     ++xtab; ++ytab; ++ztab;
16261     t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 7
16262     ++xtab; ++ytab; ++ztab;
16263 #if GROEBNER_VARS==15
16264     if (order.o==_7VAR_ORDER){
16265       z.tab[0]=t;
16266       t=0;
16267       ++xtab;++ytab;++ztab;
16268       t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 9
16269       ++xtab; ++ytab; ++ztab;
16270       t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 10
16271       ++xtab; ++ytab; ++ztab;
16272       t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 11
16273       ++xtab; ++ytab; ++ztab;
16274       t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 12
16275       ++xtab; ++ytab; ++ztab;
16276       t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 13
16277       ++xtab; ++ytab; ++ztab;
16278       t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 14
16279       ++xtab; ++ytab; ++ztab;
16280       t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 15
16281       z.tab[8]=t; // 8
16282       return;
16283     }
16284 #endif
16285     t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 8
16286     ++xtab; ++ytab; ++ztab;
16287     t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 9
16288     ++xtab; ++ytab; ++ztab;
16289     t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 10
16290     ++xtab; ++ytab; ++ztab;
16291     t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 11
16292 #if GROEBNER_VARS>11
16293     ++xtab; ++ytab; ++ztab;
16294 #if GROEBNER_VARS==15
16295     if (order.o==_11VAR_ORDER){
16296       z.tab[0]=t;
16297       t=0;
16298       ++xtab; ++ytab; ++ztab;
16299       t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 13
16300       ++xtab; ++ytab; ++ztab;
16301       t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 14
16302       ++xtab; ++ytab; ++ztab;
16303       t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 15
16304       z.tab[12]=t; // 12
16305       return;
16306     }
16307 #endif
16308     t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 12
16309     ++xtab; ++ytab; ++ztab;
16310     t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 13
16311     ++xtab; ++ytab; ++ztab;
16312     t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 14
16313     ++xtab; ++ytab; ++ztab;
16314     t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 15
16315 #endif
16316     if (order.o==_REVLEX_ORDER || order.o==_TDEG_ORDER){
16317       z.tab[0]=t;
16318     }
16319     else {
16320       z.tab[0]=(x.tab[0]>y.tab[0])?x.tab[0]:y.tab[0];
16321     }
16322   }
16323 
index_lcm_overwrite(const tdeg_t15 & x,const tdeg_t15 & y,tdeg_t15 & z,order_t order)16324   inline void index_lcm_overwrite(const tdeg_t15 & x,const tdeg_t15 & y,tdeg_t15 & z,order_t order){
16325     index_lcm(x,y,z,order);
16326   }
16327 
get_index(const tdeg_t15 & x_,index_t & idx,order_t order,int dim)16328   void get_index(const tdeg_t15 & x_,index_t & idx,order_t order,int dim){
16329     idx.resize(dim);
16330 #ifdef GBASIS_SWAP
16331     tdeg_t15 x(x_);
16332     swap_indices15(x.tab,order.o);
16333 #else
16334     const tdeg_t15 & x= x_;
16335 #endif
16336     const short * ptr=x.tab;
16337 #if GROEBNER_VARS==15
16338     if (order.o==_3VAR_ORDER){
16339       ++ptr;
16340       for (int i=1;i<=3;++ptr,++i)
16341 	idx[3-i]=*ptr;
16342       ++ptr;
16343       for (int i=1;i<=dim-3;++ptr,++i)
16344 	idx[dim-i]=*ptr;
16345       return;
16346     }
16347     if (order.o==_7VAR_ORDER){
16348       ++ptr;
16349       for (int i=1;i<=7;++ptr,++i)
16350 	idx[7-i]=*ptr;
16351       ++ptr;
16352       for (int i=1;i<=dim-7;++ptr,++i)
16353 	idx[dim-i]=*ptr;
16354       return;
16355     }
16356     if (order.o==_11VAR_ORDER){
16357       ++ptr;
16358       for (int i=1;i<=11;++ptr,++i)
16359 	idx[11-i]=*ptr;
16360       ++ptr;
16361       for (int i=1;i<=dim-11;++ptr,++i)
16362 	idx[dim-i]=*ptr;
16363       return;
16364     }
16365 #endif
16366     if (order.o==_REVLEX_ORDER || order.o==_TDEG_ORDER)
16367       ++ptr;
16368     if (order.o==_REVLEX_ORDER){
16369       for (int i=1;i<=dim;++ptr,++i)
16370 	idx[dim-i]=*ptr;
16371     }
16372     else {
16373       for (int i=0;i<dim;++ptr,++i)
16374 	idx[i]=*ptr;
16375     }
16376   }
16377 
disjoint(const tdeg_t15 & a,const tdeg_t15 & b,order_t order,short dim)16378   bool disjoint(const tdeg_t15 & a,const tdeg_t15 & b,order_t order,short dim){
16379 #if GROEBNER_VARS==15
16380     if (order.o==_3VAR_ORDER){
16381       if ( (a.tab[1] && b.tab[1]) ||
16382 	   (a.tab[2] && b.tab[2]) ||
16383 	   (a.tab[3] && b.tab[3]) ||
16384 	   (a.tab[5] && b.tab[5]) ||
16385 	   (a.tab[6] && b.tab[6]) ||
16386 	   (a.tab[7] && b.tab[7]) ||
16387 	   (a.tab[8] && b.tab[8]) ||
16388 	   (a.tab[9] && b.tab[9]) ||
16389 	   (a.tab[10] && b.tab[10]) ||
16390 	   (a.tab[11] && b.tab[11]) ||
16391 	   (a.tab[12] && b.tab[12]) ||
16392 	   (a.tab[13] && b.tab[13]) ||
16393 	   (a.tab[14] && b.tab[14]) ||
16394 	   (a.tab[15] && b.tab[15]) )
16395 	return false;
16396       return true;
16397     }
16398     if (order.o==_7VAR_ORDER){
16399       if ( (a.tab[1] && b.tab[1]) ||
16400 	   (a.tab[2] && b.tab[2]) ||
16401 	   (a.tab[3] && b.tab[3]) ||
16402 	   (a.tab[4] && b.tab[4]) ||
16403 	   (a.tab[5] && b.tab[5]) ||
16404 	   (a.tab[6] && b.tab[6]) ||
16405 	   (a.tab[7] && b.tab[7]) ||
16406 	   (a.tab[9] && b.tab[9]) ||
16407 	   (a.tab[10] && b.tab[10]) ||
16408 	   (a.tab[11] && b.tab[11]) ||
16409 	   (a.tab[12] && b.tab[12]) ||
16410 	   (a.tab[13] && b.tab[13]) ||
16411 	   (a.tab[14] && b.tab[14]) ||
16412 	   (a.tab[15] && b.tab[15]) )
16413 	return false;
16414       return true;
16415     }
16416     if (order.o==_11VAR_ORDER){
16417       if ( (a.tab[1] && b.tab[1]) ||
16418 	   (a.tab[2] && b.tab[2]) ||
16419 	   (a.tab[3] && b.tab[3]) ||
16420 	   (a.tab[4] && b.tab[4]) ||
16421 	   (a.tab[5] && b.tab[5]) ||
16422 	   (a.tab[6] && b.tab[6]) ||
16423 	   (a.tab[7] && b.tab[7]) ||
16424 	   (a.tab[8] && b.tab[8]) ||
16425 	   (a.tab[9] && b.tab[9]) ||
16426 	   (a.tab[10] && b.tab[10]) ||
16427 	   (a.tab[11] && b.tab[11]) ||
16428 	   (a.tab[13] && b.tab[13]) ||
16429 	   (a.tab[14] && b.tab[14]) ||
16430 	   (a.tab[15] && b.tab[15]))
16431 	return false;
16432       return true;
16433     }
16434 #endif
16435     const short * it=a.tab, * jt=b.tab;
16436 #ifdef GBASIS_SWAP
16437     const short * itend=it+GROEBNER_VARS+1;
16438 #endif
16439     if (order.o==_REVLEX_ORDER || order.o==_TDEG_ORDER){
16440       ++it; ++jt;
16441     }
16442 #ifndef GBASIS_SWAP
16443     const short * itend=it+dim;
16444 #endif
16445     for (;it<itend;++jt,++it){
16446       if (*it && *jt)
16447 	return false;
16448     }
16449     return true;
16450   }
16451 
16452   template<class T>
get_newres(const T & resmod,vectpoly & newres,const vectpoly & v,const vector<unsigned> & G)16453   static void get_newres(const T & resmod,vectpoly & newres,const vectpoly & v,const vector<unsigned> & G){
16454     newres=vectpoly(G.size(),polynome(v.front().dim,v.front()));
16455     for (unsigned i=0;i<G.size();++i)
16456       resmod[G[i]].get_polynome(newres[i]);
16457   }
16458 
16459   template<class tdeg_t>
get_newres_ckrur(const vectpolymod<tdeg_t> & resmod,vectpoly & newres,const vectpoly & v,const vector<unsigned> & G,modint env,int & rur)16460   static void get_newres_ckrur(const vectpolymod<tdeg_t> & resmod,vectpoly & newres,const vectpoly & v,const vector<unsigned> & G,modint env,int & rur){
16461     if (rur && !resmod.empty()){
16462       vectpolymod<tdeg_t> gbmod; gbmod.reserve(G.size());
16463       for (int i=0;i<int(G.size());++i)
16464 	gbmod.push_back(resmod[G[i]]);
16465       order_t order=resmod.front().order; int dim=resmod.front().dim;
16466       polymod<tdeg_t> lmtmp(order,dim),lmmodradical(order,dim),s(order,dim);
16467       vectpolymod<tdeg_t> rurv;
16468       if (rur_quotient_ideal_dimension(gbmod,lmtmp)<0)
16469 	rur=0;
16470       else {
16471 	if (debug_infolevel)
16472 	  CERR << CLOCK()*1e-6 << " begin modular rur computation" << '\n';
16473 	bool ok;
16474 	if (rur==2){
16475 	  vecteur m,M,res;
16476 	  s.coord.clear();
16477 	  index_t l(dim);
16478 	  l[dim-1]=1;
16479 	  s.coord.push_back(T_unsigned<modint,tdeg_t>(1,tdeg_t(l,order)));
16480 	  ok=rur_minpoly(gbmod,lmtmp,s,env,m,M);
16481 	  rur_convert_univariate(m,dim-1,gbmod[0]);
16482 	  gbmod.resize(1);
16483 	}
16484 	else {
16485 	  ok=rur_compute(gbmod,lmtmp,lmmodradical,env,s,rurv);
16486 	  if (ok)
16487 	    gbmod.swap(rurv);
16488 	}
16489 	if (!ok)
16490 	  rur=0;
16491       }
16492       if (debug_infolevel)
16493 	CERR << CLOCK()*1e-6 << " end modular rur computation" << '\n';
16494       newres=vectpoly(gbmod.size(),polynome(v.front().dim,v.front()));
16495       for (unsigned i=0;i<int(gbmod.size());++i)
16496 	gbmod[i].get_polynome(newres[i]);
16497       return;
16498     }
16499     newres=vectpoly(G.size(),polynome(v.front().dim,v.front()));
16500     for (unsigned i=0;i<G.size();++i)
16501       resmod[G[i]].get_polynome(newres[i]);
16502   }
16503 
16504   template<class T>
get_newres(const T & resmod,vectpoly & newres,const vectpoly & v)16505   static void get_newres(const T & resmod,vectpoly & newres,const vectpoly & v){
16506     newres=vectpoly(resmod.size(),polynome(v.front().dim,v.front()));
16507     for (unsigned i=0;i<resmod.size();++i)
16508       resmod[i].get_polynome(newres[i]);
16509   }
16510 
gbasis8(const vectpoly & v,order_t & order,vectpoly & newres,environment * env,bool modularalgo,bool modularcheck,int & rur,GIAC_CONTEXT,gbasis_param_t gbasis_param)16511   bool gbasis8(const vectpoly & v,order_t & order,vectpoly & newres,environment * env,bool modularalgo,bool modularcheck,int & rur,GIAC_CONTEXT,gbasis_param_t gbasis_param){
16512     bool & eliminate_flag=gbasis_param.eliminate_flag;
16513     int parallel=1;
16514 #ifdef HAVE_LIBPTHREAD
16515     if (threads_allowed && threads>1)
16516       parallel=threads;
16517 #endif
16518     int save_debuginfo=debug_infolevel;
16519     if (v.empty()){ newres.clear(); return true;}
16520 #ifdef GIAC_TDEG_T14
16521     // do not use tdeg_t14 for rur because monomials have often large degrees
16522     if (v.front().dim<=14 && order.o==_REVLEX_ORDER && !rur){
16523       try {
16524 	vectpoly8<tdeg_t14> res;
16525 	vectpolymod<tdeg_t14> resmod;
16526 	vector<unsigned> G;
16527 	vectpoly_2_vectpoly8<tdeg_t14>(v,order,res);
16528 	// Temporary workaround until rur_compute support parametric rur
16529 	if (rur && absint(order.o)!=-_RUR_REVLEX){
16530 	  rur=0;
16531 	  order.o=absint(order.o);
16532 	}
16533 	CLOCK_T c=CLOCK();
16534 	if (modularalgo && (!env || env->modulo==0 || env->moduloon==false)){
16535 	  if (mod_gbasis(res,modularcheck,
16536 			 //order.o==_REVLEX_ORDER /* zdata*/,
16537 			 1 || !rur /* zdata*/,
16538 			 rur,contextptr,gbasis_param)){
16539 	    *logptr(contextptr) << "// Groebner basis computation time " << (CLOCK()-c)*1e-6 << " Memory " << memory_usage()*1e-6 << "M" << '\n';
16540 	    get_newres(res,newres,v);
16541 	    debug_infolevel=save_debuginfo; return true;
16542 	  }
16543 	}
16544 	if (env && env->moduloon && env->modulo.type==_INT_){
16545 	  if (!res.empty() && (res.front().order.o==_REVLEX_ORDER || res.front().order.o==_3VAR_ORDER || res.front().order.o==_7VAR_ORDER || res.front().order.o==_11VAR_ORDER)){
16546 	    vector<zinfo_t<tdeg_t14> > f4buchberger_info;
16547 	    f4buchberger_info.reserve(GBASISF4_MAXITER);
16548 	    if (zgbasis(res,resmod,G,env->modulo.val,true/*totaldeg*/,0,f4buchberger_info,false/* recomputeR*/,false /* don't compute res8*/,eliminate_flag,false /* 1 mod only */,parallel,true)){
16549 	      *logptr(contextptr) << "// Groebner basis computation time " << (CLOCK()-c)*1e-6 <<  " Memory " << memory_usage()*1e-6 << "M" <<'\n';
16550 	      get_newres_ckrur(resmod,newres,v,G,env->modulo.val,rur);
16551 	      debug_infolevel=save_debuginfo; return true;
16552 	    }
16553 	  }
16554 	  else {
16555 	    if (in_gbasisf4buchbergermod<tdeg_t14>(res,resmod,G,env->modulo.val,true/*totaldeg*/,0,0,false)){
16556 	      *logptr(contextptr) << "// Groebner basis computation time " << (CLOCK()-c)*1e-6 <<  " Memory " << memory_usage()*1e-6 << "M" <<'\n';
16557 	      get_newres_ckrur(resmod,newres,v,G,env->modulo.val,rur);
16558 	      debug_infolevel=save_debuginfo; return true;
16559 	    }
16560 	  }
16561 	} // end if gbasis computation modulo integer
16562 	else {
16563 #ifdef GIAC_REDUCEMODULO
16564 	  vectpoly w(v);
16565 	  reduce(w,env);
16566 	  sort_vectpoly(w.begin(),w.end());
16567 	  vectpoly_2_vectpoly8(w,order,res);
16568 #endif
16569 	  if (in_gbasis(res,G,env,true)){
16570 	    *logptr(contextptr) << "// Groebner basis computation time " << (CLOCK()-c)*1e-6 <<  " Memory " << memory_usage()*1e-6 << "M" << '\n';
16571 	    get_newres(res,newres,v,G);
16572 	    debug_infolevel=save_debuginfo; return true;
16573 	  }
16574 	}
16575       }  catch (std::runtime_error & e){
16576 	last_evaled_argptr(contextptr)=NULL;
16577 	CERR << "Degree too large for compressed monomials. Using uncompressed monomials instead." << '\n';
16578       }
16579     }
16580 #endif
16581     if (v.front().dim<=11 && order.o==_REVLEX_ORDER){
16582       vectpoly8<tdeg_t11> res;
16583       vectpolymod<tdeg_t11> resmod;
16584       vector<unsigned> G;
16585       vectpoly_2_vectpoly8<tdeg_t11>(v,order,res);
16586       // Temporary workaround until rur_compute support parametric rur
16587       if (rur && absint(order.o)!=-_RUR_REVLEX){
16588 	rur=0;
16589 	order.o=absint(order.o);
16590       }
16591       CLOCK_T c=CLOCK();
16592       if (modularalgo && (!env || env->modulo==0 || env->moduloon==false)){
16593 	if (mod_gbasis(res,modularcheck,
16594 		       //order.o==_REVLEX_ORDER /* zdata*/,
16595 		       1 || !rur /* zdata*/,
16596 		       rur,contextptr,gbasis_param)){
16597 	  *logptr(contextptr) << "// Groebner basis computation time " << (CLOCK()-c)*1e-6 <<  " Memory " << memory_usage()*1e-6 << "M" << '\n';
16598 	  get_newres(res,newres,v);
16599 	  debug_infolevel=save_debuginfo; return true;
16600 	}
16601       }
16602       if (env && env->moduloon && env->modulo.type==_INT_){
16603 	if (!res.empty() && (res.front().order.o==_REVLEX_ORDER || res.front().order.o==_3VAR_ORDER || res.front().order.o==_7VAR_ORDER || res.front().order.o==_11VAR_ORDER)){
16604 	  vector<zinfo_t<tdeg_t11> > f4buchberger_info;
16605 	  f4buchberger_info.reserve(GBASISF4_MAXITER);
16606 	  if (zgbasis(res,resmod,G,env->modulo.val,true/*totaldeg*/,0,f4buchberger_info,false/* recomputeR*/,false /* don't compute res8*/,eliminate_flag,false /* 1 mod only */,parallel,true)){
16607 	    *logptr(contextptr) << "// Groebner basis computation time " << (CLOCK()-c)*1e-6 <<  " Memory " << memory_usage()*1e-6 << "M" << '\n';
16608 	    get_newres_ckrur(resmod,newres,v,G,env->modulo.val,rur);
16609 	    debug_infolevel=save_debuginfo; return true;
16610 	  }
16611 	}
16612 	else {
16613 	  if (in_gbasisf4buchbergermod<tdeg_t11>(res,resmod,G,env->modulo.val,true/*totaldeg*/,0,0,false)){
16614 	    *logptr(contextptr) << "// Groebner basis computation time " << (CLOCK()-c)*1e-6 <<  " Memory " << memory_usage()*1e-6 << "M" << '\n';
16615 	    get_newres_ckrur(resmod,newres,v,G,env->modulo.val,rur);
16616 	    debug_infolevel=save_debuginfo; return true;
16617 	  }
16618 	}
16619       } // end if gbasis modulo integer
16620       else {
16621 #ifdef GIAC_REDUCEMODULO
16622 	vectpoly w(v);
16623 	reduce(w,env);
16624 	sort_vectpoly(w.begin(),w.end());
16625 	vectpoly_2_vectpoly8(w,order,res);
16626 #endif
16627 	if (in_gbasis(res,G,env,true)){
16628 	  *logptr(contextptr) << "// Groebner basis computation time " << (CLOCK()-c)*1e-6 <<  " Memory " << memory_usage()*1e-6 << "M" << '\n';
16629 	  get_newres(res,newres,v,G);
16630 	  debug_infolevel=save_debuginfo; return true;
16631 	}
16632       }
16633     }
16634     if (v.front().dim<=15
16635 	//&& order.o==_REVLEX_ORDER
16636 	&&order.o<_16VAR_ORDER
16637 	){
16638       vectpoly8<tdeg_t15> res;
16639       vectpolymod<tdeg_t15> resmod;
16640       vector<unsigned> G;
16641       vectpoly_2_vectpoly8<tdeg_t15>(v,order,res);
16642       // Temporary workaround until rur_compute support parametric rur
16643       if (rur && absint(order.o)!=-_RUR_REVLEX){
16644 	rur=0;
16645 	order.o=absint(order.o);
16646       }
16647       CLOCK_T c=CLOCK();
16648       if (modularalgo && (!env || env->modulo==0 || env->moduloon==false)){
16649 	if (mod_gbasis(res,modularcheck,
16650 		       //order.o==_REVLEX_ORDER /* zdata*/,
16651 		       1 || !rur /* zdata*/,
16652 		       rur,contextptr,gbasis_param)){
16653 	  *logptr(contextptr) << "// Groebner basis computation time " << (CLOCK()-c)*1e-6 <<  " Memory " << memory_usage()*1e-6 << "M" << '\n';
16654 	  newres=vectpoly(res.size(),polynome(v.front().dim,v.front()));
16655 	  for (unsigned i=0;i<res.size();++i)
16656 	    res[i].get_polynome(newres[i]);
16657 	  debug_infolevel=save_debuginfo; return true;
16658 	}
16659       }
16660       if (env && env->moduloon && env->modulo.type==_INT_){
16661 #ifdef GBASISF4_BUCHBERGER
16662 	if (!res.empty() && (res.front().order.o==_REVLEX_ORDER || res.front().order.o==_3VAR_ORDER || res.front().order.o==_7VAR_ORDER || res.front().order.o==_11VAR_ORDER)){
16663 	  vector<zinfo_t<tdeg_t15> > f4buchberger_info;
16664 	  f4buchberger_info.reserve(GBASISF4_MAXITER);
16665 	  if (!zgbasis(res,resmod,G,env->modulo.val,true/*totaldeg*/,0,f4buchberger_info,false/* recomputeR*/,false /* don't compute res8*/,eliminate_flag,false/* 1 mod only*/,parallel,true))
16666 	    return false;
16667 	  *logptr(contextptr) << "// Groebner basis computation time " << (CLOCK()-c)*1e-6 <<  " Memory " << memory_usage()*1e-6 << "M" << '\n';
16668 #if 1
16669 	  get_newres_ckrur(resmod,newres,v,G,env->modulo.val,rur);
16670 #else
16671 	  newres=vectpoly(G.size(),polynome(v.front().dim,v.front()));
16672 	  for (unsigned i=0;i<G.size();++i)
16673 	    resmod[G[i]].get_polynome(newres[i]);
16674 #endif
16675 	  debug_infolevel=save_debuginfo; return true;
16676 	}
16677 	else
16678 	  in_gbasisf4buchbergermod<tdeg_t15>(res,resmod,G,env->modulo.val,true/*totaldeg*/,0,0,false);
16679 #else
16680 	in_gbasismod(res,resmod,G,env->modulo.val,true,0);
16681 #endif
16682 	if (debug_infolevel)
16683 	  CERR << "G=" << G << '\n';
16684       }
16685       else { // env->modoloon etc.
16686 #ifdef GIAC_REDUCEMODULO
16687 	vectpoly w(v);
16688 	reduce(w,env);
16689 	sort_vectpoly(w.begin(),w.end());
16690 	vectpoly_2_vectpoly8(w,order,res);
16691 #endif
16692 	in_gbasis(res,G,env,true);
16693       }
16694       newres=vectpoly(G.size(),polynome(v.front().dim,v.front()));
16695       for (unsigned i=0;i<G.size();++i)
16696 	res[G[i]].get_polynome(newres[i]);
16697       debug_infolevel=save_debuginfo; return true;
16698     }
16699     vectpoly8<tdeg_t64> res;
16700     vectpolymod<tdeg_t64> resmod;
16701     vector<unsigned> G;
16702     vectpoly_2_vectpoly8<tdeg_t64>(v,order,res);
16703     // Temporary workaround until rur_compute support parametric rur
16704     if (rur && absint(order.o)!=-_RUR_REVLEX){
16705       rur=0;
16706       order.o=absint(order.o);
16707     }
16708     CLOCK_T c=CLOCK();
16709     if (modularalgo && (!env || env->modulo==0 || env->moduloon==false)){
16710       if (mod_gbasis(res,modularcheck,
16711 		     //order.o==_REVLEX_ORDER /* zdata*/,
16712 		     !rur /* zdata*/,
16713 		     rur,contextptr,gbasis_param)){
16714 	*logptr(contextptr) << "// Groebner basis computation time " << (CLOCK()-c)*1e-6 <<  " Memory " << memory_usage()*1e-6 << "M" << '\n';
16715 	newres=vectpoly(res.size(),polynome(v.front().dim,v.front()));
16716 	for (unsigned i=0;i<res.size();++i)
16717 	  res[i].get_polynome(newres[i]);
16718 	debug_infolevel=save_debuginfo; return true;
16719       }
16720     }
16721     if (env && env->moduloon && env->modulo.type==_INT_){
16722 #ifdef GBASISF4_BUCHBERGER
16723       if (!res.empty() && (res.front().order.o==_REVLEX_ORDER || res.front().order.o==_3VAR_ORDER || res.front().order.o==_7VAR_ORDER || res.front().order.o==_11VAR_ORDER)){
16724 	vector<zinfo_t<tdeg_t64> > f4buchberger_info;
16725 	f4buchberger_info.reserve(GBASISF4_MAXITER);
16726 	zgbasis(res,resmod,G,env->modulo.val,true/*totaldeg*/,0,f4buchberger_info,false/* recomputeR*/,false /* don't compute res8*/,eliminate_flag,false/* 1 mod only*/,parallel,true);
16727 	*logptr(contextptr) << "// Groebner basis computation time " << (CLOCK()-c)*1e-6 <<  " Memory " << memory_usage()*1e-6 << "M" << '\n';
16728 #if 1
16729 	get_newres_ckrur(resmod,newres,v,G,env->modulo.val,rur);
16730 #else
16731 	newres=vectpoly(G.size(),polynome(v.front().dim,v.front()));
16732 	for (unsigned i=0;i<G.size();++i)
16733 	  resmod[G[i]].get_polynome(newres[i]);
16734 #endif
16735 	debug_infolevel=save_debuginfo; return true;
16736       }
16737       else
16738 	in_gbasisf4buchbergermod<tdeg_t64>(res,resmod,G,env->modulo.val,true/*totaldeg*/,0,0,false);
16739 #else
16740       in_gbasismod(res,resmod,G,env->modulo.val,true,0);
16741 #endif
16742       if (debug_infolevel)
16743 	CERR << "G=" << G << '\n';
16744     }
16745     else {
16746 #ifdef GIAC_REDUCEMODULO
16747       vectpoly w(v);
16748       reduce(w,env);
16749       sort_vectpoly(w.begin(),w.end());
16750       vectpoly_2_vectpoly8(w,order,res);
16751 #endif
16752       in_gbasis(res,G,env,true);
16753     }
16754     newres=vectpoly(G.size(),polynome(v.front().dim,v.front()));
16755     for (unsigned i=0;i<G.size();++i)
16756       res[G[i]].get_polynome(newres[i]);
16757     debug_infolevel=save_debuginfo; return true;
16758   }
16759 
greduce8(const vectpoly & v,const vectpoly & gb_,order_t & order,vectpoly & newres,environment * env,GIAC_CONTEXT)16760   bool greduce8(const vectpoly & v,const vectpoly & gb_,order_t & order,vectpoly & newres,environment * env,GIAC_CONTEXT){
16761     if (v.empty()){ newres.clear(); return true;}
16762     vectpoly8<tdeg_t64> red,gb,quo;
16763     vectpoly_2_vectpoly8(v,order,red);
16764     vectpoly_2_vectpoly8(gb_,order,gb);
16765     poly8<tdeg_t64> rem,TMP1,TMP2;
16766     vector<unsigned> G(gb_.size());
16767     for (int i=0;i<int(gb_.size());++i)
16768       G[i]=i;
16769     int dim;
16770     for (int i=0;i<int(v.size());++i){
16771       quo.clear();
16772       rem.coord.clear();
16773       dim=red[i].dim;
16774       if (debug_infolevel>1)
16775 	COUT << CLOCK()*1e-6 << " begin reduce poly no " << i << " #monomials " << red[i].coord.size() << '\n';
16776       gen lambda;
16777       reduce(red[i],gb,G,-1,quo,rem,TMP1,TMP2,lambda,env);
16778       if (debug_infolevel>1)
16779 	COUT << CLOCK()*1e-6 << " end reduce poly no " << i << " #monomials " << rem.coord.size() << '\n';
16780       for (int j=0;j<int(rem.coord.size());++j){
16781 	rem.coord[j].g=rem.coord[j].g/lambda;
16782       }
16783       red[i]=rem;
16784     }
16785     newres=vectpoly(v.size(),polynome(v.front().dim,v.front()));
16786     for (unsigned i=0;i<int(v.size());++i)
16787       red[i].get_polynome(newres[i]);
16788     return true;
16789   }
16790 
16791 #ifdef GIAC_RHASH
operator ()(const tdeg_t64 & v) const16792   inline size_t tdeg_t64_hash_function_object::operator () (const tdeg_t64 & v) const
16793   { return v.hash; }
16794 #endif
16795 
16796 #endif // CAS38_DISABLED
16797 
16798 #ifndef NO_NAMESPACE_GIAC
16799 } // namespace giac
16800 #endif // ndef NO_NAMESPACE_GIAC
16801