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