1 //   Copyright (c)  2015 Mario Albert
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/TmpPartialMorseBetti.H"
19 #include "CoCoA/RingZZ.H"
20 #include "CoCoA/DenseMatrix.H"
21 
22 using std::make_pair;
23 
24 namespace CoCoA
25 {
26   namespace Involutive
27   {
myComputeGeneralColumnBasis(long MinDeg,long lengthWedge)28     std::vector<MorseElement> PartialMorseBetti::myComputeGeneralColumnBasis(long MinDeg, long lengthWedge) const
29     {
30       std::vector<MorseElement> basis;
31       for (MorseElement::JBElemConstIter it = myBasis.begin(); it != myBasis.end(); ++it)
32       {
33         long deg(StdDeg(it->elem));
34         if (deg < MinDeg - lengthWedge - 1)
35         {
36           continue;
37         } else if (deg == MinDeg - lengthWedge - 1)
38         {
39           myComputeBasisForElement(basis, it, lengthWedge + 1);
40         } else {
41           myComputeBasisForElement(basis, it, lengthWedge);
42           myComputeBasisForElement(basis, it, lengthWedge + 1);
43         }
44       }
45       return basis;
46     }
47 
48 
myComputeGeneralSingleBasis(long degree,long lengthWedge)49     std::vector<MorseElement> PartialMorseBetti::myComputeGeneralSingleBasis(long degree, long lengthWedge) const
50     {
51       std::vector<MorseElement> basis;
52       for (MorseElement::JBElemConstIter it = myBasis.begin(); it != myBasis.end(); ++it)
53       {
54         long deg(StdDeg(it->elem));
55         if (deg == degree - lengthWedge - 1)
56         {
57           myComputeBasisForElement(basis, it, lengthWedge + 1);
58         } else if (deg == degree - lengthWedge)
59         {
60           myComputeBasisForElement(basis, it, lengthWedge);
61         }
62       }
63       return basis;
64     }
65 
66 
myComputeBasisForElement(std::vector<MorseElement> & basis,MorseElement::JBElemConstIter it,long lengthWedge)67     void PartialMorseBetti::myComputeBasisForElement(std::vector<MorseElement>& basis,
68                                                      MorseElement::JBElemConstIter it,
69                                                      long lengthWedge) const
70     {
71       const std::vector<long> NonMultVars(myDynamicBitsetToLong(flip(it->multVars)));
72       if (len(NonMultVars) >= lengthWedge)
73         {
74         std::vector<DynamicBitset> bitsets(myPossibleWedgesOfLength(NonMultVars, lengthWedge));
75         for (std::vector<DynamicBitset>::const_iterator BitsetIter = bitsets.begin(); BitsetIter != bitsets.end(); ++BitsetIter)
76         {
77           // std::cout <<  "MorseElement(*BitsetIter, it) = " << MorseElement(*BitsetIter, it) << std::endl;
78           basis.push_back(MorseElement(*BitsetIter, it));
79         }
80       }
81     }
82 
83 
myPossibleWedgesOfLength(const std::vector<long> & NonMultVars,long length)84     std::vector<DynamicBitset> PartialMorseBetti::myPossibleWedgesOfLength(const std::vector<long>& NonMultVars, long length) const
85     {
86       std::vector<std::vector<long> > ResultAsVector;
87       myVariationWithoutRepetition(ResultAsVector, std::vector<long>(), NonMultVars, length);
88       std::vector<DynamicBitset> result;
89       result.reserve(len(ResultAsVector));
90       for (std::vector<std::vector<long> >::iterator it = ResultAsVector.begin(); it != ResultAsVector.end(); ++it)
91       {
92         result.push_back(myVectorLongToDynamicBitset(*it, NumIndets(myRing)));
93       }
94       return result;
95     }
96 
97 
myComputeConstantColumnResolution(long deg,long numWedges)98     void PartialMorseBetti::myComputeConstantColumnResolution(long deg, long numWedges)
99     {
100       myResolution.clear();
101       StandardRepresentationContainer container(myMill);
102       myComputeBasicConstantGraph(myComputeGeneralColumnBasis(deg, numWedges), container);
103 
104       myConstantDirectMorseReduction(container);
105     }
106 
107 
myComputeConstantSingleResolution(long deg,long numWedges)108     void PartialMorseBetti::myComputeConstantSingleResolution(long deg, long numWedges)
109     {
110       myResolution.clear();
111       StandardRepresentationContainer container(myMill);
112       myComputeBasicConstantGraph(myComputeGeneralSingleBasis(deg, numWedges), container);
113 
114       myConstantDirectMorseReduction(container);
115     }
116 
117 
myComputeBettiNumber(long row,long col)118     long PartialMorseBetti::myComputeBettiNumber(long row, long col)
119     {
120       if (col == 0)
121       {
122         if (row == 0)
123         {
124           return 1;
125         }
126         return 0;
127       }
128       long degree = row + col;
129       long numWedges = col - 1;
130       myComputeConstantSingleResolution(degree, numWedges);
131       if (myResolution.empty())
132       {
133         return 0;
134       }
135       long rank(myComputeSinglePseudoBettiNumber(degree, numWedges));
136       long WasteRank(myComputeSingleRank(degree, numWedges));
137       return (rank - WasteRank);
138     }
139 
140 
myComputeDownToBettiNumber(long row,long col)141     matrix PartialMorseBetti::myComputeDownToBettiNumber(long row, long col)
142     {
143       if (col == 0)
144       {
145         matrix bettis(NewDenseMat(RingZZ(), 1, 1));
146         if (row == 0)
147         {
148           SetEntry(bettis, 0, 0, 1);
149         } else {
150           SetEntry(bettis, 0, 0, 0);
151         }
152         return bettis;
153       }
154       long degree = row + col;
155       long numWedges = col - 1;
156       // std::cout <<  "degree = " << degree << std::endl;
157       // std::cout <<  "numWedges = " << numWedges << std::endl;
158       myComputeConstantColumnResolution(degree, numWedges);
159       // std::cout <<  "len(myResolution) = " << len(myResolution) << std::endl;
160       if (myResolution.empty())
161       {
162         matrix bettis(NewDenseMat(RingZZ(), 1, 1));
163         SetEntry(bettis, 0, 0, 0);
164         return bettis;
165       }
166 
167       std::vector<long> ranks(myComputePartialPseudoBettiNumber(degree, numWedges));
168       // std::cout <<  "ranks = ";
169       // for (std::vector<long>::iterator i = ranks.begin(); i != ranks.end(); ++i)
170       // {
171       //   std::cout << *i << "; ";
172       // }
173       // std::cout << std::endl;
174       std::vector<long> WasteRanks(myComputePartialRanks(len(ranks), degree, numWedges));
175       // std::cout <<  "WasteRanks = ";
176       // for (std::vector<long>::iterator i = WasteRanks.begin(); i != WasteRanks.end(); ++i)
177       // {
178       //   std::cout << *i << "; ";
179       // }
180       // std::cout << std::endl;
181       CoCoA_ASSERT(len(ranks) == len(WasteRanks));
182       for (int i = 0; i < len(ranks); ++i)
183       {
184         ranks[i] -= WasteRanks[i];
185         if (ranks[i] < 0)
186         {
187           ranks[i] = 0;
188         }
189         // std::cout <<  "ranks[i] = " << ranks[i] << std::endl;
190       }
191       return myTransformPartialRanksToPartialBettis(ranks);
192     }
193 
194 
myTransformPartialRanksToPartialBettis(const std::vector<long> & ranks)195     matrix PartialMorseBetti::myTransformPartialRanksToPartialBettis(const std::vector<long>& ranks) const
196     {
197       long RowsBetti(len(ranks));
198       long TooMuch(0);
199       for (int i = (RowsBetti - 1); i >= 0; --i)
200       {
201         if (ranks[i] != 0)
202         {
203           break;
204         }
205         ++TooMuch;
206       }
207       RowsBetti -= TooMuch;
208       if (RowsBetti == 0)
209       {
210         RowsBetti = 1;
211       }
212       matrix bettis(NewDenseMat(RingZZ(), RowsBetti, 1));
213       for (long i = 0; i < RowsBetti; ++i)
214       {
215         SetEntry(bettis, i, 0, ranks[i]);
216       }
217       return bettis;
218     }
219 
220 
myComputePartialRanks(long LenWasteRanks,long MinDeg,long numWedges)221     std::vector<long> PartialMorseBetti::myComputePartialRanks(long LenWasteRanks, long MinDeg, long numWedges) const
222     {
223       // initialize the rank matrix. It has the same dimension as PseudoBettiNumber
224       std::vector<long> WasteRanks(LenWasteRanks, 0);
225       // compute the waste ranks for each map
226       // ResIter moves forward during the loop via myComputeWasteRanksPerMap
227       std::map<MorseElement, MorsePaths>::const_iterator ResIter(myResolution.begin());
228       // std::cout <<  "MinDeg = " << MinDeg << std::endl;
229       // std::cout <<  "numWedges = " << numWedges << std::endl;
230       std::vector<std::pair<long, long> > WasteRanksFirst;
231       if (numWedges > 0)
232       {
233         WasteRanksFirst = myComputePartialRanksPerDegree(ResIter,
234                                                          myComputePartialPseudoBettiNumber(MinDeg, numWedges - 1),
235                                                          myComputePartialPseudoBettiNumber(MinDeg, numWedges),
236                                                          numWedges - 1,
237                                                          MinDeg);
238       }
239       std::vector<std::pair<long, long> > WasteRanksSecond = myComputePartialRanksPerDegree(ResIter,
240                                                                                             myComputePartialPseudoBettiNumber(MinDeg, numWedges),
241                                                                                             myComputePartialPseudoBettiNumber(MinDeg, numWedges + 1),
242                                                                                             numWedges,
243                                                                                             MinDeg);
244       for (std::vector<std::pair<long, long> >::iterator wrf = WasteRanksFirst.begin(); wrf != WasteRanksFirst.end(); ++wrf)
245       {
246         WasteRanks[wrf->first - MinDeg] = wrf->second;
247       }
248 
249       for (std::vector<std::pair<long, long> >::iterator wrs = WasteRanksSecond.begin(); wrs != WasteRanksSecond.end(); ++wrs)
250       {
251         WasteRanks[wrs->first - MinDeg] += wrs->second;
252       }
253 
254       return WasteRanks;
255     }
256 
257 
myComputeSingleRank(long deg,long numWedges)258     long PartialMorseBetti::myComputeSingleRank(long deg, long numWedges) const
259     {
260 
261       std::map<MorseElement, MorsePaths>::const_iterator ResIter(myResolution.begin());
262       long res = 0;
263       if (numWedges > 0)
264       {
265         res = myComputeSingleRankPerDegree(ResIter,
266                                            myComputeSinglePseudoBettiNumber(deg, numWedges - 1),
267                                            myComputeSinglePseudoBettiNumber(deg, numWedges),
268                                            numWedges - 1,
269                                            deg);
270       }
271 
272       res += myComputeSingleRankPerDegree(ResIter,
273                                           myComputeSinglePseudoBettiNumber(deg, numWedges),
274                                           myComputeSinglePseudoBettiNumber(deg, numWedges + 1),
275                                           numWedges,
276                                           deg);
277       // std::cout <<  "(" << deg << "," << numWedges << ") = " << res << std::endl;
278       return res;
279     }
280 
281 
myComputeSingleRankPerDegree(std::map<MorseElement,MorsePaths>::const_iterator & ResIter,long RowRank,long ColRank,long PosInRes,long deg)282     long PartialMorseBetti::myComputeSingleRankPerDegree(std::map<MorseElement, MorsePaths>::const_iterator& ResIter,
283                                                          long RowRank,
284                                                          long ColRank,
285                                                          long PosInRes,
286                                                          long deg) const
287     {
288       if (RowRank == 0 || ColRank == 0)
289       {
290         return 0;
291       }
292       std::map<std::pair<long, MorseElement>, long> identifier(myGradedPositionMorseElements(PosInRes));
293       matrix SubMat(ConstructDegreeMatrix(ResIter, RowRank, ColRank, deg, PosInRes, identifier));
294       return rk(SubMat);
295     }
296 
297 
myComputeSinglePseudoBettiNumber(long deg,long numWedges)298     long PartialMorseBetti::myComputeSinglePseudoBettiNumber(long deg, long numWedges) const
299     {
300       long res(0);
301       long n(NumIndets(myRing));
302       for (long k = 1; k <= (n - numWedges); ++k)
303       {
304         BetaVector::const_iterator BetaIter = myBetaVector.find(make_pair(deg - numWedges, k));
305         if (BetaIter != myBetaVector.end())
306         {
307           res += ConvertTo<long>(binomial(n - k, numWedges) * BetaIter->second);
308         }
309       }
310       return AsUnsignedLong(res);
311     }
312 
313 
myComputePartialPseudoBettiNumber(long MinDeg,long numWedges)314     std::vector<long> PartialMorseBetti::myComputePartialPseudoBettiNumber(long MinDeg, long numWedges) const
315     {
316       const long highDeg(((myResolution.rbegin())->first).myDegree());
317       std::vector<long> ranks(highDeg - MinDeg + 1, 0);
318       for (int i = MinDeg; i <= highDeg; ++i)
319       {
320         ranks[i - MinDeg] = myComputeSinglePseudoBettiNumber(i, numWedges);
321       }
322 
323       return ranks;
324     }
325 
326 
myComputePartialRanksPerDegree(std::map<MorseElement,MorsePaths>::const_iterator & ResIter,const std::vector<long> & RowRanks,const std::vector<long> & ColRanks,long PosInRes,long MinDeg)327     std::vector<std::pair<long, long> > PartialMorseBetti::myComputePartialRanksPerDegree(std::map<MorseElement, MorsePaths>::const_iterator& ResIter,
328                                                                                           const std::vector<long>& RowRanks,
329                                                                                           const std::vector<long>& ColRanks,
330                                                                                           long PosInRes,
331                                                                                           long MinDeg) const
332     {
333       std::vector<std::pair<long, long> > RanksOfDegreeMatrices;
334 
335       std::map<std::pair<long, MorseElement>, long> identifier(myGradedPositionMorseElements(PosInRes));
336       // find a real submatrix (number of rows and cols are not zero)
337       for (long pos = 0; pos < len(RowRanks); ++pos)
338       {
339         if (RowRanks[pos] == 0 || ColRanks[pos] == 0)
340         {
341           if (RowRanks[pos] != 0)
342           {
343             while((ResIter != myResolution.end()) &&(ResIter->first).myDegree() == (pos + MinDeg) && (ResIter->first).myCountWedgeBasis() == PosInRes)
344             {
345               ++ResIter;
346             }
347           }
348           continue;
349         }
350         // extract matrix
351         // std::cout <<  "RowRanks[pos] = " << RowRanks[pos] << std::endl;
352         // std::cout <<  "ColRanks[pos] = " << ColRanks[pos] << std::endl;
353         // std::cout <<  "pos+MinDeg = " << pos+MinDeg << std::endl;
354         // std::cout <<  "PosInRes = " << PosInRes << std::endl;
355         matrix SubMat(ConstructDegreeMatrix(ResIter, RowRanks[pos], ColRanks[pos], pos + MinDeg, PosInRes, identifier));
356         // compute rank and add to result
357         RanksOfDegreeMatrices.push_back(make_pair(pos + MinDeg, rk(SubMat)));
358       }
359       return RanksOfDegreeMatrices;
360     }
361 
362 
BettiColumn(JBMill mill,long col)363     matrix BettiColumn(JBMill mill, long col)
364     {
365       if (!IsStdDegRevLex(ordering(mill.myGetPPMonoid())))
366       {
367         CoCoA_ERROR(ERR::PPOrder, "It must be the degrevlex ordering!!!");
368       }
369       if (!mill.IamHomogenous())
370       {
371         CoCoA_ERROR("The ideal isn't homogenous", __FUNCTION__);
372       }
373       PartialMorseBetti mg(mill);
374       return mg.myComputeBettiColumn(col);
375     }
376 
377 
BettiPartialColumn(JBMill mill,long MinRow,long col)378     matrix BettiPartialColumn(JBMill mill, long MinRow, long col)
379     {
380       if (!IsStdDegRevLex(ordering(mill.myGetPPMonoid())))
381       {
382         CoCoA_ERROR(ERR::PPOrder, "It must be the degrevlex ordering!!!");
383       }
384       if (!mill.IamHomogenous())
385       {
386         CoCoA_ERROR("The ideal isn't homogenous", __FUNCTION__);
387       }
388       PartialMorseBetti mg(mill);
389       return mg.myComputeDownToBettiNumber(MinRow, col);
390     }
391 
BettiNumber(JBMill mill,long row,long col)392     RingElem BettiNumber(JBMill mill, long row, long col)
393     {
394       if (!IsStdDegRevLex(ordering(mill.myGetPPMonoid())))
395       {
396         CoCoA_ERROR(ERR::PPOrder, "It must be the degrevlex ordering!!!");
397       }
398       if (!mill.IamHomogenous())
399       {
400         CoCoA_ERROR("The ideal isn't homogenous", __FUNCTION__);
401       }
402       PartialMorseBetti mg(mill);
403       return RingElem(RingZZ(), mg.myComputeBettiNumber(row, col));
404     }
405 
406   } // end namespace Involutive
407 } // end namespace CoCoA
408