1 //
2 //  FGLMStrategy.cc
3 //  PolyBoRi
4 //
5 //  Created by Michael Brickenstein on 2008-11-13.
6 //  Copyright 2008 The PolyBoRi Team.
7 //
8 #include <exception>
9 #include <polybori/groebner/FGLMStrategy.h>
10 #include <polybori/groebner/nf.h>
11 #include <polybori/groebner/add_up.h>
12 #include <polybori/groebner/interpolate.h>
13 #include <polybori/groebner/draw_matrix.h>
14 
15 using namespace std;
16 BEGIN_NAMESPACE_PBORIGB
17 
18 
19 #if 0
20 static void mult_by_combining_rows(mzd_t* dest, mzd_t* A, packedmatrix* B, packedmatrix* acc1, packedmatrix* acc2, FGLMStrategy::IndexVector& row_is_monomial){
21 
22     int i,j;
23     const int m=A->nrows;
24     const int n=A->ncols;
25     //const int nblocks=A->width;
26     mzd_t* res_row=acc1;
27     mzd_t* dest_row=acc2;
28     PBORI_ASSERT(acc1->ncols==B->ncols);
29     PBORI_ASSERT(acc2->ncols==B->ncols);
30     PBORI_ASSERT(dest->nrows==A->nrows);
31     PBORI_ASSERT(dest->ncols==B->ncols);
32 
33     for(i=0;i<m;i++){
34         mzd_row_clear_offset(acc1, 0,0);
35         mzd_row_clear_offset(acc2, 0,0);
36         mzd_row_clear_offset(dest,i,0);
37 
38         for(j=0;j<n;j+=RADIX){
39             if (mzd_read_block(A,i,j)!=0){
40                 const int j_bak=j;
41                 for(j=j_bak;(j<j_bak+RADIX) && (j<n);j++){
42                     if (mzd_read_bit(A,i,j)==1){
43                         int monomial_idx;
44                         if ((monomial_idx=row_is_monomial[j])>=0){
45                             mzd_write_bit(res_row, 0, monomial_idx, (1+ mzd_read_bit(res_row,0,monomial_idx))%2);
46                         } else {
47                             mzd_combine(dest_row,0,0,B,j,0,res_row,0,0);
48                             std::swap(res_row,dest_row);
49                         }
50                     }
51                 }
52                 j=j_bak;
53 
54             }
55         }
56 
57             //how to do that most efficiently?
58             //copy res_row to dest
59 
60             //mzd_row_clear_offset(dest_row,0,0);
61             //mzd_combine(dest,i,0,res_row,0,0,dest_row,0,0);
62 
63         mzd_copy_row(dest,i,res_row,0);
64     }
65 
66 
67 //if 0
68     int i,j;
69        const int m=A->nrows;
70        const int n=A->ncols;
71        mzd_t* res_row=acc1;
72        mzd_t* dest_row=acc2;
73        PBORI_ASSERT(acc1->ncols==B->ncols);
74        PBORI_ASSERT(acc2->ncols==B->ncols);
75        PBORI_ASSERT(dest->nrows==A->nrows);
76        PBORI_ASSERT(dest->ncols==B->ncols);
77        for(i=0;i<m;i++){
78            mzd_row_clear_offset(acc1, 0,0);
79            mzd_row_clear_offset(acc2, 0,0);
80            mzd_row_clear_offset(dest,i,0);
81            for(j=0;j<n;j++){
82                if (mzd_read_bit(A,i,j)){
83                    mzd_combine(dest_row,0,0,B,j,0,res_row,0,0);
84                    std::swap(res_row,dest_row);
85                }
86            }
87            //how to do that most efficiently?
88            //copy res_row to dest
89 
90            //mzd_row_clear_offset(dest_row,0,0);
91            //mzd_combine(dest,i,0,res_row,0,0,dest_row,0,0);
92 
93            mzd_copy_row(dest,i,res_row,0);
94        }
95 
96 //endif
97 
98 }
99 #endif
100 
101 
setupStandardMonomialsFromTables()102 void FGLMStrategy::setupStandardMonomialsFromTables(){
103 
104      standardMonomialsFromVector.resize(varietySize, from);
105      MonomialSet::const_iterator it_set=standardMonomialsFrom.begin();
106      MonomialSet::const_iterator end_set=standardMonomialsFrom.end();
107      //assume only that iteration is descending w.r.t. divisibility
108 
109      int i=standardMonomialsFrom.size()-1;
110      while(it_set!=end_set){
111          Monomial m=*it_set;
112          standardMonomialsFrom2Index[m]=i;
113          standardExponentsFrom2Index[m.exp()]=i;
114          standardMonomialsFromVector[i]=m;
115          it_set++;
116          i--;
117      }
118 
119 }
120 #if 0
121 void FGLMStrategy::writeTailToRow(MonomialSet tail, mzd_t* row){
122 
123     MonomialSet::const_iterator it=tail.begin();
124     MonomialSet::const_iterator end=tail.end();
125             //optimize that;
126     while(it!=end){
127         idx_type tail_idx=standardMonomialsFrom2Index[*it];
128         mzd_write_bit(row,0, tail_idx,1);
129         it++;
130     }
131 }
132 #else
writeTailToRow(MonomialSet tail,mzd_t * row)133 void FGLMStrategy::writeTailToRow(MonomialSet tail, mzd_t* row){
134 
135     MonomialSet::exp_iterator it=tail.expBegin();
136     MonomialSet::exp_iterator end=tail.expEnd();
137             //optimize that;
138     while(it!=end){
139         idx_type tail_idx=standardExponentsFrom2Index[*it];
140         mzd_write_bit(row,0, tail_idx,1);
141         it++;
142     }
143 }
144 #endif
writeRowToVariableDivisors(mzd_t * row,Monomial lm)145 void FGLMStrategy::writeRowToVariableDivisors(mzd_t* row, Monomial lm){
146     Monomial::const_iterator it_lm=lm.begin();
147     Monomial::const_iterator end_lm=lm.end();
148     Exponent exp=lm.exp();
149     bool first=true;
150     while(it_lm!=end_lm){
151         idx_type ring_var_index=*it_lm;
152         idx_type our_var_index=ring2Index[ring_var_index];
153         Exponent divided=exp.removeConst(ring_var_index);
154         if (standardMonomialsFrom.owns(divided)){
155             mzd_t* mat=multiplicationTables[our_var_index];
156             size_t divided_index=standardExponentsFrom2Index[divided];
157 
158             if (first){
159                 monomial2MultiplicationMatrix[lm]=our_var_index;
160                 monomial2MultiplicationMatrixRowIndex[lm]=divided_index;
161                 first=false;
162             }
163             if (transposed){
164               for(std::size_t j=0;j<varietySize;j++){
165                     mzd_write_bit(mat, j, divided_index, mzd_read_bit(row,0,j));
166                 }
167             } else {
168 
169                 /*mzd_t* window=mzd_init_window(mat,divided_index,0,divided_index+1,varietySize);
170                 mzd_copy(window,row);
171                 mzd_free_window(window);*/
172 
173                 mzd_copy_row(mat, divided_index, row,0);
174 
175                 /*for(j=0;j<varietySize;j++){
176                     mzd_write_bit(mat, divided_index, j, mzd_read_bit(row,0,j));
177                 }*/
178             }
179         }
180         it_lm++;
181     }
182 }
183 
transpose_window_to_row(mzd_t * transposed_vec,mzd_t * window)184 void transpose_window_to_row(mzd_t* transposed_vec, mzd_t* window){
185     int i;
186     const int n=window->nrows;
187     for(i=0;i<n;i++){
188         mzd_write_bit(transposed_vec,0,i, mzd_read_bit(window,i,0));
189     }
190 }
rowToPoly(mzd_t * row)191 Polynomial FGLMStrategy::rowToPoly(mzd_t* row){
192     MonomialVector vec;
193     for(std::size_t i=0;i<varietySize;i++){
194         if (mzd_read_bit(row,0,i)==1){
195             vec.push_back(standardMonomialsFromVector[i]);
196         }
197     }
198     return add_up_monomials(vec, to);
199 }
200 
setupMultiplicationTables()201 void FGLMStrategy::setupMultiplicationTables(){
202 
203     //first we write into rows, later we transpose
204     //algorithm here
205     multiplicationTables.resize(nVariables);
206     tableXRowYIsMonomialFromWithIndex.resize(nVariables);
207     for(std::size_t i=0; i < nVariables;i++){
208         multiplicationTables[i]=mzd_init(varietySize,varietySize);
209         tableXRowYIsMonomialFromWithIndex[i].resize(varietySize);
210         for(std::size_t j=0;j<varietySize;j++){
211             tableXRowYIsMonomialFromWithIndex[i][j]=-1;
212         }
213     }
214 
215     //standard monomials
216 
217     for(std::size_t i=0;i<standardMonomialsFromVector.size();i++){
218         Monomial m=standardMonomialsFromVector[i];
219         Monomial::const_iterator it=m.begin();
220         Monomial::const_iterator end=m.end();
221         while(it!=end){
222             idx_type ring_var_index=*it;
223             idx_type our_var_index=ring2Index[ring_var_index];
224             Monomial divided=m / Variable(ring_var_index, m.ring());
225             size_t divided_index=standardMonomialsFrom2Index[divided];
226             mzd_t* mat=multiplicationTables[our_var_index];
227             mzd_write_bit(mat, divided_index,i, 1);
228             tableXRowYIsMonomialFromWithIndex[our_var_index][divided_index]=i;
229             //finally treat the "edge" case: m*v->m, where v divides m
230             mzd_write_bit(mat,i,i,1);
231             tableXRowYIsMonomialFromWithIndex[our_var_index][i]=i;
232             it++;
233         }
234 
235 
236     }
237 
238     //leading monomials from gb: vertices/
239     mzd_t* row=mzd_init(1, varietySize);
240     ReductionStrategy::const_iterator start(gbFrom.begin()),
241       finish(gbFrom.end());
242     while (start != finish){
243         Monomial lm = start->lead;
244         MonomialSet tail = start->tail.set();
245         mzd_row_clear_offset(row,0,0);
246         writeTailToRow(tail, row);
247         writeRowToVariableDivisors(row,lm);
248 
249         ++start;
250     }
251     mzd_free(row);
252     //edges
253     MonomialSet edges=standardMonomialsFrom.cartesianProduct(varsSet).
254         diff(standardMonomialsFrom).diff(leadingTermsFrom);
255     Polynomial edges_poly=edges;
256     MonomialVector edges_vec(edges.size(), from);
257     std::copy(edges_poly.orderedBegin(), edges_poly.orderedEnd(), edges_vec.begin());
258 
259     //reverse is important, so that divisors and elements in the tail have already been treated
260 
261 
262 
263     MonomialVector::reverse_iterator it_edges=edges_vec.rbegin();
264     MonomialVector::reverse_iterator end_edges=edges_vec.rend();
265     edgesUnitedVerticesFrom=edges.unite(leadingTermsFrom);
266 
267     mzd_t* multiplied_row=mzd_init(1,varietySize);
268     mzd_t* reduced_problem_to_row=mzd_init(1,varietySize);
269 
270     mzd_t* acc1=mzd_init(1, varietySize);
271     mzd_t* acc2=mzd_init(1, varietySize);
272 
273     while(it_edges!=end_edges){
274         mzd_row_clear_offset(multiplied_row, 0, 0);
275         Monomial m=*it_edges;
276 
277         MonomialSet candidates=Polynomial(edgesUnitedVerticesFrom.divisorsOf(m)).gradedPart(m.deg()-1).set();
278 
279         Monomial reduced_problem_to=*(candidates.begin());
280 
281         Monomial v_m=m/reduced_problem_to;
282 
283         PBORI_ASSERT (v_m.deg()==1);
284         Variable var=*v_m.variableBegin();
285         mzd_t* mult_table=multiplicationTableForVariable(var);
286 
287         findVectorInMultTables(reduced_problem_to_row, reduced_problem_to);
288 
289         if (!(transposed)){
290 
291         //standardMonomialsFrom2Index[reduced_problem_to];
292 
293         //highly inefficient/far to many allocations
294 
295         //mzd_mul expects second arg to be transposed
296         //which is a little bit tricky as we multiply from left
297         //mzd_t* transposed_mult_table=mzd_transpose(NULL, mult_table);
298 
299         //mzd_mul_naiv(multiplied_row,reduced_problem_to_row, mult_table);
300         #if 0
301         mult_by_combining_rows(multiplied_row, reduced_problem_to_row,
302             mult_table, acc1, acc2,tableXRowYIsMonomialFromWithIndex[ring2Index[var.index()]]);
303         #else
304         _mzd_mul_va(multiplied_row, reduced_problem_to_row, mult_table, 1);
305         #endif
306         } else {
307             //mzd_t* transposed_vec=mzd_init(1,varietySize);
308             //PBORI_ASSERT (window->nrows==varietySize);
309             //PBORI_ASSERT (window->ncols==1);
310             //transpose_window_to_row(transposed_vec, window);
311             _mzd_mul_va(multiplied_row, reduced_problem_to_row, mult_table, FALSE);
312             //mzd_free(transposed_vec);
313         }
314 
315         writeRowToVariableDivisors(multiplied_row, m);
316         //matrices are transposed, so now we have write to columns
317 
318         //mzd_free(transposed_mult_table);
319         //mzd_free_window(window);
320         it_edges++;
321     }
322     mzd_free(reduced_problem_to_row);
323 
324     mzd_free(multiplied_row);
325 
326     mzd_free(acc1);
327     mzd_free(acc2);
328 
329     //transposeMultiplicationTables();
330 
331     {
332         #ifdef DRAW_MATRICES
333       for(std::size_t i=0;i<multiplicationTables.size();i++){
334             char matname[255];
335             sprintf(matname,"mult_table%d.png",(int)i);
336 
337             draw_matrix(multiplicationTables[i],matname);
338         }
339         #endif
340     }
341 }
findVectorInMultTables(mzd_t * dst,Monomial m)342 void FGLMStrategy::findVectorInMultTables(mzd_t* dst, Monomial m){
343     mzd_t* mat=multiplicationTables[monomial2MultiplicationMatrix[m]];
344     size_t idx=monomial2MultiplicationMatrixRowIndex[m];
345     if (!(transposed))
346         mzd_submatrix(dst, mat, idx, 0, idx+1, varietySize);
347     else{
348         const int n=varietySize;
349         int i;
350         for(i=0;i<n;i++){
351             mzd_write_bit(dst, 0, i, mzd_read_bit(mat,i,idx));
352         }
353     }
354 }
clear_mat(mzd_t * mat)355 void clear_mat(mzd_t* mat) {
356   for(int i = 0; i < mat->nrows; ++i) {
357     mzd_row_clear_offset(mat,i,0);
358   }
359 }
transposeMultiplicationTables()360 void FGLMStrategy::transposeMultiplicationTables(){
361     //From now on, we multiply, so here we transpose
362     mzd_t* new_mat=mzd_init(varietySize,varietySize);
363     mzd_t* swap;
364     for(std::size_t i=0;i<multiplicationTables.size();i++){
365         //unnecassary many allocations of matrices
366         //mzd_t* new_mat=mzd_init(varietySize,varietySize);
367         clear_mat(new_mat);
368         mzd_transpose(new_mat, multiplicationTables[i]);
369 
370         swap=new_mat;
371         new_mat=multiplicationTables[i];
372         multiplicationTables[i]=swap;
373         //mzd_free(new_mat);
374 
375     }
376     mzd_free(new_mat);
377     transposed=(!(transposed));
378 }
analyzeGB(const ReductionStrategy & gb)379 void FGLMStrategy::analyzeGB(const ReductionStrategy& gb){
380 
381     vars=gb.leadingTerms.usedVariables();
382     for (std::size_t i=0;i<gb.size();i++){
383         vars=vars * Monomial(gb[i].usedVariables, from);
384     }
385 
386     Monomial::variable_iterator it_var=vars.variableBegin();
387     Monomial::variable_iterator end_var=vars.variableEnd();
388     while (it_var!=end_var){
389         varsVector.push_back(*it_var);
390         it_var++;
391     }
392     VariableVector::reverse_iterator it_varvec=varsVector.rbegin();
393     VariableVector::reverse_iterator end_varvec=varsVector.rend();
394     while(it_varvec!=end_varvec){
395         varsSet=varsSet.unite(Monomial(*it_varvec).diagram());
396         it_varvec++;
397     }
398 
399 
400     nVariables=vars.size();
401     ring2Index.resize(from.nVariables());
402     index2Ring.resize(nVariables);
403     idx_type ring_index;
404     idx_type our_index=0;
405     Monomial::const_iterator it=vars.begin();
406     Monomial::const_iterator end=vars.end();
407     while(it!=end){
408         ring_index=*it;
409         ring2Index[ring_index]=our_index;
410         index2Ring[our_index]=ring_index;
411 
412         our_index++;
413         it++;
414     }
415 
416     standardMonomialsFrom=mod_mon_set(vars.divisors(), gb.leadingTerms);
417 
418     leadingTermsFrom=gb.leadingTerms;
419     varietySize=standardMonomialsFrom.size();
420 }
421 
422 class FGLMNoLinearCombinationException: public std::exception
423 {
424 public:
425     size_t firstNonZeroIndex;
FGLMNoLinearCombinationException(size_t firstNonZeroIndex)426     FGLMNoLinearCombinationException(size_t firstNonZeroIndex){
427         this->firstNonZeroIndex=firstNonZeroIndex;
428     }
429 };
430 #if 0
431 FGLMStrategy::IndexVector FGLMStrategy::rowVectorIsLinearCombinationOfRows(mzd_t* mat, mzd_t* v){
432     //returns vector with indices, where the coefficients in this linear combination are 1
433     //if no such combination exists, raises Exception
434     #ifdef DRAW_MATRICES
435     static int round=0;
436     round++;
437     PBORI_ASSERT (mat->ncols==varietySize);
438     PBORI_ASSERT (v->ncols==varietySize);
439     PBORI_ASSERT (v->nrows==1);
440     #endif
441     mzd_t* row_combined=mzd_stack(NULL, mat, v);
442     {
443         #ifdef DRAW_MATRICES
444             char matname[255];
445             sprintf(matname,"row_combined%d.png",round);
446 
447             draw_matrix(row_combined,matname);
448         #endif
449     }
450     mzd_t* col_combined=mzd_transpose(NULL, row_combined);
451     mzd_free(row_combined);
452 
453     mzd_echelonize_m4ri(col_combined,TRUE,0,NULL,NULL);
454     {
455         #ifdef DRAW_MATRICES
456             char matname[255];
457             sprintf(matname,"col_reduced%d.png",round);
458 
459             draw_matrix(col_combined,matname);
460         #endif
461     }
462     const int cols=col_combined->ncols;
463     const int rows=col_combined->nrows;
464     PBORI_ASSERT (rows>=cols-1);
465     const int ngenerators=cols-1;
466     const int last_col=cols-1;
467     int i;
468     IndexVector res;
469 
470     //first col-1 cols are linear independend -> reduced row echelon form has unimat het
471     for(i=rows-1;i>ngenerators-1;i--){
472         PBORI_ASSERT(i>=last_col);
473         if (mzd_read_bit(col_combined,i,last_col)==1){
474             //no inhomgeneous solution exists
475             mzd_free(col_combined);
476             FGLMNoLinearCombinationException ex;
477             throw ex;
478 
479         }
480     }
481     for(i=ngenerators-1;i>=0;i--){
482         PBORI_ASSERT(i<last_col);
483         if (mzd_read_bit(col_combined,i, last_col)==1){
484             PBORI_ASSERT(mzd_read_bit(col_combined,i,i)==1);
485             res.push_back(i);
486         }
487     }
488     mzd_free(col_combined);
489 
490     return res;
491 }
492 #else
rowVectorIsLinearCombinationOfRows(mzd_t * mat,mzd_t * v)493 FGLMStrategy::IndexVector FGLMStrategy::rowVectorIsLinearCombinationOfRows(mzd_t* mat, mzd_t* v){
494     const int d=mat->nrows-1;
495     mzd_row_clear_offset(mat,d,0);
496     PBORI_ASSERT (mat->ncols==2*varietySize);
497 
498     //mzd_t* copy_v_into=mzd_init_window(mat,d,0,d+1,varietySize);
499     //mzd_copy(copy_v_into,v);
500     //mzd_free_window(copy_v_into);
501 
502     mzd_copy_row(mat,d,v,0);
503     //mzd_row_clear_offset(mat,d,varietySize);//might be random data at the end as mat is wider
504 
505 
506     for(std::size_t i=0;i<varietySize;i++){
507         if (mzd_read_bit(mat,d,i)==1){
508             bool succ=false;
509             int row_idx=rowStartingWithIndex[i];
510             if (row_idx>=0){
511                 succ=true;
512                 int standard_idx;
513                 if ((standard_idx=rowIsStandardMonomialToWithIndex[row_idx])>=0){
514                     mzd_write_bit(mat,d,i,0);
515                     const int standard_idx_with_offset=varietySize+standard_idx;
516                     mzd_write_bit(mat,d,standard_idx_with_offset,(1+mzd_read_bit(mat,d,standard_idx_with_offset))%2);
517                 } else {
518                     mzd_row_add_offset(mat, d, row_idx, i);
519                 }
520 
521             }
522 
523             if (!(succ)){
524                 FGLMNoLinearCombinationException ex(i);
525                 throw ex;
526 
527             }
528         }
529     }
530     IndexVector res;
531     for(int i=0;i<d;i++){
532         if (mzd_read_bit(mat,d,i+varietySize)==1){
533             res.push_back(i);
534         }
535     }
536     return res;
537 }
538 #endif
main()539 PolynomialVector FGLMStrategy::main(){
540     PolynomialVector F;
541     const Monomial monomial_one(to);
542 
543     if (leadingTermsFrom.owns(monomial_one)){
544         F.push_back(monomial_one);
545         return F;
546     }
547     //variables are oriented at Tim Wichmanns Diploma thesis
548 
549     mzd_t* acc1=mzd_init(1, varietySize);
550     mzd_t* acc2=mzd_init(1, varietySize);
551 
552 
553     typedef std::set<Monomial> MonomialSetSTL;
554 
555     MonomialSetSTL C;
556 
557     lm2Index_map_type mon2index;
558     Exponent::idx_map_type exp2index;
559     //initialize with one monomial
560     mzd_t* v=mzd_init(varietySize, varietySize);//write vectors in rows;
561     mzd_t* w=mzd_init(varietySize+1, varietySize*2);
562     IndexVector w_start_indices;
563     rowStartingWithIndex.resize(varietySize);
564     rowIsStandardMonomialToWithIndex.resize(varietySize);
565     for(std::size_t i=0;i<rowStartingWithIndex.size();i++){
566         rowStartingWithIndex[i]=-1;
567         rowIsStandardMonomialToWithIndex[i]=-1;
568     }
569     MonomialSet b_set=monomial_one.set();
570     MonomialVector b;
571     b.push_back(monomial_one);
572     mzd_write_bit(v,0,0,1);
573     mzd_write_bit(w,0,0,1);
574     mzd_write_bit(w,0,varietySize+0,1);
575     w_start_indices.push_back(0);
576     rowStartingWithIndex[0]=0;
577     rowIsStandardMonomialToWithIndex[0]=0;
578 
579     VariableVector varsVectorTo;
580     varsVectorTo.reserve(varsVector.size());
581     for(std::size_t i=0;i<varsVector.size();i++){
582       varsVectorTo.push_back(to.coerce(varsVector[i]));
583       C.insert(varsVectorTo.back());
584     }
585 
586     mon2index[monomial_one]=0;
587     exp2index[monomial_one.exp()]=0;
588     mzd_t* v_d=mzd_init(1,varietySize);
589 
590     while(!(C.empty())){
591         const int d=b.size();
592         Monomial m=*(C.begin());
593 
594         C.erase(C.begin());
595 
596         PBORI_ASSERT(m!=monomial_one);
597         Polynomial divisors(to);
598         PBORI_ASSERT(b_set.containsDivisorsOfDecDeg(m)==(Polynomial(b_set.divisorsOf(m)).gradedPart(m.deg()-1).length()==m.deg()));
599         if (b_set.containsDivisorsOfDecDeg(m)/*varsM=Zm,Ecke oder Standard Monom*/) {
600             Polynomial divisors=Polynomial(b_set.divisorsOf(m)).gradedPart(m.deg()-1);
601             mzd_row_clear_offset(v_d,0,0);
602             PBORI_ASSERT(varietySize>0);
603             bool is_standard_monomial_from=false;
604 
605             if (edgesUnitedVerticesFrom.owns(m)){
606                 findVectorInMultTables(v_d, m);
607             } else {
608                 if (standardMonomialsFrom.owns(m)){
609                     mzd_write_bit(v_d,0, standardMonomialsFrom2Index[m],1);
610                     is_standard_monomial_from=true;
611                 } else{
612                     Exponent b_j=*divisors.expBegin();
613                     int j=exp2index[b_j];
614                     Exponent x_i_m=(m.exp()-b_j);
615                     PBORI_ASSERT (x_i_m.deg()==1);
616                     //Variable x_i=*x_i_m.variableBegin();
617                     idx_type our_x_i_index=ring2Index[*x_i_m.begin()];
618                     mzd_t* mult_table=multiplicationTables[our_x_i_index];//multiplicationTableForVariable(x_i);
619                     mzd_t* v_j=mzd_init_window(v,j,0,j+1,varietySize);
620 
621                     PBORI_ASSERT (v_j->nrows==1);
622                     PBORI_ASSERT ( v_j->ncols==varietySize);
623                     if (transposed)
624                         v_d=_mzd_mul_va(v_d, v_j, mult_table, FALSE);
625                     else{
626                         #if 0
627                         mult_by_combining_rows(v_d, v_j, mult_table, acc1, acc2, tableXRowYIsMonomialFromWithIndex[our_x_i_index]);
628                         #else
629                         _mzd_mul_va(v_d, v_j, mult_table, 1);
630                         #endif
631                     }
632                     mzd_free_window(v_j);
633                 }
634 
635             }
636 
637             PBORI_ASSERT (v_d->nrows==1);
638             PBORI_ASSERT (v_d->ncols==varietySize);
639             mzd_t* w_window=mzd_init_window(w,0,0,d+1,2*varietySize);
640             //mzd_t* w_row_window=mzd_init_window(w,d,0,d+1,varietySize);
641             try
642             {
643 
644 
645                 IndexVector lin_combination=rowVectorIsLinearCombinationOfRows(w_window,  v_d);
646                 MonomialVector p_vec;
647                 for(std::size_t i=0;i<lin_combination.size();i++){
648                     PBORI_ASSERT (lin_combination[i]<b.size());
649                     p_vec.push_back(b[lin_combination[i]]);
650                 }
651                 Polynomial p=add_up_monomials(p_vec, to.zero())+m;
652                 F.push_back(p);
653 
654 
655             }
656             catch (FGLMNoLinearCombinationException& e)
657             {
658 
659                 b_set=b_set.unite(m.diagram());
660                 b.push_back(m);
661 
662                 rowStartingWithIndex[e.firstNonZeroIndex]=d;
663                 mzd_write_bit(w,d,varietySize+d,1);
664                 if (is_standard_monomial_from){
665                     std::size_t from_idx=standardMonomialsFrom2Index[m];
666                     if (e.firstNonZeroIndex==from_idx){
667                         //we assume, the row is untached
668                         rowIsStandardMonomialToWithIndex[d]=d;
669                         //might swap rows and use a vector of bools
670                     } else {
671                         const int reduced_with_this_row=rowStartingWithIndex[from_idx];
672                         PBORI_ASSERT(reduced_with_this_row>=0);
673                         mzd_row_clear_offset(w, reduced_with_this_row,0);
674                         mzd_write_bit(w, reduced_with_this_row, from_idx,1);
675                         mzd_write_bit(w, reduced_with_this_row, varietySize+d,1);
676                         rowIsStandardMonomialToWithIndex[reduced_with_this_row]=d;
677                         //still generate the same vector space
678                     }
679                 }
680                 /*mzd_t* copy_window=mzd_init_window(v,d,0,d+1,varietySize);
681                 mzd_copy(copy_window, v_d);
682                 mzd_free_window(copy_window);*/
683                 mzd_copy_row(v,d,v_d,0);
684 
685                 idx_type m_begin=*m.begin();
686                 for(std::size_t i=0;(i<varsVectorTo.size())&&(index2Ring[i]<m_begin);i++){
687                   Variable var=varsVectorTo[i];
688                     if (!(m.reducibleBy(var))){
689                       Monomial m_v= var*m;
690                         C.insert(m_v);
691                     }
692                 }
693                 mon2index[m]=b.size()-1;
694                 exp2index[m.exp()]=b.size()-1;
695             }
696 
697             mzd_free_window(w_window);
698         }
699 
700     }
701     mzd_free(w);
702     mzd_free(v_d);
703     mzd_free(v);
704 
705     for(std::size_t i=0;i<addTheseLater.size();i++){
706         F.push_back(to.coerce(addTheseLater[i]));
707     }
708 
709     mzd_free(acc1);
710     mzd_free(acc2);
711 
712 #ifndef PBORI_NDEBUG
713     for (std::size_t idx = 0; idx < F.size(); ++idx) {
714       PBORI_ASSERT(to.id() == F[idx].ring().id());
715     }
716 #endif
717 
718     return F;
719 }
720 
testMultiplicationTables()721 void FGLMStrategy::testMultiplicationTables(){
722     #ifndef PBORI_NDEBUG
723 
724     for(std::size_t i=0;i<varsVector.size();i++){
725         Variable v=varsVector[i];
726         PBORI_ASSERT (v.index()>=i);
727         for (std::size_t j=0;j<standardMonomialsFromVector.size(); j++){
728             Monomial m=standardMonomialsFromVector[j];
729             mzd_t* table=multiplicationTableForVariable(v);
730             if (m==v){continue;}
731 
732             Polynomial product=reducedNormalFormInFromRing(m*v);
733 
734             MonomialSet product_set=product.diagram();
735             Polynomial sum(0, product.ring());
736             for(std::size_t k=0;k<varietySize;k++){
737                 Monomial m2=standardMonomialsFromVector[k];
738 
739                 if (mzd_read_bit(table,j,k)==1){
740                     sum+=m2;
741                 }
742 
743             }
744             if (sum!=product)
745                 cout<<"v:"<<v<<"\tm:"<<m<<"\tsum:"<<sum<<"\tproduct:"<<product<<endl;
746             PBORI_ASSERT(sum==product);
747         }
748     }
749     #endif
750 }
reducedNormalFormInFromRing(Polynomial f)751 Polynomial FGLMStrategy::reducedNormalFormInFromRing(Polynomial f){
752     Polynomial res=gbFrom.reducedNormalForm(f);
753     return res;
754 }
755 
canAddThisElementLaterToGB(Polynomial p)756 bool FGLMStrategy::canAddThisElementLaterToGB(Polynomial p){
757     Monomial lm_from=from.ordering().lead(p);
758     size_t length=p.length();
759     if ((lm_from.deg()==1)&& ((length==1)||((length==2) && (p.hasConstantPart())))){
760         return true;
761     }/*
762     if (lm_from.deg()==1){
763         Monomial lm_to=to.ordering().lead(p);
764         if (lm_from==lm_to){
765             return true;
766         }
767     }*/
768     return false;
769 }
FGLMStrategy(const ring_with_ordering_type & from_ring,const ring_with_ordering_type & to_ring,const PolynomialVector & gb)770 FGLMStrategy::FGLMStrategy(const ring_with_ordering_type& from_ring, const ring_with_ordering_type& to_ring,  const PolynomialVector& gb)
771   : vars(from_ring),
772 
773    standardMonomialsFrom(from_ring),
774    leadingTermsFrom(from_ring),
775    varsSet(from_ring),
776     gbFrom(from_ring), edgesUnitedVerticesFrom(from_ring), from(from_ring), to(to_ring){
777 
778     prot=false;
779     transposed=false;
780 
781     PolynomialVector::const_iterator it=gb.begin();
782     PolynomialVector::const_iterator end=gb.end();
783 
784     while(it!=end){
785         Polynomial gen=*it;
786         if (canAddThisElementLaterToGB(gen)){
787             addTheseLater.push_back(gen);
788         } else{
789             this->gbFrom.addGenerator(gen);
790         }
791         it++;
792     }
793 
794     Monomial monomial_one(from_ring);
795     if (prot)
796         cout<<"analyzing gb..."<<endl;
797     analyzeGB(this->gbFrom);
798     if (!(this->gbFrom.leadingTerms.owns(monomial_one))){
799         //cout<<standardMonomialsFrom2Index[monomial_one]<<endl;
800 
801         if (prot){
802             cout<<"varietySize:"<<varietySize<<endl;
803             cout<<"standard monomials tables..."<<endl;
804         }
805         setupStandardMonomialsFromTables();
806         if (prot)
807             cout<<"multiplication tables..."<<endl;
808         setupMultiplicationTables();
809 
810 #ifndef PBORI_NDEBUG
811         if (prot)
812             cout<<"test multiplication table..."<<endl;
813         testMultiplicationTables();
814 #endif
815         PBORI_ASSERT(standardMonomialsFrom2Index[monomial_one]==0);
816     }
817     if (prot)
818         cout<<"initialization finished"<<endl;
819 }
820 
821 
822 END_NAMESPACE_PBORIGB
823