1 //   Copyright (c) 2007 Alberto Arri
2 
3 //   This file is part of the source of CoCoALib, the CoCoA Library.
4 
5 //   CoCoALib is free software: you can redistribute it and/or modify
6 //   it under the terms of the GNU General Public License as published by
7 //   the Free Software Foundation, either version 3 of the License, or
8 //   (at your option) any later version.
9 
10 //   CoCoALib is distributed in the hope that it will be useful,
11 //   but WITHOUT ANY WARRANTY; without even the implied warranty of
12 //   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 //   GNU General Public License for more details.
14 
15 //   You should have received a copy of the GNU General Public License
16 //   along with CoCoALib.  If not, see <http://www.gnu.org/licenses/>.
17 
18 #include "CoCoA/SparsePolyOps-RingElem.H"
19 //#include "CoCoA/SparsePolyRing.H"
20 #include "CoCoA/PPMonoidOv.H"
21 #include "CoCoA/symbol.H"
22 #include "CoCoA/TmpF5.H"
23 
24 #include <cmath>
25 
26 #include <algorithm>
27 #include <utility>
28 #include <numeric>
29 
30 #include <vector>
31 #include <list>
32 #include <set>
33 #include <map>
34 #include <queue>
35 
36 #include <cassert>
37 #include <ctime>
38 #include <iostream>
39 
40 #include <iterator>
41 #include <sstream>
42 
43 #include <iomanip>
44 
45 
46 using namespace std;
47 
48 namespace CoCoA{
49 
50 namespace F5ns{
51 
52   class PPdiv_t {
53     typedef PPMonoidElem ppme;
54     int nind;
55     vector<ppme> pp;
56     vector<map<int, vector<int> > > indval;
57 
58   public:
PPdiv_t(int n)59     PPdiv_t(int n):nind(n),indval(n){}
60 
insert(ppme p)61     void insert(ppme p){
62       vector<long> x;
63       exponents(x,p);
64       pp.push_back(p);
65       int cidx = pp.size() - 1;
66       for(unsigned int i = 0; i < x.size(); i++){
67 	indval[i][x[i]].push_back(cidx);
68       }
69     }
70 
71   private:
72 
prj2grid(vector<long> & x)73     bool prj2grid(vector<long> &x)const{
74       for (unsigned int i = 0; i < x.size(); i++){
75 	map<int, vector<int> >::const_iterator it = indval[i].lower_bound(x[i]);
76 	//if (it == indval[i].end()) return false;
77 	if (it != indval[i].end() && it->first == x[i]) continue;
78 	if (it == indval[i].begin()) return false;
79 	--it;
80 	x[i] = it->first;
81       }
82       return true;
83     }
84 
85   public:
grid_size()86     long grid_size()const{
87       long res = 1;
88       for(unsigned int i = 0; i<indval.size(); i++) res *= indval[i].size();
89       return res;
90     }
91 
div(const ppme & p,int lc)92     bool div(const ppme &p, int lc)const{
93       vector<long> x;
94       exponents(x,p);
95       int o = x[lc];
96       if (!prj2grid(x)) return false;
97       if (x[lc]!=o) return false;
98       //    vector<int> &v = indval[lc][x[lc]];
99       //    cout << "lc = " << lc << ", x[lc] = " << x[lc] << endl;
100       map<int, vector<int> >::const_iterator it = indval[lc].find(x[lc]);
101       assert( it != indval[lc].end() );
102       const vector<int> &v = it->second;
103       for (unsigned int j = 0; j < v.size(); j++) {
104 	if (IsDivisible(p,pp[v[j]])) return true;
105       }
106       return false;
107 
108     }
109   };
110 
111 
112   class PolyRingElemCmp{
113   private:
114     const SparsePolyRing& env;
115     const PPMonoid& myPPM;
116   public:
PolyRingElemCmp(const SparsePolyRing & e)117     PolyRingElemCmp(const SparsePolyRing &e):env(e),myPPM(PPM(e)){}
operator()118     bool operator()(const RingElem &x, const RingElem &y) const {
119       //      assert(LPP(x)!=LPP(y));
120       return myPPM->myCmp(raw(env->myLPP(raw(x))),raw(env->myLPP(raw(y))))<0;
121     }
122   };
123 
124 
125   F5opt_t opt;
126 
127   struct deg_cmp_t{
operatordeg_cmp_t128     bool operator()(const RingElem &x, const RingElem &y) const {
129       return StdDeg(x)<StdDeg(y);
130     }
131   };
132 
133   PPMonoid *mtPPM = nullptr;
134 
135   PPMonoidElem ppe2ppm(const PPMonoidElem &pm, const PPMonoid &ppm = *mtPPM){
136     vector<long> x;
137     exponents(x,pm);
138     return PPMonoidElem(ppm,x);
139   }
140 
141   class module_term_t{
142 
143   public:
144     PPMonoidElem term;
145 
146     int index;
module_term_t(int i)147     module_term_t(int i):term(*mtPPM), index(i){};
module_term_t(ConstRefPPMonoidElem PPMel,int i)148     module_term_t(ConstRefPPMonoidElem PPMel, int i):term(*mtPPM), index(i){
149       term = ppe2ppm(PPMel);
150     };
151     bool operator < (const module_term_t & rhs) const { //REVPOS + TO
152       if (index!=rhs.index) return index<rhs.index;
153       return term<rhs.term;
154     }
155     module_term_t operator * (const PPMonoidElem &rhs) const { return module_term_t( term * ppe2ppm(rhs), index); }
156     bool operator  == (const module_term_t &rhs) const { return term == rhs.term && index == rhs.index; }
157     friend ostream &operator <<( ostream &os, const module_term_t &mt);
158   };
159 
160   class labeled_RingElem_t: public RingElem, public module_term_t{
161   public:
labeled_RingElem_t(ConstRefRingElem e,int i)162     labeled_RingElem_t(ConstRefRingElem e, int i):RingElem(e), module_term_t(i) {};
labeled_RingElem_t(ConstRefRingElem e,const module_term_t & mt)163     labeled_RingElem_t(ConstRefRingElem e, const module_term_t &mt):RingElem(e), module_term_t(mt) {};
164 
165     using module_term_t::operator <;
166   };
167 
168   struct row_t{ //inherit order from labels ie module_terms
169     PPMonoidElem LT; //this is the LT of *re
170     mutable bool touched;
171 
172   private:
173     mutable RingElem *re;
compute_rerow_t174     void compute_re()const{}
175   public:
176 
row_trow_t177     row_t(const row_t &r):LT(r.LT){
178 
179       if (r.re) re = new RingElem(*r.re); else re = nullptr;
180       touched=false;
181     }
182 
row_trow_t183     row_t(const RingElem *_base, const RefPPMonoidElem& _coeff):
184       LT(owner(_coeff)),re(nullptr){
185 
186       SparsePolyRing env = owner(*_base);
187       re = new RingElem (monomial(env,one(CoeffRing(env)),_coeff) * *_base);
188       LT = LPP(*_base) * _coeff;
189       touched=false;
190     }
191 
~row_trow_t192     ~row_t(){
193       if (re) delete re;
194     }
195 
196     row_t &operator =(const row_t &r){
197       LT = r.LT;
198       touched=r.touched;
199       if (re) delete re;
200       if (r.re) re = new RingElem(*r.re); else re = nullptr;
201       return *this;
202     }
203 
204     row_t &operator *=(const PPMonoidElem &ppme){
205       LT *= ppme;
206       assert(re);
207       SparsePolyRingPtr(owner(*re))->myMulByPP(raw(*re),raw(ppme));
208       touched = false;
209       return *this;
210     }
211 
elemrow_t212     const RingElem &elem()const{ compute_re(); return *re; }
elemrow_t213     RingElem &elem(){ compute_re(); return *re; }
214 
215     bool operator <(const row_t &rhs)const{ return LT<rhs.LT; }
is_evaluatedrow_t216     bool is_evaluated()const{ return true; }
217 
reducerow_t218     bool reduce(const row_t &r){ //returns false when result is Zero
219       assert(LT==r.LT);
220       touched = true;
221       r.touched = true;
222       SparsePolyRingPtr(owner(elem()))->myReductionStep(raw(*re),raw(r.elem()));
223       if (!IsZero(elem())) {
224 	LT = LPP(elem());
225 	return true;
226       } else return false;
227     }
228     friend ostream &operator <<( ostream &os, const row_t &r);
229   };
230 
231   ostream &operator <<( ostream &os, const module_term_t &mt){
232     return os << "(" << mt.term << "," << mt.index << ")";
233   }
234 
235   ostream &operator <<( ostream &os, const row_t &r){
236     return os << r.elem();
237   }
238 
239   ostream &operator <<( ostream &os, const labeled_RingElem_t &r){
240     return os << (const module_term_t&)r << " - " << (const RingElem&) r;
241   }
242 
243   struct cpair_t{
244     PPMonoidElem lcm,u1,u2;
245     set<labeled_RingElem_t>::iterator r1,r2;
cpair_tcpair_t246     cpair_t(set<labeled_RingElem_t>::iterator &_r1, set<labeled_RingElem_t>::iterator &_r2):
247       lcm( CoCoA::lcm(LPP(*_r1),LPP(*_r2))),
248       u1(PPM(owner(*_r1))),
249       u2(PPM(owner(*_r1))),
250       r1(_r1),r2(_r2)
251     {
252       u1 = lcm / LPP(*r1);
253       u2 = lcm / LPP(*r2);
254     }
mtcpair_t255     module_term_t mt(int i)const{ // returns the mt/label of ui*ri
256       assert(i==1 || i==2);
257       if (i==1) return static_cast<const module_term_t&>(*r1)*u1;
258       return static_cast<const module_term_t&>(*r2)*u2;
259     }
labelcpair_t260     module_term_t label()const{
261       return max(mt(1),mt(2));
262     }
degcpair_t263     long deg()const{ return StdDeg(lcm); }
264   };
265 
266   ostream &operator << (ostream &os, const cpair_t &p){
267     os << p.label() << "  " << p.lcm;
268     return os;
269   }
270 
271   typedef map<module_term_t,row_t> matrix_t;
272   typedef matrix_t::value_type mmvt_t; //mmvt = map matrix value type = pair<module_term_t,row_t>
273   typedef matrix_t::iterator mit_t;
274 
275   ostream &operator <<( ostream &os, const matrix_t &m){
276     for (matrix_t::const_iterator it = m.begin(); it != m.end(); ++it){
277       os << it->first << ";\t " << it->second << endl;
278     }
279     return os;
280   }
281 
282   class GB_t{
283     unsigned long maxdeg, npoly;
284   public:
285     int nind;
GB_t(int n,int m)286     GB_t(int n, int m):maxdeg(0), npoly(m), nind(n), GB(),lastNRi(-1){};
287     set<labeled_RingElem_t> GB;
288     typedef set<labeled_RingElem_t>::iterator GBit_t;
289     vector<set<PPMonoidElem> > lt_I_i; //lt_set[i] contains the leading terms of I_i
290 
291     vector<set<PPMonoidElem> > lt_Syz_i; //lt_set[i] contains the leading terms of Syz_i \ LT( I_i )
292 
293     vector<PPdiv_t> PPdiv;
294 
295     vector<vector<cpair_t> > pairs;
296 
LPPinsert(const PPMonoidElem & PPM,unsigned int idx)297     void LPPinsert(const PPMonoidElem &PPM, unsigned int idx){
298       if (idx >= lt_I_i.size()) {
299 	lt_I_i.resize(idx+1);
300 	lt_Syz_i.resize(idx+1); //just to keep them the same len
301       }
302       if (idx >= PPdiv.size()){
303 	PPdiv.resize(idx+1,PPdiv_t(nind));
304 	if (idx!=0) PPdiv[idx] = PPdiv[idx-1];
305       }
306       lt_I_i[idx].insert(PPM);
307       PPdiv[idx].insert(PPM);
308     }
309 
Syz_LPPinsert(const PPMonoidElem & PPM,unsigned int idx)310     void Syz_LPPinsert(const PPMonoidElem &PPM, unsigned int idx){
311       if (idx >= lt_Syz_i.size()) {
312 	lt_Syz_i.resize(idx+1);
313 	lt_I_i.resize(idx+1);
314       }
315       if (idx >= PPdiv.size()){
316 	PPdiv.resize(idx+1,PPdiv_t(nind));
317 	if (idx!=0) PPdiv[idx] = PPdiv[idx-1];
318       }
319       lt_Syz_i[idx].insert(PPM);
320       PPdiv[idx].insert(PPM);
321     }
322 
323     void NR(RingElem &e, int i = 5000){
324       //      cout << "NR " << i << "   " << e;
325       if ( lastNRi != i || (i==5000 && vecGB.size() != GB.size()) ){
326 	//	cout << "NR f";
327 	vecGB.clear();
328 	vecGB.reserve(GB.size());
329 	for (GBit_t it = GB.begin(); it != GB.end(); ++it)
330 	  if (it->index <= i) vecGB.push_back(*it);
331 	//	copy(GB.begin(),GB.end(),back_inserter(vecGB));
332       }
333       lastNRi = i;
334 
335       e = CoCoA::NR(e, vecGB);
336       //      cout << " -> " << e << endl;
337     }
338 
339   private:
340     int lastNRi;
341     vector<RingElem> vecGB;
342 
add_pair(GBit_t i1,GBit_t i2)343     bool add_pair(GBit_t i1,GBit_t i2){
344       cpair_t pair(i1,i2);
345       unsigned int deg = pair.deg();
346       //      cout << "add_pair" << pair.mt(1) << "; " << pair.mt(2) << endl;
347       if (pair.mt(1) == pair.mt(2) || is_syz_reducible(pair.mt(1)) || is_syz_reducible(pair.mt(2))) return false; //F5-pair criterion
348       //      cout << "ok" << endl;
349       if (deg >= pairs.size()) pairs.resize(deg+1);
350       pairs[deg].push_back(pair);
351       //      cout << endl << "Pair in deg = " << deg << endl;
352       return true;
353     }
354 
pair_update(GBit_t & in)355     void pair_update(GBit_t &in){
356       unsigned int mp = max_pair();
357       PPMonoidElem LPin = LPP(*in);
358       for (GBit_t it = GB.begin(); it!= GB.end(); ++it)	if (it!=in) {
359 	unsigned int ndeg = StdDeg(lcm(LPP(*it),LPin));
360 	if ( ndeg > mp )
361 	  add_pair(it,in);
362       }
363     }
364   public:
min_pair()365     unsigned int min_pair()const{
366       for (unsigned int i = 0; i<pairs.size();i++) if (pairs[i].size()!=0) return i;
367       return 0; //ie pairs is empty
368     }
369 
max_pair()370     unsigned int max_pair()const{
371       if (pairs.size()==0) return 0;
372       for (unsigned int i = pairs.size()-1; i>0; i--) if (pairs[i].size()!=0) return i;
373       return 0;
374     }
375 
insert(ConstRefRingElem re,unsigned int pos)376     GBit_t insert(ConstRefRingElem re, unsigned int pos){
377       GBit_t lit = GB.insert(labeled_RingElem_t(re,pos)).first;
378       if (opt.GBLT2SYZLT) LPPinsert(ppe2ppm(LPP(re)),pos);
379       if (static_cast<unsigned long>(StdDeg(re))>maxdeg) maxdeg = StdDeg(re);
380       pair_update(lit);
381       return lit;
382     }
383 
insert(const labeled_RingElem_t & lre)384     GBit_t insert(const labeled_RingElem_t &lre){
385       pair<GBit_t, bool> in = GB.insert(lre);
386       if (!in.second){//this is tricky.
387 	GB.erase(lre);
388 	in = GB.insert(lre);
389 	assert(in.second);
390       }
391       if (opt.GBLT2SYZLT) LPPinsert(ppe2ppm(LPP(lre)),lre.index);
392       if (static_cast<unsigned long>(StdDeg(lre))>maxdeg) maxdeg = StdDeg(lre);
393       pair_update(in.first);
394       return in.first;
395     }
396 
max_deg()397     long max_deg() const { return maxdeg; }
398 
is_syz_reducible(const PPMonoidElem & PPE,int index)399     bool is_syz_reducible(const PPMonoidElem &PPE, int index)const{
400       if (index<0) return false;
401 
402 
403       assert(static_cast<unsigned int>(index) <= lt_I_i.size());
404       if (static_cast<unsigned int>(index) < lt_Syz_i.size())
405 	for (set<PPMonoidElem>::const_iterator it = lt_Syz_i[index].begin(); it!= lt_Syz_i[index].end(); ++it)
406 	  if (IsDivisible(PPE,*it))  return true;
407 
408       if (static_cast<unsigned int>(index) < lt_I_i.size())
409 	for (set<PPMonoidElem>::const_iterator it = lt_I_i[index].begin(); it!= lt_I_i[index].end(); ++it)
410 	  if (IsDivisible(PPE,*it)) return true;
411 
412       return false;
413     }
414 
is_syz_reducible_gen(const module_term_t & mt,int lc)415     bool is_syz_reducible_gen(const module_term_t& mt, int lc)const{
416       if (mt.index<1) return false;
417       return PPdiv[mt.index-1].div(mt.term,lc);
418     }
419 
is_syz_reducible(const module_term_t & mt)420     bool is_syz_reducible(const module_term_t& mt)const{ return mt.index==0?false:is_syz_reducible(mt.term,mt.index-1);}
421 
422     const labeled_RingElem_t *is_reducible(const PPMonoidElem &PPE, int idx = 5000)const{
423       for (GBit_t it = GB.begin(); it!= GB.end(); ++it)
424 	if (it->index <= idx && IsDivisible(PPE, LPP(*it))) return &*it;
425       return nullptr;
426     }
427 
LT_print()428     void LT_print(){
429       for(unsigned int i = 0; i<lt_I_i.size(); i++){
430 	cout << "Set #" << i << " = { ";
431 	for (set<PPMonoidElem>::const_iterator it = lt_I_i[i].begin(); it!=lt_I_i[i].end(); ++it){
432 	  cout << *it << ", ";
433 	}
434 	cout << " }" << endl;
435       }
436     }
437   };
438 
439   class matrF5_t{
440   private:
441     const PPMonoid& myPPM;
442     SparsePolyRing env;
443   public:
444     unsigned int curr_deg,curr_poly,red2zero,n_indets,max_gen_deg;
445     const vector<PPMonoidElem> &PPMindets;
446     vector<PPMonoidElem> mtPPMindets;
447     vector<RingElem> gens;
448     GB_t GB;
449 
450     matrF5_t(const vector<RingElem> &I);
451     void do_it();
452 
453   private:
454     void do_poly_step();
455     map<int, map<int, matrix_t> > matrix_hist;
456     //    PPmap<RingElem *> fast_reductor;
457     bool do_deg_step();
458 
459     mmvt_t * matrix_insert_row(matrix_t &mtr, module_term_t mt, row_t row)const;
460 
461     bool gen_macaulay_rows(matrix_t &mtr, const set<labeled_RingElem_t>::iterator &set_it, RefPPMonoidElem& ppme,
462 			   unsigned int d, unsigned int ri = 0);
463     void generate_macaulay( matrix_t &matrix, int mini = -1, int max1 = 5000 );
464 
465     void generate_macaulay_xx( matrix_t &matrix );
466 
467     struct gauss_stat_t{
468       int r2z,sums;
gauss_stat_tgauss_stat_t469       gauss_stat_t():r2z(0),sums(0){};
470     };
471 
472     gauss_stat_t gauss( matrix_t &m);
473     int pNF(RingElem &p, int idx);
474     map<PPMonoidElem,int> red_frq;
475   };
476 
matrF5_t(const vector<RingElem> & I)477   matrF5_t::matrF5_t(const vector<RingElem> &I): myPPM(PPM(owner(I[0]))),
478 						 env(owner(I[0])),
479 						 PPMindets(indets(PPM(owner(I[0])))),
480 						 gens(I),
481 						 GB(NumIndets(PPM(owner(I[0]))),I.size())
482   {
483     red2zero = curr_deg = curr_poly = 0;
484     n_indets = NumIndets(myPPM);
485 
486     mtPPM = new PPMonoid(NewPPMonoidOv(symbols(myPPM), StdDegRevLex)); // :(
487 
488     mtPPMindets = indets(*mtPPM);
489 
490     sort(gens.begin(),gens.end(),deg_cmp_t());
491 
492     for(unsigned int i = 0; i<gens.size(); i++) assert(IsHomog(gens[i]));
493     max_gen_deg = 0;
494     for(unsigned int i=0;i<gens.size();i++) max_gen_deg = max<unsigned int>(max_gen_deg,StdDeg(gens[i]));
495 
496     GB.lt_I_i.reserve(gens.size());
497 
498     if (opt.incremental) { GB.insert(gens[0],0); /*fast_reductor[LPP(gens[0])] = &gens[0];*/ }
499   }
500 
do_it()501   void matrF5_t::do_it(){
502     if (opt.verbose) cout << "poly\t" << "deg\t"  << "Rows\t" << "CoeffLen\t" <<
503 		       "rsteps\t" << "Ctime\t" << "Gtime\t" << "R2Z\t" << "Sums\t"
504 			  << "Touched\t" << "New\t" << endl;
505     if (opt.incremental){
506       curr_poly = 1;
507       while(curr_poly < gens.size()) do_poly_step();
508     } else {//non inc.
509       GB.lt_I_i.resize(gens.size());
510       GB.lt_Syz_i.resize(gens.size());
511 
512       //      GB.PPdiv.resize(gens.size(),PPdiv_t(GB.nind));
513       for (unsigned int i=0; i<gens.size();i++) {
514 	RingElem pnf(env); //pnf = poly normal form
515 	pnf = gens[i];
516 	GB.NR(pnf);
517 	GB.insert(pnf,i);
518 	gens[i] = pnf;
519 	//	fast_reductor[LPP(gens[i])] = &gens[i];
520       }
521 
522       curr_poly = gens.size();
523       curr_deg = 100;
524       for (unsigned int i=0; i<gens.size();i++) curr_deg = min<int>(curr_deg,StdDeg(gens[i]));
525       //      GB.pairs.resize(max_gen_deg+1);
526       matrix_t &m = matrix_hist[curr_poly][curr_deg];
527 
528       generate_macaulay(m,0,curr_poly);
529       curr_deg++;
530 
531       while(curr_deg <= max(GB.min_pair(),max_gen_deg)) {
532 	do_deg_step();
533 	if (opt.verbose) cout << "GBmin = " << GB.min_pair() << endl;
534 	if (GB.min_pair()==0) break;
535       }
536     }
537 
538     /*
539     for (unsigned int i = 0; i < GB.lt_I_i.size(); i++){
540       cout << "lt_I_" << i << "\t";
541       copy(GB.lt_I_i[i].begin(), GB.lt_I_i[i].end() ,ostream_iterator<PPMonoidElem>(cout,",  "));
542       cout << "  NPSZ ";
543       copy(GB.lt_Syz_i[i].begin(), GB.lt_Syz_i[i].end() ,ostream_iterator<PPMonoidElem>(cout,",  "));
544       cout << endl;
545     }
546     */
547 
548 //     vector<int> frq;
549 //     frq.resize(100);
550 //     for (map<PPMonoidElem,int>::iterator it = red_frq.begin(); it != red_frq.end(); ++it) frq[it->second]++;
551 //     copy(frq.begin(),frq.end(),ostream_iterator<int>(cout, " "));
552 //    cout << endl << accumulate(frq.begin(),frq.end(),0) << endl;
553   }
554 
do_poly_step()555   void matrF5_t::do_poly_step(){
556     RingElem pnf(env); //pnf = poly normal form
557     do {
558       pnf = gens[curr_poly];
559       GB.NR(pnf);
560       if (IsZero(pnf)) {
561 	gens.erase(gens.begin()+curr_poly);
562 	if (curr_poly == gens.size()) return;
563       }
564     } while(IsZero(pnf));
565 
566     GB.insert(pnf,curr_poly);
567     curr_deg = StdDeg(pnf);
568     matrix_t &m = matrix_hist[curr_poly][curr_deg];
569     generate_macaulay(m,opt.skip_rows?curr_poly:0,curr_poly);
570     curr_deg++;
571     while(GB.min_pair()!=0) if (!do_deg_step()) break;
572     matrix_hist[curr_poly].clear();
573     curr_poly++;
574   }
575 
576   struct matrixrow_sorter: public binary_function<bool,mmvt_t *,mmvt_t *>{
577     const SparsePolyRing &env;
578     const PPMonoid& myPPM;
matrixrow_sortermatrixrow_sorter579     matrixrow_sorter(const SparsePolyRing &e):env(e),myPPM(PPM(e)){}
operatormatrixrow_sorter580     bool operator () (const mmvt_t *x,const mmvt_t *y){
581       int cmp = myPPM->myCmp(raw(x->second.LT),raw(y->second.LT));
582       //      if (x->second.LT != y->second.LT) return x->second.LT < y->second.LT;
583       if (cmp!=0) return cmp<0;
584       return !(x->first < y->first);
585     }
586   };
587 
pNF(RingElem & p,int idx)588   int matrF5_t::pNF(RingElem &p, int idx){
589     const labeled_RingElem_t *rrle = nullptr;
590     int loop_cnt = 0;
591     PPMonoidElem LPPp = LPP(p);
592 
593     for(;;){
594       rrle = GB.is_reducible(LPPp, idx);
595       if (!rrle) return loop_cnt;
596       env->myReductionStep(raw(p),raw(*rrle));
597       if (IsZero(p)) return loop_cnt;
598       LPPp = LPP(p);
599       loop_cnt++;
600     }
601 
602 //     while ( (!IsZero(p)) && (rrle = GB.is_reducible(LPPp, idx) )) {
603 //       bool didit = false;
604 //       //red_frq[LPP(p)]++;
605 //       if (opt.prev_red){
606 // 	int idl = rrle->index;
607 // 	for(; idl>=0; idl--) {
608 // 	  map<int, matrix_t>::iterator it = matrix_hist[idl].find(curr_deg);
609 // 	  if (it != matrix_hist[idl].end() ) {
610 // 	    for(mit_t mit = it->second.begin(); mit!=it->second.end(); ++mit) if (!IsZero(mit->second.elem())){
611 // 	      if (mit->second.LT == LPPp) {
612 // 		env->myReductionStep(raw(p),raw(mit->second.elem()));
613 // 		if (IsZero(p)) return loop_cnt;
614 // 		LPPp = LPP(p);
615 // 		didit = true;
616 // 		break;
617 // 	      }
618 // 	    }
619 // 	    if (didit) break;
620 // 	  }
621 // 	}
622 //       }
623 //       if (!didit) env->myReductionStep(raw(p),raw(*rrle));
624 //       if (IsZero(p)) return loop_cnt;
625 //       LPPp = LPP(p);
626 //       loop_cnt++;
627 //     }
628     return loop_cnt;
629   }
630 
gauss(matrix_t & m)631   matrF5_t::gauss_stat_t matrF5_t::gauss( matrix_t &m) {
632     gauss_stat_t gs;
633     if (m.size() < 1) { if (opt.verbose) cout << "gauss: empty matrix"; return gs; }
634     matrixrow_sorter mrs(env);
635     priority_queue< mmvt_t *, vector<mmvt_t*>, matrixrow_sorter> pq(mrs);
636     int realred = 0, rsteps = 0;
637     long ml  = 0;
638 //     for (mit_t it = m.begin(); it!=m.end(); ++it) {
639 //       for (SparsePolyIter sit = BeginIter(it->second.elem()); sit != EndIter(it->second.elem());++sit) {
640 // 	ostringstream oss;
641 // 	oss << coeff(sit);
642 // 	ml = max(ml,len(oss.str()));
643 //       }
644 //     }
645     if (opt.verbose)  cout << "\t&" << ml;
646     for (mit_t it = m.begin(); it!=m.end(); ++it) {
647       if (opt.skip_rows){
648 	int loop_cnt=0;
649 	if (opt.use_NR) GB.NR(it->second.elem(),curr_poly - 1); else loop_cnt=pNF(it->second.elem(),curr_poly - 1);
650 	if (loop_cnt!=0 || opt.use_NR) {
651 	  it->second.touched = true;
652 	  realred++;
653 	  rsteps+=loop_cnt;
654 	  if (IsZero(it->second.elem())) { gs.r2z++; continue; }
655 	  it->second.LT = LPP(it->second.elem());
656 	}
657       }
658       pq.push(&*it);
659     }
660     //    cout << "\t" << realred;
661     if (pq.size() <= 1) {  if (opt.verbose) cout << "one liner"; return gs; }
662     do{
663       mmvt_t *i = pq.top();
664       pq.pop();
665       PPMonoidElem cLT = i->second.LT;
666 //???SET BUT NOT USED (JAA,2013-03-13)      bool did_loop = false;
667       while ( ( !pq.empty()) && pq.top()->second.LT == cLT ){
668 //???SET BUT NOT USED (JAA,2013-03-13)        did_loop = true;
669 	mmvt_t *j = pq.top();
670 	//cout << endl << "P1 = " << i->second.elem() << ";" << endl << "P2 = " << j->second.elem() << endl;
671 	pq.pop(); //	cout << i->first << "   " << j->first << endl;
672 	assert(i->first < j->first); //*i has smaller label
673 	gs.sums++;
674 	if (j->second.reduce(i->second)){ //*i won't be changed
675 	  assert(j->second.LT < i->second.LT);
676 	  if (opt.skip_rows && !opt.use_NR) rsteps += pNF(j->second.elem(),curr_poly - 1);
677 	  if (!IsZero(j->second.elem())) {
678 	    j->second.LT = LPP(j->second.elem());
679 	    assert(j->second.elem()!=0);
680 	    pq.push(j);
681 	  } else {  gs.r2z++; }
682 	} else {  gs.r2z++; } //we had a reduction to zero :(
683       }
684     } while(! pq.empty());
685     if (opt.verbose) cout << "\t&" << rsteps + realred;
686     return gs;
687   }
688 
matrix_insert_row(matrix_t & mtr,module_term_t mt,row_t row)689   mmvt_t * matrF5_t::matrix_insert_row(matrix_t &mtr, module_term_t mt, row_t row)const{
690     mit_t it = mtr.find(mt);
691 
692     PPMonoidElem rwc(myPPM);
693     if (it == mtr.end()){ //new row
694       it = mtr.insert(make_pair(mt,row)).first;
695       return &*it;
696     }
697     else return nullptr;
698     return &*it;
699   }
700 
gen_macaulay_rows(matrix_t & mtr,const set<labeled_RingElem_t>::iterator & set_it,RefPPMonoidElem & ppme,unsigned int d,unsigned int ri)701   bool matrF5_t::gen_macaulay_rows(matrix_t &mtr, const set<labeled_RingElem_t>::iterator &set_it,
702 				   RefPPMonoidElem& ppme,
703 				   unsigned int d, unsigned int ri){
704 
705     if (GB.is_syz_reducible(ppme,set_it->index - 1)) {
706       //      cout << "F5 criteria killed " << ppme << " idx " << set_it->index << endl;
707       return false;
708     }
709     if (d == 0) { //try adding row
710       module_term_t mt(ppme, set_it->index);
711       row_t row(&*set_it,ppe2ppm(ppme/set_it->term,myPPM));
712       return matrix_insert_row(mtr,mt,row);
713     }
714     unsigned int i=d;
715     if (ri != n_indets - 1) {
716       if (gen_macaulay_rows(mtr,set_it,ppme,d,ri+1))
717 	for (i = 1; i<=d; i++) {
718 	  ppme *= mtPPMindets[ri];
719 	  if (!gen_macaulay_rows(mtr,set_it,ppme,d-i,ri+1)) break;
720 	}
721     } else {
722       ppme *= power(mtPPMindets[ri],d);
723       gen_macaulay_rows(mtr,set_it,ppme,0,ri+1);
724       i=d;
725     }
726     ppme /= power(mtPPMindets[ri], i>=d ? d : i);
727     return true;
728   }
729 
generate_macaulay(matrix_t & matrix,int mini,int maxi)730   void matrF5_t::generate_macaulay( matrix_t &matrix, int mini, int maxi){
731     if (GB.pairs.size()>=curr_deg) GB.pairs[curr_deg].clear();
732     for(GB_t::GBit_t it = GB.GB.begin(); it != GB.GB.end(); ++it) if (mini <= it->index && it->index <= maxi){
733       int delta_deg = curr_deg - StdDeg(*it);
734       PPMonoidElem wt = it->term;
735       if (delta_deg >= 0) gen_macaulay_rows(matrix,it,wt,delta_deg);
736     }
737   }
738 
generate_macaulay_xx(matrix_t & matrix)739   void matrF5_t::generate_macaulay_xx( matrix_t &matrix){
740     if (GB.pairs.size()>=curr_deg) GB.pairs[curr_deg].clear();
741     matrix_t &oldm = matrix_hist[curr_poly][curr_deg-1];
742     matrix.clear();
743     if (!opt.incremental){
744       for(unsigned int i = 0; i < gens.size(); ++i )
745 	if ((!IsZero(gens[i])) && static_cast<unsigned long>(StdDeg(gens[i])) == curr_deg) {
746 	  //GB.NR(gens[i], curr_poly - 1);
747 	  if (!IsZero(gens[i])){
748 	    //	  cout << "New gen " << i << endl;
749 	    GB_t::GBit_t it = GB.insert(gens[i],i);
750 	    matrix.insert(mmvt_t(*it,row_t(&*it,PPMonoidElem(myPPM))));
751 	  } else {
752 	    if (opt.verbose) cout << "Gen #" << i << " is useless" << endl;
753 	  }
754 	}
755     }
756 
757     RingElem TheOne(one(env));
758     PPMonoidElem TheId(one(myPPM));
759     row_t TheOtherOne(&TheOne,TheId);
760 
761     for (mit_t it = oldm.begin(); it!=oldm.end(); ++it) if (!IsZero(it->second.elem())) {
762       for (unsigned int i=0; i<n_indets; i++){
763 	module_term_t mt = it->first;
764 	assert(static_cast<unsigned long>(StdDeg(it->second.LT)) + 1 == curr_deg);
765 	mt.term *= mtPPMindets[i];
766  	if (!GB.is_syz_reducible_gen(mt,i)){
767 	  mit_t ip = matrix.find(mt);
768 	  if (ip==matrix.end()) { //new row/label
769 	    ip = matrix.insert(mmvt_t(mt,TheOtherOne )).first;
770 		    //ip = matrix.insert(mmvt_t(mt,it->second )).first;
771 	    ip->second = it->second;
772 	    ip->second *= PPMindets[i];
773 	  }else {
774 	    //if (1 + StdDeg(it->second.coeff) <= StdDeg(ip->second.coeff)){
775 	    if (PPMindets[i]*it->second.LT < ip->second.LT){
776 	      ip->second = it->second;
777 	      ip->second *= PPMindets[i];
778 	    //	    cout << "** delta = " << 1 + StdDeg(it->second.coeff) << "; Old lt = " << ip->second.LT
779 	    //	 << "; NewLT = " << nrw.LT << endl;
780 	    } //else
781 	  }
782 // 	} else {
783 // 	  cout << mt << i << "  killed" << endl;
784 	}//if us syz etc..
785       }//end for indet
786     }//end for it
787     oldm.clear();
788   }
789 
do_deg_step()790   bool matrF5_t::do_deg_step(){
791     matrix_t &matrix = matrix_hist[curr_poly][curr_deg];
792     if (curr_deg==0) return false;
793     if (opt.verbose) cout << curr_poly << "\t&" << setw(2) << curr_deg; //<< "\t" << GB.pairs[curr_deg].size();
794 
795     //    copy(GB.pairs[curr_deg].begin(),GB.pairs[curr_deg].end(),ostream_iterator<cpair_t>(cout, "\n"));
796     clock_t timeb4 = clock(),timeafter;
797     double gtime = 0;
798     generate_macaulay_xx(matrix);
799     if (opt.verbose){
800       timeafter = clock();
801       gtime = static_cast<double>(timeafter - timeb4) / CLOCKS_PER_SEC;
802       cout << "\t&" << setw(5) << matrix.size() << flush;
803       //        cout << endl << "Before Gauss:" << endl << matrix;
804       timeb4 = clock();
805     }
806     gauss_stat_t gs = gauss(matrix);
807     if (opt.verbose) {
808       timeafter = clock();
809       cout << "\t&" << gtime << "\t& " << static_cast<double>(timeafter - timeb4) / CLOCKS_PER_SEC ;
810     }
811     int newel=0,touched=0;
812     if (opt.verbose) cout << " \t&" << gs.r2z << " \t&" << setw(5) << gs.sums << flush;
813     //        cout << endl << "After Gauss:" << endl << matrix;
814 
815     for( mit_t it = matrix.begin(); it != matrix.end(); ++it)
816       if (it->second.is_evaluated()) {
817 	if (it->second.touched) touched++;
818 	RingElem &rre = it->second.elem();
819 	if (rre == 0) {
820 	  GB.Syz_LPPinsert(it->first.term,it->first.index-1); // *non Faugere extension*
821 	  continue;
822 	}
823 	if (!GB.is_reducible(LPP(rre))) {
824 	  //	  cout << "New poly :" << it->first << " : " << LPP(rre) << endl;
825 	  newel++;
826 	  GB.insert(labeled_RingElem_t(rre,it->first));
827 	}
828 	//	fast_reductor[LPP(rre)] = &it->second.elem();
829       }
830     if (opt.verbose) cout << "\t& " << setw(5) << touched << "\t& " << newel << "\\\\" << endl;
831     curr_deg++;
832     //        if (touched==0) return false; //?? why ??
833     return true;
834   }
835 
836 
837 
interreduce(vector<RingElem> & v)838   void interreduce(vector<RingElem> &v){
839     SparsePolyRing env = owner(v[0]);
840     for(unsigned int i = 0; i < v.size(); i++){
841       vector<RingElem> rl;
842       for(unsigned int j = 0; j < v.size(); j++) if (i!=j && !IsZero(v[j])) rl.push_back(v[j]);
843       v[i] = NR(v[i],rl);
844     }
845     vector<RingElem>::iterator nend = remove(v.begin(),v.end(),zero(env));
846     v.erase(nend,v.end());
847     for(unsigned int i = 0; i < v.size(); i++) v[i] /= monomial(env,LC(v[i]),one(PPM(env)));
848 
849   }
850 
GBtest(vector<RingElem> & v)851   bool GBtest(vector<RingElem> &v){
852     SparsePolyRing env = owner(v[0]);
853     vector<RingElem> GB = TidyGens(ideal(env,v));
854     for(unsigned int i = 0; i < GB.size(); i++) GB[i] /= monomial(env,LC(GB[i]),one(PPM(env)));
855     F5ns::PolyRingElemCmp prec(env);
856     if (v.size() != GB.size() ) { cout << "sizes differ"; return false; }
857     sort(GB.begin(),GB.end(),prec);
858     sort(v.begin(),v.end(),prec);
859     //     copy(GB.begin(),GB.end(),ostream_iterator<RingElem>(cout,"\n"));
860     //     cout << endl << " ^^^^ Real GB. F5GB vvvvv" << endl;
861     //     copy(v.begin(),v.end(),ostream_iterator<RingElem>(cout,"\n"));
862     return v == GB;
863   }
864 
865 }//end of namespace F5ns
866 
F5(vector<RingElem> & GB,const vector<RingElem> & I,const F5ns::F5opt_t &)867   void F5(vector<RingElem> &GB, const vector<RingElem> &I, const F5ns::F5opt_t &/*F5opt*/ ){
868 
869     if (F5ns::opt.verbose) {
870       cout << "F5 starting ";
871       copy(I.begin(),I.end(),ostream_iterator<RingElem>(cout,"\n"));
872       cout << endl;
873     }
874     F5ns::matrF5_t F5i(I);
875 
876     F5i.do_it();
877     GB.clear();
878     GB.reserve(F5i.GB.GB.size());
879     if (F5ns::opt.verbose) cout << "GB size = " << F5i.GB.GB.size() << endl;
880     //    copy(F5i.GB.GB.begin(),F5i.GB.GB.end(),back_inserter(GB));
881     GB.insert(GB.end(), F5i.GB.GB.begin(), F5i.GB.GB.end());
882 
883     //check answer
884     if (F5ns::opt.checkGB) {
885       cout << "Checking GB .... " << flush;
886       F5ns::interreduce(GB);
887       cout << (F5ns::GBtest(GB) ? "ok" : "not ok") << endl;
888     }
889   }
890 
891 }
892 
893 // RCS header/log in the next few lines
894 // $Header: /Volumes/Home_1/cocoa/cvs-repository/CoCoALib-0.99/src/AlgebraicCore/TmpF5Mat.C,v 1.17 2019/03/19 11:07:08 abbott Exp $
895 // $Log: TmpF5Mat.C,v $
896 // Revision 1.17  2019/03/19 11:07:08  abbott
897 // Summary: Replaced 0 by nullptr where appropriate
898 //
899 // Revision 1.16  2018/05/18 16:38:51  bigatti
900 // -- added include SparsePolyOps-RingElem.H
901 //
902 // Revision 1.15  2018/03/15 14:39:20  bigatti
903 // -- new file SparsePolyOps-ideal.H
904 //
905 // Revision 1.14  2017/11/10 16:02:27  abbott
906 // Summary: Removed NewLexOrdering, NewStdDegLexOrdering, NewStdDegRevLexOrdering; consequential changes
907 //
908 // Revision 1.13  2014/07/07 14:12:17  abbott
909 // Summary: Corrected silly typo
910 // Author: JAA
911 //
912 // Revision 1.12  2014/07/07 12:51:09  abbott
913 // Summary: Removed AsSparsePolyRing
914 // Author: JAA
915 //
916 // Revision 1.11  2014/04/30 16:14:12  abbott
917 // Summary: Replaced size_t by long
918 // Author: JAA
919 //
920 // Revision 1.10  2014/01/16 16:13:57  abbott
921 // Replaced  RingElem(env,0)  by  zero(env)
922 //
923 // Revision 1.9  2013/03/15 17:49:57  abbott
924 // Commented out unused variable.
925 //
926 // Revision 1.8  2012/10/16 10:15:43  abbott
927 // Replaced  RefRingElem  by  RingElem&  (in an old style cast?!?)
928 //
929 // Revision 1.7  2012/01/26 16:47:49  bigatti
930 // -- changed back_inserter into insert
931 //
932 // Revision 1.6  2012/01/26 16:37:10  abbott
933 // Removed an apparently totally pointless CPP symbol definition (NDEBUG).
934 //
935 // Revision 1.5  2008/06/30 17:15:41  abbott
936 // Used const_iterator instead of iterator (where appropriate).
937 //
938 // Revision 1.4  2008/05/30 12:50:31  abbott
939 // Comment out some unused formal parameters (to avoid compiler warnings)
940 //
941 // Revision 1.3  2008/03/12 16:35:18  bigatti
942 // -- changed: IsHomogeneous --> IsHomog
943 // -- changed: ERR:ZeroPoly --> ERR::ZeroRingElem
944 //
945 // Revision 1.2  2007/12/11 14:39:25  bigatti
946 // --
947 //
948 // Revision 1.1  2007/11/20 10:01:26  bigatti
949 // -- change: TmpF5.C --> TmpF5Mat.C  (by Alberto Arri)
950 // -- updated and improved test-F5.C
951 //
952