8 #include "GmshConfig.h"
9 #if defined(HAVE_KBIPACK)
13 ChainComplex::ChainComplex(
CellComplex *cellComplex,
int domain)
15 _dim = cellComplex->
getDim();
16 _cellComplex = cellComplex;
18 for(
int i = 0; i < 5; i++) {
19 _hMatrix[i] =
nullptr;
22 _jMatrix[i] =
nullptr;
23 _qMatrix[i] =
nullptr;
28 for(
int dim = 0; dim < 4; dim++) {
29 std::size_t cols = cellComplex->
getSize(dim);
34 for(
auto cit = cellComplex->
firstCell(dim);
35 cit != cellComplex->
lastCell(dim); cit++) {
38 if((domain == 0 && !cell->
inSubdomain()) || domain == 1 ||
41 _cellIndices[dim][cell] = index;
45 _cellIndices[dim][cell] = 0;
48 if(dim > 0) rows = lastCols;
52 _hMatrix[dim] =
nullptr;
55 _hMatrix[dim] = create_gmp_matrix_zero(1, cols);
60 _hMatrix[dim] = create_gmp_matrix_zero(rows, cols);
61 for(
auto cit = cellComplex->
firstCell(dim);
62 cit != cellComplex->
lastCell(dim); cit++) {
64 if((domain == 0 && !cell->
inSubdomain()) || domain == 1 ||
68 Cell *bdCell = it->first;
69 if(it->second.get() == 0)
continue;
70 if((domain == 0 && !bdCell->
inSubdomain()) || domain == 1 ||
73 int bdCellIndex = getCellIndex(bdCell);
74 int cellIndex = getCellIndex(cell);
75 if(bdCellIndex > (
int)gmp_matrix_rows(_hMatrix[dim]) ||
77 cellIndex > (
int)gmp_matrix_cols(_hMatrix[dim]) ||
79 Msg::Debug(
"Index out of bound! HMatrix: %d", dim);
82 gmp_matrix_get_elem(
elem, bdCellIndex, cellIndex,
84 old_elem = mpz_get_si(
elem);
85 mpz_set_si(
elem, old_elem + it->second.get());
86 if(abs((old_elem + it->second.get())) > 1) {
90 gmp_matrix_set_elem(
elem, bdCellIndex, cellIndex,
100 _codH[dim] =
nullptr;
101 _jMatrix[dim] =
nullptr;
102 _qMatrix[dim] =
nullptr;
103 _hbasis[dim] =
nullptr;
107 ChainComplex::~ChainComplex()
109 for(
int i = 0; i < 5; i++) {
110 destroy_gmp_matrix(_hMatrix[i]);
111 destroy_gmp_matrix(_kerH[i]);
112 destroy_gmp_matrix(_codH[i]);
113 destroy_gmp_matrix(_jMatrix[i]);
114 destroy_gmp_matrix(_qMatrix[i]);
115 destroy_gmp_matrix(_hbasis[i]);
119 void ChainComplex::transposeHMatrices()
121 for(
int i = 0; i < 5; i++)
122 if(_hMatrix[i] !=
nullptr) gmp_matrix_transp(_hMatrix[i]);
124 void ChainComplex::transposeHMatrix(
int dim)
126 if(dim > -1 && dim < 5 && _hMatrix[dim] !=
nullptr)
127 gmp_matrix_transp(_hMatrix[dim]);
130 void ChainComplex::KerCod(
int dim)
132 if(dim < 0 || dim > 3 || _hMatrix[dim] ==
nullptr)
return;
134 gmp_matrix *HMatrix =
135 copy_gmp_matrix(_hMatrix[dim], 1, 1, gmp_matrix_rows(_hMatrix[dim]),
136 gmp_matrix_cols(_hMatrix[dim]));
138 gmp_normal_form *normalForm =
139 create_gmp_Hermite_normal_form(HMatrix, NOT_INVERTED, INVERTED);
144 int minRowCol = std::min(gmp_matrix_rows(normalForm->canonical),
145 gmp_matrix_cols(normalForm->canonical));
151 while(rank < minRowCol) {
152 gmp_matrix_get_elem(
elem, rank + 1, rank + 1, normalForm->canonical);
153 if(mpz_cmp_si(
elem, 0) == 0)
break;
157 if(rank != (
int)gmp_matrix_cols(normalForm->canonical)) {
158 _kerH[dim] = copy_gmp_matrix(normalForm->right, 1, rank + 1,
159 gmp_matrix_rows(normalForm->right),
160 gmp_matrix_cols(normalForm->right));
164 _codH[dim] = copy_gmp_matrix(normalForm->canonical, 1, 1,
165 gmp_matrix_rows(normalForm->canonical), rank);
166 gmp_matrix_left_mult(normalForm->left, _codH[dim]);
170 destroy_gmp_normal_form(normalForm);
176 void ChainComplex::Inclusion(
int lowDim,
int highDim)
178 if(getKerHMatrix(lowDim) ==
nullptr || getCodHMatrix(highDim) ==
nullptr ||
179 abs(lowDim - highDim) != 1)
183 copy_gmp_matrix(_kerH[lowDim], 1, 1, gmp_matrix_rows(_kerH[lowDim]),
184 gmp_matrix_cols(_kerH[lowDim]));
186 copy_gmp_matrix(_codH[highDim], 1, 1, gmp_matrix_rows(_codH[highDim]),
187 gmp_matrix_cols(_codH[highDim]));
189 int rows = gmp_matrix_rows(Bbasis);
190 int cols = gmp_matrix_cols(Bbasis);
192 destroy_gmp_matrix(Zbasis);
193 destroy_gmp_matrix(Bbasis);
197 rows = gmp_matrix_rows(Zbasis);
198 cols = gmp_matrix_cols(Zbasis);
200 destroy_gmp_matrix(Zbasis);
201 destroy_gmp_matrix(Bbasis);
206 gmp_normal_form *normalForm =
207 create_gmp_Smith_normal_form(Zbasis, INVERTED, INVERTED);
212 for(
int i = 1; i <= cols; i++) {
213 gmp_matrix_get_elem(
elem, i, i, normalForm->canonical);
214 if(mpz_cmp_si(
elem, 0) == 0) {
215 destroy_gmp_matrix(Bbasis);
216 destroy_gmp_normal_form(normalForm);
221 gmp_matrix_left_mult(normalForm->left, Bbasis);
223 gmp_matrix *LB = copy_gmp_matrix(Bbasis, 1, 1, gmp_matrix_cols(Zbasis),
224 gmp_matrix_cols(Bbasis));
225 destroy_gmp_matrix(Bbasis);
227 rows = gmp_matrix_rows(LB);
228 cols = gmp_matrix_cols(LB);
237 for(
int i = 1; i <= rows; i++) {
238 gmp_matrix_get_elem(divisor, i, i, normalForm->canonical);
239 for(
int j = 1; j <= cols; j++) {
240 gmp_matrix_get_elem(
elem, i, j, LB);
241 mpz_cdiv_qr(result, remainder,
elem, divisor);
242 if(mpz_cmp_si(remainder, 0) == 0) {
243 gmp_matrix_set_elem(result, i, j, LB);
246 destroy_gmp_matrix(Zbasis);
247 destroy_gmp_matrix(LB);
248 destroy_gmp_normal_form(normalForm);
254 gmp_matrix_left_mult(normalForm->right, LB);
256 setJMatrix(lowDim, LB);
261 destroy_gmp_normal_form(normalForm);
264 void ChainComplex::Quotient(
int dim,
int setDim)
266 if(dim < 0 || dim > 4 || _jMatrix[dim] ==
nullptr)
return;
267 if(setDim < 0 || setDim > 4)
return;
269 gmp_matrix *JMatrix =
270 copy_gmp_matrix(_jMatrix[dim], 1, 1, gmp_matrix_rows(_jMatrix[dim]),
271 gmp_matrix_cols(_jMatrix[dim]));
272 int rows = gmp_matrix_rows(JMatrix);
273 int cols = gmp_matrix_cols(JMatrix);
275 gmp_normal_form *normalForm =
276 create_gmp_Smith_normal_form(JMatrix, NOT_INVERTED, NOT_INVERTED);
285 for(
int i = 1; i <= cols; i++) {
286 gmp_matrix_get_elem(
elem, i, i, normalForm->canonical);
287 if(mpz_cmp_si(
elem, 0) == 0) {
288 destroy_gmp_normal_form(normalForm);
291 if(mpz_cmp_si(
elem, 1) > 0) {
292 _torsion[setDim].push_back(mpz_get_si(
elem));
296 int rank = cols - _torsion[setDim].size();
297 if(rows - rank > 0) {
299 copy_gmp_matrix(normalForm->left, 1, rank + 1, rows, rows);
300 _qMatrix[dim] = Hbasis;
304 destroy_gmp_normal_form(normalForm);
308 void ChainComplex::computeHomology(
bool dual)
314 if(dual) transposeHMatrices();
316 for(
int i = -1; i < 4; i++) {
318 lowDim = getDim() + 1 - i;
319 highDim = getDim() + 1 - (i + 1);
331 if(lowDim == 0 && !dual && gmp_matrix_cols(getHMatrix(lowDim)) > 0 &&
332 getHMatrix(highDim) ==
nullptr) {
333 setHbasis(setDim, create_gmp_matrix_identity(
334 gmp_matrix_cols(getHMatrix(lowDim))));
336 else if(highDim == 0 && dual && gmp_matrix_rows(getHMatrix(highDim)) > 0 &&
337 getHMatrix(lowDim) ==
nullptr) {
338 setHbasis(setDim, create_gmp_matrix_identity(
339 gmp_matrix_rows(getHMatrix(highDim))));
343 else if(getHMatrix(setDim) ==
nullptr) {
344 setHbasis(setDim,
nullptr);
347 else if(getHMatrix(highDim) ==
nullptr) {
349 copy_gmp_matrix(getKerHMatrix(lowDim), 1, 1,
350 gmp_matrix_rows(getKerHMatrix(lowDim)),
351 gmp_matrix_cols(getKerHMatrix(lowDim))));
360 if(getHMatrix(lowDim) ==
nullptr) {
361 setKerHMatrix(lowDim, create_gmp_matrix_identity(
362 gmp_matrix_rows(getHMatrix(highDim))));
364 Inclusion(lowDim, highDim);
365 Quotient(lowDim, setDim);
367 if(getCodHMatrix(highDim) ==
nullptr) {
369 copy_gmp_matrix(getKerHMatrix(lowDim), 1, 1,
370 gmp_matrix_rows(getKerHMatrix(lowDim)),
371 gmp_matrix_cols(getKerHMatrix(lowDim))));
373 else if(getJMatrix(lowDim) ==
nullptr || getQMatrix(lowDim) ==
nullptr) {
374 setHbasis(setDim,
nullptr);
378 copy_gmp_matrix(getKerHMatrix(lowDim), 1, 1,
379 gmp_matrix_rows(getKerHMatrix(lowDim)),
380 gmp_matrix_cols(getKerHMatrix(lowDim))));
382 gmp_matrix_right_mult(getHbasis(setDim), getQMatrix(lowDim));
386 destroy_gmp_matrix(getJMatrix(lowDim));
387 destroy_gmp_matrix(getQMatrix(lowDim));
389 setJMatrix(lowDim,
nullptr);
390 setQMatrix(lowDim,
nullptr);
395 void ChainComplex::matrixTest()
400 long int elems[rows * cols];
401 for(
int i = 1; i <= rows * cols; i++) elems[i - 1] = i;
403 gmp_matrix *matrix = create_gmp_matrix_int(rows, cols, elems);
404 gmp_matrix *copymatrix = copy_gmp_matrix(matrix, 3, 2, 3, 5);
406 printMatrix(copymatrix);
407 destroy_gmp_matrix(matrix);
408 destroy_gmp_matrix(copymatrix);
411 std::vector<int> ChainComplex::getCoeffVector(
int dim,
int chainNumber)
413 std::vector<int> coeffVector;
415 if(dim < 0 || dim > 4)
return coeffVector;
416 if(_hbasis[dim] ==
nullptr ||
417 (
int)gmp_matrix_cols(_hbasis[dim]) < chainNumber)
420 int rows = gmp_matrix_rows(_hbasis[dim]);
427 for(
int i = 1; i <= rows; i++) {
428 gmp_matrix_get_elem(
elem, i, chainNumber, _hbasis[dim]);
429 elemli = mpz_get_si(
elem);
431 coeffVector.push_back(elemi);
439 gmp_matrix *ChainComplex::getBasis(
int dim,
int basis)
441 if(dim > -2 && dim < 4 && basis == 2)
return _codH[dim + 1];
442 if(dim < 0 || dim > 4)
452 void ChainComplex::getBasisChain(std::map<Cell *, int, CellPtrLessThan> &chain,
453 int num,
int dim,
int basis,
bool deform)
455 if(basis < 0 || basis > 3)
return;
456 gmp_matrix *basisMatrix = getBasis(dim, basis);
459 if(dim < 0 || dim > 3)
return;
460 if(basisMatrix ==
nullptr || (
int)gmp_matrix_cols(basisMatrix) < num) {
470 if(basis == 3) torsion = getTorsion(dim, num);
472 for(
auto cit = this->firstCell(dim); cit != this->lastCell(dim); cit++) {
473 Cell *cell = cit->first;
474 int index = cit->second;
475 gmp_matrix_get_elem(
elem, index, num, basisMatrix);
476 elemli = mpz_get_si(
elem);
479 std::map<Cell *, int, CellPtrLessThan> subCells;
481 for(
auto it = subCells.begin(); it != subCells.end(); it++) {
482 Cell *subCell = it->first;
483 int coeff = it->second * elemi * torsion;
484 if(coeff == 0)
continue;
485 chain[subCell] = coeff;
491 if(deform && basis == 3 && (dim == 1 || dim == 2)) smoothenChain(chain);
494 int ChainComplex::getBasisSize(
int dim,
int basis)
496 gmp_matrix *basisMatrix;
497 if(basis == 0 && _hMatrix[dim] !=
nullptr) {
498 return gmp_matrix_cols(_hMatrix[dim]);
501 basisMatrix = getBasis(dim, 1);
503 basisMatrix = getBasis(dim, 2);
505 basisMatrix = getBasis(dim, 3);
509 if(basisMatrix !=
nullptr && gmp_matrix_rows(basisMatrix) != 0)
510 return gmp_matrix_cols(basisMatrix);
515 int ChainComplex::getTorsion(
int dim,
int num)
517 if(dim < 0 || dim > 4)
return 0;
518 if(_hbasis[dim] ==
nullptr || (
int)gmp_matrix_cols(_hbasis[dim]) < num)
520 if(_torsion[dim].empty() || (
int)_torsion[dim].size() < num)
523 return _torsion[dim].at(num - 1);
526 bool ChainComplex::deform(
527 std::map<Cell *, int, CellPtrLessThan> &cells,
528 std::map<Cell *, int, CellPtrLessThan> &cellsInChain,
529 std::map<Cell *, int, CellPtrLessThan> &cellsNotInChain)
534 for(
auto cit = cellsInChain.begin(); cit != cellsInChain.end(); cit++) {
535 Cell *
c = (*cit).first;
537 if(!
c->inSubdomain()) {
539 auto it = cells.find(
c);
540 if(it != cells.end()) coeff = it->second;
542 bc.push_back((*cit).second);
546 if(cc.empty() || (getDim() == 2 && cc.size() < 2))
return false;
547 int inout = cc[0] * bc[0];
548 for(std::size_t i = 0; i < cc.size(); i++) {
549 if(cc[i] * bc[i] != inout)
return false;
552 for(
auto cit = cellsInChain.begin(); cit != cellsInChain.end(); cit++) {
553 Cell *cell = cit->first;
554 auto it = cells.find(cell);
555 if(it != cells.end()) cells[cell] = 0;
559 for(
auto cit = cellsNotInChain.begin(); cit != cellsNotInChain.end(); cit++) {
560 Cell *cell = (*cit).first;
565 int coeff = -1 * inout * (*cit).second;
567 std::pair<citer, bool> insert = cells.insert(std::make_pair(cell, coeff));
568 if(!insert.second && (*insert.first).second == 0) {
569 (*insert.first).second = coeff;
571 else if(!insert.second && (*insert.first).second != 0) {
579 bool ChainComplex::deformChain(std::map<Cell *, int, CellPtrLessThan> &cells,
580 std::pair<Cell *, int> cell,
bool bend)
583 int dim =
c1->getDim();
584 for(
auto cit =
c1->firstCoboundary(
true); cit !=
c1->lastCoboundary();
586 std::map<Cell *, int, CellPtrLessThan> cellsInChain;
587 std::map<Cell *, int, CellPtrLessThan> cellsNotInChain;
588 Cell *c1CbdCell = cit->first;
592 Cell *c1CbdBdCell = cit2->first;
593 int coeff = cit2->second.geto();
594 if(coeff == 0)
continue;
595 if((cells.find(c1CbdBdCell) != cells.end() && cells[c1CbdBdCell] != 0) ||
597 cellsInChain.insert(std::make_pair(c1CbdBdCell, coeff));
600 cellsNotInChain.insert(std::make_pair(c1CbdBdCell, coeff));
605 for(
auto cit2 = cellsInChain.begin(); cit2 != cellsInChain.end(); cit2++) {
606 Cell *
c = (*cit2).first;
608 auto it = cells.find(
c);
609 if(it != cells.end()) coeff = it->second;
610 if(
c->getImmune()) next =
true;
611 if(
c->inSubdomain()) bend =
false;
612 if(coeff > 1 || coeff < -1) next =
true;
615 for(
auto cit2 = cellsNotInChain.begin(); cit2 != cellsNotInChain.end();
617 Cell *
c = (*cit2).first;
618 if(
c->inSubdomain()) next =
true;
622 if((dim == 1 && cellsInChain.size() == 2 && cellsNotInChain.size() == 1) ||
623 (dim == 2 && cellsInChain.size() == 3 && cellsNotInChain.size() == 1)) {
625 return deform(cells, cellsInChain, cellsNotInChain);
627 else if((dim == 1 && cellsInChain.size() == 1 &&
628 cellsNotInChain.size() == 2 && bend) ||
629 (dim == 2 && cellsInChain.size() == 2 &&
630 cellsNotInChain.size() == 2 && bend)) {
632 return deform(cells, cellsInChain, cellsNotInChain);
634 else if((dim == 1 && cellsInChain.size() == 3 &&
635 cellsNotInChain.size() == 0) ||
636 (dim == 2 && cellsInChain.size() == 4 &&
637 cellsNotInChain.size() == 0)) {
639 return deform(cells, cellsInChain, cellsNotInChain);
646 void ChainComplex::smoothenChain(std::map<Cell *, int, CellPtrLessThan> &cells)
648 if(!_cellComplex->simplicial() || cells.size() < 2)
return;
649 int dim = cells.begin()->first->getDim();
650 int start = cells.size();
653 for(
int i = 0; i < 20; i++) {
654 int size = cells.size();
655 for(
auto cit = cells.begin(); cit != cells.end(); cit++) {
656 if(dim == 2) deformChain(cells, *cit,
true);
657 deformChain(cells, *cit,
false);
660 deImmuneCells(cells);
661 eraseNullCells(cells);
663 if(size >= (
int)cells.size())
667 if(useless > 5)
break;
670 deImmuneCells(cells);
671 for(
auto cit = cells.begin(); cit != cells.end(); cit++) {
672 deformChain(cells, *cit,
false);
674 eraseNullCells(cells);
675 int size = cells.size();
676 Msg::Debug(
"Simplified a %d-chain from %d cells to %d cells", dim, start,
680 void ChainComplex::eraseNullCells(std::map<Cell *, int, CellPtrLessThan> &cells)
682 std::vector<Cell *> toRemove;
683 for(
auto cit = cells.begin(); cit != cells.end(); cit++) {
684 if(cit->second == 0) toRemove.push_back(cit->first);
686 for(std::size_t i = 0; i < toRemove.size(); i++) cells.erase(toRemove[i]);
689 void ChainComplex::deImmuneCells(std::map<Cell *, int, CellPtrLessThan> &cells)
691 for(
auto cit = cells.begin(); cit != cells.end(); cit++) {
692 Cell *cell = (*cit).first;